View
@@ -1,131 +1,46 @@
# Annotator core
# Annotator
annotator:
filters: uglifyjs
output: scripts/annotator/annotator.min.js
contents:
- h:static/scripts/vendor/annotator.js
- filters: coffeescript
output: scripts/annotator/monkey.js
contents: h:static/scripts/annotator/monkey.coffee
# Annotator app plugins
annotator_plugins_app:
filters: uglifyjs
output: scripts/annotator/annotator-app.min.js
contents: h:static/scripts/vendor/annotator.auth.js
# Annotator inject plugins
annotator_plugins_inject:
filters: uglifyjs
output: scripts/annotator/annotator-inject.min.js
contents:
# Non-anchoring-related stuff
- filters: coffeescript
output: scripts/annotator/plugin/bridge.js
contents:
- h:static/scripts/annotator/plugin/cross-frame.coffee
- h:static/scripts/discovery.coffee
- h:static/scripts/bridge.coffee
- h:static/scripts/annotation-sync.coffee
- filters: coffeescript
output: scripts/annotator/plugin/bucket-bar.js
contents: h:static/scripts/annotator/plugin/bucket-bar.coffee
- h:static/scripts/vendor/annotator.document.js
- filters: coffeescript
output: scripts/annotator/plugin/toolbar.js
contents: h:static/scripts/annotator/plugin/toolbar.coffee
# Drawing highlights
- filters: coffeescript
output: scripts/annotator/plugin/texthighlights.js
contents: h:static/scripts/annotator/plugin/texthighlights.coffee
# Creating selections
- filters: coffeescript
output: scripts/annotator/plugin/textselection.js
contents: h:static/scripts/annotator/plugin/textselection.coffee
output: scripts/vendor/annotator.min.js
contents: h:static/scripts/vendor/annotator.js
# URL fragments
- filters: coffeescript
output: scripts/annotator/plugin/fragmentselector.js
contents: h:static/scripts/annotator/plugin/fragmentselector.coffee
# Anchoring
- h:static/scripts/vendor/dom_text_mapper.js
- filters: coffeescript
output: scripts/annotator/annotator.anchoring.js
contents:
- h:static/scripts/annotator/plugin/enhancedanchoring.coffee
- h:static/scripts/annotator/plugin/domtextmapper.coffee
- h:static/scripts/annotator/plugin/textposition.coffee
- h:static/scripts/annotator/plugin/textquote.coffee
- h:static/scripts/annotator/plugin/textrange.coffee
# PDF
- h:static/scripts/vendor/page_text_mapper_core.js
- filters: coffeescript
output: scripts/annotator/annotator.pdf.js
contents: h:static/scripts/annotator/plugin/pdf.coffee
# Fuzzy
- h:static/scripts/vendor/diff_match_patch_uncompressed.js
- h:static/scripts/vendor/dom_text_matcher.js
- h:static/scripts/vendor/text_match_engines.js
- filters: coffeescript
output: scripts/annotator/annotator.fuzzy.js
contents:
- h:static/scripts/annotator/plugin/fuzzytextanchors.coffee
# Angular
angular:
filters: uglifyjs
output: scripts/vendor/angular.min.js
contents:
- h:static/scripts/vendor/angular.js
contents: h:static/scripts/vendor/angular.js
angular_animate:
filters: uglifyjs
output: scripts/vendor/angular-animate.min.js
contents:
- h:static/scripts/vendor/angular-animate.js
contents: h:static/scripts/vendor/angular-animate.js
angular_bootstrap:
filters: uglifyjs
output: scripts/vendor/angular-bootstrap.min.js
contents:
- h:static/scripts/vendor/angular-bootstrap.js
contents: h:static/scripts/vendor/angular-bootstrap.js
angular_resource:
filters: uglifyjs
output: scripts/vendor/angular-resource.min.js
contents:
- h:static/scripts/vendor/angular-resource.js
contents: h:static/scripts/vendor/angular-resource.js
angular_route:
filters: uglifyjs
output: scripts/vendor/angular-route.min.js
contents:
- h:static/scripts/vendor/angular-route.js
contents: h:static/scripts/vendor/angular-route.js
angular_sanitize:
filters: uglifyjs
output: scripts/vendor/angular-sanitize.min.js
contents:
- h:static/scripts/vendor/angular-sanitize.js
contents: h:static/scripts/vendor/angular-sanitize.js
angular_tags_input:
filters: uglifyjs
output: scripts/vendor/ng-tags-input.min.js
contents:
- h:static/scripts/vendor/ng-tags-input.js
contents: h:static/scripts/vendor/ng-tags-input.js
# jQuery
jquery:
filters: uglifyjs
output: scripts/vendor/jquery.min.js
contents:
- h:static/scripts/vendor/jquery.js
jquery_scrollintoview:
filters: uglifyjs
output: scripts/vendor/jquery.scrollintoview.min.js
contents:
- h:static/scripts/vendor/jquery.scrollintoview.js
contents: h:static/scripts/vendor/jquery.js
# TeX rendering
@@ -139,110 +54,71 @@ katex:
autofill:
filters: uglifyjs
output: scripts/vendor/polyfills/autofill-event.min.js
contents:
- h:static/scripts/vendor/polyfills/autofill-event.js
contents: h:static/scripts/vendor/polyfills/autofill-event.js
bind:
filters: uglifyjs
output: scripts/vendor/polyfills/bind.min.js
contents: h:static/scripts/vendor/polyfills/bind.js
wgxpath:
filters: uglifyjs
output: scripts/vendor/polyfills/wgxpath.install.min.js
contents:
- h:static/scripts/vendor/polyfills/wgxpath.install.js
contents: h:static/scripts/vendor/polyfills/wgxpath.install.js
url:
filters: uglifyjs
output: scripts/vendor/polyfills/url.min.js
contents:
- h:static/scripts/vendor/polyfills/url.js
contents: h:static/scripts/vendor/polyfills/url.js
# Other dependencies
jschannel:
filters: uglifyjs
output: scripts/vendor/jschannel.min.js
contents:
- h:static/scripts/vendor/jschannel.js
jwz:
filters: uglifyjs
output: scripts/vendor/jwz.min.js
contents:
- h:static/scripts/vendor/jwz.js
momentjs:
contents:
- filters: uglifyjs
output: scripts/vendor/moment.min.js
contents:
- h:static/scripts/vendor/moment-with-langs.js
contents: h:static/scripts/vendor/moment-with-langs.js
- filters: uglifyjs
output: scripts/vendor/jstz.min.js
contents:
- h:static/scripts/vendor/jstz.js
contents: h:static/scripts/vendor/jstz.js
- filters: uglifyjs
output: scripts/vendor/moment-timezone.min.js
contents:
- h:static/scripts/vendor/moment-timezone.js
contents: h:static/scripts/vendor/moment-timezone.js
- filters: uglifyjs
output: scripts/vendor/moment-timezone-data.min.js
contents:
- h:static/scripts/vendor/moment-timezone-data.js
pagedown:
filters: uglifyjs
output: scripts/vendor/Markdown.Converter.min.js
contents:
- h:static/scripts/vendor/Markdown.Converter.js
unorm:
filters: uglifyjs
output: scripts/vendor/unorm.min.js
contents:
- h:static/scripts/vendor/unorm.js
uuid:
filters: uglifyjs
output: scripts/vendor/uuid.min.js
contents:
- h:static/scripts/vendor/uuid.js
contents: h:static/scripts/vendor/moment-timezone-data.js
# Application
app:
contents:
- jquery
- angular
- angular_animate
- angular_bootstrap
- angular_resource
- angular_route
- angular_sanitize
- angular_tags_input
- annotator
- autofill
- bind
- katex
- momentjs
- url
- helpers
- app_css
- app_js
- helpers
app_js:
output: scripts/app.min.js
contents:
- jschannel
- jwz
- katex
- momentjs
- pagedown
- autofill
- unorm
- url
- uuid
- angular_tags_input
- annotator
- annotator_plugins_app
- filters: uglifyjs
contents:
- filters: coffeescript
output: scripts/app.js
contents:
- h:static/scripts/app.coffee
- h:static/scripts/controllers.coffee
- h:static/scripts/directives.coffee
- h:static/scripts/directives/*.coffee
- h:static/scripts/filters.coffee
- h:static/scripts/searchfilters.coffee
- h:static/scripts/services.coffee
- h:static/scripts/*-service.coffee
- h:static/scripts/streamsearch.coffee
- h:static/scripts/annotation-sync.coffee
- h:static/scripts/annotation-ui-sync.coffee
- h:static/scripts/bridge.coffee
- h:static/scripts/discovery.coffee
filters:
- browserify
- uglifyjs
contents: h:static/scripts/app.coffee
depends:
- h:static/scripts/*.coffee
- h:static/scripts/annotator/*.coffee
- h:static/scripts/annotator/plugin/*.coffee
- h:static/scripts/directives/*.coffee
- h:static/scripts/session/*.coffee
app_css:
filters: cleancss, cssrewrite
@@ -280,46 +156,32 @@ account:
contents:
- jquery
- angular
- angular_bootstrap
- angular_route
- helpers
- session
- output: scripts/account.min.js
filters: uglifyjs
contents:
- output: scripts/account.js
filters: coffeescript
contents:
- h:static/scripts/account/account.coffee
- h:static/scripts/account/*-controller.coffee
- h:static/scripts/account/*-service.coffee
filters:
- browserify
- uglifyjs
contents: h:static/scripts/account/account.coffee
depends: h:static/scripts/account/*
helpers:
output: scripts/helpers.min.js
contents:
- angular_bootstrap
- filters: uglifyjs
contents:
- filters: coffeescript
output: scripts/helpers.js
contents:
- h:static/scripts/helpers/helpers.coffee
- h:static/scripts/helpers/*-helpers.coffee
- h:static/scripts/helpers/*-service.coffee
filters:
- browserify
- uglifyjs
contents: h:static/scripts/helpers/helpers.coffee
depends: h:static/scripts/helpers/*
session:
output: scripts/session.min.js
contents:
- contents:
- filters: uglifyjs
contents:
- filters: coffeescript
output: scripts/session.js
contents:
- h:static/scripts/session/session.coffee
- h:static/scripts/session/*-service.coffee
filters:
- browserify
- uglifyjs
contents: h:static/scripts/session/session.coffee
depends: h:static/scripts/session/*
# The inject bundle is intended to be loaded into pages for bootstrapping
# the application. It sets up RPC channels for cross-domain communication
@@ -331,23 +193,18 @@ inject:
- inject_js
inject_js:
output: scripts/hypothesis.min.js
contents:
- jquery
- jquery_scrollintoview
- jschannel
- annotator
- annotator_plugins_inject
- url
- filters: uglifyjs
contents:
- filters: coffeescript
output: scripts/hypothesis.js
contents:
- h:static/scripts/guest.coffee
- h:static/scripts/host.coffee
- h:static/bootstrap.js
- jquery
- annotator
- output: scripts/hypothesis.min.js
filters: browserify
contents: h:static/bootstrap.js
depends:
- h:static/scripts/*.coffee
- h:static/scripts/annotator/*.coffee
- h:static/scripts/annotator/plugin/*.coffee
- h:static/scripts/directives/*.coffee
- h:static/scripts/session/*.coffee
inject_css:
output: styles/hypothesis.min.css
View
@@ -1,4 +1,49 @@
var Klass = window.Annotator.Host;
var Annotator = require('annotator');
// Monkeypatch annotator!
require('./scripts/annotator/monkey');
// Cross-frame communication
require('./scripts/annotator/plugin/cross-frame');
require('./scripts/annotation-sync');
require('./scripts/bridge');
require('./scripts/discovery');
// Document plugin
require('./scripts/vendor/annotator.document');
// Bucket bar
require('./scripts/annotator/plugin/bucket-bar');
// Toolbar
require('./scripts/annotator/plugin/toolbar');
// Drawing highlights
require('./scripts/annotator/plugin/texthighlights');
// Creating selections
require('./scripts/annotator/plugin/textselection');
// URL fragments
require('./scripts/annotator/plugin/fragmentselector');
// Anchoring
require('./scripts/vendor/dom_text_mapper');
require('./scripts/annotator/plugin/enhancedanchoring');
require('./scripts/annotator/plugin/domtextmapper');
require('./scripts/annotator/plugin/textposition');
require('./scripts/annotator/plugin/textquote');
require('./scripts/annotator/plugin/textrange');
// PDF
require('./scripts/vendor/page_text_mapper_core');
require('./scripts/annotator/plugin/pdf');
// Fuzzy
require('./scripts/vendor/dom_text_matcher');
require('./scripts/annotator/plugin/fuzzytextanchors');
var Klass = require('./scripts/host');
var docs = 'https://github.com/hypothesis/h/blob/master/README.rst#customized-embedding';
var options = {
app: jQuery('link[type="application/annotator+html"]').attr('href'),
@@ -23,4 +68,4 @@ if (window.hasOwnProperty('hypothesisConfig')) {
}
window.annotator = new Klass(document.body, options);
window.Annotator.noConflict().$.noConflict(true);
Annotator.noConflict().$.noConflict(true);
View

This file was deleted.

Oops, something went wrong.
View
@@ -1,3 +1,5 @@
angular = require('angular')
AUTH_SESSION_ACTIONS = [
'login'
'logout'
@@ -124,3 +126,6 @@ angular.module('h')
.config(configure)
.controller('AuthAppController', AuthAppController)
.controller('AuthPageController', AuthPageController)
require('./account-controller')
require('./auth-controller')
View
@@ -1,3 +1,5 @@
Annotator = require('annotator')
# Save references to Range and Util (because we call Annotator.noConflict() when
# bootstrapping)
Range = Annotator.Range
View
@@ -1,3 +1,5 @@
Annotator = require('annotator')
$ = Annotator.$
class Annotator.Plugin.BucketBar extends Annotator.Plugin
@@ -338,3 +340,5 @@ class Annotator.Plugin.BucketBar extends Annotator.Plugin
isUpper: (i) -> i == 1
isLower: (i) -> i == @index.length - 2
exports.BucketBar = Annotator.Plugin.BucketBar
View
@@ -1,3 +1,5 @@
Annotator = require('annotator')
$ = Annotator.$
# Extracts individual keys from an object and returns a new one.
@@ -45,3 +47,5 @@ CrossFrame = class Annotator.Plugin.CrossFrame extends Annotator.Plugin
this.onConnect = (fn) ->
bridge.onConnect(fn)
exports.CrossFrame = CrossFrame
View
@@ -1,4 +1,4 @@
Annotator = @Annotator
Annotator = require('annotator')
$ = Annotator.$
# Fake two-phase / pagination support, used for HTML documents
@@ -293,3 +293,5 @@ class Annotator.Plugin.EnhancedAnchoring extends Annotator.Plugin
selectors
exports.Anchor = Anchor
exports.EnhancedAnchoring = Annotator.Plugin.EnhancedAnchoring
View
@@ -1,3 +1,5 @@
require('../../vendor/jquery.scrollintoview')
$ = Annotator.$
# Public: Wraps the DOM Nodes within the provided range with a highlight
@@ -125,3 +127,5 @@ class Annotator.Plugin.TextHighlights extends Annotator.Plugin
pluginInit: ->
# Export the text highlight class for other plugins
Annotator.TextHighlight = TextHighlight
exports.TextHighlight = TextHighlight
View
@@ -1,3 +1,11 @@
angular = require('angular')
uuid = require('./vendor/uuid')
# These services are provided in their own angular modules and thus must be
# loaded first.
require('./identity-service')
require('./streamer-service')
imports = [
'ngAnimate'
'ngRoute'
@@ -92,3 +100,38 @@ module = angular.module('h', imports)
unless mocha? # Crude method of detecting test environment.
module.run(setupCrossFrame)
module.run(setupStreamer)
require('./vendor/annotator.auth.js')
require('./annotator/monkey')
require('./controllers')
require('./directives')
require('./directives/annotation')
require('./directives/deep-count')
require('./directives/markdown')
require('./directives/privacy')
require('./directives/simple-search')
require('./directives/status-button')
require('./directives/thread-filter')
require('./directives/thread')
require('./filters')
require('./searchfilters')
require('./services')
require('./annotation-mapper-service')
require('./annotation-ui-service')
require('./auth-service')
require('./cross-frame-service')
require('./flash-service')
require('./permissions-service')
require('./store-service')
require('./threading-service')
require('./streamsearch')
require('./annotation-sync')
require('./annotation-ui-sync')
require('./bridge')
require('./discovery')
View
@@ -1,3 +1,6 @@
$ = require('jquery')
Channel = require('./vendor/jschannel')
class Bridge
options:
# Scope identifier to distinguish this channel from any others
View
@@ -22,13 +22,13 @@ class AppController
this.$inject = [
'$controller', '$document', '$location', '$route', '$scope', '$window',
'auth', 'drafts', 'identity',
'permissions', 'streamer', 'streamfilter', 'annotationUI',
'permissions', 'streamer', 'annotationUI',
'annotationMapper', 'threading'
]
constructor: (
$controller, $document, $location, $route, $scope, $window,
auth, drafts, identity,
permissions, streamer, streamfilter, annotationUI,
permissions, streamer, annotationUI,
annotationMapper, threading
) ->
$controller(AnnotationUIController, {$scope})
@@ -176,11 +176,11 @@ class AnnotationViewerController
class ViewerController
this.$inject = [
'$scope', '$route', 'annotationUI', 'crossframe', 'annotationMapper',
'auth', 'flash', 'streamer', 'streamfilter', 'store'
'auth', 'streamer', 'streamfilter', 'store'
]
constructor: (
$scope, $route, annotationUI, crossframe, annotationMapper,
auth, flash, streamer, streamfilter, store
auth, streamer, streamfilter, store
) ->
# Tells the view that these annotations are embedded into the owner doc
$scope.isEmbedded = true
View
@@ -1,3 +1,6 @@
angular = require('angular')
Markdown = require('./vendor/Markdown.Converter')
class Converter extends Markdown.Converter
constructor: ->
super
View
@@ -1,8 +1,9 @@
Annotator = @Annotator
$ = Annotator.$
$ = require('jquery')
Annotator = require('annotator')
Channel = require('./vendor/jschannel')
class Annotator.Guest extends Annotator
module.exports = class Annotator.Guest extends Annotator
SHOW_HIGHLIGHTS_CLASS = 'annotator-highlights-always-on'
# Events to be bound on Annotator#element.
View
@@ -1 +1,9 @@
angular = require('angular')
angular.module('h.helpers', ['bootstrap'])
require('./form-helpers')
require('./string-helpers')
require('./time-helpers')
require('./ui-helpers')
require('./xsrf-service')
View
@@ -1,3 +1,6 @@
angular = require('angular')
unorm = require('../vendor/unorm')
# Shared helper methods for working with strings/unicode strings
# For unicode normalization we use the unorm library
createStringHelpers = ->
View
@@ -1,8 +1,9 @@
Annotator = @Annotator
$ = Annotator.$
$ = require('jquery')
Annotator = require('annotator')
Guest = require('./guest')
class Annotator.Host extends Annotator.Guest
module.exports = class Annotator.Host extends Annotator.Guest
# Drag state variables
drag:
delta: 0
View
@@ -1 +1,5 @@
angular = require('angular')
angular.module('h.session', ['ngResource', 'h.helpers'])
require('./session-service')
View
@@ -1,3 +1,6 @@
angular = require('angular')
mail = require('./vendor/jwz')
class ThreadingService
# Mix in message thread properties into the prototype. The body of the
# class will overwrite any methods applied here. If you need inheritance
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View
@@ -10,52 +10,43 @@ module.exports = function(config) {
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['mocha'],
frameworks: [
'browserify',
'mocha'
],
// list of files / patterns to load in the browser
files: [
'h/static/scripts/vendor/polyfills/bind.js',
'h/static/scripts/vendor/polyfills/url.js',
'h/static/scripts/vendor/polyfills/promise.js',
// Application external deps
'h/static/scripts/vendor/jquery.js',
'h/static/scripts/vendor/jschannel.js',
'h/static/scripts/vendor/jwz.js',
'h/static/scripts/vendor/moment-with-langs.js',
'h/static/scripts/vendor/jstz.js',
'h/static/scripts/vendor/moment-timezone.js',
'h/static/scripts/vendor/moment-timezone-data.js',
'h/static/scripts/vendor/Markdown.Converter.js',
'h/static/scripts/vendor/unorm.js',
'h/static/scripts/vendor/uuid.js',
'h/static/scripts/vendor/annotator.js',
'h/static/scripts/annotator/monkey.js',
'h/static/scripts/vendor/annotator.auth.js',
'h/static/scripts/annotator/plugin/bridge.js',
'h/static/scripts/annotator/plugin/bucket-bar.js',
'h/static/scripts/vendor/dom_text_mapper.js',
'h/static/scripts/annotator/annotator.anchoring.js',
// Angular needs to be included after annotator to avoid the
// CrossFrame dependencies in Bridge picking up the angular object.
'h/static/scripts/vendor/angular.js',
'h/static/scripts/vendor/angular-mocks.js',
'h/static/scripts/vendor/angular-animate.js',
'h/static/scripts/vendor/angular-bootstrap.js',
'h/static/scripts/vendor/angular-resource.js',
'h/static/scripts/vendor/angular-route.js',
'h/static/scripts/vendor/angular-sanitize.js',
'h/static/scripts/vendor/ng-tags-input.js',
'h/static/scripts/annotator/plugin/texthighlights.js',
'h/static/scripts/app.js',
'h/static/scripts/account.js',
'h/static/scripts/helpers.js',
'h/static/scripts/session.js',
'h/static/scripts/hypothesis.js',
'h/static/scripts/vendor/annotator.js',
'h/static/scripts/vendor/polyfills/autofill-event.js',
'h/static/scripts/vendor/polyfills/bind.js',
'h/static/scripts/vendor/katex/katex.js',
'h/static/scripts/vendor/moment-with-langs.js',
'h/static/scripts/vendor/jstz.js',
'h/static/scripts/vendor/moment-timezone.js',
'h/static/scripts/vendor/moment-timezone-data.js',
'h/static/scripts/vendor/polyfills/url.js',
// Test deps
'h/static/scripts/vendor/angular-mocks.js',
'h/static/scripts/vendor/polyfills/promise.js',
'h/static/scripts/vendor/sinon.js',
'h/static/scripts/vendor/chai.js',
'h/templates/client/*.html',
'tests/js/bootstrap.coffee',
'tests/js/**/*-test.coffee'
// Tests
'tests/js/**/*-test.coffee',
],
@@ -72,10 +63,14 @@ module.exports = function(config) {
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'**/*.coffee': ['coffee'],
'**/*.coffee': ['browserify'],
'h/templates/client/*.html': ['ng-html2js'],
},
browserify: {
debug: true,
extensions: ['.coffee']
},
// test results reporter to use
// possible values: 'dots', 'progress'
@@ -97,7 +92,7 @@ module.exports = function(config) {
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
autoWatch: true,
// start these browsers
View
@@ -4,14 +4,17 @@
"version": "0.0.0",
"description": "The Internet, peer reviewed.",
"dependencies": {
"coffee-script": "1.7.1",
"browserify": "^9.0.3",
"browserify-shim": "^3.8.3",
"clean-css": "2.2.2",
"coffee-script": "1.7.1",
"coffeeify": "^1.0.0",
"uglify-js": "2.4.14"
},
"devDependencies": {
"karma": "^0.12.17",
"karma-browserify": "^3.0.3",
"karma-cli": "0.0.4",
"karma-coffee-preprocessor": "^0.2.1",
"karma-mocha": "^0.1.4",
"karma-ng-html2js-preprocessor": "^0.1.0",
"karma-phantomjs-launcher": "^0.1.4",
@@ -32,5 +35,29 @@
"bugs": {
"url": "https://github.com/hypothesis/h/issues"
},
"homepage": "https://github.com/hypothesis/h"
"homepage": "https://github.com/hypothesis/h",
"browserify": {
"transform": ["coffeeify", "browserify-shim"]
},
"browser": {
"jquery": "./h/static/scripts/vendor/jquery.js",
"annotator": "./h/static/scripts/vendor/annotator.js",
"angular": "./h/static/scripts/vendor/angular.js",
"angular-mock": "./h/static/scripts/vendor/angular-mocks.js"
},
"browserify-shim": {
"jquery": "global:jQuery",
"annotator": "global:Annotator",
"angular": "global:angular",
"angular-mock": "global:angular.mock",
"./h/static/scripts/vendor/jschannel.js": "Channel",
"./h/static/scripts/vendor/page_text_mapper_core.js": "PageTextMapperCore",
"./h/static/scripts/vendor/dom_text_matcher.js": {
"exports": "DomTextMatcher",
"depends": [
"./h/static/scripts/vendor/diff_match_patch_uncompressed.js",
"./h/static/scripts/vendor/text_match_engines.js"
]
}
}
}
View
@@ -66,11 +66,10 @@ jinja2.extensions: h.jinja_extensions:IncludeRawExtension
webassets.base_dir: h:static
webassets.base_url: assets
webassets.cache_max_age: 31536000
webassets.coffee_no_bare: True
webassets.static_view: True
webassets.uglifyjs_bin: %(here)s/node_modules/.bin/uglifyjs
webassets.cleancss_bin: %(here)s/node_modules/.bin/cleancss
webassets.coffee_bin: %(here)s/node_modules/.bin/coffee
webassets.browserify_pipe_bin: %(here)s/tools/browserify-pipe
[filter:proxy-prefix]
View
@@ -1,8 +1,10 @@
{inject, module} = require('angular-mock')
assert = chai.assert
sinon.assert.expose assert, prefix: null
sandbox = sinon.sandbox.create()
describe 'AccountController', ->
describe 'h:AccountController', ->
$scope = null
fakeFlash = null
fakeSession = null
@@ -13,10 +15,16 @@ describe 'AccountController', ->
disableUserPromise = null
profilePromise = null
createController = null
sandbox = null
before ->
angular.module('h', [])
require('../../../h/static/scripts/account/account-controller')
beforeEach module('h')
beforeEach module ($provide, $filterProvider) ->
sandbox = sinon.sandbox.create()
fakeSession = {}
fakeFlash = sandbox.spy()
fakeIdentity =
@@ -49,6 +57,9 @@ describe 'AccountController', ->
createController = ->
$controller('AccountController', {$scope: $scope})
afterEach ->
sandbox.restore()
describe '.submit', ->
createFakeForm = (overrides={}) ->
defaults =
View
@@ -1,3 +1,5 @@
{inject, module} = require('angular-mock')
assert = chai.assert
sinon.assert.expose assert, prefix: null
sandbox = sinon.sandbox.create()
@@ -19,12 +21,16 @@ class MockSession
mockFlash = sandbox.spy()
mockFormHelpers = applyValidationErrors: sandbox.spy()
describe 'AuthController', ->
describe 'h:AuthController', ->
$scope = null
$timeout = null
auth = null
session = null
before ->
angular.module('h', [])
require('../../../h/static/scripts/account/auth-controller')
beforeEach module('h')
beforeEach module('h.templates')
View
@@ -1,6 +1,9 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose(assert, prefix: '')
describe 'AnnotationMapperService', ->
sandbox = sinon.sandbox.create()
@@ -9,6 +12,10 @@ describe 'AnnotationMapperService', ->
fakeThreading = null
annotationMapper = null
before ->
angular.module('h', [])
require('../../h/static/scripts/annotation-mapper-service')
beforeEach module('h')
beforeEach module ($provide) ->
View
@@ -1,6 +1,9 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose(assert, prefix: '')
describe 'AnnotationSync', ->
sandbox = sinon.sandbox.create()
publish = null
@@ -10,6 +13,10 @@ describe 'AnnotationSync', ->
options = null
PARENT_WINDOW = 'PARENT_WINDOW'
before ->
angular.module('h', [])
require('../../h/static/scripts/annotation-sync')
beforeEach module('h')
beforeEach inject (AnnotationSync, $rootScope) ->
listeners = {}
View
@@ -1,9 +1,16 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose(assert, prefix: '')
describe 'AnnotationUI', ->
annotationUI = null
before ->
angular.module('h', [])
require('../../h/static/scripts/annotation-ui-service')
beforeEach module('h')
beforeEach inject (_annotationUI_) ->
annotationUI = _annotationUI_
View
@@ -1,6 +1,9 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose(assert, prefix: '')
describe 'AnnotationUISync', ->
sandbox = sinon.sandbox.create()
$digest = null
@@ -13,6 +16,10 @@ describe 'AnnotationUISync', ->
createChannel = -> {notify: sandbox.stub()}
PARENT_WINDOW = 'PARENT_WINDOW'
before ->
angular.module('h', [])
require('../../h/static/scripts/annotation-ui-sync')
beforeEach module('h')
beforeEach inject (AnnotationUISync, $rootScope) ->
$digest = sandbox.stub($rootScope, '$digest')
View
@@ -1,10 +1,12 @@
bb = require('../../../../h/static/scripts/annotator/plugin/bucket-bar')
assert = chai.assert
sinon.assert.expose(assert, prefix: '')
describe 'Annotator.BucketBar', ->
createBucketBar = (options) ->
element = document.createElement('div')
new Annotator.Plugin.BucketBar(element, options || {})
new bb.BucketBar(element, options || {})
# Yes this is testing a private method. Yes this is bad practice, but I'd
# rather test this functionality in a private method than not test it at all.
View
@@ -1,8 +1,10 @@
cf = require('../../../../h/static/scripts/annotator/plugin/cross-frame')
assert = chai.assert
sinon.assert.expose(assert, prefix: '')
describe 'Annotator.Plugin.CrossFrame', ->
CrossFrame = null
fakeDiscovery = null
fakeBridge = null
fakeAnnotationSync = null
@@ -13,7 +15,7 @@ describe 'Annotator.Plugin.CrossFrame', ->
on: sandbox.stub()
emit: sandbox.stub()
element = document.createElement('div')
return new Annotator.Plugin.CrossFrame(element, $.extend({}, defaults, options))
return new cf.CrossFrame(element, $.extend({}, defaults, options))
beforeEach ->
fakeDiscovery =
@@ -29,44 +31,38 @@ describe 'Annotator.Plugin.CrossFrame', ->
fakeAnnotationSync =
sync: sandbox.stub()
CrossFrame = Annotator.Plugin.CrossFrame
sandbox.stub(CrossFrame, 'AnnotationSync').returns(fakeAnnotationSync)
sandbox.stub(CrossFrame, 'Discovery').returns(fakeDiscovery)
sandbox.stub(CrossFrame, 'Bridge').returns(fakeBridge)
cf.CrossFrame.AnnotationSync = sandbox.stub().returns(fakeAnnotationSync)
cf.CrossFrame.Discovery = sandbox.stub().returns(fakeDiscovery)
cf.CrossFrame.Bridge = sandbox.stub().returns(fakeBridge)
afterEach ->
sandbox.restore()
describe 'constructor', ->
it 'instantiates the Discovery component', ->
createCrossFrame()
assert.called(CrossFrame.Discovery)
assert.calledWith(CrossFrame.Discovery, window)
assert.calledWith(cf.CrossFrame.Discovery, window)
it 'passes the options along to the bridge', ->
createCrossFrame(server: true)
assert.called(CrossFrame.Discovery)
assert.calledWith(CrossFrame.Discovery, window, server: true)
assert.calledWith(cf.CrossFrame.Discovery, window, server: true)
it 'instantiates the CrossFrame component', ->
createCrossFrame()
assert.called(CrossFrame.Bridge)
assert.calledWith(CrossFrame.Discovery)
assert.calledWith(cf.CrossFrame.Discovery)
it 'passes the options along to the bridge', ->
createCrossFrame(scope: 'myscope')
assert.called(CrossFrame.Bridge)
assert.calledWith(CrossFrame.Bridge, scope: 'myscope')
assert.calledWith(cf.CrossFrame.Bridge, scope: 'myscope')
it 'instantiates the AnnotationSync component', ->
createCrossFrame()
assert.called(CrossFrame.AnnotationSync)
assert.called(cf.CrossFrame.AnnotationSync)
it 'passes along options to AnnotationSync', ->
formatter = (x) -> x
createCrossFrame(formatter: formatter)
assert.called(CrossFrame.AnnotationSync)
assert.calledWith(CrossFrame.AnnotationSync, fakeBridge, {
assert.calledWith(cf.CrossFrame.AnnotationSync, fakeBridge, {
on: sinon.match.func
emit: sinon.match.func
formatter: formatter
View
@@ -1,11 +1,18 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose assert, prefix: null
describe 'h', ->
fakeAnnotator = null
fakeIdentity = null
sandbox = null
before ->
angular.module('h', [])
require('../../h/static/scripts/auth-service')
beforeEach module('h')
beforeEach module ($provide) ->
View
@@ -1,11 +1,19 @@
{module, inject} = require('angular-mock')
Channel = require('../../h/static/scripts/vendor/jschannel.js')
assert = chai.assert
sinon.assert.expose assert, prefix: null
describe 'Bridge', ->
sandbox = sinon.sandbox.create()
createBridge = null
createChannel = null
before ->
angular.module('h', [])
require('../../h/static/scripts/bridge')
beforeEach module('h')
beforeEach inject (Bridge) ->
createBridge = (options) ->
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -1,6 +1,9 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose assert, prefix: null
describe 'CrossFrameService', ->
sandbox = sinon.sandbox.create()
crossframe = null
@@ -14,6 +17,10 @@ describe 'CrossFrameService', ->
fakeAnnotationSync = null
fakeAnnotationUISync = null
before ->
angular.module('h', [])
require('../../h/static/scripts/cross-frame-service')
beforeEach module('h')
beforeEach module ($provide) ->
$fakeDocument = {}
View
@@ -1,140 +1,24 @@
assert = chai.assert
describe 'h.directives', ->
$scope = null
$compile = null
$injector = null
fakeWindow = null
beforeEach module ($provide, $filterProvider) ->
fakeWindow = {open: sinon.spy()}
fakeDocument = angular.element({
createElement: (tag) -> document.createElement(tag)
baseURI: 'http://example.com'
})
{module, inject} = require('angular-mock')
$provide.value('$window', fakeWindow)
$provide.value('$document', fakeDocument)
assert = chai.assert
$filterProvider.register 'persona', ->
(user, part) ->
parts = user.slice(5).split('@')
{username: parts[0], provider: parts[1]}[part]
return
describe 'h:directives', ->
before ->
angular.module('h', [])
require('../../h/static/scripts/directives')
beforeEach module('h')
beforeEach inject (_$compile_, _$rootScope_, _$injector_) ->
$compile = _$compile_
$scope = _$rootScope_.$new()
$injector = _$injector_
describe '.formValidate', ->
$element = null
beforeEach ->
$scope.model = {username: undefined}
template = '''
<form form-validate name="login" onsubmit="return false">
<div class="form-field">
<input type="text" class="form-input" name="username"
ng-model="model.username" name="username"
required ng-minlength="3" />
</div>
</form>
'''
$element = $compile(angular.element(template))($scope)
$scope.$digest()
it 'should remove an error class to an valid field on change', ->
$field = $element.find('.form-field').addClass('form-field-error')
$input = $element.find('[name=username]').addClass('form-field-error')
$input.controller('ngModel').$setViewValue('abc')
$scope.$digest()
assert.notInclude($field.prop('className'), 'form-field-error')
assert.notInclude($input.prop('className'), 'form-field-error')
it 'should apply an error class to an invalid field on submit', ->
$field = $element.find('.form-field')
$element.triggerHandler('submit')
assert.include($field.prop('className'), 'form-field-error')
it 'should remove an error class from a valid field on submit', ->
$field = $element.find('.form-field').addClass('form-field-error')
$input = $element.find('[name=username]')
$input.val('abc').triggerHandler('input')
$element.triggerHandler('submit')
assert.notInclude($field.prop('className'), 'form-field-error')
it 'should apply an error class if the form recieves errors after a submit action', ->
$element.trigger('submit')
$element.controller('form').username.$setValidity('response', false)
$field = $element.find('.form-field')
assert.include $field.prop('className'), 'form-field-error'
it 'should remove an error class on valid input when the view model changes', ->
$field = $element.find('.form-field').addClass('form-field-error')
$input = $element.find('[name=username]')
$input.val('abc').triggerHandler('input')
assert.notInclude($field.prop('className'), 'form-field-error')
it 'should not add an error class on invalid input on when the view changes', ->
$field = $element.find('.form-field')
$input = $element.find('[name=username]')
$input.val('ab').triggerHandler('input')
assert.notInclude($field.prop('className'), 'form-field-error')
it 'should reset the "response" error when the view changes', ->
$field = $element.find('.form-field')
$input = $element.find('[name=username]')
controller = $input.controller('ngModel')
controller.$setViewValue('abc')
# Submit Event
$element.triggerHandler('submit')
controller.$setValidity('response', false)
controller.responseErrorMessage = 'fail'
$scope.$digest()
assert.include($field.prop('className'), 'form-field-error', 'Fail fast check')
controller.$setViewValue('abc')
$scope.$digest()
assert.notInclude($field.prop('className'), 'form-field-error')
it 'should hide errors if the model is marked as pristine', ->
$field = $element.find('.form-field').addClass('form-field-error')
$input = $element.find('[name=username]')
controller = $input.controller('ngModel')
# Submit Event
$element.triggerHandler('submit')
controller.$setValidity('response', false)
controller.responseErrorMessage = 'fail'
$scope.$digest()
assert.include($field.prop('className'), 'form-field-error', 'Fail fast check')
# Then clear it out and mark it as pristine
controller.$setPristine()
$scope.$digest()
assert.notInclude($field.prop('className'), 'form-field-error')
describe '.match', ->
$compile = null
$element = null
$isolateScope = null
$scope = null
beforeEach inject (_$compile_, _$rootScope_) ->
$compile = _$compile_
$scope = _$rootScope_.$new()
beforeEach ->
$scope.model = {a: 1, b: 1}
View
@@ -1,5 +1,7 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sandbox = sinon.sandbox.create()
describe 'h.directives.annotation', ->
$compile = null
@@ -8,17 +10,28 @@ describe 'h.directives.annotation', ->
$timeout = null
annotation = null
createController = null
flash = null
fakeAuth = null
fakeStore = null
fakeUser = null
fakeAnnotationMapper = null
fakeAnnotationUI = null
fakeAuth = null
fakeDrafts = null
fakeFlash = null
fakeMomentFilter = null
fakePermissions = null
fakePersonaFilter = null
fakeStore = null
fakeTimeHelpers = null
fakeUrlEncodeFilter = null
sandbox = null
before ->
angular.module('h', [])
require('../../../h/static/scripts/directives/annotation')
beforeEach module('h')
beforeEach module('h.templates')
beforeEach module ($provide) ->
sandbox = sinon.sandbox.create()
fakeAuth =
user: 'acct:bill@localhost'
fakeAnnotationMapper =
@@ -30,11 +43,37 @@ describe 'h.directives.annotation', ->
admin: ['acct:bill@localhost']
deleteAnnotation: sandbox.stub()
fakeAnnotationUI = {}
fakeDrafts = {
add: sandbox.stub()
remove: sandbox.stub()
}
fakeFlash = sandbox.stub()
fakeMomentFilter = sandbox.stub().returns('ages ago')
fakePermissions = {
isPublic: sandbox.stub().returns(true)
isPrivate: sandbox.stub().returns(false)
permits: sandbox.stub().returns(true)
public: sandbox.stub().returns({read: ['everybody']})
private: sandbox.stub().returns({read: ['justme']})
}
fakePersonaFilter = sandbox.stub().returnsArg(0)
fakeTimeHelpers = {
toFuzzyString: sandbox.stub().returns('a while ago')
nextFuzzyUpdate: sandbox.stub().returns(30)
}
fakeUrlEncodeFilter = (v) -> encodeURIComponent(v)
$provide.value 'auth', fakeAuth
$provide.value 'store', fakeStore
$provide.value 'annotationMapper', fakeAnnotationMapper
$provide.value 'annotationUI', fakeAnnotationUI
$provide.value 'auth', fakeAuth
$provide.value 'drafts', fakeDrafts
$provide.value 'flash', fakeFlash
$provide.value 'momentFilter', fakeMomentFilter
$provide.value 'permissions', fakePermissions
$provide.value 'personaFilter', fakePersonaFilter
$provide.value 'store', fakeStore
$provide.value 'timeHelpers', fakeTimeHelpers
$provide.value 'urlencodeFilter', fakeUrlEncodeFilter
return
beforeEach inject (_$compile_, $controller, _$document_, $rootScope, _$timeout_) ->
@@ -50,12 +89,10 @@ describe 'h.directives.annotation', ->
target: [{}]
uri: 'http://example.com'
user: 'acct:bill@localhost'
flash = sinon.spy()
createController = ->
$controller 'AnnotationController',
$scope: $scope
flash: flash
afterEach ->
sandbox.restore()
@@ -82,7 +119,7 @@ describe 'h.directives.annotation', ->
delete annotation.id
controller = createController()
$scope.$digest()
assert controller.isPrivate()
assert.deepEqual annotation.permissions, {read: ['justme']}
describe '#reply', ->
controller = null
@@ -102,26 +139,19 @@ describe 'h.directives.annotation', ->
match = sinon.match {references: [annotation.id], uri: annotation.uri}
assert.calledWith(fakeAnnotationMapper.createAnnotation, match)
it 'adds the world readable principal if the parent is public', ->
it 'makes the annotation public if the parent is public', ->
reply = {}
fakeAnnotationMapper.createAnnotation.returns(reply)
annotation.permissions.read.push('group:__world__')
fakePermissions.isPublic.returns(true)
controller.reply()
assert.include(reply.permissions.read, 'group:__world__')
assert.deepEqual(reply.permissions, {read: ['everybody']})
it 'does not add the world readable principal if the parent is private', ->
reply = {}
fakeAnnotationMapper.createAnnotation.returns(reply)
fakePermissions.isPublic.returns(false)
controller.reply()
assert.notInclude(reply.permissions.read, 'group:__world__')
it 'fills the other permissions too', ->
reply = {}
fakeAnnotationMapper.createAnnotation.returns(reply)
controller.reply()
assert.equal(reply.permissions.update[0], 'acct:bill@localhost')
assert.equal(reply.permissions.delete[0], 'acct:bill@localhost')
assert.equal(reply.permissions.admin[0], 'acct:bill@localhost')
assert.deepEqual(reply.permissions, {read: ['justme']})
describe '#render', ->
controller = null
@@ -297,18 +327,15 @@ describe 'h.directives.annotation', ->
it 'is updated on first digest', ->
$scope.$digest()
assert.isNotNull(controller.timestamp)
assert.equal(controller.timestamp, 'a while ago')
it 'is updated after a timeout', ->
fakeTimeHelpers.nextFuzzyUpdate.returns(10)
$scope.$digest()
timestamp = controller.timestamp
clock.tick(30000)
$timeout.flush()
assert.notEqual(timestamp, controller.timestamp)
timestamp = controller.timestamp
clock.tick(30000)
clock.tick(11000)
fakeTimeHelpers.toFuzzyString.returns('ages ago')
$timeout.flush()
assert.notEqual(timestamp, controller.timestamp)
assert.equal(controller.timestamp, 'ages ago')
it 'is no longer updated after the scope is destroyed', ->
$scope.$digest()
View
@@ -1,108 +1,93 @@
{module, inject} = require('angular-mock')
assert = chai.assert
VISIBILITY_KEY ='hypothesis.visibility'
VISIBILITY_PUBLIC = 'public'
VISIBILITY_PRIVATE = 'private'
describe 'h.directives.privacy', ->
$window = null
$scope = null
$compile = null
$injector = null
$element = null
$isolateScope = null
$scope = null
$window = null
fakeAuth = null
fakePermissions = null
sandbox = null
before ->
angular.module('h', [])
require('../../../h/static/scripts/directives/privacy')
beforeEach module('h')
beforeEach module('h.templates')
describe 'memory fallback', ->
fakeAuth = null
sandbox = null
beforeEach module ($provide) ->
sandbox = sinon.sandbox.create()
fakeAuth = {
user: 'acct:angry.joe@texas.com'
}
$provide.value 'auth', fakeAuth
return
afterEach ->
sandbox.restore()
beforeEach module ($provide) ->
sandbox = sinon.sandbox.create()
describe 'has memory fallback', ->
$window = null
$scope2 = null
fakeAuth = {
user: 'acct:angry.joe@texas.com'
}
beforeEach inject (_$compile_, _$rootScope_, _$window_) ->
$compile = _$compile_
$scope = _$rootScope_.$new()
$scope2 = _$rootScope_.$new()
$window = _$window_
fakePermissions = {
isPublic: sandbox.stub().returns(true)
isPrivate: sandbox.stub().returns(false)
permits: sandbox.stub().returns(true)
public: sandbox.stub().returns({read: ['everybody']})
private: sandbox.stub().returns({read: ['justme']})
}
$window.localStorage = null
$provide.value 'auth', fakeAuth
$provide.value 'permissions', fakePermissions
return
it 'stores the default visibility level when it changes', ->
$scope.permissions = {read: ['acct:user@example.com']}
$element = $compile('<privacy ng-model="permissions">')($scope)
$scope.$digest()
$isolateScope = $element.isolateScope()
$isolateScope.setLevel(name: VISIBILITY_PUBLIC)
beforeEach inject (_$compile_, _$rootScope_, _$window_) ->
$compile = _$compile_
$scope = _$rootScope_.$new()
$window = _$window_
$scope2.permissions = {read: []}
$element = $compile('<privacy ng-model="permissions">')($scope2)
$scope2.$digest()
afterEach ->
sandbox.restore()
# Roundabout way: the storage works because the directive
# could read out the privacy level
readPermissions = $scope2.permissions.read[0]
assert.equal readPermissions, 'group:__world__'
describe 'has localStorage', ->
sandbox = null
fakeAuth = null
beforeEach module ($provide) ->
sandbox = sinon.sandbox.create()
describe 'memory fallback', ->
$scope2 = null
fakeAuth = {
user: 'acct:angry.joe@texas.com'
}
beforeEach inject (_$rootScope_) ->
$scope2 = _$rootScope_.$new()
$provide.value 'auth', fakeAuth
return
$window.localStorage = null
afterEach ->
sandbox.restore()
it 'stores the default visibility level when it changes', ->
$scope.permissions = {read: ['acct:user@example.com']}
$element = $compile('<privacy ng-model="permissions">')($scope)
$scope.$digest()
$isolateScope = $element.isolateScope()
$isolateScope.setLevel(name: VISIBILITY_PUBLIC)
beforeEach inject (_$compile_, _$rootScope_, _$injector_, _$window_) ->
$compile = _$compile_
$scope = _$rootScope_.$new()
$injector = _$injector_
$window = _$window_
$scope2.permissions = {read: []}
$element = $compile('<privacy ng-model="permissions">')($scope2)
$scope2.$digest()
describe 'storage', ->
store = null
# Roundabout way: the storage works because the directive
# could read out the privacy level
readPermissions = $scope2.permissions.read[0]
assert.equal readPermissions, 'everybody'
beforeEach ->
store = $window.localStorage
describe 'has localStorage', ->
it 'stores the default visibility level when it changes', ->
$scope.permissions = {read: ['acct:user@example.com']}
$element = $compile('<privacy ng-model="permissions">')($scope)
$scope.$digest()
$isolateScope = $element.isolateScope()
$isolateScope.setLevel(name: VISIBILITY_PUBLIC)
it 'stores the default visibility level when it changes', ->
$scope.permissions = {read: ['acct:user@example.com']}
$element = $compile('<privacy ng-model="permissions">')($scope)
$scope.$digest()
$isolateScope = $element.isolateScope()
$isolateScope.setLevel(name: VISIBILITY_PUBLIC)
expected = VISIBILITY_PUBLIC
stored = store.getItem VISIBILITY_KEY
assert.equal stored, expected
expected = VISIBILITY_PUBLIC
stored = $window.localStorage.getItem VISIBILITY_KEY
assert.equal stored, expected
describe 'setting permissions', ->
$element = null
store = null
modelCtrl = null
beforeEach ->
store = $window.localStorage
@@ -125,17 +110,15 @@ describe 'h.directives.privacy', ->
$scope.permissions = {read: []}
$element = $compile('<privacy ng-model="permissions">')($scope)
$scope.$digest()
$isolateScope = $element.isolateScope()
it 'sets the initial permissions based on the stored privacy level', ->
assert.equal $isolateScope.level.name, VISIBILITY_PUBLIC
assert.equal $element.isolateScope().level.name, VISIBILITY_PUBLIC
it 'does not alter the level on subsequent renderings', ->
modelCtrl = $element.controller('ngModel')
store.setItem VISIBILITY_KEY, VISIBILITY_PRIVATE
$scope.permissions.read = ['acct:user@example.com']
$scope.$digest()
assert.equal $isolateScope.level.name, VISIBILITY_PUBLIC
assert.equal $element.isolateScope().level.name, VISIBILITY_PUBLIC
describe 'when permissions.read is filled', ->
it 'does not alter the level', ->
@@ -156,25 +139,11 @@ describe 'h.directives.privacy', ->
$element = $compile('<privacy ng-model="permissions">')($scope)
$scope.$digest()
readPermissions = $scope.permissions.read[0]
updatePermissions = $scope.permissions.update[0]
deletePermissions = $scope.permissions.delete[0]
adminPermissions = $scope.permissions.admin[0]
assert.equal readPermissions, fakeAuth.user
assert.equal updatePermissions, fakeAuth.user
assert.equal deletePermissions, fakeAuth.user
assert.equal adminPermissions, fakeAuth.user
assert.deepEqual $scope.permissions, fakePermissions.private()
it 'puts group_world into the read permissions for public visibility', ->
store.setItem VISIBILITY_KEY, VISIBILITY_PUBLIC
$element = $compile('<privacy ng-model="permissions">')($scope)
$scope.$digest()
readPermissions = $scope.permissions.read[0]
updatePermissions = $scope.permissions.update[0]
deletePermissions = $scope.permissions.delete[0]
adminPermissions = $scope.permissions.admin[0]
assert.equal readPermissions, 'group:__world__'
assert.equal updatePermissions, fakeAuth.user
assert.equal deletePermissions, fakeAuth.user
assert.equal adminPermissions, fakeAuth.user
assert.deepEqual $scope.permissions, fakePermissions.public()
View
@@ -1,73 +1,78 @@
{module, inject} = require('angular-mock')
assert = chai.assert
describe 'h.directives', ->
$scope = null
describe 'h:directives.simple-search', ->
$compile = null
$element = null
$scope = null
fakeWindow = null
isolate = null
before ->
angular.module('h', [])
require('../../../h/static/scripts/directives/simple-search')
beforeEach module('h')
beforeEach inject (_$compile_, _$rootScope_) ->
$compile = _$compile_
$scope = _$rootScope_.$new()
describe '.simpleSearch', ->
$element = null
beforeEach ->
$scope.update = sinon.spy()
$scope.clear = sinon.spy()
template= '''
<div class="simpleSearch"
query="query"
on-search="update(query)"
on-clear="clear()">
</div>
'''
$element = $compile(angular.element(template))($scope)
$scope.$digest()
isolate = $element.isolateScope()
it 'updates the search-bar', ->
$scope.query = "Test query"
$scope.$digest()
assert.equal(isolate.searchtext, $scope.query)
it 'calls the given search function', ->
isolate.searchtext = "Test query"
isolate.$digest()
$element.find('form').triggerHandler('submit')
sinon.assert.calledWith($scope.update, "Test query")
it 'calls the given clear function', ->
$element.find('.simple-search-clear').click()
assert($scope.clear.called)
it 'clears the search-bar', ->
isolate.query = ''
isolate.$digest()
isolate.searchtext = "Test query"
isolate.$digest()
$element.find('.simple-search-clear').click()
assert.equal(isolate.searchtext, '')
it 'invokes callbacks when the input model changes', ->
$scope.query = "Test query"
$scope.$digest()
sinon.assert.calledOnce($scope.update)
$scope.query = ""
$scope.$digest()
sinon.assert.calledOnce($scope.clear)
it 'adds a class to the form when there is no input value', ->
$form = $element.find('.simple-search-form')
assert.include($form.prop('className'), 'simple-search-inactive')
it 'removes the class from the form when there is an input value', ->
$scope.query = "Test query"
$scope.$digest()
$form = $element.find('.simple-search-form')
assert.notInclude($form.prop('className'), 'simple-search-inactive')
$scope.update = sinon.spy()
$scope.clear = sinon.spy()
template= '''
<div class="simpleSearch"
query="query"
on-search="update(query)"
on-clear="clear()">
</div>
'''
$element = $compile(angular.element(template))($scope)
$scope.$digest()
isolate = $element.isolateScope()
it 'updates the search-bar', ->
$scope.query = "Test query"
$scope.$digest()
assert.equal(isolate.searchtext, $scope.query)
it 'calls the given search function', ->
isolate.searchtext = "Test query"
isolate.$digest()
$element.find('form').triggerHandler('submit')
sinon.assert.calledWith($scope.update, "Test query")
it 'calls the given clear function', ->
$element.find('.simple-search-clear').click()
assert($scope.clear.called)
it 'clears the search-bar', ->
isolate.query = ''
isolate.$digest()
isolate.searchtext = "Test query"
isolate.$digest()
$element.find('.simple-search-clear').click()
assert.equal(isolate.searchtext, '')
it 'invokes callbacks when the input model changes', ->
$scope.query = "Test query"
$scope.$digest()
sinon.assert.calledOnce($scope.update)
$scope.query = ""
$scope.$digest()
sinon.assert.calledOnce($scope.clear)
it 'adds a class to the form when there is no input value', ->
$form = $element.find('.simple-search-form')
assert.include($form.prop('className'), 'simple-search-inactive')
it 'removes the class from the form when there is an input value', ->
$scope.query = "Test query"
$scope.$digest()
$form = $element.find('.simple-search-form')
assert.notInclude($form.prop('className'), 'simple-search-inactive')
View
@@ -1,10 +1,17 @@
{module, inject} = require('angular-mock')
assert = chai.assert
describe 'h.directives.statusButton', ->
describe 'h:directives.status-button', ->
$scope = null
$compile = null
$element = null
before ->
angular.module('h', [])
require('../../../h/static/scripts/directives/status-button')
beforeEach module('h')
beforeEach inject (_$compile_, _$rootScope_) ->
View
@@ -1,155 +1,167 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose assert, prefix: null
describe 'h.directives.thread.ThreadController', ->
$scope = null
createController = null
beforeEach module('h')
beforeEach inject ($controller, $rootScope) ->
$scope = $rootScope.$new()
createController = ->
controller = $controller 'ThreadController'
controller
describe '#toggleCollapsed', ->
it 'sets the collapsed property', ->
controller = createController()
before = controller.collapsed
controller.toggleCollapsed()
after = controller.collapsed
assert.equal(before, !after)
describe '#shouldShowReply', ->
count = null
controller = null
beforeEach ->
controller = createController()
count = sinon.stub()
describe 'when root', ->
beforeEach -> controller.isRoot = true
describe 'and when not filtered', ->
it 'shows the reply if the thread is not collapsed and has children', ->
count.withArgs('message').returns(1)
assert.isTrue(controller.shouldShowReply(count, false))
it 'does not show the reply if the thread is not collapsed and has no children', ->
count.withArgs('message').returns(0)
assert.isFalse(controller.shouldShowReply(count, false))
it 'shows the reply if the thread is collapsed and has children', ->
count.withArgs('message').returns(1)
controller.collapsed = true
assert.isTrue(controller.shouldShowReply(count, false))
it 'does not show the reply if the thread is collapsed and has no children', ->
count.withArgs('message').returns(0)
controller.collapsed = true
assert.isFalse(controller.shouldShowReply(count, false))
describe 'and when filtered with children', ->
it 'shows the reply if the thread is not collapsed', ->
count.withArgs('match').returns(1)
count.withArgs('message').returns(1)
assert.isTrue(controller.shouldShowReply(count, true))
it 'does not show the reply if the thread is not collapsed and the message count does not match the match count', ->
count.withArgs('match').returns(0)
count.withArgs('message').returns(1)
assert.isFalse(controller.shouldShowReply(count, true))
describe 'when reply', ->
beforeEach -> controller.isRoot = false
describe 'and when not filtered', ->
it 'shows the reply if the thread is not collapsed and has children', ->
count.withArgs('message').returns(1)
assert.isTrue(controller.shouldShowReply(count, false))
it 'does not show the reply if the thread is not collapsed and has no children', ->
count.withArgs('message').returns(0)
assert.isFalse(controller.shouldShowReply(count, false))
it 'does not show the reply if the thread is collapsed and has children', ->
count.withArgs('message').returns(1)
controller.collapsed = true
assert.isFalse(controller.shouldShowReply(count, false))
it 'does not show the reply if the thread is collapsed and has no children', ->
count.withArgs('message').returns(0)
controller.collapsed = true
assert.isFalse(controller.shouldShowReply(count, false))
describe 'and when filtered with children', ->
it 'shows the reply if the thread is not collapsed', ->
count.withArgs('match').returns(1)
count.withArgs('message').returns(1)
assert.isTrue(controller.shouldShowReply(count, true))
it 'does not show the reply if the thread is not collapsed and the message count does not match the match count', ->
count.withArgs('match').returns(0)
count.withArgs('message').returns(1)
assert.isFalse(controller.shouldShowReply(count, true))
describe 'h.directives.thread.thread', ->
createElement = null
$element = null
$isolateScope = null
fakePulse = null
describe 'h:directives.thread', ->
fakeRender = null
sandbox = null
before ->
angular.module('h', [])
require('../../../h/static/scripts/directives/thread')
beforeEach module('h')
beforeEach module ($provide) ->
sandbox = sinon.sandbox.create()
fakePulse = sandbox.spy()
$provide.value 'pulse', fakePulse
fakeRender = sandbox.spy()
$provide.value 'render', fakeRender
return
beforeEach inject ($compile, $rootScope) ->
createElement = (html) -> $compile(html or '<div thread></div>')($rootScope.$new())
$element = createElement()
$isolateScope = $element.scope()
afterEach ->
sandbox.restore()
it 'sets the threadRoot on the controller to false', ->
controller = $element.controller('thread')
assert.isFalse(controller.isRoot)
it 'sets the threadRoot on the controller to true when the thread-root attr is set', ->
$element = createElement('<div thread thread-root="true"></div>')
controller = $element.controller('thread')
assert.isTrue(controller.isRoot)
it 'pulses the current thread on an annotationUpdated event', ->
$element.scope().$emit('annotationUpdate')
assert.called(fakePulse)
it 'does not pulse the thread if it is hidden (parent collapsed)', ->
fakeParent = {
controller: -> {collapsed: true}
}
sandbox.stub(angular.element.prototype, 'parent').returns(fakeParent)
$element.scope().$emit('annotationUpdate')
assert.notCalled(fakePulse)
it 'does not pulse the thread if it is hidden (grandparent collapsed)', ->
fakeGrandParent = {
controller: -> {collapsed: true}
}
fakeParent = {
controller: -> {collapsed: false}
parent: -> fakeGrandParent
}
sandbox.stub(angular.element.prototype, 'parent').returns(fakeParent)
$element.scope().$emit('annotationUpdate')
assert.notCalled(fakePulse)
describe '.ThreadController', ->
$scope = null
createController = null
beforeEach inject ($controller, $rootScope) ->
$scope = $rootScope.$new()
createController = ->
controller = $controller 'ThreadController'
controller
describe '#toggleCollapsed', ->
it 'sets the collapsed property', ->
controller = createController()
before = controller.collapsed
controller.toggleCollapsed()
after = controller.collapsed
assert.equal(before, !after)
describe '#shouldShowReply', ->
count = null
controller = null
beforeEach ->
controller = createController()
count = sinon.stub()
describe 'when root', ->
beforeEach -> controller.isRoot = true
describe 'and when not filtered', ->
it 'shows the reply if the thread is not collapsed and has children', ->
count.withArgs('message').returns(1)
assert.isTrue(controller.shouldShowReply(count, false))
it 'does not show the reply if the thread is not collapsed and has no children', ->
count.withArgs('message').returns(0)
assert.isFalse(controller.shouldShowReply(count, false))
it 'shows the reply if the thread is collapsed and has children', ->
count.withArgs('message').returns(1)
controller.collapsed = true
assert.isTrue(controller.shouldShowReply(count, false))
it 'does not show the reply if the thread is collapsed and has no children', ->
count.withArgs('message').returns(0)
controller.collapsed = true
assert.isFalse(controller.shouldShowReply(count, false))
describe 'and when filtered with children', ->
it 'shows the reply if the thread is not collapsed', ->
count.withArgs('match').returns(1)
count.withArgs('message').returns(1)
assert.isTrue(controller.shouldShowReply(count, true))
it 'does not show the reply if the thread is not collapsed and the message count does not match the match count', ->
count.withArgs('match').returns(0)
count.withArgs('message').returns(1)
assert.isFalse(controller.shouldShowReply(count, true))
describe 'when reply', ->
beforeEach -> controller.isRoot = false
describe 'and when not filtered', ->
it 'shows the reply if the thread is not collapsed and has children', ->
count.withArgs('message').returns(1)
assert.isTrue(controller.shouldShowReply(count, false))
it 'does not show the reply if the thread is not collapsed and has no children', ->
count.withArgs('message').returns(0)
assert.isFalse(controller.shouldShowReply(count, false))
it 'does not show the reply if the thread is collapsed and has children', ->
count.withArgs('message').returns(1)
controller.collapsed = true
assert.isFalse(controller.shouldShowReply(count, false))
it 'does not show the reply if the thread is collapsed and has no children', ->
count.withArgs('message').returns(0)
controller.collapsed = true
assert.isFalse(controller.shouldShowReply(count, false))
describe 'and when filtered with children', ->
it 'shows the reply if the thread is not collapsed', ->
count.withArgs('match').returns(1)
count.withArgs('message').returns(1)
assert.isTrue(controller.shouldShowReply(count, true))
it 'does not show the reply if the thread is not collapsed and the message count does not match the match count', ->
count.withArgs('match').returns(0)
count.withArgs('message').returns(1)
assert.isFalse(controller.shouldShowReply(count, true))
describe '.thread', ->
createElement = null
$element = null
$isolateScope = null
fakePulse = null
beforeEach module ($provide) ->
fakePulse = sandbox.spy()
$provide.value 'pulse', fakePulse
return
beforeEach inject ($compile, $rootScope) ->
createElement = (html) -> $compile(html or '<div thread></div>')($rootScope.$new())
$element = createElement()
$isolateScope = $element.scope()
it 'sets the threadRoot on the controller to false', ->
controller = $element.controller('thread')
assert.isFalse(controller.isRoot)
it 'sets the threadRoot on the controller to true when the thread-root attr is set', ->
$element = createElement('<div thread thread-root="true"></div>')
controller = $element.controller('thread')
assert.isTrue(controller.isRoot)
it 'pulses the current thread on an annotationUpdated event', ->
$element.scope().$emit('annotationUpdate')
assert.called(fakePulse)
it 'does not pulse the thread if it is hidden (parent collapsed)', ->
fakeParent = {
controller: -> {collapsed: true}
}
sandbox.stub(angular.element.prototype, 'parent').returns(fakeParent)
$element.scope().$emit('annotationUpdate')
assert.notCalled(fakePulse)
it 'does not pulse the thread if it is hidden (grandparent collapsed)', ->
fakeGrandParent = {
controller: -> {collapsed: true}
}
fakeParent = {
controller: -> {collapsed: false}
parent: -> fakeGrandParent
}
sandbox.stub(angular.element.prototype, 'parent').returns(fakeParent)
$element.scope().$emit('annotationUpdate')
assert.notCalled(fakePulse)
View
@@ -1,12 +1,19 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose assert, prefix: null
describe 'Discovery', ->
sandbox = sinon.sandbox.create()
fakeTopWindow = null
fakeFrameWindow = null
createDiscovery = null
before ->
angular.module('h', [])
require('../../h/static/scripts/discovery')
beforeEach module('h')
beforeEach inject (Discovery) ->
createDiscovery = (win, options) ->
View
@@ -1,38 +1,46 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose assert, prefix: null
describe 'persona', ->
filter = null
term = 'acct:hacker@example.com'
describe 'h:filters', ->
before ->
angular.module('h', [])
require('../../h/static/scripts/filters')
describe 'persona', ->
filter = null
term = 'acct:hacker@example.com'
beforeEach module('h')
beforeEach inject ($filter) ->
filter = $filter('persona')
beforeEach module('h')
beforeEach inject ($filter) ->
filter = $filter('persona')
it 'should return the whole term by request', ->
result = filter('acct:hacker@example.com', 'term')
assert.equal result, 'acct:hacker@example.com'
it 'should return the whole term by request', ->
result = filter('acct:hacker@example.com', 'term')
assert.equal result, 'acct:hacker@example.com'
it 'should return the requested part', ->
assert.equal filter(term), 'hacker'
assert.equal filter(term, 'term'), term,
assert.equal filter(term, 'username'), 'hacker'
assert.equal filter(term, 'provider'), 'example.com'
it 'should return the requested part', ->
assert.equal filter(term), 'hacker'
assert.equal filter(term, 'term'), term,
assert.equal filter(term, 'username'), 'hacker'
assert.equal filter(term, 'provider'), 'example.com'
it 'should pass through unrecognized terms as username or term', ->
assert.equal filter('bogus'), 'bogus'
assert.equal filter('bogus', 'username'), 'bogus'
it 'should pass through unrecognized terms as username or term', ->
assert.equal filter('bogus'), 'bogus'
assert.equal filter('bogus', 'username'), 'bogus'
it 'should handle error cases', ->
assert.notOk filter()
assert.notOk filter('bogus', 'provider')
it 'should handle error cases', ->
assert.notOk filter()
assert.notOk filter('bogus', 'provider')
describe 'urlencode', ->
filter = null
describe 'urlencode', ->
filter = null
beforeEach module('h')
beforeEach inject ($filter) ->
filter = $filter('urlencode')
beforeEach module('h')
beforeEach inject ($filter) ->
filter = $filter('urlencode')
it 'encodes reserved characters in the term', ->
assert.equal(filter('#hello world'), '%23hello%20world')
it 'encodes reserved characters in the term', ->
assert.equal(filter('#hello world'), '%23hello%20world')
View
@@ -1,23 +1,42 @@
Annotator = require('annotator')
Guest = require('../../h/static/scripts/guest')
assert = chai.assert
sinon.assert.expose(assert, prefix: '')
describe 'Annotator.Guest', ->
sandbox = sinon.sandbox.create()
sandbox = null
fakeCrossFrame = null
createGuest = (options) ->
element = document.createElement('div')
return new Annotator.Guest(element, options || {})
# Silence Annotator's sassy backchat
beforeEach -> sandbox.stub(console, 'log')
afterEach -> sandbox.restore()
return new Guest(element, options || {})
beforeEach ->
sandbox = sinon.sandbox.create()
fakeCrossFrame =
onConnect: sandbox.stub()
on: sandbox.stub()
sandbox.stub(Annotator.Plugin, 'CrossFrame').returns(fakeCrossFrame)
# Mock out the anchoring plugin. Oh how I wish I didn't have to do crazy
# shit like this.
Annotator.Plugin.EnhancedAnchoring = -> {
pluginInit: ->
@annotator.anchoring = this
_scan: sandbox.stub()
getHighlights: sandbox.stub().returns([])
getAnchors: sandbox.stub().returns([])
}
Annotator.Plugin.CrossFrame = -> fakeCrossFrame
sandbox.spy(Annotator.Plugin, 'CrossFrame')
afterEach ->
sandbox.restore()
describe 'setting up the bridge', ->
it 'sets the scope for the cross frame bridge', ->
@@ -177,7 +196,7 @@ describe 'Annotator.Guest', ->
{annotation: {$$tag: 'tag1'}, setFocused: sandbox.stub()}
{annotation: {$$tag: 'tag2'}, setFocused: sandbox.stub()}
]
sandbox.stub(guest.anchoring, 'getHighlights').returns(highlights)
guest.anchoring.getHighlights.returns(highlights)
emitGuestEvent('focusAnnotations', 'ctx', ['tag1'])
assert.called(highlights[0].setFocused)
assert.calledWith(highlights[0].setFocused, true)
@@ -188,7 +207,7 @@ describe 'Annotator.Guest', ->
{annotation: {$$tag: 'tag1'}, setFocused: sandbox.stub()}
{annotation: {$$tag: 'tag2'}, setFocused: sandbox.stub()}
]
sandbox.stub(guest.anchoring, 'getHighlights').returns(highlights)
guest.anchoring.getHighlights.returns(highlights)
emitGuestEvent('focusAnnotations', 'ctx', ['tag1'])
assert.called(highlights[1].setFocused)
assert.calledWith(highlights[1].setFocused, false)
@@ -199,7 +218,7 @@ describe 'Annotator.Guest', ->
anchors = [
{annotation: {$$tag: 'tag1'}, scrollToView: sandbox.stub()}
]
sandbox.stub(guest.anchoring, 'getAnchors').returns(anchors)
guest.anchoring.getAnchors.returns(anchors)
emitGuestEvent('scrollToAnnotation', 'ctx', 'tag1')
assert.called(anchors[0].scrollToView)
View
@@ -0,0 +1,156 @@
{module, inject} = require('angular-mock')
assert = chai.assert
angular = require('angular')
describe 'h.helpers:form-helpers', ->
$compile = null
$scope = null
formHelpers = null
before ->
angular.module('h.helpers', [])
require('../../../h/static/scripts/helpers/form-helpers')
beforeEach module('h.helpers')
beforeEach inject (_$compile_, _$rootScope_, _formHelpers_) ->
$compile = _$compile_
$scope = _$rootScope_.$new()
formHelpers = _formHelpers_
describe '.formValidate', ->
$element = null
beforeEach ->
$scope.model = {username: undefined}
template = '''
<form form-validate name="login" onsubmit="return false">
<div class="form-field">
<input type="text" class="form-input" name="username"
ng-model="model.username" name="username"
required ng-minlength="3" />
</div>
</form>
'''
$element = $compile(angular.element(template))($scope)
$scope.$digest()
it 'should remove an error class to an valid field on change', ->
$field = $element.find('.form-field').addClass('form-field-error')
$input = $element.find('[name=username]').addClass('form-field-error')
$input.controller('ngModel').$setViewValue('abc')
$scope.$digest()
assert.notInclude($field.prop('className'), 'form-field-error')
assert.notInclude($input.prop('className'), 'form-field-error')
it 'should apply an error class to an invalid field on submit', ->
$field = $element.find('.form-field')
$element.triggerHandler('submit')
assert.include($field.prop('className'), 'form-field-error')
it 'should remove an error class from a valid field on submit', ->
$field = $element.find('.form-field').addClass('form-field-error')
$input = $element.find('[name=username]')
$input.val('abc').triggerHandler('input')
$element.triggerHandler('submit')
assert.notInclude($field.prop('className'), 'form-field-error')
it 'should apply an error class if the form recieves errors after a submit action', ->
$element.trigger('submit')
$element.controller('form').username.$setValidity('response', false)
$field = $element.find('.form-field')
assert.include $field.prop('className'), 'form-field-error'
it 'should remove an error class on valid input when the view model changes', ->
$field = $element.find('.form-field').addClass('form-field-error')
$input = $element.find('[name=username]')
$input.val('abc').triggerHandler('input')
assert.notInclude($field.prop('className'), 'form-field-error')
it 'should not add an error class on invalid input on when the view changes', ->
$field = $element.find('.form-field')
$input = $element.find('[name=username]')
$input.val('ab').triggerHandler('input')
assert.notInclude($field.prop('className'), 'form-field-error')
it 'should reset the "response" error when the view changes', ->
$field = $element.find('.form-field')
$input = $element.find('[name=username]')
controller = $input.controller('ngModel')
controller.$setViewValue('abc')
# Submit Event
$element.triggerHandler('submit')
controller.$setValidity('response', false)
controller.responseErrorMessage = 'fail'
$scope.$digest()
assert.include($field.prop('className'), 'form-field-error', 'Fail fast check')
controller.$setViewValue('abc')
$scope.$digest()
assert.notInclude($field.prop('className'), 'form-field-error')
it 'should hide errors if the model is marked as pristine', ->
$field = $element.find('.form-field').addClass('form-field-error')
$input = $element.find('[name=username]')
controller = $input.controller('ngModel')
# Submit Event
$element.triggerHandler('submit')
controller.$setValidity('response', false)
controller.responseErrorMessage = 'fail'
$scope.$digest()
assert.include($field.prop('className'), 'form-field-error', 'Fail fast check')
# Then clear it out and mark it as pristine
controller.$setPristine()
$scope.$digest()
assert.notInclude($field.prop('className'), 'form-field-error')
describe '.applyValidationErrors', ->
form = null
beforeEach ->
form =
$setValidity: sinon.spy()
username: {$setValidity: sinon.spy()}
password: {$setValidity: sinon.spy()}
it 'sets the "response" error key for each field with errors', ->
formHelpers.applyValidationErrors form,
username: 'must be at least 3 characters'
password: 'must be present'
assert.calledWith(form.username.$setValidity, 'response', false)
assert.calledWith(form.password.$setValidity, 'response', false)
it 'adds an error message to each input controller', ->
formHelpers.applyValidationErrors form,
username: 'must be at least 3 characters'
password: 'must be present'
assert.equal(form.username.responseErrorMessage, 'must be at least 3 characters')
assert.equal(form.password.responseErrorMessage, 'must be present')
it 'sets the "response" error key if the form has a failure reason', ->
formHelpers.applyValidationErrors form, null, 'fail'
assert.calledWith(form.$setValidity, 'response', false)
it 'adds an reason message as the response error', ->
formHelpers.applyValidationErrors form, null, 'fail'
assert.equal(form.responseErrorMessage, 'fail')
View
@@ -1,9 +1,16 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose(assert, prefix: '')
describe 'h.helpers.stringHelpers', ->
describe 'h.helpers:string-helpers', ->
stringHelpers = null
before ->
angular.module('h.helpers', [])
require('../../../h/static/scripts/helpers/string-helpers')
beforeEach module('h.helpers')
beforeEach inject (_stringHelpers_) ->
View
@@ -1,3 +1,5 @@
{module, inject} = require('angular-mock')
assert = chai.assert
minute = 60
@@ -33,11 +35,16 @@ FIXTURES_NEXT_FUZZY_UPDATE = [
[8 * year, 24 * day] # by setTimout
]
describe 'timeHelpers', ->
beforeEach module('h.helpers')
describe 'h.helpers:time-helpers', ->
timeHelpers = null
sandbox = null
before ->
angular.module('h.helpers', [])
require('../../../h/static/scripts/helpers/time-helpers')
beforeEach module('h.helpers')
beforeEach inject (_timeHelpers_) ->
timeHelpers = _timeHelpers_
sandbox = sinon.sandbox.create()
View
@@ -1,3 +1,6 @@
Annotator = require('annotator')
Host = require('../../h/static/scripts/host')
assert = chai.assert
sinon.assert.expose(assert, prefix: '')
@@ -7,7 +10,7 @@ describe 'Annotator.Host', ->
createHost = (options={}) ->
element = document.createElement('div')
return new Annotator.Host(element, options)
return new Host(element, options)
beforeEach ->
# Disable Annotator's ridiculous logging.
View
@@ -1,11 +1,17 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose assert, prefix: null
sandbox = sinon.sandbox.create()
describe 'identity', ->
describe 'h.identity', ->
provider = null
mockInjectable = {}
before ->
require('../../h/static/scripts/identity-service')
beforeEach module('h.identity')
beforeEach module ($provide, identityProvider) ->
View
@@ -1,10 +1,17 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose assert, prefix: null
describe 'h', ->
describe 'h:permissions', ->
sandbox = null
fakeAuth = null
before ->
angular.module('h', [])
require('../../h/static/scripts/permissions-service')
beforeEach module('h')
beforeEach module ($provide) ->
View
@@ -1,20 +1,16 @@
Annotator = require('annotator')
ea = require('../../../h/static/scripts/annotator/plugin/enhancedanchoring')
assert = chai.assert
sinon.assert.expose(assert, prefix: '')
# In order to be able to create highlights,
# the Annotator.TextHighlight class must exist.
# This class is registered then the TextHighlights plugin
# is initialized, so we will do that.
th = new Annotator.Plugin.TextHighlights()
th.pluginInit()
# Then Anchor class is not supposed to be used directly.
# Every concrete implementation should have it's own class,
# encompassing a way to identify the given segment of the document.
#
# For testing, we will use the TestAnchor class,
# which does not actually identify a real segment of the HTML document.
class TestAnchor extends Annotator.Anchor
class TestAnchor extends ea.Anchor
_getSegment: -> "html segment for " + @id
@@ -24,6 +20,7 @@ class TestAnchor extends Annotator.Anchor
@id = "fake anchor for " + target.id
describe 'Annotator.Plugin.EnhancedAnchoring', ->
sandbox = null
pendingTest = null
@@ -33,13 +30,15 @@ describe 'Annotator.Plugin.EnhancedAnchoring', ->
beforeEach ->
sandbox = sinon.sandbox.create()
sandbox.stub Annotator.TextHighlight, 'createFrom',
(segment, anchor, page) ->
Annotator.TextHighlight = {
createFrom: (segment, anchor, page) ->
segment: segment
anchor: anchor
page: page
removeFromDocument: sinon.spy()
scrollToView: sinon.spy -> pendingTest?.resolve()
}
afterEach ->
sandbox.restore()
@@ -59,7 +58,7 @@ describe 'Annotator.Plugin.EnhancedAnchoring', ->
annotator =
publish: sinon.spy()
am = new Annotator.Plugin.EnhancedAnchoring()
am = new ea.EnhancedAnchoring()
am.annotator = annotator
am.pluginInit()
@@ -287,7 +286,7 @@ describe 'Annotator.Plugin.EnhancedAnchoring', ->
annotator =
publish: sinon.spy()
am = new Annotator.Plugin.EnhancedAnchoring()
am = new ea.EnhancedAnchoring()
am.annotator = annotator
am.pluginInit()
View
@@ -1,12 +1,9 @@
Annotator = require('annotator')
th = require('../../../h/static/scripts/annotator/plugin/texthighlights')
assert = chai.assert
sinon.assert.expose(assert, prefix: '')
# In order to be able to create highlights,
# the Annotator.TextHighlight class must exist.
# This class is registered then the TextHighlights plugin
# is initialized, so we will do that.
th = new Annotator.Plugin.TextHighlights()
th.pluginInit()
describe 'Annotator.Plugin.TextHighlight', ->
sandbox = null
@@ -23,11 +20,11 @@ describe 'Annotator.Plugin.TextHighlight', ->
element:
delegate: sinon.spy()
new Annotator.TextHighlight anchor, "test page", "test range"
new th.TextHighlight anchor, "test page", "test range"
beforeEach ->
sandbox = sinon.sandbox.create()
sandbox.stub Annotator.TextHighlight, 'highlightRange',
sandbox.stub th.TextHighlight, 'highlightRange',
(normedRange, cssClass) ->
hl = document.createElement "hl"
hl.appendChild document.createTextNode "test highlight span"
@@ -44,7 +41,7 @@ describe 'Annotator.Plugin.TextHighlight', ->
describe "constructor", ->
it 'wraps a highlight span around the given range', ->
hl = createTestHighlight()
assert.calledWith Annotator.TextHighlight.highlightRange, "test range"
assert.calledWith th.TextHighlight.highlightRange, "test range"
it 'stores the created highlight spans in _highlights', ->
hl = createTestHighlight()
View
@@ -1,3 +1,5 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose assert, prefix: null
@@ -13,36 +15,45 @@ poem =
“’Tis some visitor,” I muttered, “tapping at my chamber door—
Only this and nothing more.”'
describe 'h', ->
describe 'h:services', ->
sandbox = null
fakeStringHelpers = null
before ->
angular.module('h', [])
require('../../h/static/scripts/services')
beforeEach module('h')
beforeEach module ($provide) ->
sandbox = sinon.sandbox.create()
fakeStringHelpers = {
uniFold: sinon.stub().returnsArg(0)
}
$provide.value('stringHelpers', fakeStringHelpers)
return
afterEach ->
sandbox.restore()
describe 'viewFilter service', ->
viewFilter = null
stringHelpers = null
beforeEach inject (_stringHelpers_, _viewFilter_) ->
stringHelpers = _stringHelpers_
beforeEach inject (_viewFilter_) ->
viewFilter = _viewFilter_
describe 'filter', ->
it 'normalizes the filter terms', ->
stringHelpers.uniFold = sandbox.spy()
filters =
text:
terms: ['Tiger']
operator: 'and'
viewFilter.filter [], filters
assert.calledWith stringHelpers.uniFold, 'tiger'
assert.calledWith fakeStringHelpers.uniFold, 'tiger'
describe 'filter operators', ->
annotations = null
View
@@ -1,20 +1,37 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose assert, prefix: null
sandbox = sinon.sandbox.create()
mockFlash = sandbox.spy()
mockDocument = {prop: -> '/session'}
describe 'session', ->
describe 'h.session', ->
fakeFlash = null
fakeDocument = null
fakeXsrf = null
sandbox = null
before ->
angular.module('h.session', ['ngResource'])
require('../../h/static/scripts/session/session-service')
beforeEach module('h.session')
beforeEach module ($provide, sessionProvider) ->
$provide.value '$document', mockDocument
$provide.value 'flash', mockFlash
sandbox = sinon.sandbox.create()
fakeFlash = sandbox.spy()
fakeDocument = {prop: -> '/session'}
fakeXsrf = {token: 'faketoken'}
$provide.value '$document', fakeDocument
$provide.value 'flash', fakeFlash
$provide.value 'xsrf', fakeXsrf
sessionProvider.actions =
login:
url: '/login'
method: 'POST'
return
afterEach ->
@@ -23,12 +40,10 @@ describe 'session', ->
describe 'sessionService', ->
$httpBackend = null
session = null
xsrf = null
beforeEach inject (_$httpBackend_, _session_, _xsrf_) ->
beforeEach inject (_$httpBackend_, _session_) ->
$httpBackend = _$httpBackend_
session = _session_
xsrf = _xsrf_
describe '#<action>()', ->
url = '/login'
@@ -45,7 +60,7 @@ describe 'session', ->
$httpBackend.expectPOST(url).respond(response)
result = session.login({})
$httpBackend.flush()
assert.calledWith mockFlash, 'error', 'fail'
assert.calledWith fakeFlash, 'error', 'fail'
it 'should assign errors and status reasons to the model', ->
response =
@@ -71,7 +86,7 @@ describe 'session', ->
request = $httpBackend.expectPOST(url).respond({model})
result = session.login({})
$httpBackend.flush()
assert.equal xsrf.token, token
assert.equal fakeXsrf.token, token
$httpBackend.expectPOST(url, {}, headers).respond({})
session.login({})
View
@@ -1,12 +1,19 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose assert, prefix: null
describe 'store', ->
$httpBackend = null
sandbox = null
store = null
fakeDocument = null
before ->
angular.module('h', ['ngResource'])
require('../../h/static/scripts/store-service')
beforeEach module('h')
beforeEach module ($provide) ->
View
@@ -1,16 +1,23 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose assert, prefix: null
sandbox = sinon.sandbox.create()
describe 'streamer', ->
WebSocket = null
fakeSock = null
streamer = null
url = 'wss://magicstreemz/giraffe'
sandbox = null
before ->
require('../../h/static/scripts/streamer-service')
beforeEach module('h.streamer')
beforeEach module ->
sandbox = sinon.sandbox.create()
fakeSock = {
send: sandbox.spy()
close: sandbox.spy()
View
@@ -1,9 +1,16 @@
{module, inject} = require('angular-mock')
assert = chai.assert
sinon.assert.expose(assert, prefix: '')
describe 'Threading', ->
instance = null
before ->
angular.module('h', [])
require('../../h/static/scripts/threading-service')
beforeEach module('h')
beforeEach inject (_threading_) ->
View

This file was deleted.

Oops, something went wrong.
View
@@ -0,0 +1,45 @@
#!/usr/bin/env node
//
// browserify-pipe
//
// A simple browserify commandline that supports CoffeeScript on STDIN.
//
// The vanilla browserify commandline tool doesn't deal well with piping input
// over STDIN: it loses filenames and hence can't deal with non-JavaScript
// inputs (because it doesn't know the correct file extension). browserify-pipe
// browserifies a single piped file, using the filename given as a required
// positional argument.
//
var path = require('path');
var browserify = require('browserify');
var debug = false;
var args = process.argv.slice(2);
if (args.indexOf('-d') !== -1) {
debug = true;
args.splice(args.indexOf('-d'), 1);
}
if (args.length !== 1) {
console.log('Usage: browserify-pipe [-d] <filename>');
process.exit(1);
}
var filename = args[0];
browserify({
debug: debug,
extensions: ['.coffee']
})
.require(process.stdin, {
entry: true,
basedir: path.dirname(filename),
file: path.resolve(filename)
})
.bundle()
.on('error', function (err) {
console.log(err.stack);
process.exit(1);
})
.pipe(process.stdout);