From 5fd821d59ee3e84d3f6d554e3242982cfa5a1a91 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Mon, 2 Feb 2015 12:16:31 +0100 Subject: [PATCH] More ember-cli compat in views --- assets/scripts/app/transforms/object.coffee | 4 +- .../scripts/app/utils/lines-selector.coffee | 4 +- assets/scripts/app/utils/log-chunks.coffee | 4 +- assets/scripts/app/utils/log-folder.coffee | 4 +- assets/scripts/app/vendor/log.js | 1075 +++++++++++++++++ assets/scripts/app/views/accounts-info.coffee | 11 + assets/scripts/app/views/accounts-list.coffee | 30 + assets/scripts/app/views/accounts.coffee | 34 - assets/scripts/app/views/annotation.coffee | 8 +- assets/scripts/app/views/annotations.coffee | 5 +- assets/scripts/app/views/application.coffee | 32 +- assets/scripts/app/views/build.coffee | 15 +- assets/scripts/app/views/dashboard.coffee | 4 +- assets/scripts/app/views/first-sync.coffee | 4 +- assets/scripts/app/views/flash-item.coffee | 15 + assets/scripts/app/views/flash.coffee | 21 +- assets/scripts/app/views/hooks.coffee | 12 + assets/scripts/app/views/jobs-item.coffee | 7 +- assets/scripts/app/views/left.coffee | 20 - assets/scripts/app/views/log.coffee | 164 +-- assets/scripts/app/views/pre.coffee | 113 ++ .../scripts/app/views/profile-accounts.coffee | 11 + assets/scripts/app/views/profile-tabs.coffee | 22 + assets/scripts/app/views/profile.coffee | 56 +- assets/scripts/app/views/repo.coffee | 7 +- assets/scripts/app/views/repos-list.coffee | 2 +- assets/scripts/app/views/signin.coffee | 9 +- assets/scripts/app/views/stats.coffee | 73 -- .../app/views/status-image-input.coffee | 4 +- assets/scripts/app/views/status-images.coffee | 7 +- assets/scripts/app/views/top.coffee | 42 +- assets/scripts/travis.coffee | 9 +- assets/scripts/vendor/log.js | 2 - 33 files changed, 1432 insertions(+), 398 deletions(-) create mode 100644 assets/scripts/app/vendor/log.js create mode 100644 assets/scripts/app/views/accounts-info.coffee create mode 100644 assets/scripts/app/views/accounts-list.coffee delete mode 100644 assets/scripts/app/views/accounts.coffee create mode 100644 assets/scripts/app/views/flash-item.coffee create mode 100644 assets/scripts/app/views/hooks.coffee delete mode 100644 assets/scripts/app/views/left.coffee create mode 100644 assets/scripts/app/views/pre.coffee create mode 100644 assets/scripts/app/views/profile-accounts.coffee create mode 100644 assets/scripts/app/views/profile-tabs.coffee delete mode 100644 assets/scripts/app/views/stats.coffee delete mode 100644 assets/scripts/vendor/log.js diff --git a/assets/scripts/app/transforms/object.coffee b/assets/scripts/app/transforms/object.coffee index 1b7d6e55..13fba95d 100644 --- a/assets/scripts/app/transforms/object.coffee +++ b/assets/scripts/app/transforms/object.coffee @@ -1,6 +1,8 @@ -Travis.ObjectTransform = DS.Transform.extend +Transform = DS.Transform.extend deserialize: (serialized) -> serialized serialize: (deserialized) -> deserialized + +Travis.ObjectTransform = Transform diff --git a/assets/scripts/app/utils/lines-selector.coffee b/assets/scripts/app/utils/lines-selector.coffee index 1f81002c..a70008ad 100644 --- a/assets/scripts/app/utils/lines-selector.coffee +++ b/assets/scripts/app/utils/lines-selector.coffee @@ -1,4 +1,4 @@ -class Travis.LinesSelector +class LinesSelector Location: getHash: -> window.location.hash @@ -71,3 +71,5 @@ class Travis.LinesSelector first = match[1] last = match[3] || match[1] {first: first, last: last} + +Travis.LinesSelector = LinesSelector diff --git a/assets/scripts/app/utils/log-chunks.coffee b/assets/scripts/app/utils/log-chunks.coffee index 9570ad4a..3689ba50 100644 --- a/assets/scripts/app/utils/log-chunks.coffee +++ b/assets/scripts/app/utils/log-chunks.coffee @@ -1,4 +1,4 @@ -Travis.LogChunks = Em.ArrayProxy.extend +LogChunks = Ember.ArrayProxy.extend timeout: 30000 init: -> @@ -80,3 +80,5 @@ Travis.LogChunks = Em.ArrayProxy.extend Ember.run.once this, -> @tryFinalizing() @resetTimeout() + +Travis.LogChunks = LogChunks diff --git a/assets/scripts/app/utils/log-folder.coffee b/assets/scripts/app/utils/log-folder.coffee index 1d1bb1be..22b7e86e 100644 --- a/assets/scripts/app/utils/log-folder.coffee +++ b/assets/scripts/app/utils/log-folder.coffee @@ -1,4 +1,4 @@ -class Travis.LogFolder +class LogFolder constructor: (@element) -> @element.on 'click', '.fold', (event) => folder = @getFolderFromLine $(event.target) @@ -22,3 +22,5 @@ class Travis.LogFolder getFolderFromLine: (line) -> line.parent('.fold') + + Travis.LogFolder = LogFolder diff --git a/assets/scripts/app/vendor/log.js b/assets/scripts/app/vendor/log.js new file mode 100644 index 00000000..496e44d1 --- /dev/null +++ b/assets/scripts/app/vendor/log.js @@ -0,0 +1,1075 @@ +var Log = function() { + this.autoCloseFold = true; + this.listeners = []; + this.renderer = new Log.Renderer; + this.children = new Log.Nodes(this); + this.parts = {}; + this.folds = new Log.Folds(this); + this.times = new Log.Times(this); + return this; +}; + +Log.extend = function(one, other) { + var name; + for (name in other) { + one[name] = other[name]; + } + return one; +}; + +Log.extend(Log, { + DEBUG: true, + SLICE: 500, + TIMEOUT: 25, + FOLD: /fold:(start|end):([\w_\-\.]+)/, + TIME: /time:(start|end):([\w_\-\.]+):?([\w_\-\.\=\,]*)/, + create: function(options) { + var listener, log, _i, _len, _ref; + options || (options = {}); + log = new Log(); + if (options.limit) { + log.listeners.push(log.limit = new Log.Limit(options.limit)); + } + _ref = options.listeners || []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + listener = _ref[_i]; + log.listeners.push(listener); + } + return log; + } +}); + +var newLineAtTheEndRegexp, newLineRegexp, rRegexp, removeCarriageReturns; + +Log.Node = function(id, num) { + this.id = id; + this.num = num; + this.key = Log.Node.key(this.id); + this.children = new Log.Nodes(this); + return this; +}; + +Log.extend(Log.Node, { + key: function(id) { + if (id) { + return id.split('-').map(function(i) { + return '000000'.concat(i).slice(-6); + }).join(''); + } + } +}); + +Log.extend(Log.Node.prototype, { + addChild: function(node) { + return this.children.add(node); + }, + remove: function() { + this.log.remove(this.element); + return this.parent.children.remove(this); + } +}); + +Object.defineProperty(Log.Node.prototype, 'log', { + get: function() { + var _ref; + return this._log || (this._log = ((_ref = this.parent) != null ? _ref.log : void 0) || this.parent); + } +}); + +Object.defineProperty(Log.Node.prototype, 'firstChild', { + get: function() { + return this.children.first; + } +}); + +Object.defineProperty(Log.Node.prototype, 'lastChild', { + get: function() { + return this.children.last; + } +}); + +Log.Nodes = function(parent) { + if (parent) { + this.parent = parent; + } + this.items = []; + this.index = {}; + return this; +}; + +Log.extend(Log.Nodes.prototype, { + add: function(item) { + var ix, next, prev, _ref, _ref1; + ix = this.position(item) || 0; + this.items.splice(ix, 0, item); + if (this.parent) { + item.parent = this.parent; + } + prev = function(item) { + while (item && !item.children.last) { + item = item.prev; + } + return item != null ? item.children.last : void 0; + }; + next = function(item) { + while (item && !item.children.first) { + item = item.next; + } + return item != null ? item.children.first : void 0; + }; + if (item.prev = this.items[ix - 1] || prev((_ref = this.parent) != null ? _ref.prev : void 0)) { + item.prev.next = item; + } + if (item.next = this.items[ix + 1] || next((_ref1 = this.parent) != null ? _ref1.next : void 0)) { + item.next.prev = item; + } + return item; + }, + remove: function(item) { + this.items.splice(this.items.indexOf(item), 1); + if (item.next) { + item.next.prev = item.prev; + } + if (item.prev) { + item.prev.next = item.next; + } + if (this.items.length === 0) { + return this.parent.remove(); + } + }, + position: function(item) { + var ix, _i, _ref; + for (ix = _i = _ref = this.items.length - 1; _i >= 0; ix = _i += -1) { + if (this.items[ix].key < item.key) { + return ix + 1; + } + } + }, + indexOf: function() { + return this.items.indexOf.apply(this.items, arguments); + }, + slice: function() { + return this.items.slice.apply(this.items, arguments); + }, + each: function(func) { + return this.items.slice().forEach(func); + }, + map: function(func) { + return this.items.map(func); + } +}); + +Object.defineProperty(Log.Nodes.prototype, 'first', { + get: function() { + return this.items[0]; + } +}); + +Object.defineProperty(Log.Nodes.prototype, 'last', { + get: function() { + return this.items[this.length - 1]; + } +}); + +Object.defineProperty(Log.Nodes.prototype, 'length', { + get: function() { + return this.items.length; + } +}); + +Log.Part = function(id, num, string) { + Log.Node.apply(this, arguments); + this.string = string || ''; + this.string = this.string.replace(/\033\[1000D/gm, '\r'); + this.string = this.string.replace(/\r+\n/gm, '\n'); + this.strings = this.string.split(/^/gm) || []; + this.slices = ((function() { + var _results; + _results = []; + while (this.strings.length > 0) { + _results.push(this.strings.splice(0, Log.SLICE)); + } + return _results; + }).call(this)); + return this; +}; + +Log.extend(Log.Part, { + create: function(log, num, string) { + var part; + part = new Log.Part(num.toString(), num, string); + log.addChild(part); + return part.process(0, -1); + } +}); + +Log.Part.prototype = Log.extend(new Log.Node, { + remove: function() {}, + process: function(slice, num) { + var node, span, spans, string, _i, _j, _len, _len1, _ref, _ref1, _ref2, _ref3, _ref4, + _this = this; + _ref = this.slices[slice] || []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + string = _ref[_i]; + if ((_ref1 = this.log.limit) != null ? _ref1.limited : void 0) { + return; + } + spans = []; + _ref2 = Log.Deansi.apply(string); + for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { + node = _ref2[_j]; + span = Log.Span.create(this, "" + this.id + "-" + (num += 1), num, node.text, node["class"]); + span.render(); + spans.push(span); + } + if ((_ref3 = spans[0]) != null ? (_ref4 = _ref3.line) != null ? _ref4.cr : void 0 : void 0) { + spans[0].line.clear(); + } + } + if (!(slice >= this.slices.length - 1)) { + return setTimeout((function() { + return _this.process(slice + 1, num); + }), Log.TIMEOUT); + } + } +}); + +newLineAtTheEndRegexp = new RegExp("\n$"); + +newLineRegexp = new RegExp("\n"); + +rRegexp = new RegExp("\r"); + +removeCarriageReturns = function(string) { + var index; + index = string.lastIndexOf("\r"); + if (index === -1) { + return string; + } + return string.substr(index + 1); +}; + +Log.Span = function(id, num, text, classes) { + var fold, time, _ref; + Log.Node.apply(this, arguments); + if (fold = text.match(Log.FOLD)) { + this.fold = true; + this.event = fold[1]; + this.text = this.name = fold[2]; + } else if (time = text.match(Log.TIME)) { + this.time = true; + this.event = time[1]; + this.name = time[2]; + this.stats = time[3]; + } else { + this.text = text; + this.text = removeCarriageReturns(this.text); + this.text = this.text.replace(newLineAtTheEndRegexp, ''); + this.nl = !!((_ref = text[text.length - 1]) != null ? _ref.match(newLineRegexp) : void 0); + this.cr = !!text.match(rRegexp); + this["class"] = this.cr && ['clears'] || classes; + } + return this; +}; + +Log.extend(Log.Span, { + create: function(parent, id, num, text, classes) { + var span; + span = new Log.Span(id, num, text, classes); + parent.addChild(span); + return span; + }, + render: function(parent, id, num, text, classes) { + var span; + span = this.create(parent, id, num, text, classes); + return span.render(); + } +}); + +Log.Span.prototype = Log.extend(new Log.Node, { + render: function() { + var tail; + if (this.time && this.event === 'end' && this.prev) { + if (Log.DEBUG) { + console.log("S.0 insert " + this.id + " after prev " + this.prev.id); + } + this.nl = this.prev.nl; + this.log.insert(this.data, { + after: this.prev.element + }); + this.line = this.prev.line; + } else if (!this.fold && this.prev && !this.prev.fold && !this.prev.nl) { + if (Log.DEBUG) { + console.log("S.1 insert " + this.id + " after prev " + this.prev.id); + } + this.log.insert(this.data, { + after: this.prev.element + }); + this.line = this.prev.line; + } else if (!this.fold && this.next && !this.next.fold && !this.next.time) { + if (Log.DEBUG) { + console.log("S.2 insert " + this.id + " before next " + this.next.id); + } + this.log.insert(this.data, { + before: this.next.element + }); + this.line = this.next.line; + } else { + this.line = Log.Line.create(this.log, [this]); + this.line.render(); + } + if (this.nl && (tail = this.tail).length > 0) { + this.split(tail); + } + if (this.time) { + return this.log.times.add(this); + } + }, + remove: function() { + Log.Node.prototype.remove.apply(this); + if (this.line) { + return this.line.remove(this); + } + }, + split: function(spans) { + var line, span, _i, _len; + if (Log.DEBUG) { + console.log("S.4 split [" + (spans.map(function(span) { + return span.id; + }).join(', ')) + "]"); + } + for (_i = 0, _len = spans.length; _i < _len; _i++) { + span = spans[_i]; + this.log.remove(span.element); + } + line = Log.Line.create(this.log, spans); + line.render(); + if (line.cr) { + return line.clear(); + } + }, + clear: function() { + if (this.prev && this.isSibling(this.prev) && this.isSequence(this.prev)) { + this.prev.clear(); + return this.prev.remove(); + } + }, + isSequence: function(other) { + return this.parent.num - other.parent.num === this.log.children.indexOf(this.parent) - this.log.children.indexOf(other.parent); + }, + isSibling: function(other) { + var _ref, _ref1; + return ((_ref = this.element) != null ? _ref.parentNode : void 0) === ((_ref1 = other.element) != null ? _ref1.parentNode : void 0); + }, + siblings: function(type) { + var siblings, span; + siblings = []; + while ((span = (span || this)[type]) && this.isSibling(span)) { + siblings.push(span); + } + return siblings; + } +}); + +Object.defineProperty(Log.Span.prototype, 'data', { + get: function() { + return { + id: this.id, + type: 'span', + text: this.text, + "class": this["class"], + time: this.time + }; + } +}); + +Object.defineProperty(Log.Span.prototype, 'line', { + get: function() { + return this._line; + }, + set: function(line) { + if (this.line) { + this.line.remove(this); + } + this._line = line; + if (this.line) { + return this.line.add(this); + } + } +}); + +Object.defineProperty(Log.Span.prototype, 'element', { + get: function() { + return document.getElementById(this.id); + } +}); + +Object.defineProperty(Log.Span.prototype, 'head', { + get: function() { + return this.siblings('prev').reverse(); + } +}); + +Object.defineProperty(Log.Span.prototype, 'tail', { + get: function() { + return this.siblings('next'); + } +}); + +Log.Line = function(log) { + this.log = log; + this.spans = []; + return this; +}; + +Log.extend(Log.Line, { + create: function(log, spans) { + var line, span, _i, _len; + if ((span = spans[0]) && span.fold) { + line = new Log.Fold(log, span.event, span.name); + } else { + line = new Log.Line(log); + } + for (_i = 0, _len = spans.length; _i < _len; _i++) { + span = spans[_i]; + span.line = line; + } + return line; + } +}); + +Log.extend(Log.Line.prototype, { + add: function(span) { + var ix; + if (span.cr) { + this.cr = true; + } + if (this.spans.indexOf(span) > -1) { + + } else if ((ix = this.spans.indexOf(span.prev)) > -1) { + return this.spans.splice(ix + 1, 0, span); + } else if ((ix = this.spans.indexOf(span.next)) > -1) { + return this.spans.splice(ix, 0, span); + } else { + return this.spans.push(span); + } + }, + remove: function(span) { + var ix; + if ((ix = this.spans.indexOf(span)) > -1) { + return this.spans.splice(ix, 1); + } + }, + render: function() { + var fold; + if ((fold = this.prev) && fold.event === 'start' && fold.active) { + if (this.next && !this.next.fold) { + if (Log.DEBUG) { + console.log("L.0 insert " + this.id + " before next " + this.next.id); + } + return this.element = this.log.insert(this.data, { + before: this.next.element + }); + } else { + if (Log.DEBUG) { + console.log("L.0 insert " + this.id + " into fold " + fold.id); + } + fold = this.log.folds.folds[fold.name].fold; + return this.element = this.log.insert(this.data, { + into: fold + }); + } + } else if (this.prev) { + if (Log.DEBUG) { + console.log("L.1 insert " + this.spans[0].id + " after prev " + this.prev.id); + } + return this.element = this.log.insert(this.data, { + after: this.prev.element + }); + } else if (this.next) { + if (Log.DEBUG) { + console.log("L.2 insert " + this.spans[0].id + " before next " + this.next.id); + } + return this.element = this.log.insert(this.data, { + before: this.next.element + }); + } else { + if (Log.DEBUG) { + console.log("L.3 insert " + this.spans[0].id + " into #log"); + } + return this.element = this.log.insert(this.data); + } + }, + clear: function() { + var cr, _i, _len, _ref, _results; + _ref = this.crs; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + cr = _ref[_i]; + _results.push(cr.clear()); + } + return _results; + } +}); + +Object.defineProperty(Log.Line.prototype, 'id', { + get: function() { + var _ref; + return (_ref = this.spans[0]) != null ? _ref.id : void 0; + } +}); + +Object.defineProperty(Log.Line.prototype, 'data', { + get: function() { + return { + type: 'paragraph', + nodes: this.nodes + }; + } +}); + +Object.defineProperty(Log.Line.prototype, 'nodes', { + get: function() { + return this.spans.map(function(span) { + return span.data; + }); + } +}); + +Object.defineProperty(Log.Line.prototype, 'prev', { + get: function() { + var _ref; + return (_ref = this.spans[0].prev) != null ? _ref.line : void 0; + } +}); + +Object.defineProperty(Log.Line.prototype, 'next', { + get: function() { + var _ref; + return (_ref = this.spans[this.spans.length - 1].next) != null ? _ref.line : void 0; + } +}); + +Object.defineProperty(Log.Line.prototype, 'crs', { + get: function() { + return this.spans.filter(function(span) { + return span.cr; + }); + } +}); + +Log.Fold = function(log, event, name) { + Log.Line.apply(this, arguments); + this.fold = true; + this.event = event; + this.name = name; + return this; +}; + +Log.Fold.prototype = Log.extend(new Log.Line, { + render: function() { + var element, _ref; + if (this.prev && this.prev.element) { + if (Log.DEBUG) { + console.log("F.1 insert " + this.id + " after prev " + this.prev.id); + } + element = this.prev.element; + this.element = this.log.insert(this.data, { + after: element + }); + } else if (this.next) { + if (Log.DEBUG) { + console.log("F.2 insert " + this.id + " before next " + this.next.id); + } + element = this.next.element || this.next.element.parentNode; + this.element = this.log.insert(this.data, { + before: element + }); + } else { + if (Log.DEBUG) { + console.log("F.3 insert " + this.id); + } + this.element = this.log.insert(this.data); + } + if (this.span.next && ((_ref = this.span.prev) != null ? _ref.isSibling(this.span.next) : void 0)) { + this.span.prev.split([this.span.next].concat(this.span.next.tail)); + } + return this.active = this.log.folds.add(this.data); + } +}); + +Object.defineProperty(Log.Fold.prototype, 'id', { + get: function() { + return "fold-" + this.event + "-" + this.name; + } +}); + +Object.defineProperty(Log.Fold.prototype, 'span', { + get: function() { + return this.spans[0]; + } +}); + +Object.defineProperty(Log.Fold.prototype, 'data', { + get: function() { + return { + type: 'fold', + id: this.id, + event: this.event, + name: this.name + }; + } +}); + +Log.prototype = Log.extend(new Log.Node, { + set: function(num, string) { + if (this.parts[num]) { + return console.log("part " + num + " exists"); + } else { + this.parts[num] = true; + return Log.Part.create(this, num, string); + } + }, + insert: function(data, pos) { + this.trigger('insert', data, pos); + return this.renderer.insert(data, pos); + }, + remove: function(node) { + this.trigger('remove', node); + return this.renderer.remove(node); + }, + hide: function(node) { + this.trigger('hide', node); + return this.renderer.hide(node); + }, + trigger: function() { + var args, ix, listener, _i, _len, _ref, _results; + args = [this].concat(Array.prototype.slice.apply(arguments)); + _ref = this.listeners; + _results = []; + for (ix = _i = 0, _len = _ref.length; _i < _len; ix = ++_i) { + listener = _ref[ix]; + _results.push(listener.notify.apply(listener, args)); + } + return _results; + } +}); + +Log.Listener = function() {}; + +Log.extend(Log.Listener.prototype, { + notify: function(log, event) { + if (this[event]) { + return this[event].apply(this, [log].concat(Array.prototype.slice.call(arguments, 2))); + } + } +}); + +Log.Folds = function(log) { + this.log = log; + this.folds = {}; + return this; +}; + +Log.extend(Log.Folds.prototype, { + add: function(data) { + var fold, _base, _name; + fold = (_base = this.folds)[_name = data.name] || (_base[_name] = new Log.Folds.Fold); + fold.receive(data, { + autoCloseFold: this.log.autoCloseFold + }); + return fold.active; + } +}); + +Log.Folds.Fold = function() { + return this; +}; + +Log.extend(Log.Folds.Fold.prototype, { + receive: function(data, options) { + this[data.event] = data.id; + if (this.start && this.end && !this.active) { + return this.activate(options); + } + }, + activate: function(options) { + var fragment, nextSibling, node, parentNode, toRemove, _i, _len, _ref; + options || (options = {}); + if (Log.DEBUG) { + console.log("F.n - activate " + this.start); + } + toRemove = this.fold.parentNode; + parentNode = toRemove.parentNode; + nextSibling = toRemove.nextSibling; + parentNode.removeChild(toRemove); + fragment = document.createDocumentFragment(); + _ref = this.nodes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + node = _ref[_i]; + fragment.appendChild(node); + } + this.fold.appendChild(fragment); + parentNode.insertBefore(toRemove, nextSibling); + this.fold.setAttribute('class', this.classes(options['autoCloseFold'])); + return this.active = true; + }, + classes: function(autoCloseFold) { + var classes; + classes = this.fold.getAttribute('class').split(' '); + classes.push('fold'); + if (!autoCloseFold) { + classes.push('open'); + } + if (this.fold.childNodes.length > 2) { + classes.push('active'); + } + return classes.join(' '); + } +}); + +Object.defineProperty(Log.Folds.Fold.prototype, 'fold', { + get: function() { + return this._fold || (this._fold = document.getElementById(this.start)); + } +}); + +Object.defineProperty(Log.Folds.Fold.prototype, 'nodes', { + get: function() { + var node, nodes; + node = this.fold; + nodes = []; + while ((node = node.nextSibling) && node.id !== this.end) { + nodes.push(node); + } + return nodes; + } +}); + +Log.Times = function(log) { + this.log = log; + this.times = {}; + return this; +}; + +Log.extend(Log.Times.prototype, { + add: function(node) { + var time, _base, _name; + time = (_base = this.times)[_name = node.name] || (_base[_name] = new Log.Times.Time); + return time.receive(node); + }, + duration: function(name) { + if (this.times[name]) { + return this.times[name].duration; + } + } +}); + +Log.Times.Time = function() { + return this; +}; + +Log.extend(Log.Times.Time.prototype, { + receive: function(node) { + this[node.event] = node; + if (Log.DEBUG) { + console.log("T.0 - " + node.event + " " + node.name); + } + if (this.start && this.end) { + return this.finish(); + } + }, + finish: function() { + var element; + if (Log.DEBUG) { + console.log("T.1 - finish " + this.start.name); + } + element = document.getElementById(this.start.id); + if (element) { + return this.update(element); + } + }, + update: function(element) { + element.setAttribute('class', 'duration'); + element.setAttribute('title', "This command finished after " + this.duration + " seconds."); + return element.lastChild.nodeValue = "" + this.duration + "s"; + } +}); + +Object.defineProperty(Log.Times.Time.prototype, 'duration', { + get: function() { + var duration; + duration = this.stats.duration / 1000 / 1000 / 1000; + return duration.toFixed(2); + } +}); + +Object.defineProperty(Log.Times.Time.prototype, 'stats', { + get: function() { + var stat, stats, _i, _len, _ref; + if (!(this.end && this.end.stats)) { + return {}; + } + stats = {}; + _ref = this.end.stats.split(','); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + stat = _ref[_i]; + stat = stat.split('='); + stats[stat[0]] = stat[1]; + } + return stats; + } +}); + +Log.Deansi = { + CLEAR_ANSI: /(?:\033)(?:\[0?c|\[[0356]n|\[7[lh]|\[\?25[lh]|\(B|H|\[(?:\d+(;\d+){,2})?G|\[(?:[12])?[JK]|[DM]|\[0K)/gm, + apply: function(string) { + var nodes, + _this = this; + if (!string) { + return []; + } + string = string.replace(this.CLEAR_ANSI, ''); + nodes = ansiparse(string).map(function(part) { + return _this.node(part); + }); + return nodes; + }, + node: function(part) { + var classes, node; + node = { + type: 'span', + text: part.text + }; + if (classes = this.classes(part)) { + node["class"] = classes.join(' '); + } + return node; + }, + classes: function(part) { + var result; + result = []; + result = result.concat(this.colors(part)); + if (result.length > 0) { + return result; + } + }, + colors: function(part) { + var colors; + colors = []; + if (part.foreground) { + colors.push(part.foreground); + } + if (part.background) { + colors.push("bg-" + part.background); + } + if (part.bold) { + colors.push('bold'); + } + if (part.italic) { + colors.push('italic'); + } + if (part.underline) { + colors.push('underline'); + } + return colors; + }, + hidden: function(part) { + if (part.text.match(/\r/)) { + part.text = part.text.replace(/^.*\r/gm, ''); + return true; + } + } +}; + +Log.Limit = function(max_lines) { + this.max_lines = max_lines || 1000; + return this; +}; + +Log.Limit.prototype = Log.extend(new Log.Listener, { + count: 0, + insert: function(log, node, pos) { + if (node.type === 'paragraph' && !node.hidden) { + return this.count += 1; + } + } +}); + +Object.defineProperty(Log.Limit.prototype, 'limited', { + get: function() { + return this.count >= this.max_lines; + } +}); + +Log.Renderer = function() { + this.frag = document.createDocumentFragment(); + this.para = this.createParagraph(); + this.span = this.createSpan(); + this.text = document.createTextNode(''); + this.fold = this.createFold(); + return this; +}; + +Log.extend(Log.Renderer.prototype, { + insert: function(data, pos) { + var after, before, into, node; + node = this.render(data); + if (into = pos != null ? pos.into : void 0) { + if (typeof into === 'String') { + into = document.getElementById(pos != null ? pos.into : void 0); + } + if (pos != null ? pos.prepend : void 0) { + this.prependTo(node, into); + } else { + this.appendTo(node, into); + } + } else if (after = pos != null ? pos.after : void 0) { + if (typeof after === 'String') { + after = document.getElementById(pos); + } + this.insertAfter(node, after); + } else if (before = pos != null ? pos.before : void 0) { + if (typeof before === 'String') { + before = document.getElementById(pos != null ? pos.before : void 0); + } + this.insertBefore(node, before); + } else { + this.insertBefore(node); + } + return node; + }, + hide: function(node) { + node.setAttribute('class', this.addClass(node.getAttribute('class'), 'hidden')); + return node; + }, + remove: function(node) { + if (node) { + node.parentNode.removeChild(node); + } + return node; + }, + render: function(data) { + var frag, node, type, _i, _len; + if (data instanceof Array) { + frag = this.frag.cloneNode(true); + for (_i = 0, _len = data.length; _i < _len; _i++) { + node = data[_i]; + node = this.render(node); + if (node) { + frag.appendChild(node); + } + } + return frag; + } else { + data.type || (data.type = 'paragraph'); + type = data.type[0].toUpperCase() + data.type.slice(1); + return this["render" + type](data); + } + }, + renderParagraph: function(data) { + var node, para, type, _i, _len, _ref; + para = this.para.cloneNode(true); + if (data.id) { + para.setAttribute('id', data.id); + } + if (data.hidden) { + para.setAttribute('style', 'display: none;'); + } + _ref = data.nodes || []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + node = _ref[_i]; + type = node.type[0].toUpperCase() + node.type.slice(1); + node = this["render" + type](node); + para.appendChild(node); + } + return para; + }, + renderFold: function(data) { + var fold; + fold = this.fold.cloneNode(true); + fold.setAttribute('id', data.id || ("fold-" + data.event + "-" + data.name)); + fold.setAttribute('class', "fold-" + data.event); + if (data.event === 'start') { + fold.lastChild.lastChild.nodeValue = data.name; + } else { + fold.removeChild(fold.lastChild); + } + return fold; + }, + renderSpan: function(data) { + var span; + span = this.span.cloneNode(true); + if (data.id) { + span.setAttribute('id', data.id); + } + if (data["class"]) { + span.setAttribute('class', data["class"]); + } + span.lastChild.nodeValue = data.text || ''; + return span; + }, + renderText: function(data) { + var text; + text = this.text.cloneNode(true); + text.nodeValue = data.text; + return text; + }, + createParagraph: function() { + var para; + para = document.createElement('p'); + para.appendChild(document.createElement('a')); + return para; + }, + createFold: function() { + var fold; + fold = document.createElement('div'); + fold.appendChild(this.createSpan()); + fold.lastChild.setAttribute('class', 'fold-name'); + return fold; + }, + createSpan: function() { + var span; + span = document.createElement('span'); + span.appendChild(document.createTextNode(' ')); + return span; + }, + insertBefore: function(node, other) { + var log; + if (other) { + return other.parentNode.insertBefore(node, other); + } else { + log = document.getElementById('log'); + return log.insertBefore(node, log.firstChild); + } + }, + insertAfter: function(node, other) { + if (other.nextSibling) { + return this.insertBefore(node, other.nextSibling); + } else { + return this.appendTo(node, other.parentNode); + } + }, + prependTo: function(node, other) { + if (other.firstChild) { + return other.insertBefore(node, other.firstChild); + } else { + return appendTo(node, other); + } + }, + appendTo: function(node, other) { + return other.appendChild(node); + }, + addClass: function(classes, string) { + if (classes != null ? classes.indexOf(string) : void 0) { + return; + } + if (classes) { + return "" + classes + " " + string; + } else { + return string; + } + } +}); + +window.Log = Log; diff --git a/assets/scripts/app/views/accounts-info.coffee b/assets/scripts/app/views/accounts-info.coffee new file mode 100644 index 00000000..e2b8a067 --- /dev/null +++ b/assets/scripts/app/views/accounts-info.coffee @@ -0,0 +1,11 @@ +BasicView = Travis.BasicView + +View = BasicView.extend + templateName: 'profile/tabs/user' + userBinding: 'controller.user' + + gravatarUrl: (-> + "#{location.protocol}//www.gravatar.com/avatar/#{@get('user.gravatarId')}?s=200&d=mm" + ).property('user.gravatarId') + +AccountsInfoView = View diff --git a/assets/scripts/app/views/accounts-list.coffee b/assets/scripts/app/views/accounts-list.coffee new file mode 100644 index 00000000..6a0ee89e --- /dev/null +++ b/assets/scripts/app/views/accounts-list.coffee @@ -0,0 +1,30 @@ +accountUrl = Travis.Urls.account + +View = Ember.CollectionView.extend + elementId: 'accounts' + accountBinding: 'content' + tagName: 'ul' + + emptyView: Ember.View.extend + template: Ember.Handlebars.compile('
Loading
') + + itemViewClass: Ember.View.extend + accountBinding: 'content' + typeBinding: 'content.type' + selectedBinding: 'account.selected' + + classNames: ['account'] + classNameBindings: ['type', 'selected'] + + name: (-> + @get('content.name') || @get('content.login') + ).property('content.login', 'content.name') + + urlAccount: (-> + accountUrl(@get('account.login')) + ).property('account.login') + + click: -> + @get('controller').transitionToRoute("account", @get('account.login')) + +AccountsListView = View diff --git a/assets/scripts/app/views/accounts.coffee b/assets/scripts/app/views/accounts.coffee deleted file mode 100644 index 5d479445..00000000 --- a/assets/scripts/app/views/accounts.coffee +++ /dev/null @@ -1,34 +0,0 @@ -@Travis.reopen - ProfileAccountsView: Travis.BasicView.extend - tabBinding: 'controller.tab' - templateName: 'profile/accounts' - classAccounts: (-> - 'active' if @get('tab') == 'accounts' - ).property('tab') - - AccountsListView: Em.CollectionView.extend - elementId: 'accounts' - accountBinding: 'content' - tagName: 'ul' - - emptyView: Ember.View.extend - template: Ember.Handlebars.compile('
Loading
') - - itemViewClass: Travis.BasicView.extend - accountBinding: 'content' - typeBinding: 'content.type' - selectedBinding: 'account.selected' - - classNames: ['account'] - classNameBindings: ['type', 'selected'] - - name: (-> - @get('content.name') || @get('content.login') - ).property('content.login', 'content.name') - - urlAccount: (-> - Travis.Urls.account(@get('account.login')) - ).property('account.login') - - click: -> - @get('controller').transitionToRoute("account", @get('account.login')) diff --git a/assets/scripts/app/views/annotation.coffee b/assets/scripts/app/views/annotation.coffee index b3afe483..3ae89392 100644 --- a/assets/scripts/app/views/annotation.coffee +++ b/assets/scripts/app/views/annotation.coffee @@ -1,4 +1,6 @@ -Travis.reopen - AnnotationsView: Travis.BasicView.extend - templateName: 'annotations/list' +BasicView = Travis.BasicView +View = BasicView.extend + templateName: 'annotations/list' + +Travis.AnnotationsView = View diff --git a/assets/scripts/app/views/annotations.coffee b/assets/scripts/app/views/annotations.coffee index ac8376a0..5045bd7d 100644 --- a/assets/scripts/app/views/annotations.coffee +++ b/assets/scripts/app/views/annotations.coffee @@ -1,2 +1,3 @@ -Travis.reopen - AnnotationsView: Travis.BasicView.extend +View = Ember.View.extend() + +Travis.AnnotationsView = View diff --git a/assets/scripts/app/views/application.coffee b/assets/scripts/app/views/application.coffee index fd595908..f6581f30 100644 --- a/assets/scripts/app/views/application.coffee +++ b/assets/scripts/app/views/application.coffee @@ -1,17 +1,19 @@ -Travis.reopen - ApplicationView: Travis.BasicView.extend - classNames: ['application'] - click: (event) -> - # TODO: this solves the case of closing menus and popups, - # but I would like to rewrite it later, not sure how - # yet, but this does not seem optimal - targetAndParents = $(event.target).parents().andSelf() - if ! ( targetAndParents.hasClass('open-popup') || targetAndParents.hasClass('popup') ) - @popupCloseAll() +BasicView = Travis.BasicView - # TODO: I needed to add second check to this conditional, because for some reason - # event.stopPropagation() in menu() function in RepoShowToolsView does - # not prevent calling following code - if ! targetAndParents.hasClass('menu') && !targetAndParents.is('#tools > a') - $('.menu').removeClass('display') +View = BasicView.extend + classNames: ['application'] + click: (event) -> + # TODO: this solves the case of closing menus and popups, + # but I would like to rewrite it later, not sure how + # yet, but this does not seem optimal + targetAndParents = $(event.target).parents().andSelf() + if ! ( targetAndParents.hasClass('open-popup') || targetAndParents.hasClass('popup') ) + @popupCloseAll() + # TODO: I needed to add second check to this conditional, because for some reason + # event.stopPropagation() in menu() function in RepoShowToolsView does + # not prevent calling following code + if ! targetAndParents.hasClass('menu') && !targetAndParents.is('#tools > a') + $('.menu').removeClass('display') + +ApplicationView = View diff --git a/assets/scripts/app/views/build.coffee b/assets/scripts/app/views/build.coffee index 1ef531c9..1e062f38 100644 --- a/assets/scripts/app/views/build.coffee +++ b/assets/scripts/app/views/build.coffee @@ -1,12 +1,13 @@ colorForState = Travis.Helpers.colorForState +BasicView = Travis.BasicView -View = Travis.BasicView.extend - classNameBindings: ['color', 'loading'] - buildBinding: 'controller.build' - loadingBinding: 'controller.loading' +View = BasicView.extend + classNameBindings: ['color', 'loading'] + buildBinding: 'controller.build' + loadingBinding: 'controller.loading' - color: (-> - colorForState(@get('build.state')) - ).property('build.state') + color: (-> + colorForState(@get('build.state')) + ).property('build.state') Travis.BuildView = View diff --git a/assets/scripts/app/views/dashboard.coffee b/assets/scripts/app/views/dashboard.coffee index 3cc467af..09081a55 100644 --- a/assets/scripts/app/views/dashboard.coffee +++ b/assets/scripts/app/views/dashboard.coffee @@ -1,8 +1,6 @@ require 'views/basic' -TravisView = Travis.BasicView - -View = TravisView.extend +View = Ember.View.extend layoutName: 'layouts/dashboard' classNames: ['dashboard'] diff --git a/assets/scripts/app/views/first-sync.coffee b/assets/scripts/app/views/first-sync.coffee index 88c61a0f..18934520 100644 --- a/assets/scripts/app/views/first-sync.coffee +++ b/assets/scripts/app/views/first-sync.coffee @@ -1,4 +1,6 @@ -View = Travis.BasicView.extend +BasicView = Travis.BasicView + +View = BasicView.extend layoutName: 'layouts/simple' Travis.FirstSyncView = View diff --git a/assets/scripts/app/views/flash-item.coffee b/assets/scripts/app/views/flash-item.coffee new file mode 100644 index 00000000..7ae2bc66 --- /dev/null +++ b/assets/scripts/app/views/flash-item.coffee @@ -0,0 +1,15 @@ +BasicView = Travis.BasicView + +View = BasicView.extend + tagName: 'li' + classNameBindings: ['type'] + + type: (-> + @get('flash.type') || 'broadcast' + ).property('flash.type') + + actions: + close: -> + @get('controller').close(@get('flash')) + +FlashItemView = View diff --git a/assets/scripts/app/views/flash.coffee b/assets/scripts/app/views/flash.coffee index b1fe7451..7bad9961 100644 --- a/assets/scripts/app/views/flash.coffee +++ b/assets/scripts/app/views/flash.coffee @@ -1,17 +1,8 @@ -@Travis.reopen - FlashView: Travis.BasicView.extend - classNames: ['flash'] - tagName: 'ul' - templateName: 'layouts/flash' +BasicView = Travis.BasicView - FlashItemView: Travis.BasicView.extend - tagName: 'li' - classNameBindings: ['type'] +View = BasicView.extend + classNames: ['flash'] + tagName: 'ul' + templateName: 'layouts/flash' - type: (-> - @get('flash.type') || 'broadcast' - ).property('flash.type') - - actions: - close: -> - @get('controller').close(@get('flash')) +Travis.FlashView = View diff --git a/assets/scripts/app/views/hooks.coffee b/assets/scripts/app/views/hooks.coffee new file mode 100644 index 00000000..bdca93a9 --- /dev/null +++ b/assets/scripts/app/views/hooks.coffee @@ -0,0 +1,12 @@ +BasicView = Travis.BasicView +githubAdminUrl = Travis.Urls.githubAdmin + +View = BasicView.extend + templateName: 'profile/tabs/hooks' + userBinding: 'controller.user' + + urlGithubAdmin: (-> + githubAdminUrl(@get('hook.slug')) + ).property('hook.slug') + +HooksView = View diff --git a/assets/scripts/app/views/jobs-item.coffee b/assets/scripts/app/views/jobs-item.coffee index 77fff83d..e9ca8e8d 100644 --- a/assets/scripts/app/views/jobs-item.coffee +++ b/assets/scripts/app/views/jobs-item.coffee @@ -1,11 +1,14 @@ -View = Travis.BasicView.extend +colorForState = Travis.Helpers.colorForState +BasicView = Travis.BasicView + +View = BasicView.extend tagName: 'tr' classNameBindings: ['color'] repoBinding: 'context.repo' jobBinding: 'context' color: (-> - Travis.Helpers.colorForState(@get('job.state')) + colorForState(@get('job.state')) ).property('job.state') Travis.JobsItemView = View diff --git a/assets/scripts/app/views/left.coffee b/assets/scripts/app/views/left.coffee deleted file mode 100644 index 02c9eba9..00000000 --- a/assets/scripts/app/views/left.coffee +++ /dev/null @@ -1,20 +0,0 @@ -@Travis.reopen - ReposView: Travis.BasicView.extend - templateName: 'repos/list' - tabBinding: 'controller.tab' - - classRecent: (-> - 'active' if @get('tab') == 'recent' - ).property('tab') - - classOwned: (-> - classes = [] - classes.push('active') if @get('tab') == 'owned' - classes.push('display') if @get('controller.currentUser') - classes.join(' ') - ).property('tab', 'controller.currentUser') - - classSearch: (-> - 'active' if @get('tab') == 'search' - ).property('tab') - diff --git a/assets/scripts/app/views/log.coffee b/assets/scripts/app/views/log.coffee index c0241462..9b6a0a36 100644 --- a/assets/scripts/app/views/log.coffee +++ b/assets/scripts/app/views/log.coffee @@ -1,153 +1,35 @@ -require 'log' -require 'utils/lines-selector' -require 'utils/log-folder' +BasicView = Travis.BasicView Log.DEBUG = false Log.LIMIT = 10000 - config = ENV.config -Travis.reopen - LogView: Travis.BasicView.extend - templateName: 'jobs/log' - logBinding: 'job.log' +View = BasicView.extend + templateName: 'jobs/log' + logBinding: 'job.log' - didInsertElement: -> - @setupLog() + didInsertElement: -> + @setupLog() - logDidChange: (-> - @setupLog() - ).observes('log') + logDidChange: (-> + @setupLog() + ).observes('log') - logWillChange: (-> - @teardownLog() - ).observesBefore('log') + logWillChange: (-> + @teardownLog() + ).observesBefore('log') - willDestroyElement: -> - @teardownLog() + willDestroyElement: -> + @teardownLog() - teardownLog: -> - job = @get('job') - job.unsubscribe() if job + teardownLog: -> + job = @get('job') + job.unsubscribe() if job - setupLog: -> - job = @get('job') - if job - job.get('log').fetch() - job.subscribe() + setupLog: -> + job = @get('job') + if job + job.get('log').fetch() + job.subscribe() - PreView: Em.View.extend - templateName: 'jobs/pre' - - logWillChange: (-> - console.log 'log view: log will change' if Log.DEBUG - @teardownLog() - ).observesBefore('log') - - didInsertElement: -> - console.log 'log view: did insert' if Log.DEBUG - @_super.apply this, arguments - @createEngine() - - willDestroyElement: -> - console.log 'log view: will destroy' if Log.DEBUG - @teardownLog() - - versionDidChange: (-> - @rerender() if @get('_state') == 'inDOM' - ).observes('log.version') - - logDidChange: (-> - console.log 'log view: log did change: rerender' if Log.DEBUG - - if @get('log') - @createEngine() - @rerender() if @get('_state') == 'inDOM' - ).observes('log') - - teardownLog: -> - if log = @get('log') - parts = log.get('parts') - parts.removeArrayObserver(@, didChange: 'partsDidChange', willChange: 'noop') - parts.destroy() - log.notifyPropertyChange('parts') - @lineSelector?.willDestroy() - - createEngine: -> - if @get('log') - console.log 'log view: create engine' if Log.DEBUG - @scroll = new Log.Scroll beforeScroll: => - @unfoldHighlight() - @engine = Log.create(limit: Log.LIMIT, listeners: [@scroll]) - @logFolder = new Travis.LogFolder(@$().find('#log')) - @lineSelector = new Travis.LinesSelector(@$().find('#log'), @scroll, @logFolder) - @observeParts() - - unfoldHighlight: -> - @lineSelector.unfoldLines() - - observeParts: -> - if log = @get('log') - parts = log.get('parts') - parts.addArrayObserver(@, didChange: 'partsDidChange', willChange: 'noop') - parts = parts.slice(0) - @partsDidChange(parts, 0, null, parts.length) - - partsDidChange: (parts, start, _, added) -> - console.log 'log view: parts did change' if Log.DEBUG - for part, i in parts.slice(start, start + added) - # console.log "limit in log view: #{@get('limited')}" - break if @get('limited') - @engine.set(part.number, part.content) - @propertyDidChange('limited') - - limited: (-> - @engine?.limit?.limited - ).property() - - plainTextLogUrl: (-> - if id = @get('log.job.id') - url = Travis.Urls.plainTextLog(id) - if config.pro - url += "&access_token=#{@get('job.log.token')}" - url - ).property('job.log.id', 'job.log.token') - - actions: - toTop: () -> - $(window).scrollTop(0) - - toggleTailing: -> - Travis.tailing.toggle() - @engine.autoCloseFold = !Travis.tailing.isActive() - event.preventDefault() - - noop: -> # TODO required? - -Log.Scroll = (options) -> - options ||= {} - @beforeScroll = options.beforeScroll - this -Log.Scroll.prototype = $.extend new Log.Listener, - insert: (log, data, pos) -> - @tryScroll() if @numbers - true - - tryScroll: -> - if element = $("#log p:visible.highlight:first") - if @beforeScroll - @beforeScroll() - $('#main').scrollTop(0) - $('html, body').scrollTop(element.offset()?.top - (window.innerHeight / 3)) # weird, html works in chrome, body in firefox - -# Log.Logger = -> -# Log.Logger.prototype = $.extend new Log.Listener, -# receive: (log, num, string) -> -# @log("rcv #{num} #{JSON.stringify(string)}") -# true -# insert: (log, element, pos) -> -# @log("ins #{element.id}, #{if pos.before then 'before' else 'after'}: #{pos.before || pos.after || '?'}, #{JSON.stringify(element)}") -# remove: (log, element) -> -# @log("rem #{element.id}") -# log: (line) -> -# console.log(line) +Travis.LogView = View diff --git a/assets/scripts/app/views/pre.coffee b/assets/scripts/app/views/pre.coffee new file mode 100644 index 00000000..d7bb8d48 --- /dev/null +++ b/assets/scripts/app/views/pre.coffee @@ -0,0 +1,113 @@ +require 'utils/lines-selector' +require 'utils/log-folder' + +config = ENV.config +plainTextLogUrl = Travis.Urls.plainTextLog +LogFolder = Travis.LogFolder +LinesSelector = Travis.LinesSelector + +Log.Scroll = (options) -> + options ||= {} + @beforeScroll = options.beforeScroll + this +Log.Scroll.prototype = $.extend new Log.Listener, + insert: (log, data, pos) -> + @tryScroll() if @numbers + true + + tryScroll: -> + if element = $("#log p:visible.highlight:first") + if @beforeScroll + @beforeScroll() + $('#main').scrollTop(0) + $('html, body').scrollTop(element.offset()?.top - (window.innerHeight / 3)) # weird, html works in chrome, body in firefox + +View = Ember.View.extend + templateName: 'jobs/pre' + + logWillChange: (-> + console.log 'log view: log will change' if Log.DEBUG + @teardownLog() + ).observesBefore('log') + + didInsertElement: -> + console.log 'log view: did insert' if Log.DEBUG + @_super.apply this, arguments + @createEngine() + + willDestroyElement: -> + console.log 'log view: will destroy' if Log.DEBUG + @teardownLog() + + versionDidChange: (-> + @rerender() if @get('_state') == 'inDOM' + ).observes('log.version') + + logDidChange: (-> + console.log 'log view: log did change: rerender' if Log.DEBUG + + if @get('log') + @createEngine() + @rerender() if @get('_state') == 'inDOM' + ).observes('log') + + teardownLog: -> + if log = @get('log') + parts = log.get('parts') + parts.removeArrayObserver(@, didChange: 'partsDidChange', willChange: 'noop') + parts.destroy() + log.notifyPropertyChange('parts') + @lineSelector?.willDestroy() + + createEngine: -> + if @get('log') + console.log 'log view: create engine' if Log.DEBUG + @scroll = new Log.Scroll beforeScroll: => + @unfoldHighlight() + @engine = Log.create(limit: Log.LIMIT, listeners: [@scroll]) + @logFolder = new LogFolder(@$().find('#log')) + @lineSelector = new LinesSelector(@$().find('#log'), @scroll, @logFolder) + @observeParts() + + unfoldHighlight: -> + @lineSelector.unfoldLines() + + observeParts: -> + if log = @get('log') + parts = log.get('parts') + parts.addArrayObserver(@, didChange: 'partsDidChange', willChange: 'noop') + parts = parts.slice(0) + @partsDidChange(parts, 0, null, parts.length) + + partsDidChange: (parts, start, _, added) -> + console.log 'log view: parts did change' if Log.DEBUG + for part, i in parts.slice(start, start + added) + # console.log "limit in log view: #{@get('limited')}" + break if @get('limited') + @engine.set(part.number, part.content) + @propertyDidChange('limited') + + limited: (-> + @engine?.limit?.limited + ).property() + + plainTextLogUrl: (-> + if id = @get('log.job.id') + url = plainTextLogUrl(id) + if config.pro + url += "&access_token=#{@get('job.log.token')}" + url + ).property('job.log.id', 'job.log.token') + + actions: + toTop: () -> + $(window).scrollTop(0) + + toggleTailing: -> + Travis.tailing.toggle() + @engine.autoCloseFold = !Travis.tailing.isActive() + event.preventDefault() + + noop: -> # TODO required? + +Travis.PreView = View diff --git a/assets/scripts/app/views/profile-accounts.coffee b/assets/scripts/app/views/profile-accounts.coffee new file mode 100644 index 00000000..c76b8e47 --- /dev/null +++ b/assets/scripts/app/views/profile-accounts.coffee @@ -0,0 +1,11 @@ +BasicView = Travis.BasicView + +View = BasicView.extend + tabBinding: 'controller.tab' + templateName: 'profile/accounts' + classAccounts: (-> + 'active' if @get('tab') == 'accounts' + ).property('tab') + + +ProfileAccountsView = View diff --git a/assets/scripts/app/views/profile-tabs.coffee b/assets/scripts/app/views/profile-tabs.coffee new file mode 100644 index 00000000..fda52920 --- /dev/null +++ b/assets/scripts/app/views/profile-tabs.coffee @@ -0,0 +1,22 @@ +BasicView = Travis.BasicView + +View = BasicView.extend + templateName: 'profile/tabs' + tabBinding: 'controller.tab' + + activate: -> + @get('controller').activate(event.target.name) + + classHooks: (-> + 'active' if @get('tab') == 'hooks' + ).property('tab') + + classUser: (-> + 'active' if @get('tab') == 'user' + ).property('tab') + + displayUser: (-> + @get('controller.account.login') == @get('controller.user.login') + ).property('controller.account.login', 'controller.user.login') + +ProfileTabsView = View diff --git a/assets/scripts/app/views/profile.coffee b/assets/scripts/app/views/profile.coffee index dadf0518..cb59eb84 100644 --- a/assets/scripts/app/views/profile.coffee +++ b/assets/scripts/app/views/profile.coffee @@ -1,47 +1,15 @@ -Travis.reopen - ProfileView: Travis.BasicView.extend - templateName: 'profile/show' - layoutName: 'layouts/profile' - classNames: ['profile-view'] - accountBinding: 'controller.account' - subscribedBinding: 'account.subscribed' - educationBinding: 'account.education' +BasicView = Travis.BasicView - name: (-> - @get('account.name') || @get('account.login') - ).property('account.name', 'account.login') +View = BasicView.extend + templateName: 'profile/show' + layoutName: 'layouts/profile' + classNames: ['profile-view'] + accountBinding: 'controller.account' + subscribedBinding: 'account.subscribed' + educationBinding: 'account.education' - ProfileTabsView: Travis.BasicView.extend - templateName: 'profile/tabs' - tabBinding: 'controller.tab' + name: (-> + @get('account.name') || @get('account.login') + ).property('account.name', 'account.login') - activate: -> - @get('controller').activate(event.target.name) - - classHooks: (-> - 'active' if @get('tab') == 'hooks' - ).property('tab') - - classUser: (-> - 'active' if @get('tab') == 'user' - ).property('tab') - - displayUser: (-> - @get('controller.account.login') == @get('controller.user.login') - ).property('controller.account.login', 'controller.user.login') - - HooksView: Travis.BasicView.extend - templateName: 'profile/tabs/hooks' - userBinding: 'controller.user' - - urlGithubAdmin: (-> - Travis.Urls.githubAdmin(@get('hook.slug')) - ).property('hook.slug') - - AccountsInfoView: Travis.BasicView.extend - templateName: 'profile/tabs/user' - userBinding: 'controller.user' - - gravatarUrl: (-> - "#{location.protocol}//www.gravatar.com/avatar/#{@get('user.gravatarId')}?s=200&d=mm" - ).property('user.gravatarId') +ProfileView = View diff --git a/assets/scripts/app/views/repo.coffee b/assets/scripts/app/views/repo.coffee index 9f8c309d..58ce2672 100644 --- a/assets/scripts/app/views/repo.coffee +++ b/assets/scripts/app/views/repo.coffee @@ -1,8 +1,9 @@ statusImage = Travis.Urls.statusImage StatusImagesView = Travis.StatusImagesView config = ENV.config +BasicView = Travis.BasicView -View = Travis.BasicView.extend +View = BasicView.extend reposBinding: 'controllers.repos' repoBinding: 'controller.repo' buildBinding: 'controller.build' @@ -23,11 +24,11 @@ View = Travis.BasicView.extend statusImages: () -> @popupCloseAll() view = StatusImagesView.create(toolsView: this) - Travis.BasicView.currentPopupView = view + BasicView.currentPopupView = view view.appendTo($('body')) return false - ReposEmptyView: Travis.BasicView.extend + ReposEmptyView: BasicView.extend template: (-> if config.pro 'pro/repos/show/empty' diff --git a/assets/scripts/app/views/repos-list.coffee b/assets/scripts/app/views/repos-list.coffee index 4d38d6ba..a4e7c6ee 100644 --- a/assets/scripts/app/views/repos-list.coffee +++ b/assets/scripts/app/views/repos-list.coffee @@ -1,6 +1,6 @@ colorForState = Travis.Helpers.colorForState -View = Em.CollectionView.extend +View = Ember.CollectionView.extend elementId: 'repos' tagName: 'ul' diff --git a/assets/scripts/app/views/signin.coffee b/assets/scripts/app/views/signin.coffee index 3365fcfa..b6e975db 100644 --- a/assets/scripts/app/views/signin.coffee +++ b/assets/scripts/app/views/signin.coffee @@ -1,3 +1,6 @@ -@Travis.reopen - SigninView: Travis.BasicView.extend - templateName: 'auth/signin' +BasicView = Travis.BasicView + +View = BasicView.extend + templateName: 'auth/signin' + +Travis.SigninView = View diff --git a/assets/scripts/app/views/stats.coffee b/assets/scripts/app/views/stats.coffee deleted file mode 100644 index 7043e232..00000000 --- a/assets/scripts/app/views/stats.coffee +++ /dev/null @@ -1,73 +0,0 @@ -@Travis.reopen - StatsView: Travis.BasicView.extend - templateName: 'stats/show' - didInsertElement: -> - # @renderChart(config) for name, config of @CHARTS - - renderChart: (config) -> - chart = new Highcharts.Chart(config) - @fetch config.source, (data) -> - stats = (config.map(stats) for stats in data.stats) - chart.series[0].setData(stats) - - fetch: (url, callback) -> - $.ajax - type: 'GET' - url: url - accepts: { json: 'application/vnd.travis-ci.2+json' } - success: callback - - CHARTS: - repos: - source: '/api/stats/repos' - total: 0 - map: (data) -> - [Date.parse(data.date), @total += parseInt(data.count)] - chart: - renderTo: "repos_stats" - title: - text: "Total Projects/Repositories" - xAxis: - type: "datetime" - dateTimeLabelFormats: # don't display the dummy year - month: "%e. %b" - year: "%b" - yAxis: - title: - text: "Count" - min: 0 - tooltip: - formatter: -> - Highcharts.dateFormat("%e. %b", @x) + ": " + @y + " repos" - series: [ - name: "Repository Growth" - data: [] - ] - - builds: - source: '/api/stats/tests' - map: (data) -> - [Date.parse(data.date), parseInt(data.count)] - chart: - renderTo: "tests_stats" - type: "column" - title: - text: "Build Count" - subtitle: - text: "last month" - xAxis: - type: "datetime" - dateTimeLabelFormats: # don't display the dummy year - month: "%e. %b" - year: "%b" - yAxis: - title: - text: "Count" - min: 0 - tooltip: - formatter: -> - Highcharts.dateFormat("%e. %b", @x) + ": " + @y + " builds" - series: [ - name: "Total Builds" - data: [] - ] diff --git a/assets/scripts/app/views/status-image-input.coffee b/assets/scripts/app/views/status-image-input.coffee index dd8c4530..69b77117 100644 --- a/assets/scripts/app/views/status-image-input.coffee +++ b/assets/scripts/app/views/status-image-input.coffee @@ -1,3 +1,5 @@ -Travis.StatusImageInput = Em.TextArea.extend +View = Ember.TextArea.extend click: -> @get('element').select() + +Travis.StatusImageInput = View diff --git a/assets/scripts/app/views/status-images.coffee b/assets/scripts/app/views/status-images.coffee index f3e733e5..f851ad21 100644 --- a/assets/scripts/app/views/status-images.coffee +++ b/assets/scripts/app/views/status-images.coffee @@ -1,4 +1,6 @@ -Travis.StatusImagesView = Em.View.extend +format = Travis.StatusImageFormats.format + +View = Ember.View.extend templateName: 'status_images' elementId: 'status-images' classNames: ['popup'] @@ -46,6 +48,7 @@ Travis.StatusImagesView = Em.View.extend ).observes('repo.branches', 'repo.branches.isLoaded', 'build.commit.branch') statusString: (-> - Travis.StatusImageFormatter.format(@get('statusImageFormat'), @get('repo.slug'), @get('statusImageBranch.commit.branch')) + format(@get('statusImageFormat'), @get('repo.slug'), @get('statusImageBranch.commit.branch')) ).property('statusImageFormat', 'repo.slug', 'statusImageBranch.commit.branch') +Travis.StatusImagesView = View diff --git a/assets/scripts/app/views/top.coffee b/assets/scripts/app/views/top.coffee index 7ddcb7ce..be1fcc39 100644 --- a/assets/scripts/app/views/top.coffee +++ b/assets/scripts/app/views/top.coffee @@ -1,26 +1,28 @@ -@Travis.reopen - TopView: Travis.BasicView.extend - tabBinding: 'controller.tab' +BasicView = Travis.BasicView - # hrm. how to parametrize bind-attr? - classHome: (-> - 'active' if @get('tab') == 'home' - ).property('tab') +View = BasicView.extend + tabBinding: 'controller.tab' - classStats: (-> - 'active' if @get('tab') == 'stats' - ).property('tab') + # hrm. how to parametrize bind-attr? + classHome: (-> + 'active' if @get('tab') == 'home' + ).property('tab') - classProfile: (-> - classes = ['profile menu'] - classes.push('active') if @get('tab') == 'profile' - classes.push(@get('controller.auth.state') || 'signed-out') - classes.join(' ') - ).property('tab', 'controller.auth.state') + classStats: (-> + 'active' if @get('tab') == 'stats' + ).property('tab') - showProfile: -> - $('#top .profile ul').show() + classProfile: (-> + classes = ['profile menu'] + classes.push('active') if @get('tab') == 'profile' + classes.push(@get('controller.auth.state') || 'signed-out') + classes.join(' ') + ).property('tab', 'controller.auth.state') - hideProfile: -> - $('#top .profile ul').hide() + showProfile: -> + $('#top .profile ul').show() + hideProfile: -> + $('#top .profile ul').hide() + +Travis.TopView = View diff --git a/assets/scripts/travis.coffee b/assets/scripts/travis.coffee index c16a518f..dfcb1c21 100644 --- a/assets/scripts/travis.coffee +++ b/assets/scripts/travis.coffee @@ -182,8 +182,13 @@ require 'models/user' require 'models/env-var' require 'models/ssh-key' +require 'vendor/log' + require 'views/basic' -require 'views/accounts' +require 'views/flash-item' +require 'views/accounts-info' +require 'views/hooks' +require 'views/pre' require 'views/annotation' require 'views/application' require 'views/build' @@ -199,7 +204,7 @@ require 'views/repo-show-tools' require 'views/repo-show-tabs' require 'views/repo-actions' require 'views/profile' -require 'views/stats' +require 'views/profile-tabs' require 'views/signin' require 'views/top' require 'views/status-images' diff --git a/assets/scripts/vendor/log.js b/assets/scripts/vendor/log.js deleted file mode 100644 index 715e47b5..00000000 --- a/assets/scripts/vendor/log.js +++ /dev/null @@ -1,2 +0,0 @@ -minispade.register('log', "(function() {(function() {\n\n this.Log = function() {\n this.autoCloseFold = true;\n this.listeners = [];\n this.renderer = new Log.Renderer;\n this.children = new Log.Nodes(this);\n this.parts = {};\n this.folds = new Log.Folds(this);\n this.times = new Log.Times(this);\n return this;\n };\n\n Log.extend = function(one, other) {\n var name;\n for (name in other) {\n one[name] = other[name];\n }\n return one;\n };\n\n Log.extend(Log, {\n DEBUG: true,\n SLICE: 500,\n TIMEOUT: 25,\n FOLD: /fold:(start|end):([\\w_\\-\\.]+)/,\n TIME: /time:(start|end):([\\w_\\-\\.]+):?([\\w_\\-\\.\\=\\,]*)/,\n create: function(options) {\n var listener, log, _i, _len, _ref;\n options || (options = {});\n log = new Log();\n if (options.limit) {\n log.listeners.push(log.limit = new Log.Limit(options.limit));\n }\n _ref = options.listeners || [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n listener = _ref[_i];\n log.listeners.push(listener);\n }\n return log;\n }\n });\nminispade.require('log/nodes');\n\n Log.prototype = Log.extend(new Log.Node, {\n set: function(num, string) {\n if (this.parts[num]) {\n return console.log(\"part \" + num + \" exists\");\n } else {\n this.parts[num] = true;\n return Log.Part.create(this, num, string);\n }\n },\n insert: function(data, pos) {\n this.trigger('insert', data, pos);\n return this.renderer.insert(data, pos);\n },\n remove: function(node) {\n this.trigger('remove', node);\n return this.renderer.remove(node);\n },\n hide: function(node) {\n this.trigger('hide', node);\n return this.renderer.hide(node);\n },\n trigger: function() {\n var args, ix, listener, _i, _len, _ref, _results;\n args = [this].concat(Array.prototype.slice.apply(arguments));\n _ref = this.listeners;\n _results = [];\n for (ix = _i = 0, _len = _ref.length; _i < _len; ix = ++_i) {\n listener = _ref[ix];\n _results.push(listener.notify.apply(listener, args));\n }\n return _results;\n }\n });\n\n Log.Listener = function() {};\n\n Log.extend(Log.Listener.prototype, {\n notify: function(log, event) {\n if (this[event]) {\n return this[event].apply(this, [log].concat(Array.prototype.slice.call(arguments, 2)));\n }\n }\n });\nminispade.require('log/folds');\nminispade.require('log/times');\nminispade.require('log/deansi');\nminispade.require('log/limit');\nminispade.require('log/renderer');\n\n}).call(this);\n\n})();\n//@ sourceURL=log");minispade.register('log/deansi', "(function() {(function() {\n\n Log.Deansi = {\n CLEAR_ANSI: /(?:\\033)(?:\\[0?c|\\[[0356]n|\\[7[lh]|\\[\\?25[lh]|\\(B|H|\\[(?:\\d+(;\\d+){,2})?G|\\[(?:[12])?[JK]|[DM]|\\[0K)/gm,\n apply: function(string) {\n var nodes,\n _this = this;\n if (!string) {\n return [];\n }\n string = string.replace(this.CLEAR_ANSI, '');\n nodes = ansiparse(string).map(function(part) {\n return _this.node(part);\n });\n return nodes;\n },\n node: function(part) {\n var classes, node;\n node = {\n type: 'span',\n text: part.text\n };\n if (classes = this.classes(part)) {\n node[\"class\"] = classes.join(' ');\n }\n return node;\n },\n classes: function(part) {\n var result;\n result = [];\n result = result.concat(this.colors(part));\n if (result.length > 0) {\n return result;\n }\n },\n colors: function(part) {\n var colors;\n colors = [];\n if (part.foreground) {\n colors.push(part.foreground);\n }\n if (part.background) {\n colors.push(\"bg-\" + part.background);\n }\n if (part.bold) {\n colors.push('bold');\n }\n if (part.italic) {\n colors.push('italic');\n }\n if (part.underline) {\n colors.push('underline');\n }\n return colors;\n },\n hidden: function(part) {\n if (part.text.match(/\\r/)) {\n part.text = part.text.replace(/^.*\\r/gm, '');\n return true;\n }\n }\n };\n\n}).call(this);\n\n})();\n//@ sourceURL=log/deansi");minispade.register('log/folds', "(function() {(function() {\n\n Log.Folds = function(log) {\n this.log = log;\n this.folds = {};\n return this;\n };\n\n Log.extend(Log.Folds.prototype, {\n add: function(data) {\n var fold, _base, _name;\n fold = (_base = this.folds)[_name = data.name] || (_base[_name] = new Log.Folds.Fold);\n fold.receive(data, {\n autoCloseFold: this.log.autoCloseFold\n });\n return fold.active;\n }\n });\n\n Log.Folds.Fold = function() {\n return this;\n };\n\n Log.extend(Log.Folds.Fold.prototype, {\n receive: function(data, options) {\n this[data.event] = data.id;\n if (this.start && this.end && !this.active) {\n return this.activate(options);\n }\n },\n activate: function(options) {\n var fragment, nextSibling, node, parentNode, toRemove, _i, _len, _ref;\n options || (options = {});\n if (Log.DEBUG) {\n console.log(\"F.n - activate \" + this.start);\n }\n toRemove = this.fold.parentNode;\n parentNode = toRemove.parentNode;\n nextSibling = toRemove.nextSibling;\n parentNode.removeChild(toRemove);\n fragment = document.createDocumentFragment();\n _ref = this.nodes;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n node = _ref[_i];\n fragment.appendChild(node);\n }\n this.fold.appendChild(fragment);\n parentNode.insertBefore(toRemove, nextSibling);\n this.fold.setAttribute('class', this.classes(options['autoCloseFold']));\n return this.active = true;\n },\n classes: function(autoCloseFold) {\n var classes;\n classes = this.fold.getAttribute('class').split(' ');\n classes.push('fold');\n if (!autoCloseFold) {\n classes.push('open');\n }\n if (this.fold.childNodes.length > 2) {\n classes.push('active');\n }\n return classes.join(' ');\n }\n });\n\n Object.defineProperty(Log.Folds.Fold.prototype, 'fold', {\n get: function() {\n return this._fold || (this._fold = document.getElementById(this.start));\n }\n });\n\n Object.defineProperty(Log.Folds.Fold.prototype, 'nodes', {\n get: function() {\n var node, nodes;\n node = this.fold;\n nodes = [];\n while ((node = node.nextSibling) && node.id !== this.end) {\n nodes.push(node);\n }\n return nodes;\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=log/folds");minispade.register('log/limit', "(function() {(function() {\n\n Log.Limit = function(max_lines) {\n this.max_lines = max_lines || 1000;\n return this;\n };\n\n Log.Limit.prototype = Log.extend(new Log.Listener, {\n count: 0,\n insert: function(log, node, pos) {\n if (node.type === 'paragraph' && !node.hidden) {\n return this.count += 1;\n }\n }\n });\n\n Object.defineProperty(Log.Limit.prototype, 'limited', {\n get: function() {\n return this.count >= this.max_lines;\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=log/limit");minispade.register('log/nodes', "(function() {(function() {\n var newLineAtTheEndRegexp, newLineRegexp, rRegexp, removeCarriageReturns;\n\n Log.Node = function(id, num) {\n this.id = id;\n this.num = num;\n this.key = Log.Node.key(this.id);\n this.children = new Log.Nodes(this);\n return this;\n };\n\n Log.extend(Log.Node, {\n key: function(id) {\n if (id) {\n return id.split('-').map(function(i) {\n return '000000'.concat(i).slice(-6);\n }).join('');\n }\n }\n });\n\n Log.extend(Log.Node.prototype, {\n addChild: function(node) {\n return this.children.add(node);\n },\n remove: function() {\n this.log.remove(this.element);\n return this.parent.children.remove(this);\n }\n });\n\n Object.defineProperty(Log.Node.prototype, 'log', {\n get: function() {\n var _ref;\n return this._log || (this._log = ((_ref = this.parent) != null ? _ref.log : void 0) || this.parent);\n }\n });\n\n Object.defineProperty(Log.Node.prototype, 'firstChild', {\n get: function() {\n return this.children.first;\n }\n });\n\n Object.defineProperty(Log.Node.prototype, 'lastChild', {\n get: function() {\n return this.children.last;\n }\n });\n\n Log.Nodes = function(parent) {\n if (parent) {\n this.parent = parent;\n }\n this.items = [];\n this.index = {};\n return this;\n };\n\n Log.extend(Log.Nodes.prototype, {\n add: function(item) {\n var ix, next, prev, _ref, _ref1;\n ix = this.position(item) || 0;\n this.items.splice(ix, 0, item);\n if (this.parent) {\n item.parent = this.parent;\n }\n prev = function(item) {\n while (item && !item.children.last) {\n item = item.prev;\n }\n return item != null ? item.children.last : void 0;\n };\n next = function(item) {\n while (item && !item.children.first) {\n item = item.next;\n }\n return item != null ? item.children.first : void 0;\n };\n if (item.prev = this.items[ix - 1] || prev((_ref = this.parent) != null ? _ref.prev : void 0)) {\n item.prev.next = item;\n }\n if (item.next = this.items[ix + 1] || next((_ref1 = this.parent) != null ? _ref1.next : void 0)) {\n item.next.prev = item;\n }\n return item;\n },\n remove: function(item) {\n this.items.splice(this.items.indexOf(item), 1);\n if (item.next) {\n item.next.prev = item.prev;\n }\n if (item.prev) {\n item.prev.next = item.next;\n }\n if (this.items.length === 0) {\n return this.parent.remove();\n }\n },\n position: function(item) {\n var ix, _i, _ref;\n for (ix = _i = _ref = this.items.length - 1; _i >= 0; ix = _i += -1) {\n if (this.items[ix].key < item.key) {\n return ix + 1;\n }\n }\n },\n indexOf: function() {\n return this.items.indexOf.apply(this.items, arguments);\n },\n slice: function() {\n return this.items.slice.apply(this.items, arguments);\n },\n each: function(func) {\n return this.items.slice().forEach(func);\n },\n map: function(func) {\n return this.items.map(func);\n }\n });\n\n Object.defineProperty(Log.Nodes.prototype, 'first', {\n get: function() {\n return this.items[0];\n }\n });\n\n Object.defineProperty(Log.Nodes.prototype, 'last', {\n get: function() {\n return this.items[this.length - 1];\n }\n });\n\n Object.defineProperty(Log.Nodes.prototype, 'length', {\n get: function() {\n return this.items.length;\n }\n });\n\n Log.Part = function(id, num, string) {\n Log.Node.apply(this, arguments);\n this.string = string || '';\n this.string = this.string.replace(/\\033\\[1000D/gm, '\\r');\n this.string = this.string.replace(/\\r+\\n/gm, '\\n');\n this.strings = this.string.split(/^/gm) || [];\n this.slices = ((function() {\n var _results;\n _results = [];\n while (this.strings.length > 0) {\n _results.push(this.strings.splice(0, Log.SLICE));\n }\n return _results;\n }).call(this));\n return this;\n };\n\n Log.extend(Log.Part, {\n create: function(log, num, string) {\n var part;\n part = new Log.Part(num.toString(), num, string);\n log.addChild(part);\n return part.process(0, -1);\n }\n });\n\n Log.Part.prototype = Log.extend(new Log.Node, {\n remove: function() {},\n process: function(slice, num) {\n var node, span, spans, string, _i, _j, _len, _len1, _ref, _ref1, _ref2, _ref3, _ref4,\n _this = this;\n _ref = this.slices[slice] || [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n string = _ref[_i];\n if ((_ref1 = this.log.limit) != null ? _ref1.limited : void 0) {\n return;\n }\n spans = [];\n _ref2 = Log.Deansi.apply(string);\n for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {\n node = _ref2[_j];\n span = Log.Span.create(this, \"\" + this.id + \"-\" + (num += 1), num, node.text, node[\"class\"]);\n span.render();\n spans.push(span);\n }\n if ((_ref3 = spans[0]) != null ? (_ref4 = _ref3.line) != null ? _ref4.cr : void 0 : void 0) {\n spans[0].line.clear();\n }\n }\n if (!(slice >= this.slices.length - 1)) {\n return setTimeout((function() {\n return _this.process(slice + 1, num);\n }), Log.TIMEOUT);\n }\n }\n });\n\n newLineAtTheEndRegexp = new RegExp(\"\\n$\");\n\n newLineRegexp = new RegExp(\"\\n\");\n\n rRegexp = new RegExp(\"\\r\");\n\n removeCarriageReturns = function(string) {\n var index;\n index = string.lastIndexOf(\"\\r\");\n if (index === -1) {\n return string;\n }\n return string.substr(index + 1);\n };\n\n Log.Span = function(id, num, text, classes) {\n var fold, time, _ref;\n Log.Node.apply(this, arguments);\n if (fold = text.match(Log.FOLD)) {\n this.fold = true;\n this.event = fold[1];\n this.text = this.name = fold[2];\n } else if (time = text.match(Log.TIME)) {\n this.time = true;\n this.event = time[1];\n this.name = time[2];\n this.stats = time[3];\n } else {\n this.text = text;\n this.text = removeCarriageReturns(this.text);\n this.text = this.text.replace(newLineAtTheEndRegexp, '');\n this.nl = !!((_ref = text[text.length - 1]) != null ? _ref.match(newLineRegexp) : void 0);\n this.cr = !!text.match(rRegexp);\n this[\"class\"] = this.cr && ['clears'] || classes;\n }\n return this;\n };\n\n Log.extend(Log.Span, {\n create: function(parent, id, num, text, classes) {\n var span;\n span = new Log.Span(id, num, text, classes);\n parent.addChild(span);\n return span;\n },\n render: function(parent, id, num, text, classes) {\n var span;\n span = this.create(parent, id, num, text, classes);\n return span.render();\n }\n });\n\n Log.Span.prototype = Log.extend(new Log.Node, {\n render: function() {\n var tail;\n if (this.time && this.event === 'end' && this.prev) {\n if (Log.DEBUG) {\n console.log(\"S.0 insert \" + this.id + \" after prev \" + this.prev.id);\n }\n this.nl = this.prev.nl;\n this.log.insert(this.data, {\n after: this.prev.element\n });\n this.line = this.prev.line;\n } else if (!this.fold && this.prev && !this.prev.fold && !this.prev.nl) {\n if (Log.DEBUG) {\n console.log(\"S.1 insert \" + this.id + \" after prev \" + this.prev.id);\n }\n this.log.insert(this.data, {\n after: this.prev.element\n });\n this.line = this.prev.line;\n } else if (!this.fold && this.next && !this.next.fold && !this.next.time) {\n if (Log.DEBUG) {\n console.log(\"S.2 insert \" + this.id + \" before next \" + this.next.id);\n }\n this.log.insert(this.data, {\n before: this.next.element\n });\n this.line = this.next.line;\n } else {\n this.line = Log.Line.create(this.log, [this]);\n this.line.render();\n }\n if (this.nl && (tail = this.tail).length > 0) {\n this.split(tail);\n }\n if (this.time) {\n return this.log.times.add(this);\n }\n },\n remove: function() {\n Log.Node.prototype.remove.apply(this);\n if (this.line) {\n return this.line.remove(this);\n }\n },\n split: function(spans) {\n var line, span, _i, _len;\n if (Log.DEBUG) {\n console.log(\"S.4 split [\" + (spans.map(function(span) {\n return span.id;\n }).join(', ')) + \"]\");\n }\n for (_i = 0, _len = spans.length; _i < _len; _i++) {\n span = spans[_i];\n this.log.remove(span.element);\n }\n line = Log.Line.create(this.log, spans);\n line.render();\n if (line.cr) {\n return line.clear();\n }\n },\n clear: function() {\n if (this.prev && this.isSibling(this.prev) && this.isSequence(this.prev)) {\n this.prev.clear();\n return this.prev.remove();\n }\n },\n isSequence: function(other) {\n return this.parent.num - other.parent.num === this.log.children.indexOf(this.parent) - this.log.children.indexOf(other.parent);\n },\n isSibling: function(other) {\n var _ref, _ref1;\n return ((_ref = this.element) != null ? _ref.parentNode : void 0) === ((_ref1 = other.element) != null ? _ref1.parentNode : void 0);\n },\n siblings: function(type) {\n var siblings, span;\n siblings = [];\n while ((span = (span || this)[type]) && this.isSibling(span)) {\n siblings.push(span);\n }\n return siblings;\n }\n });\n\n Object.defineProperty(Log.Span.prototype, 'data', {\n get: function() {\n return {\n id: this.id,\n type: 'span',\n text: this.text,\n \"class\": this[\"class\"],\n time: this.time\n };\n }\n });\n\n Object.defineProperty(Log.Span.prototype, 'line', {\n get: function() {\n return this._line;\n },\n set: function(line) {\n if (this.line) {\n this.line.remove(this);\n }\n this._line = line;\n if (this.line) {\n return this.line.add(this);\n }\n }\n });\n\n Object.defineProperty(Log.Span.prototype, 'element', {\n get: function() {\n return document.getElementById(this.id);\n }\n });\n\n Object.defineProperty(Log.Span.prototype, 'head', {\n get: function() {\n return this.siblings('prev').reverse();\n }\n });\n\n Object.defineProperty(Log.Span.prototype, 'tail', {\n get: function() {\n return this.siblings('next');\n }\n });\n\n Log.Line = function(log) {\n this.log = log;\n this.spans = [];\n return this;\n };\n\n Log.extend(Log.Line, {\n create: function(log, spans) {\n var line, span, _i, _len;\n if ((span = spans[0]) && span.fold) {\n line = new Log.Fold(log, span.event, span.name);\n } else {\n line = new Log.Line(log);\n }\n for (_i = 0, _len = spans.length; _i < _len; _i++) {\n span = spans[_i];\n span.line = line;\n }\n return line;\n }\n });\n\n Log.extend(Log.Line.prototype, {\n add: function(span) {\n var ix;\n if (span.cr) {\n this.cr = true;\n }\n if (this.spans.indexOf(span) > -1) {\n\n } else if ((ix = this.spans.indexOf(span.prev)) > -1) {\n return this.spans.splice(ix + 1, 0, span);\n } else if ((ix = this.spans.indexOf(span.next)) > -1) {\n return this.spans.splice(ix, 0, span);\n } else {\n return this.spans.push(span);\n }\n },\n remove: function(span) {\n var ix;\n if ((ix = this.spans.indexOf(span)) > -1) {\n return this.spans.splice(ix, 1);\n }\n },\n render: function() {\n var fold;\n if ((fold = this.prev) && fold.event === 'start' && fold.active) {\n if (this.next && !this.next.fold) {\n if (Log.DEBUG) {\n console.log(\"L.0 insert \" + this.id + \" before next \" + this.next.id);\n }\n return this.element = this.log.insert(this.data, {\n before: this.next.element\n });\n } else {\n if (Log.DEBUG) {\n console.log(\"L.0 insert \" + this.id + \" into fold \" + fold.id);\n }\n fold = this.log.folds.folds[fold.name].fold;\n return this.element = this.log.insert(this.data, {\n into: fold\n });\n }\n } else if (this.prev) {\n if (Log.DEBUG) {\n console.log(\"L.1 insert \" + this.spans[0].id + \" after prev \" + this.prev.id);\n }\n return this.element = this.log.insert(this.data, {\n after: this.prev.element\n });\n } else if (this.next) {\n if (Log.DEBUG) {\n console.log(\"L.2 insert \" + this.spans[0].id + \" before next \" + this.next.id);\n }\n return this.element = this.log.insert(this.data, {\n before: this.next.element\n });\n } else {\n if (Log.DEBUG) {\n console.log(\"L.3 insert \" + this.spans[0].id + \" into #log\");\n }\n return this.element = this.log.insert(this.data);\n }\n },\n clear: function() {\n var cr, _i, _len, _ref, _results;\n _ref = this.crs;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n cr = _ref[_i];\n _results.push(cr.clear());\n }\n return _results;\n }\n });\n\n Object.defineProperty(Log.Line.prototype, 'id', {\n get: function() {\n var _ref;\n return (_ref = this.spans[0]) != null ? _ref.id : void 0;\n }\n });\n\n Object.defineProperty(Log.Line.prototype, 'data', {\n get: function() {\n return {\n type: 'paragraph',\n nodes: this.nodes\n };\n }\n });\n\n Object.defineProperty(Log.Line.prototype, 'nodes', {\n get: function() {\n return this.spans.map(function(span) {\n return span.data;\n });\n }\n });\n\n Object.defineProperty(Log.Line.prototype, 'prev', {\n get: function() {\n var _ref;\n return (_ref = this.spans[0].prev) != null ? _ref.line : void 0;\n }\n });\n\n Object.defineProperty(Log.Line.prototype, 'next', {\n get: function() {\n var _ref;\n return (_ref = this.spans[this.spans.length - 1].next) != null ? _ref.line : void 0;\n }\n });\n\n Object.defineProperty(Log.Line.prototype, 'crs', {\n get: function() {\n return this.spans.filter(function(span) {\n return span.cr;\n });\n }\n });\n\n Log.Fold = function(log, event, name) {\n Log.Line.apply(this, arguments);\n this.fold = true;\n this.event = event;\n this.name = name;\n return this;\n };\n\n Log.Fold.prototype = Log.extend(new Log.Line, {\n render: function() {\n var element, _ref;\n if (this.prev && this.prev.element) {\n if (Log.DEBUG) {\n console.log(\"F.1 insert \" + this.id + \" after prev \" + this.prev.id);\n }\n element = this.prev.element;\n this.element = this.log.insert(this.data, {\n after: element\n });\n } else if (this.next) {\n if (Log.DEBUG) {\n console.log(\"F.2 insert \" + this.id + \" before next \" + this.next.id);\n }\n element = this.next.element || this.next.element.parentNode;\n this.element = this.log.insert(this.data, {\n before: element\n });\n } else {\n if (Log.DEBUG) {\n console.log(\"F.3 insert \" + this.id);\n }\n this.element = this.log.insert(this.data);\n }\n if (this.span.next && ((_ref = this.span.prev) != null ? _ref.isSibling(this.span.next) : void 0)) {\n this.span.prev.split([this.span.next].concat(this.span.next.tail));\n }\n return this.active = this.log.folds.add(this.data);\n }\n });\n\n Object.defineProperty(Log.Fold.prototype, 'id', {\n get: function() {\n return \"fold-\" + this.event + \"-\" + this.name;\n }\n });\n\n Object.defineProperty(Log.Fold.prototype, 'span', {\n get: function() {\n return this.spans[0];\n }\n });\n\n Object.defineProperty(Log.Fold.prototype, 'data', {\n get: function() {\n return {\n type: 'fold',\n id: this.id,\n event: this.event,\n name: this.name\n };\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=log/nodes");minispade.register('log/renderer', "(function() {(function() {\n\n Log.Renderer = function() {\n this.frag = document.createDocumentFragment();\n this.para = this.createParagraph();\n this.span = this.createSpan();\n this.text = document.createTextNode('');\n this.fold = this.createFold();\n return this;\n };\n\n Log.extend(Log.Renderer.prototype, {\n insert: function(data, pos) {\n var after, before, into, node;\n node = this.render(data);\n if (into = pos != null ? pos.into : void 0) {\n if (typeof into === 'String') {\n into = document.getElementById(pos != null ? pos.into : void 0);\n }\n if (pos != null ? pos.prepend : void 0) {\n this.prependTo(node, into);\n } else {\n this.appendTo(node, into);\n }\n } else if (after = pos != null ? pos.after : void 0) {\n if (typeof after === 'String') {\n after = document.getElementById(pos);\n }\n this.insertAfter(node, after);\n } else if (before = pos != null ? pos.before : void 0) {\n if (typeof before === 'String') {\n before = document.getElementById(pos != null ? pos.before : void 0);\n }\n this.insertBefore(node, before);\n } else {\n this.insertBefore(node);\n }\n return node;\n },\n hide: function(node) {\n node.setAttribute('class', this.addClass(node.getAttribute('class'), 'hidden'));\n return node;\n },\n remove: function(node) {\n if (node) {\n node.parentNode.removeChild(node);\n }\n return node;\n },\n render: function(data) {\n var frag, node, type, _i, _len;\n if (data instanceof Array) {\n frag = this.frag.cloneNode(true);\n for (_i = 0, _len = data.length; _i < _len; _i++) {\n node = data[_i];\n node = this.render(node);\n if (node) {\n frag.appendChild(node);\n }\n }\n return frag;\n } else {\n data.type || (data.type = 'paragraph');\n type = data.type[0].toUpperCase() + data.type.slice(1);\n return this[\"render\" + type](data);\n }\n },\n renderParagraph: function(data) {\n var node, para, type, _i, _len, _ref;\n para = this.para.cloneNode(true);\n if (data.id) {\n para.setAttribute('id', data.id);\n }\n if (data.hidden) {\n para.setAttribute('style', 'display: none;');\n }\n _ref = data.nodes || [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n node = _ref[_i];\n type = node.type[0].toUpperCase() + node.type.slice(1);\n node = this[\"render\" + type](node);\n para.appendChild(node);\n }\n return para;\n },\n renderFold: function(data) {\n var fold;\n fold = this.fold.cloneNode(true);\n fold.setAttribute('id', data.id || (\"fold-\" + data.event + \"-\" + data.name));\n fold.setAttribute('class', \"fold-\" + data.event);\n if (data.event === 'start') {\n fold.lastChild.lastChild.nodeValue = data.name;\n } else {\n fold.removeChild(fold.lastChild);\n }\n return fold;\n },\n renderSpan: function(data) {\n var span;\n span = this.span.cloneNode(true);\n if (data.id) {\n span.setAttribute('id', data.id);\n }\n if (data[\"class\"]) {\n span.setAttribute('class', data[\"class\"]);\n }\n span.lastChild.nodeValue = data.text || '';\n return span;\n },\n renderText: function(data) {\n var text;\n text = this.text.cloneNode(true);\n text.nodeValue = data.text;\n return text;\n },\n createParagraph: function() {\n var para;\n para = document.createElement('p');\n para.appendChild(document.createElement('a'));\n return para;\n },\n createFold: function() {\n var fold;\n fold = document.createElement('div');\n fold.appendChild(this.createSpan());\n fold.lastChild.setAttribute('class', 'fold-name');\n return fold;\n },\n createSpan: function() {\n var span;\n span = document.createElement('span');\n span.appendChild(document.createTextNode(' '));\n return span;\n },\n insertBefore: function(node, other) {\n var log;\n if (other) {\n return other.parentNode.insertBefore(node, other);\n } else {\n log = document.getElementById('log');\n return log.insertBefore(node, log.firstChild);\n }\n },\n insertAfter: function(node, other) {\n if (other.nextSibling) {\n return this.insertBefore(node, other.nextSibling);\n } else {\n return this.appendTo(node, other.parentNode);\n }\n },\n prependTo: function(node, other) {\n if (other.firstChild) {\n return other.insertBefore(node, other.firstChild);\n } else {\n return appendTo(node, other);\n }\n },\n appendTo: function(node, other) {\n return other.appendChild(node);\n },\n addClass: function(classes, string) {\n if (classes != null ? classes.indexOf(string) : void 0) {\n return;\n }\n if (classes) {\n return \"\" + classes + \" \" + string;\n } else {\n return string;\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=log/renderer");minispade.register('log/times', "(function() {(function() {\n\n Log.Times = function(log) {\n this.log = log;\n this.times = {};\n return this;\n };\n\n Log.extend(Log.Times.prototype, {\n add: function(node) {\n var time, _base, _name;\n time = (_base = this.times)[_name = node.name] || (_base[_name] = new Log.Times.Time);\n return time.receive(node);\n },\n duration: function(name) {\n if (this.times[name]) {\n return this.times[name].duration;\n }\n }\n });\n\n Log.Times.Time = function() {\n return this;\n };\n\n Log.extend(Log.Times.Time.prototype, {\n receive: function(node) {\n this[node.event] = node;\n if (Log.DEBUG) {\n console.log(\"T.0 - \" + node.event + \" \" + node.name);\n }\n if (this.start && this.end) {\n return this.finish();\n }\n },\n finish: function() {\n var element;\n if (Log.DEBUG) {\n console.log(\"T.1 - finish \" + this.start.name);\n }\n element = document.getElementById(this.start.id);\n if (element) {\n return this.update(element);\n }\n },\n update: function(element) {\n element.setAttribute('class', 'duration');\n element.setAttribute('title', \"This command finished after \" + this.duration + \" seconds.\");\n return element.lastChild.nodeValue = \"\" + this.duration + \"s\";\n }\n });\n\n Object.defineProperty(Log.Times.Time.prototype, 'duration', {\n get: function() {\n var duration;\n duration = this.stats.duration / 1000 / 1000 / 1000;\n return duration.toFixed(2);\n }\n });\n\n Object.defineProperty(Log.Times.Time.prototype, 'stats', {\n get: function() {\n var stat, stats, _i, _len, _ref;\n if (!(this.end && this.end.stats)) {\n return {};\n }\n stats = {};\n _ref = this.end.stats.split(',');\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n stat = _ref[_i];\n stat = stat.split('=');\n stats[stat[0]] = stat[1];\n }\n return stats;\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=log/times"); -