Merge pull request #336 from travis-ci/favicon-changing
Change favicon color based on the build state
|
@ -8,6 +8,7 @@ Controller = Ember.Controller.extend GithubUrlPropertievs,
|
||||||
commitBinding: 'build.commit'
|
commitBinding: 'build.commit'
|
||||||
currentUserBinding: 'controllers.repo.currentUser'
|
currentUserBinding: 'controllers.repo.currentUser'
|
||||||
tabBinding: 'controllers.repo.tab'
|
tabBinding: 'controllers.repo.tab'
|
||||||
|
sendFaviconStateChanges: true
|
||||||
|
|
||||||
currentItemBinding: 'build'
|
currentItemBinding: 'build'
|
||||||
|
|
||||||
|
@ -23,4 +24,9 @@ Controller = Ember.Controller.extend GithubUrlPropertievs,
|
||||||
gravatarImage(@get('commit.authorEmail'), 40)
|
gravatarImage(@get('commit.authorEmail'), 40)
|
||||||
).property('commit.authorEmail')
|
).property('commit.authorEmail')
|
||||||
|
|
||||||
|
buildStateDidChange: (->
|
||||||
|
if @get('sendFaviconStateChanges')
|
||||||
|
@send('faviconStateDidChange', @get('build.state'))
|
||||||
|
).observes('build.state')
|
||||||
|
|
||||||
`export default Controller`
|
`export default Controller`
|
||||||
|
|
|
@ -16,4 +16,8 @@ Controller = Ember.Controller.extend
|
||||||
githubCommit(@get('repo.slug'), @get('commit.sha'))
|
githubCommit(@get('repo.slug'), @get('commit.sha'))
|
||||||
).property('repo.slug', 'commit.sha')
|
).property('repo.slug', 'commit.sha')
|
||||||
|
|
||||||
|
jobStateDidChange: (->
|
||||||
|
@send('faviconStateDidChange', @get('job.state'))
|
||||||
|
).observes('job.state')
|
||||||
|
|
||||||
`export default Controller`
|
`export default Controller`
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
<title>{{title}}</title>
|
<title>{{title}}</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" type="image/png" href="/images/favicon.png" />
|
||||||
|
|
||||||
{{content-for 'head'}}
|
{{content-for 'head'}}
|
||||||
|
|
||||||
|
|
30
app/mixins/build-favicon.coffee
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
`import Ember from 'ember'`
|
||||||
|
`import { colorForState } from 'travis/utils/helpers'`
|
||||||
|
`import FaviconManager from 'travis/utils/favicon-manager'`
|
||||||
|
`import getFaviconUri from 'travis/utils/favicon-data-uris'`
|
||||||
|
|
||||||
|
Mixin = Ember.Mixin.create
|
||||||
|
actions:
|
||||||
|
faviconStateDidChange: (state) ->
|
||||||
|
if state
|
||||||
|
@setFaviconForState(state)
|
||||||
|
else
|
||||||
|
@setDefault()
|
||||||
|
|
||||||
|
init: ->
|
||||||
|
@faviconManager = new FaviconManager()
|
||||||
|
|
||||||
|
@_super.apply this, arguments
|
||||||
|
|
||||||
|
setFaviconForState: (state) ->
|
||||||
|
color = colorForState(state)
|
||||||
|
|
||||||
|
@setFavicon(getFaviconUri(color))
|
||||||
|
|
||||||
|
setDefault: ->
|
||||||
|
@setFavicon(getFaviconUri('default'))
|
||||||
|
|
||||||
|
setFavicon: (href) ->
|
||||||
|
@faviconManager.setFavicon(href)
|
||||||
|
|
||||||
|
`export default Mixin`
|
|
@ -15,6 +15,8 @@ Route = TravisRoute.extend
|
||||||
deactivate: ->
|
deactivate: ->
|
||||||
@controllerFor('repo').removeObserver(@get('path'), this, 'contentDidChange')
|
@controllerFor('repo').removeObserver(@get('path'), this, 'contentDidChange')
|
||||||
|
|
||||||
|
@_super.apply(this, arguments)
|
||||||
|
|
||||||
contentDidChange: ->
|
contentDidChange: ->
|
||||||
path = @get('path')
|
path = @get('path')
|
||||||
@controllerFor('builds').set('model', @controllerFor('repo').get(path))
|
@controllerFor('builds').set('model', @controllerFor('repo').get(path))
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
`import TravisRoute from 'travis/routes/basic'`
|
`import TravisRoute from 'travis/routes/basic'`
|
||||||
`import config from 'travis/config/environment'`
|
`import config from 'travis/config/environment'`
|
||||||
|
`import BuildFaviconMixin from 'travis/mixins/build-favicon'`
|
||||||
|
|
||||||
Route = TravisRoute.extend
|
Route = TravisRoute.extend BuildFaviconMixin,
|
||||||
needsAuth: false
|
needsAuth: false
|
||||||
|
|
||||||
renderTemplate: ->
|
renderTemplate: ->
|
||||||
|
|
|
@ -22,6 +22,7 @@ Route = TravisRoute.extend
|
||||||
@store.find('build', params.build_id)
|
@store.find('build', params.build_id)
|
||||||
|
|
||||||
deactivate: ->
|
deactivate: ->
|
||||||
|
@_super.apply(this, arguments)
|
||||||
@controllerFor('job').set('job', null)
|
@controllerFor('job').set('job', null)
|
||||||
@controllerFor('build').set('build', null)
|
@controllerFor('build').set('build', null)
|
||||||
|
|
||||||
|
|
|
@ -20,13 +20,24 @@ Route = TravisRoute.extend
|
||||||
|
|
||||||
if build = model.get('build')
|
if build = model.get('build')
|
||||||
build = @store.recordForId('build', build.get('id'))
|
build = @store.recordForId('build', build.get('id'))
|
||||||
@controllerFor('build').set('build', build)
|
buildController = @controllerFor('build')
|
||||||
|
|
||||||
|
# this is a hack to not set favicon changes from build
|
||||||
|
# controller while we're viewing job, this should go away
|
||||||
|
# after refactoring of controllers
|
||||||
|
buildController.set('sendFaviconStateChanges', false)
|
||||||
|
|
||||||
|
buildController.set('build', build)
|
||||||
|
|
||||||
model: (params) ->
|
model: (params) ->
|
||||||
@store.find('job', params.job_id)
|
@store.find('job', params.job_id)
|
||||||
|
|
||||||
deactivate: ->
|
deactivate: ->
|
||||||
|
buildController = @controllerFor('build')
|
||||||
|
buildController.set('sendFaviconStateChanges', true)
|
||||||
@controllerFor('build').set('build', null)
|
@controllerFor('build').set('build', null)
|
||||||
@controllerFor('job').set('job', null)
|
@controllerFor('job').set('job', null)
|
||||||
|
|
||||||
|
@_super.apply(this, arguments)
|
||||||
|
|
||||||
`export default Route`
|
`export default Route`
|
||||||
|
|
|
@ -17,6 +17,8 @@ Route = TravisRoute.extend
|
||||||
deactivate: ->
|
deactivate: ->
|
||||||
@controllerFor('repos').removeObserver('firstObject', this, 'currentRepoDidChange')
|
@controllerFor('repos').removeObserver('firstObject', this, 'currentRepoDidChange')
|
||||||
|
|
||||||
|
@_super.apply(this, arguments)
|
||||||
|
|
||||||
currentRepoDidChange: ->
|
currentRepoDidChange: ->
|
||||||
if repo = @controllerFor('repos').get('firstObject')
|
if repo = @controllerFor('repos').get('firstObject')
|
||||||
@controllerFor('repo').set('repo', repo)
|
@controllerFor('repo').set('repo', repo)
|
||||||
|
|
|
@ -10,6 +10,7 @@ Route = AbstractBuildsRoute.extend(
|
||||||
this.controllerFor('builds').set('isPullRequestsList', true)
|
this.controllerFor('builds').set('isPullRequestsList', true)
|
||||||
|
|
||||||
deactivate: ->
|
deactivate: ->
|
||||||
|
@_super.apply(this, arguments)
|
||||||
this.controllerFor('builds').set('isPullRequestsList', false)
|
this.controllerFor('builds').set('isPullRequestsList', false)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -16,4 +16,6 @@ Route = TravisRoute.extend
|
||||||
@controllerFor('build').set('build', null)
|
@controllerFor('build').set('build', null)
|
||||||
@controllerFor('job').set('job', null)
|
@controllerFor('job').set('job', null)
|
||||||
|
|
||||||
|
@_super.apply(this, arguments)
|
||||||
|
|
||||||
`export default Route`
|
`export default Route`
|
||||||
|
|
13
app/utils/favicon-data-uris.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
var __inlineImageDataUri__ = function() {}; // in case image inliner doesn't run
|
||||||
|
|
||||||
|
var uris = {
|
||||||
|
default: __inlineImageDataUri__('favicon.png'),
|
||||||
|
red: __inlineImageDataUri__('favicon-red.png'),
|
||||||
|
gray: __inlineImageDataUri__('favicon-gray.png'),
|
||||||
|
green: __inlineImageDataUri__('favicon-green.png'),
|
||||||
|
yellow: __inlineImageDataUri__('favicon-yellow.png')
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function(type) {
|
||||||
|
return uris[type] || uris.default;
|
||||||
|
}
|
38
app/utils/favicon-manager.coffee
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
`import Ember from 'ember'`
|
||||||
|
|
||||||
|
manager = (headTag) ->
|
||||||
|
@headTag = headTag if headTag
|
||||||
|
|
||||||
|
return this
|
||||||
|
|
||||||
|
manager.prototype.getHeadTag = ->
|
||||||
|
@headTag || document.getElementsByTagName('head')[0]
|
||||||
|
|
||||||
|
manager.prototype.setFavicon = (href) ->
|
||||||
|
head = @getHeadTag()
|
||||||
|
|
||||||
|
if oldLink = @getLinkTag()
|
||||||
|
head.removeChild(oldLink)
|
||||||
|
|
||||||
|
link = @createLinkTag()
|
||||||
|
head.appendChild(link)
|
||||||
|
|
||||||
|
link.setAttribute('href', href)
|
||||||
|
setTimeout ->
|
||||||
|
link.setAttribute('href', href)
|
||||||
|
, 1
|
||||||
|
|
||||||
|
manager.prototype.getLinkTag = ->
|
||||||
|
links = @getHeadTag().getElementsByTagName('link')
|
||||||
|
if links.length
|
||||||
|
for link in links
|
||||||
|
if (link.getAttribute('rel') || '').trim() == 'icon'
|
||||||
|
return link
|
||||||
|
|
||||||
|
manager.prototype.createLinkTag = ->
|
||||||
|
link = document.createElement('link')
|
||||||
|
link.setAttribute('rel', 'icon')
|
||||||
|
link.setAttribute('type', 'image/png')
|
||||||
|
@getHeadTag().appendChild(link)
|
||||||
|
|
||||||
|
`export default manager`
|
|
@ -31,7 +31,7 @@
|
||||||
"ember-cli-htmlbars": "^0.6.0",
|
"ember-cli-htmlbars": "^0.6.0",
|
||||||
"ember-cli-ic-ajax": "0.1.1",
|
"ember-cli-ic-ajax": "0.1.1",
|
||||||
"ember-cli-inject-live-reload": "^1.3.0",
|
"ember-cli-inject-live-reload": "^1.3.0",
|
||||||
"ember-cli-inline-images": "^0.0.3",
|
"ember-cli-inline-images": "^0.0.4",
|
||||||
"ember-cli-pretender": "0.3.1",
|
"ember-cli-pretender": "0.3.1",
|
||||||
"ember-cli-qunit": "0.3.0",
|
"ember-cli-qunit": "0.3.0",
|
||||||
"ember-cli-sauce": "0.0.7",
|
"ember-cli-sauce": "0.0.7",
|
||||||
|
|
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 4.2 KiB |
BIN
public/images/favicon-gray.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
public/images/favicon-green.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
public/images/favicon-red.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
public/images/favicon-yellow.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
public/images/favicon.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 4.2 KiB |
51
tests/unit/utils/favicon-manager-test.coffee
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
`import Ember from 'ember'`
|
||||||
|
`import FaviconManager from 'travis/utils/favicon-manager'`
|
||||||
|
|
||||||
|
manager = null
|
||||||
|
fakeHead = null
|
||||||
|
|
||||||
|
module("Favicon manager",
|
||||||
|
beforeEach: ->
|
||||||
|
fakeHead = $('<div id="fake-head"></div>').appendTo($('#qunit-fixture'))
|
||||||
|
manager = new FaviconManager(fakeHead[0])
|
||||||
|
afterEach: ->
|
||||||
|
fakeHead.remove()
|
||||||
|
manager = null
|
||||||
|
)
|
||||||
|
|
||||||
|
test 'use <head> tag by default', ->
|
||||||
|
manager = new FaviconManager()
|
||||||
|
equal manager.getHeadTag(), $('head')[0]
|
||||||
|
|
||||||
|
test 'set favicon if there is no link tag in head', ->
|
||||||
|
equal fakeHead.find('link').length, 0, 'there should be no link tags initially'
|
||||||
|
|
||||||
|
manager.setFavicon('foobar')
|
||||||
|
|
||||||
|
link = fakeHead.find('link')[0]
|
||||||
|
|
||||||
|
ok link, 'link tag should be added by favicon manager'
|
||||||
|
equal link.getAttribute('href'), 'foobar', 'href attribute for the link should be properly set'
|
||||||
|
equal link.getAttribute('rel'), 'icon', 'rel attribute for the link should be properly set'
|
||||||
|
equal link.getAttribute('type'), 'image/png', 'type attribute for the link should be properly set'
|
||||||
|
|
||||||
|
test 'replace exisiting link tag', ->
|
||||||
|
fakeHead.append($('<link id="foo" rel="icon"></link>'))
|
||||||
|
|
||||||
|
ok 'foo', fakeHead.find('link').attr('id'), 'initially link should exist'
|
||||||
|
|
||||||
|
manager.setFavicon('foobar')
|
||||||
|
|
||||||
|
links = fakeHead.find('link')
|
||||||
|
equal links.length, 1, 'there should be only one link in head'
|
||||||
|
|
||||||
|
link = links[0]
|
||||||
|
|
||||||
|
ok !link.getAttribute('id'), 'existing link should be replaced with a new one'
|
||||||
|
equal link.getAttribute('href'), 'foobar', 'href attribute for the link should be properly set'
|
||||||
|
equal link.getAttribute('rel'), 'icon', 'rel attribute for the link should be properly set'
|
||||||
|
equal link.getAttribute('type'), 'image/png', 'type attribute for the link should be properly set'
|
||||||
|
|
||||||
|
test 'find link with rel=icon only', ->
|
||||||
|
fakeHead.append($('<link id="foo" rel="foo"></link>'))
|
||||||
|
ok !manager.getLinkTag()
|