diff --git a/app/components/log-content.coffee b/app/components/log-content.coffee deleted file mode 100644 index 09b5a225..00000000 --- a/app/components/log-content.coffee +++ /dev/null @@ -1,157 +0,0 @@ -`import Ember from 'ember'` -`import LinesSelector from 'travis/utils/lines-selector'` -`import LogFolder from 'travis/utils/log-folder'` -`import config from 'travis/config/environment'` -`import { plainTextLog as plainTextLogUrl } from 'travis/utils/urls'` - -Log.DEBUG = false -Log.LIMIT = 10000 - -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.Limit = (max_lines, limitedLogCallback) -> - @max_lines = max_lines || 1000 - @limitedLogCallback = limitedLogCallback || (->) - this - -Log.Limit.prototype = Log.extend new Log.Listener, - count: 0, - insert: (log, node, pos) -> - if node.type == 'paragraph' && !node.hidden - @count += 1 - if @limited - @limitedLogCallback() - return @count - -Object.defineProperty Log.Limit.prototype, 'limited', - get: -> - @count >= @max_lines - -LogContentComponent = Ember.Component.extend - popup: Ember.inject.service() - - currentUserBinding: 'auth.currentUser' - - 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() - - teardownLog: (log) -> - if log || log = @get('log') - parts = log.get('parts') - parts.removeArrayObserver(@, didChange: 'partsDidChange', willChange: 'noop') - parts.destroy() - log.notifyPropertyChange('parts') - @lineSelector?.willDestroy() - if logElement = this.$('#log') - logElement.empty() - - createEngine: (log) -> - if log || log = @get('log') - if logElement = this.$('#log') - logElement.empty() - - log.onClear => - @teardownLog() - @createEngine() - - @scroll = new Log.Scroll beforeScroll: => - @unfoldHighlight() - @limit = new Log.Limit Log.LIMIT, => - @set('limited', true) - @engine = Log.create(listeners: [@scroll, @limit]) - @engine.limit = @limit - @logFolder = new LogFolder(@$('#log')) - @lineSelector = new LinesSelector(@$('#log'), @scroll, @logFolder) - @observeParts(log) - - didUpdateAttrs: (changes) -> - @_super.apply(this, arguments) - - return unless changes.oldAttrs - - if changes.newAttrs.job.value && changes.oldAttrs.job.value && - changes.newAttrs.job.value != changes.oldAttrs.job.value - - @teardownLog(changes.oldAttrs.job.value.get('log')) - @createEngine(changes.newAttrs.job.value.get('log')) - - unfoldHighlight: -> - @lineSelector.unfoldLines() - - observeParts: (log) -> - if log || 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 - return unless @get('state') == 'inDOM' - - for part, i in parts.slice(start, start + added) - # console.log "limit in log view: #{@get('limited')}" - break if @engine?.limit?.limited - @engine.set(part.number, part.content) - - 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') - - hasPermission: (-> - if permissions = @get('currentUser.permissions') - permissions.contains parseInt(@get('job.repo.id')) - ).property('currentUser.permissions.length', 'job.repo.id') - - canRemoveLog: (-> - if job = @get('job') - job.get('canRemoveLog') && @get('hasPermission') - ).property('job.canRemoveLog', 'hasPermission') - - showToTop: (-> - @get('log.hasContent') && @get('job.canRemoveLog') - ).property('log.hasContent', 'job.canRemoveLog') - showTailing: Ember.computed.alias('showToTop') - - actions: - toTop: () -> - Travis.tailing.stop() - $(window).scrollTop(0) - - toggleTailing: -> - Travis.tailing.toggle() - @engine.autoCloseFold = !Travis.tailing.isActive() - event.preventDefault() - - removeLogPopup: -> - if @get('canRemoveLog') - @get('popup').open('remove-log-popup') - return false - - noop: -> # TODO required? - -`export default LogContentComponent` diff --git a/app/components/log-content.js b/app/components/log-content.js new file mode 100644 index 00000000..14110bc4 --- /dev/null +++ b/app/components/log-content.js @@ -0,0 +1,227 @@ +import Ember from 'ember'; +import LinesSelector from 'travis/utils/lines-selector'; +import LogFolder from 'travis/utils/log-folder'; +import config from 'travis/config/environment'; +import { plainTextLog as plainTextLogUrl } from 'travis/utils/urls'; + +Log.DEBUG = false; + +Log.LIMIT = 10000; + +Log.Scroll = function(options) { + options = options || {}; + this.beforeScroll = options.beforeScroll; + return this; +}; + +Log.Scroll.prototype = $.extend(new Log.Listener(), { + insert: function(log, data, pos) { + if (this.numbers) { + this.tryScroll(); + } + return true; + }, + tryScroll: function() { + var element, ref; + if (element = $("#log p:visible.highlight:first")) { + if (this.beforeScroll) { + this.beforeScroll(); + } + $('#main').scrollTop(0); + return $('html, body').scrollTop(((ref = element.offset()) != null ? ref.top : void 0) - (window.innerHeight / 3)); + } + } +}); + +Log.Limit = function(max_lines, limitedLogCallback) { + this.max_lines = max_lines || 1000; + this.limitedLogCallback = limitedLogCallback || (function() {}); + return this; +}; + +Log.Limit.prototype = Log.extend(new Log.Listener(), { + count: 0, + insert: function(log, node, pos) { + if (node.type === 'paragraph' && !node.hidden) { + this.count += 1; + if (this.limited) { + this.limitedLogCallback(); + } + return this.count; + } + } +}); + +Object.defineProperty(Log.Limit.prototype, 'limited', { + get: function() { + return this.count >= this.max_lines; + } +}); + +export default Ember.Component.extend({ + popup: Ember.inject.service(), + currentUserBinding: 'auth.currentUser', + + didInsertElement() { + if (Log.DEBUG) { + console.log('log view: did insert'); + } + this._super.apply(this, arguments); + return this.createEngine(); + }, + + willDestroyElement() { + if (Log.DEBUG) { + console.log('log view: will destroy'); + } + return this.teardownLog(); + }, + + teardownLog(log) { + var logElement, parts, ref; + if (log || (log = this.get('log'))) { + parts = log.get('parts'); + parts.removeArrayObserver(this, { + didChange: 'partsDidChange', + willChange: 'noop' + }); + parts.destroy(); + log.notifyPropertyChange('parts'); + if ((ref = this.lineSelector) != null) { + ref.willDestroy(); + } + if (logElement = this.$('#log')) { + return logElement.empty(); + } + } + }, + + createEngine(log) { + var logElement; + if (log || (log = this.get('log'))) { + if (logElement = this.$('#log')) { + logElement.empty(); + } + log.onClear(() => { + this.teardownLog(); + return this.createEngine(); + }); + this.scroll = new Log.Scroll({ + beforeScroll: () => { + return this.unfoldHighlight(); + } + }); + this.limit = new Log.Limit(Log.LIMIT, () => { + return this.set('limited', true); + }); + this.engine = Log.create({ + listeners: [this.scroll, this.limit] + }); + this.engine.limit = this.limit; + this.logFolder = new LogFolder(this.$('#log')); + this.lineSelector = new LinesSelector(this.$('#log'), this.scroll, this.logFolder); + return this.observeParts(log); + } + }, + + didUpdateAttrs(changes) { + this._super.apply(this, arguments); + if (!changes.oldAttrs) { + return; + } + if (changes.newAttrs.job.value && changes.oldAttrs.job.value && changes.newAttrs.job.value !== changes.oldAttrs.job.value) { + this.teardownLog(changes.oldAttrs.job.value.get('log')); + return this.createEngine(changes.newAttrs.job.value.get('log')); + } + }, + + unfoldHighlight() { + return this.lineSelector.unfoldLines(); + }, + + observeParts(log) { + var parts; + if (log || (log = this.get('log'))) { + parts = log.get('parts'); + parts.addArrayObserver(this, { + didChange: 'partsDidChange', + willChange: 'noop' + }); + parts = parts.slice(0); + return this.partsDidChange(parts, 0, null, parts.length); + } + }, + + partsDidChange(parts, start, _, added) { + var i, j, len, part, ref, ref1, ref2, results; + if (Log.DEBUG) { + console.log('log view: parts did change'); + } + if (this.get('state') !== 'inDOM') { + return; + } + ref = parts.slice(start, start + added); + results = []; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + part = ref[i]; + if ((ref1 = this.engine) != null ? (ref2 = ref1.limit) != null ? ref2.limited : void 0 : void 0) { + break; + } + results.push(this.engine.set(part.number, part.content)); + } + return results; + }, + + plainTextLogUrl: function() { + var id, url; + if (id = this.get('log.job.id')) { + url = plainTextLogUrl(id); + if (config.pro) { + url += "&access_token=" + (this.get('job.log.token')); + } + return url; + } + }.property('job.log.id', 'job.log.token'), + + hasPermission: function() { + var permissions; + if (permissions = this.get('currentUser.permissions')) { + return permissions.contains(parseInt(this.get('job.repo.id'))); + } + }.property('currentUser.permissions.length', 'job.repo.id'), + + canRemoveLog: function() { + var job; + if (job = this.get('job')) { + return job.get('canRemoveLog') && this.get('hasPermission'); + } + }.property('job.canRemoveLog', 'hasPermission'), + + showToTop: function() { + return this.get('log.hasContent') && this.get('job.canRemoveLog'); + }.property('log.hasContent', 'job.canRemoveLog'), + + showTailing: Ember.computed.alias('showToTop'), + + actions: { + toTop() { + Travis.tailing.stop(); + return $(window).scrollTop(0); + }, + + toggleTailing() { + Travis.tailing.toggle(); + this.engine.autoCloseFold = !Travis.tailing.isActive(); + return false; + }, + + removeLogPopup() { + if (this.get('canRemoveLog')) { + this.get('popup').open('remove-log-popup'); + return false; + } + } + }, + + noop() {} +});