From 186ba1dd45243d8903a3aca3422b4318d94bf9d0 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 9 Oct 2012 03:54:11 +0200 Subject: [PATCH] Fix links to log line numbers This is working implementation of links on log line numbers. Although it does the job, it's really hacky and involves overriding some of the ember's methods (resolvePath, routeMatcher) beacuse currently HistoryLocation can't handle hash additions in an easy way. This code should be fixed as soon as ember's router gets more powerful and gives much more granular control over matching routes. --- assets/scripts/app/routes.coffee | 148 ++++++++++++++++++++++++++- assets/scripts/app/views/job.coffee | 20 ++++ assets/scripts/lib/travis/log.coffee | 2 +- 3 files changed, 167 insertions(+), 3 deletions(-) diff --git a/assets/scripts/app/routes.coffee b/assets/scripts/app/routes.coffee index 6bf2ac83..a1c9c157 100644 --- a/assets/scripts/app/routes.coffee +++ b/assets/scripts/app/routes.coffee @@ -1,5 +1,116 @@ +require 'travis/location' + +defaultRoute = Ember.Route.extend + route: '/' + index: 1000 + +lineNumberRoute = Ember.Route.extend + route: '#L:number' + index: 1 + routeMatcher: Ember.computed(-> + if route = @get 'route' + Ember._RouteMatcher.create + route: route + # TODO: overriding such things is not cool, I need to check what's the status of + # router rewrite and make sure we can do such stuff without overriding anything + init: -> + escapeForRegex = (text) -> + text.replace(/[\-\[\]{}()*+?.,\\\^\$|#\s]/g, "\\$&") + + route = @route + identifiers = [] + count = 1 + + if route.charAt(0) == '/' + route = @route = route.substr(1) + + escaped = escapeForRegex(route) + + regex = escaped.replace /:([a-z_]+)(?=$|\/)/gi, (match, id) -> + identifiers[count++] = id + "([0-9]+)" + + @identifiers = identifiers + @regex = new RegExp(regex) + ).cacheable() + + +nonHashRouteMatcher = Ember.computed(-> + if route = @get 'route' + Ember._RouteMatcher.create + route: route + # TODO: overriding such things is not cool, I need to check what's the status of + # router rewrite and make sure we can do such stuff without overriding anything + init: -> + escapeForRegex = (text) -> + text.replace(/[\-\[\]{}()*+?.,\\\^\$|#\s]/g, "\\$&") + + route = @route + identifiers = [] + count = 1 + + if route.charAt(0) == '/' + route = @route = route.substr(1) + + escaped = escapeForRegex(route) + + regex = escaped.replace /:([a-z_]+)(?=$|\/)/gi, (match, id) -> + identifiers[count++] = id + "([^/#]+)" + + @identifiers = identifiers + @regex = new RegExp("^/?" + regex) +).cacheable() + +resolvePath = (manager, path) -> + if @get('isLeafRoute') + return Ember.A() + + childStates = @get('childStates') + + childStates = Ember.A(childStates.filterProperty('isRoutable')) + + childStates = childStates.sort (a, b) -> + aDynamicSegments = a.get('routeMatcher.identifiers.length') + bDynamicSegments = b.get('routeMatcher.identifiers.length') + aRoute = a.get('route') + bRoute = b.get('route') + aIndex = a.get('index') + bIndex = b.get('index') + + if aIndex && bIndex + return aIndex - bIndex + + if aRoute.indexOf(bRoute) == 0 + return -1 + else if bRoute.indexOf(aRoute) == 0 + return 1 + + if aDynamicSegments != bDynamicSegments + return aDynamicSegments - bDynamicSegments + + return b.get('route.length') - a.get('route.length') + + match = null + console.log(childStates.map( (s) -> s.get('route'))) + state = childStates.find (state) -> + matcher = state.get('routeMatcher') + if match = matcher.match(path) + match + + Ember.assert("Could not find state for path " + path, !!state) + + resolvedState = Ember._ResolvedState.create + manager: manager + state: state + match: match + + states = state.resolvePath(manager, match.remaining) + + Ember.A([resolvedState]).pushObjects(states) + Travis.Router = Ember.Router.extend - location: 'history' + location: 'travis' enableLogging: true initialState: 'loading' @@ -25,6 +136,10 @@ Travis.Router = Ember.Router.extend loading: Ember.Route.extend routePath: (router, path) -> + if match = path.match(/#.*$/) + router.set 'lineNumberHash', match[0] + + sessionStorage.setItem('travis.path', path) if router.needsAuth(path) router.transitionTo('root.auth') @@ -124,9 +239,20 @@ Travis.Router = Ember.Router.extend connectOutlets: (router) -> router.get('repoController').activate('index') + initialState: 'default' + default: defaultRoute + lineNumber: lineNumberRoute + resolvePath: resolvePath + + showWithLineNumber: Ember.Route.extend + route: '/#/L:number' + connectOutlets: (router) -> + router.get('repoController').activate('index') + repo: Ember.Route.extend initialState: 'show' route: '/:owner/:name' + routeMatcher: nonHashRouteMatcher connectOutlets: (router, repo) -> router.get('repoController').set 'repo', repo @@ -156,6 +282,11 @@ Travis.Router = Ember.Router.extend connectOutlets: (router) -> router.get('repoController').activate('current') + initialState: 'default' + default: defaultRoute + lineNumber: lineNumberRoute + resolvePath: resolvePath + builds: Ember.Route.extend route: '/builds' initialState: 'index' @@ -199,6 +330,14 @@ Travis.Router = Ember.Router.extend deferred.promise() + # TODO: this is not dry, but for some weird + # reason Mixins don't play nice with Ember.Route + initialState: 'default' + default: defaultRoute + lineNumber: lineNumberRoute + routeMatcher: nonHashRouteMatcher + resolvePath: resolvePath + pullRequests: Ember.Route.extend route: '/pull_requests' connectOutlets: (router, repo) -> @@ -210,7 +349,6 @@ Travis.Router = Ember.Router.extend router.get('repoController').activate 'branches' job: Ember.Route.extend - route: '/jobs/:job_id' connectOutlets: (router, job) -> unless job.get @@ -235,3 +373,9 @@ Travis.Router = Ember.Router.extend deferred.resolve job job.addObserver 'id', observer deferred.promise() + + initialState: 'default' + default: defaultRoute + lineNumber: lineNumberRoute + routeMatcher: nonHashRouteMatcher + resolvePath: resolvePath diff --git a/assets/scripts/app/views/job.coffee b/assets/scripts/app/views/job.coffee index 3ca6acb3..0f75b20c 100644 --- a/assets/scripts/app/views/job.coffee +++ b/assets/scripts/app/views/job.coffee @@ -48,6 +48,26 @@ templateName: 'jobs/log' logBinding: 'job.log' + scrollTo: (hash) -> + $('body').scrollTop $(hash).offset().top + Travis.app.router.set 'lineNumberHash', null + + didInsertElement: -> + @_super.apply this, arguments + + if hash = Travis.app.router.get 'lineNumberHash' + self = this + + checker = -> + return if self.get('isDestroyed') + + if $(hash).length + self.scrollTo(hash) + else + setTimeout checker, 100 + + checker() + click: (event) -> $(event.target).closest('.fold').toggleClass('open') diff --git a/assets/scripts/lib/travis/log.coffee b/assets/scripts/lib/travis/log.coffee index 99d7b8e4..be3b274c 100644 --- a/assets/scripts/lib/travis/log.coffee +++ b/assets/scripts/lib/travis/log.coffee @@ -27,7 +27,7 @@ result = '' $.each log.trim().split('\n'), (ix, line) -> number = ix + 1 - path = Travis.Log.location().substr(1).replace(/\/L\d+/, '') + '/L' + number + path = Travis.Log.location().substr(1).replace(/L\d+/, '') + 'L' + number result += '

%@%@

\n'.fmt(path, path, number, number, line) result.trim()