Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
76706c5e
Commit
76706c5e
authored
Jun 10, 2016
by
Nick Stenning
Committed by
GitHub
Jun 10, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3444 from hypothesis/timestamp-component
Extract timestamp out into its own component
parents
14ee63db
0052c0b4
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
168 additions
and
163 deletions
+168
-163
app.js
h/static/scripts/app.js
+1
-0
annotation.js
h/static/scripts/directive/annotation.js
+3
-39
search-status-bar.js
h/static/scripts/directive/search-status-bar.js
+1
-0
sort-dropdown.js
h/static/scripts/directive/sort-dropdown.js
+2
-1
annotation-test.js
h/static/scripts/directive/test/annotation-test.js
+0
-116
h-tooltip-test.js
h/static/scripts/directive/test/h-tooltip-test.js
+1
-0
timestamp-test.js
h/static/scripts/directive/test/timestamp-test.js
+89
-0
util.js
h/static/scripts/directive/test/util.js
+6
-0
timestamp.js
h/static/scripts/directive/timestamp.js
+60
-0
annotation.html
h/templates/client/annotation.html
+5
-7
No files found.
h/static/scripts/app.js
View file @
76706c5e
...
...
@@ -152,6 +152,7 @@ module.exports = angular.module('h', [
.
directive
(
'sortDropdown'
,
require
(
'./directive/sort-dropdown'
))
.
directive
(
'spinner'
,
require
(
'./directive/spinner'
))
.
directive
(
'statusButton'
,
require
(
'./directive/status-button'
))
.
directive
(
'timestamp'
,
require
(
'./directive/timestamp'
))
.
directive
(
'topBar'
,
require
(
'./directive/top-bar'
))
.
directive
(
'windowScroll'
,
require
(
'./directive/window-scroll'
))
...
...
h/static/scripts/directive/annotation.js
View file @
76706c5e
...
...
@@ -4,7 +4,6 @@
var
angular
=
require
(
'angular'
);
var
annotationMetadata
=
require
(
'../annotation-metadata'
);
var
dateUtil
=
require
(
'../date-util'
);
var
documentDomain
=
require
(
'../filter/document-domain'
);
var
documentTitle
=
require
(
'../filter/document-title'
);
var
events
=
require
(
'../events'
);
...
...
@@ -111,7 +110,7 @@ function updateDomainModel(domainModel, vm, permissions) {
}
/** Update the view model from the domain model changes. */
function
updateViewModel
(
$scope
,
time
,
domainModel
,
function
updateViewModel
(
$scope
,
domainModel
,
vm
,
permissions
)
{
vm
.
form
=
{
...
...
@@ -132,22 +131,6 @@ function updateViewModel($scope, time, domainModel,
vm
.
isPrivate
=
permissions
.
isPrivate
(
domainModel
.
permissions
,
domainModel
.
user
);
function
updateTimestamp
()
{
vm
.
relativeTimestamp
=
time
.
toFuzzyString
(
domainModel
.
updated
);
vm
.
absoluteTimestamp
=
dateUtil
.
format
(
new
Date
(
domainModel
.
updated
));
}
if
(
domainModel
.
updated
)
{
if
(
vm
.
cancelTimestampRefresh
)
{
vm
.
cancelTimestampRefresh
();
}
vm
.
cancelTimestampRefresh
=
time
.
decayingInterval
(
domainModel
.
updated
,
function
()
{
$scope
.
$apply
(
updateTimestamp
);
});
updateTimestamp
();
}
var
documentMetadata
=
extractDocumentMetadata
(
domainModel
);
vm
.
documentTitle
=
documentTitle
(
documentMetadata
);
vm
.
documentDomain
=
documentDomain
(
documentMetadata
);
...
...
@@ -175,7 +158,7 @@ function viewModelTagsFromDomainModelTags(domainModelTags) {
function
AnnotationController
(
$document
,
$q
,
$rootScope
,
$scope
,
$timeout
,
$window
,
annotationUI
,
annotationMapper
,
drafts
,
flash
,
features
,
groups
,
permissions
,
session
,
settings
,
tags
,
time
)
{
settings
,
tags
)
{
var
vm
=
this
;
var
domainModel
;
...
...
@@ -213,21 +196,6 @@ function AnnotationController(
/** Whether or not this annotation is private. */
vm
.
isPrivate
=
false
;
/** A fuzzy, relative (eg. '6 days ago') format of the annotation's
* last update timestamp
*/
vm
.
relativeTimestamp
=
null
;
/** A formatted version of the annotation's last update timestamp
* (eg. 'Tue 22nd Dec 2015, 16:00')
*/
vm
.
absoluteTimestamp
=
''
;
/** A callback for resetting the automatic refresh of
* vm.relativeTimestamp and vm.absoluteTimestamp
*/
vm
.
cancelTimestampRefresh
=
undefined
;
/** Determines whether controls to expand/collapse the annotation body
* are displayed adjacent to the tags field.
*/
...
...
@@ -304,7 +272,7 @@ function AnnotationController(
}
function
updateView
(
domainModel
)
{
updateViewModel
(
$scope
,
time
,
domainModel
,
vm
,
permissions
);
updateViewModel
(
$scope
,
domainModel
,
vm
,
permissions
);
}
function
onAnnotationUpdated
(
event
,
updatedDomainModel
)
{
...
...
@@ -330,10 +298,6 @@ function AnnotationController(
if
(
vm
.
editing
())
{
saveToDrafts
(
drafts
,
domainModel
,
vm
);
}
if
(
vm
.
cancelTimestampRefresh
)
{
vm
.
cancelTimestampRefresh
();
}
}
function
onGroupFocused
()
{
...
...
h/static/scripts/directive/search-status-bar.js
View file @
76706c5e
...
...
@@ -3,6 +3,7 @@
// @ngInject
module
.
exports
=
function
()
{
return
{
controller
:
function
()
{},
restrict
:
'E'
,
scope
:
{
filterActive
:
'<'
,
...
...
h/static/scripts/directive/sort-dropdown.js
View file @
76706c5e
...
...
@@ -2,6 +2,7 @@
module
.
exports
=
function
()
{
return
{
controller
:
function
()
{},
restrict
:
'E'
,
scope
:
{
/** The name of the currently selected sort key. */
...
...
@@ -12,5 +13,5 @@ module.exports = function () {
onChangeSortKey
:
'&'
,
},
template
:
require
(
'../../../templates/client/sort_dropdown.html'
),
}
}
;
};
h/static/scripts/directive/test/annotation-test.js
View file @
76706c5e
...
...
@@ -144,7 +144,6 @@ describe('annotation', function() {
var
fakeGroups
;
var
fakePermissions
;
var
fakeSession
;
var
fakeTime
;
var
sandbox
;
function
createDirective
(
annotation
)
{
...
...
@@ -236,11 +235,6 @@ describe('annotation', function() {
store
:
sandbox
.
stub
()
};
fakeTime
=
{
toFuzzyString
:
sandbox
.
stub
().
returns
(
'a while ago'
),
decayingInterval
:
function
()
{},
};
fakeGroups
=
{
focused
:
function
()
{
return
{};
...
...
@@ -257,7 +251,6 @@ describe('annotation', function() {
$provide
.
value
(
'session'
,
fakeSession
);
$provide
.
value
(
'settings'
,
fakeSettings
);
$provide
.
value
(
'tags'
,
fakeTags
);
$provide
.
value
(
'time'
,
fakeTime
);
$provide
.
value
(
'groups'
,
fakeGroups
);
}));
...
...
@@ -742,115 +735,6 @@ describe('annotation', function() {
});
});
describe
(
'relativeTimestamp'
,
function
()
{
var
annotation
;
var
clock
;
beforeEach
(
function
()
{
clock
=
sinon
.
useFakeTimers
();
annotation
=
fixtures
.
defaultAnnotation
();
annotation
.
created
=
(
new
Date
()).
toString
();
annotation
.
updated
=
(
new
Date
()).
toString
();
});
afterEach
(
function
()
{
clock
.
restore
();
});
it
(
'is not updated for unsaved annotations'
,
function
()
{
annotation
.
updated
=
null
;
var
controller
=
createDirective
(
annotation
).
controller
;
// Unsaved annotations don't have an updated time yet so a timestamp
// string can't be computed for them.
$scope
.
$digest
();
assert
.
equal
(
controller
.
relativeTimestamp
,
null
);
});
it
(
'is updated when a new annotation is saved'
,
function
()
{
fakeTime
.
decayingInterval
=
function
(
date
,
callback
)
{
callback
();
};
// fake clocks are not required for this test
clock
.
restore
();
annotation
.
updated
=
null
;
annotation
.
$create
=
function
()
{
annotation
.
updated
=
(
new
Date
()).
toString
();
return
Promise
.
resolve
(
annotation
);
};
var
controller
=
createDirective
(
annotation
).
controller
;
controller
.
action
=
'create'
;
controller
.
form
.
text
=
'test'
;
return
controller
.
save
().
then
(
function
()
{
assert
.
equal
(
controller
.
relativeTimestamp
,
'a while ago'
);
});
});
it
(
'is updated when a change to an existing annotation is saved'
,
function
()
{
fakeTime
.
toFuzzyString
=
function
(
date
)
{
var
ONE_MINUTE
=
60
*
1000
;
if
(
Date
.
now
()
-
new
Date
(
date
)
<
ONE_MINUTE
)
{
return
'just now'
;
}
else
{
return
'ages ago'
;
}
};
clock
.
tick
(
10
*
60
*
1000
);
annotation
.
$update
=
function
()
{
this
.
updated
=
(
new
Date
()).
toString
();
return
Promise
.
resolve
(
this
);
};
var
controller
=
createDirective
(
annotation
).
controller
;
assert
.
equal
(
controller
.
relativeTimestamp
,
'ages ago'
);
controller
.
edit
();
controller
.
form
.
text
=
'test'
;
clock
.
restore
();
return
controller
.
save
().
then
(
function
()
{
assert
.
equal
(
controller
.
relativeTimestamp
,
'just now'
);
});
});
it
(
'is updated on first digest'
,
function
()
{
var
controller
=
createDirective
(
annotation
).
controller
;
$scope
.
$digest
();
assert
.
equal
(
controller
.
relativeTimestamp
,
'a while ago'
);
});
it
(
'is updated after a timeout'
,
function
()
{
fakeTime
.
decayingInterval
=
function
(
date
,
callback
)
{
setTimeout
(
callback
,
10
);
};
var
controller
=
createDirective
(
annotation
).
controller
;
fakeTime
.
toFuzzyString
.
returns
(
'ages ago'
);
$scope
.
$digest
();
clock
.
tick
(
11000
);
assert
.
equal
(
controller
.
relativeTimestamp
,
'ages ago'
);
});
it
(
'is no longer updated after the scope is destroyed'
,
function
()
{
createDirective
(
annotation
);
$scope
.
$digest
();
$scope
.
$destroy
();
$timeout
.
verifyNoPendingTasks
();
});
});
describe
(
'absoluteTimestamp'
,
function
()
{
it
(
'returns the current time'
,
function
()
{
var
annotation
=
fixtures
.
defaultAnnotation
();
var
controller
=
createDirective
(
annotation
).
controller
;
var
expectedDate
=
new
Date
(
annotation
.
updated
);
// the exact format of the result will depend on the current locale,
// but check that at least the current year and time are present
assert
.
match
(
controller
.
absoluteTimestamp
,
new
RegExp
(
'.*2015.*'
+
expectedDate
.
toLocaleTimeString
()));
});
});
describe
(
'deleteAnnotation() method'
,
function
()
{
beforeEach
(
function
()
{
fakeAnnotationMapper
.
deleteAnnotation
=
sandbox
.
stub
();
...
...
h/static/scripts/directive/test/h-tooltip-test.js
View file @
76706c5e
...
...
@@ -6,6 +6,7 @@ var util = require('./util');
function
testComponent
()
{
return
{
controller
:
function
()
{},
restrict
:
'E'
,
template
:
'<div aria-label="Share" h-tooltip>Label</div>'
,
};
...
...
h/static/scripts/directive/test/timestamp-test.js
0 → 100644
View file @
76706c5e
'use strict'
;
var
angular
=
require
(
'angular'
);
var
util
=
require
(
'./util'
);
describe
(
'timestamp'
,
function
()
{
var
clock
;
var
fakeTime
;
before
(
function
()
{
angular
.
module
(
'app'
,[])
.
directive
(
'timestamp'
,
require
(
'../timestamp'
));
});
beforeEach
(
function
()
{
clock
=
sinon
.
useFakeTimers
();
fakeTime
=
{
toFuzzyString
:
sinon
.
stub
().
returns
(
'a while ago'
),
decayingInterval
:
function
()
{},
};
angular
.
mock
.
module
(
'app'
,
{
time
:
fakeTime
,
});
});
afterEach
(
function
()
{
clock
.
restore
();
});
describe
(
'#relativeTimestamp'
,
function
()
{
it
(
'displays a relative time string'
,
function
()
{
var
element
=
util
.
createDirective
(
document
,
'timestamp'
,
{
timestamp
:
'2016-06-10T10:04:04.939Z'
,
});
assert
.
equal
(
element
.
ctrl
.
relativeTimestamp
,
'a while ago'
);
});
it
(
'is updated when the timestamp changes'
,
function
()
{
var
element
=
util
.
createDirective
(
document
,
'timestamp'
,
{
timestamp
:
'1776-07-04T10:04:04.939Z'
,
});
element
.
scope
.
timestamp
=
'1863-11-19T12:00:00.939Z'
;
fakeTime
.
toFuzzyString
.
returns
(
'four score and seven years ago'
);
element
.
scope
.
$digest
();
assert
.
equal
(
element
.
ctrl
.
relativeTimestamp
,
'four score and seven years ago'
);
});
it
(
'is updated after time passes'
,
function
()
{
fakeTime
.
decayingInterval
=
function
(
date
,
callback
)
{
setTimeout
(
callback
,
10
);
};
var
element
=
util
.
createDirective
(
document
,
'timestamp'
,
{
timestamp
:
'2016-06-10T10:04:04.939Z'
,
});
fakeTime
.
toFuzzyString
.
returns
(
'60 jiffies'
);
element
.
scope
.
$digest
();
clock
.
tick
(
1000
);
assert
.
equal
(
element
.
ctrl
.
relativeTimestamp
,
'60 jiffies'
);
});
it
(
'is no longer updated after the component is destroyed'
,
function
()
{
var
cancelRefresh
=
sinon
.
stub
();
fakeTime
.
decayingInterval
=
function
()
{
return
cancelRefresh
;
};
var
element
=
util
.
createDirective
(
document
,
'timestamp'
,
{
timestamp
:
'2016-06-10T10:04:04.939Z'
,
});
element
.
ctrl
.
$onDestroy
();
assert
.
called
(
cancelRefresh
);
});
});
describe
(
'#absoluteTimestamp'
,
function
()
{
it
(
'displays the current time'
,
function
()
{
var
expectedDate
=
new
Date
(
'2016-06-10T10:04:04.939Z'
);
var
element
=
util
.
createDirective
(
document
,
'timestamp'
,
{
timestamp
:
expectedDate
.
toISOString
(),
});
// The exact format of the result will depend on the current locale,
// but check that at least the current year and time are present
assert
.
match
(
element
.
ctrl
.
absoluteTimestamp
,
new
RegExp
(
'.*2016.*'
+
expectedDate
.
toLocaleTimeString
()));
});
});
});
h/static/scripts/directive/test/util.js
View file @
76706c5e
...
...
@@ -151,6 +151,12 @@ function createDirective(document, name, attrs, initialScope, initialHtml, opts)
element
.
scope
=
childScope
;
childScope
.
$digest
();
element
.
ctrl
=
element
.
controller
(
name
);
if
(
!
element
.
ctrl
)
{
throw
new
Error
(
'Failed to create "'
+
name
+
'" directive in test.'
+
'Did you forget to register it with angular.module(...).directive() ?'
);
}
return
element
;
};
...
...
h/static/scripts/directive/timestamp.js
0 → 100644
View file @
76706c5e
'use strict'
;
var
dateUtil
=
require
(
'../date-util'
);
// @ngInject
function
TimestampController
(
$scope
,
time
)
{
var
vm
=
this
;
// A fuzzy, relative (eg. '6 days ago') format of the timestamp.
vm
.
relativeTimestamp
=
null
;
// A formatted version of the timestamp (eg. 'Tue 22nd Dec 2015, 16:00')
vm
.
absoluteTimestamp
=
''
;
var
cancelTimestampRefresh
;
function
updateTimestamp
()
{
vm
.
relativeTimestamp
=
time
.
toFuzzyString
(
vm
.
timestamp
);
vm
.
absoluteTimestamp
=
dateUtil
.
format
(
new
Date
(
vm
.
timestamp
));
if
(
vm
.
timestamp
)
{
if
(
cancelTimestampRefresh
)
{
cancelTimestampRefresh
();
}
cancelTimestampRefresh
=
time
.
decayingInterval
(
vm
.
timestamp
,
function
()
{
updateTimestamp
();
$scope
.
$digest
();
});
}
}
this
.
$onChanges
=
function
(
changes
)
{
if
(
changes
.
timestamp
)
{
updateTimestamp
();
}
};
this
.
$onDestroy
=
function
()
{
if
(
cancelTimestampRefresh
)
{
cancelTimestampRefresh
();
}
};
}
module
.
exports
=
function
()
{
return
{
bindToController
:
true
,
controller
:
TimestampController
,
controllerAs
:
'vm'
,
restrict
:
'E'
,
scope
:
{
className
:
'<'
,
href
:
'<'
,
timestamp
:
'<'
,
},
template
:
[
'<a class="{{vm.className}}" target="_blank" ng-title="vm.absoluteTimestamp"'
,
' href="{{vm.href}}"'
,
'>{{vm.relativeTimestamp}}</a>'
].
join
(
''
),
};
};
h/templates/client/annotation.html
View file @
76706c5e
...
...
@@ -40,13 +40,11 @@
<span
class=
"u-flex-spacer"
></span>
<!-- Timestamp -->
<a
class=
"annotation-header__timestamp"
target=
"_blank"
title=
"{{vm.absoluteTimestamp}}"
ng-if=
"!vm.editing() && vm.updated()"
ng-href=
"{{vm.linkHTML}}"
>
{{vm.relativeTimestamp}}
</a>
<timestamp
class-name=
"'annotation-header__timestamp'"
timestamp=
"vm.updated()"
href=
"vm.linkHTML"
ng-if=
"!vm.editing() && vm.updated()"
></timestamp>
</header>
<!-- Excerpts -->
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment