Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base: 7a6bdfbccd
...
compare: 76c3d33eef
Checking mergeability… Don't worry, you can still create the pull request.
  • 7 commits
  • 12 files changed
  • 0 commit comments
  • 1 contributor
View
7 css/annotator.readmill.css
@@ -36,6 +36,13 @@
text-transform: uppercase;
}
+/* Disable the connect button when reading. */
+.annotator-readmill-connect a[href="#reading"]:hover,
+.annotator-readmill-connect a[href="#reading"]:active {
+ cursor: default;
+ text-decoration: none;
+}
+
.annotator-readmill-avatar {
position: absolute;
display: none;
View
50 example.html
@@ -4635,27 +4635,43 @@
</pre>
<script src="./vendor/jquery.js"></script>
<script src="./vendor/annotator.js"></script>
-
- <!-- Developement files created by `make watch` -->
- <script src="./lib/readmill.js"></script>
- <script src="./lib/readmill/utils.js"></script>
- <script src="./lib/readmill/store.js"></script>
- <script src="./lib/readmill/client.js"></script>
- <script src="./lib/readmill/auth.js"></script>
- <script src="./lib/readmill/view.js"></script>
+ <script src="./vendor/coffeescript.js"></script>
+ <script type="text/coffeescript">
+ jQuery.ajaxSetup async: false
+
+ modules = jQuery.trim """
+ readmill
+ readmill/utils
+ readmill/store
+ readmill/client
+ readmill/auth
+ readmill/view
+ """
+ modules = modules.split(/\s+/)
+
+ run = (file, source) ->
+ filename = file.replace(/coffee$/, "js")
+ compiled = "#{CoffeeScript.compile(source)}\n//@ sourceURL=#{filename}"
+ eval(compiled)
+
+ sources = ("./src/#{script}.coffee" for script in modules)
+ requests = jQuery.map sources, (script) ->
+ jQuery.get(script, jQuery.proxy(run, this, script))
+
+ jQuery.when.apply(jQuery, requests).done ->
+ book = jQuery('#book').annotator().annotator('addPlugin', 'Readmill'
+ book: {id: ""}
+ clientId: ""
+ callbackUrl: ""
+ apiEndpoint: ""
+ authEndpoint: ""
+ )
+ window.annotator = book.data('annotator')
+ </script>
<!-- In production use the minified version generated by `make build` -->
<!-- <script src="./lib/annotator.readmill.min.js"></script> -->
<script>
- var annotator = jQuery('#book').annotator().annotator('addPlugin', 'Readmill', {
- book: {id: ""},
- clientId: "",
- callbackUrl: "",
- apiEndpoint: "",
- authEndpoint: ""
- }).data('annotator');
- </script>
- <script>
jQuery("[data-collapsed]").each(function () {
var $element = jQuery(this).hide();
var $anchor = jQuery("<a />", {
View
8 src/readmill.coffee
@@ -83,7 +83,7 @@ Annotator.Readmill = class Readmill extends Annotator.Plugin
for own key, value of this when key.indexOf("Error") > -1
this[key] = @_createUnauthorizedHandler(value)
- token = options.accessToken or @store.get "access-token"
+ token = options.accessToken or @store.get("access-token")
@connected(token, silent: true) if token
@unsaved = []
@@ -99,7 +99,11 @@ Annotator.Readmill = class Readmill extends Annotator.Plugin
@view.on "disconnect", @disconnect
jQuery("body").append @view.render()
- @lookupBook()
+
+ if @client.isAuthorized()
+ @lookupReading().done => @view.reading()
+ else
+ @lookupBook()
# Public: Fetches the book resource from the Readmill API and updates the
# view when complete. This method is usually called as part of the plugin
View
2  src/readmill/utils.coffee
@@ -135,7 +135,7 @@ Annotator.Readmill.utils = do ->
annotationFromHighlight: (highlight, client) ->
# Try and extract annotation metadata from the locators object.
meta = try JSON.parse(highlight.locators.annotator) catch e then null
- meta = (try {range: JSON.parse(highlight.pre)} catch e then null) unless meta
+ meta = (try ranges: JSON.parse(highlight.pre) catch e then null) unless meta
deferred = new jQuery.Deferred()
if meta
View
23 src/readmill/view.coffee
@@ -26,7 +26,7 @@ Annotator.Readmill.View = class View extends Annotator.Class
states:
CONNECT: "connect"
START_READING: "start"
- FINISH_READING: "finish"
+ NOW_READING: "reading"
# Classes used to manipulate view state.
classes:
@@ -119,16 +119,21 @@ Annotator.Readmill.View = class View extends Annotator.Class
# Public: Switches the current view state to reading. This should be called
# once the user decides to start a reading session.
#
- # Publishes the "reading" event once the view has updated. Passes true as the
- # first argument to all callbacks if the reading is private.
- #
- # isPrivate - True if the user has determined this a private reading session.
+ # Publishes the "reading" event once the view has updated.
#
# Returns itself.
reading: ->
- @updateState(@states.FINISH_READING)
+ @updateState(@states.NOW_READING)
@publish "reading", [this]
+ # Public: Switches the current view state to "finish". This should be called
+ # once a user decides to end a reading session.
+ #
+ # Publishes the "finish" event once the view has updated.
+ #
+ # param - comment
+ #
+ # Returns itself.
finish: ->
@publish "finish", [this]
@login()
@@ -202,7 +207,7 @@ Annotator.Readmill.View = class View extends Annotator.Class
map = {}
map[@states.CONNECT] = "Connect With Readmill&hellip;"
map[@states.START_READING] = "Begin Reading&hellip;"
- map[@states.FINISH_READING] = "Finish Reading&hellip;"
+ map[@states.NOW_READING] = "Now Reading&hellip;"
@element.find(".annotator-readmill-connect a").html(map[state])
.attr("href", "#" + state)
@@ -252,10 +257,6 @@ Annotator.Readmill.View = class View extends Annotator.Class
switch event.target.hash.slice(1)
when @states.CONNECT then @connect()
when @states.START_READING then @reading()
- when @states.FINISH_READING
- msg = "Are you sure you wish to finish reading? This will remove all annotations from the page"
- if window.confirm msg
- @finish()
# Callback for click events on the "logout" button.
#
View
14 test/index.html
@@ -1,4 +1,3 @@
-
<!DOCTYPE html>
<html>
<head>
@@ -10,7 +9,7 @@
<div id="mocha"></div>
<script src="../vendor/jquery.js"></script>
<script src="../vendor/annotator.js"></script>
- <script src="./vendor/coffeescript.js"></script>
+ <script src="../vendor/coffeescript.js"></script>
<script src="./vendor/mocha.js"></script>
<script src="./vendor/sinon.js"></script>
<script src="./vendor/chai.js"></script>
@@ -32,10 +31,17 @@
"""
modules = modules.split(/\s+/)
+ run = (file, source) ->
+ filename = file.replace(/coffee$/, "js")
+ compiled = "#{CoffeeScript.compile(source)}\n//@ sourceURL=#{filename}"
+ eval(compiled)
+
specs = ("spec/#{script}.coffee" for script in modules)
source = ("../src/#{script}.coffee" for script in modules)
- requests = jQuery.map source, (script) -> jQuery.get(script, CoffeeScript.run)
- requests.concat jQuery.map(specs, (script) -> jQuery.get(script, CoffeeScript.run))
+ requests = jQuery.map source, (script) ->
+ jQuery.get(script, jQuery.proxy(run, this, script))
+ requests.concat jQuery.map(specs, (script) ->
+ jQuery.get(script, jQuery.proxy(run, this, script)))
jQuery.when.apply(jQuery, requests).done ->
mocha.run().globals(['Annotator', 'jQuery', 'open'])
View
20 test/spec/readmill.coffee
@@ -67,6 +67,7 @@ describe "Readmill", ->
beforeEach ->
sinon.stub(jQuery.fn, "append")
sinon.stub(readmill, "lookupBook")
+ sinon.stub(readmill, "lookupReading")
afterEach ->
jQuery.fn.append.restore()
@@ -76,10 +77,27 @@ describe "Readmill", ->
expect(jQuery.fn.append).was.called()
expect(jQuery.fn.append).was.calledWith(readmill.view.element)
- it "should call @lookupBook", ->
+ it "should call @lookupBook()", ->
readmill.pluginInit()
expect(readmill.lookupBook).was.called()
+ it "should call @lookupReading() if authorised", ->
+ sinon.stub(readmill.client, "isAuthorized").returns(true)
+ readmill.lookupReading.returns(done: sinon.stub())
+ readmill.pluginInit()
+ expect(readmill.lookupReading).was.called()
+
+ it "should updated the view when the reading is loaded", ->
+ target = sinon.stub()
+ sinon.stub(readmill.client, "isAuthorized").returns(true)
+ sinon.stub(readmill.view, "reading")
+ readmill.lookupReading.returns(done: target)
+ readmill.pluginInit()
+ expect(target).was.called()
+
+ target.args[0][0]()
+ expect(readmill.view.reading).was.called()
+
it "should register view event listeners", ->
target = sinon.stub(readmill.view, "on")
readmill.pluginInit()
View
12 test/spec/readmill/view.coffee
@@ -32,7 +32,7 @@ describe "View", ->
target = sinon.stub(view, "updateState")
view.reading()
expect(target).was.called()
- expect(target).was.calledWith(view.states.FINISH_READING)
+ expect(target).was.calledWith(view.states.NOW_READING)
it "should publish the \"reading\" event", ->
view.reading()
@@ -151,7 +151,7 @@ describe "View", ->
map = {}
map[view.states.CONNECT] = "Connect With Readmill…"
map[view.states.START_READING] = "Begin Reading…"
- map[view.states.FINISH_READING] = "Finish Reading…"
+ map[view.states.NOW_READING] = "Now Reading…"
for key, state of view.states
view.updateState(state)
@@ -200,14 +200,6 @@ describe "View", ->
view._onConnectClick(event)
expect(target).was.called()
- it "should call @login() if the hash equals #finish", ->
- sinon.stub(window, "confirm").returns(true)
- event.target.hash = "#finish"
- target = sinon.stub(view, "login")
- view._onConnectClick(event)
- expect(target).was.called()
- window.confirm.restore()
-
it "should prevent the default browser action", ->
view._onConnectClick(event)
expect(event.preventDefault).was.called()
View
24 test/vendor/mocha.css
@@ -1,6 +1,6 @@
body {
- font: 20px/1.5 "Helvetica Neue", Helvetica, Aria;, sans-serif;
+ font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
padding: 60px 50px;
}
@@ -40,6 +40,10 @@ body {
color: #888;
}
+#mocha .test.pending:hover h2::after {
+ content: '(pending)';
+}
+
#mocha .test.pass::before {
content: '';
font-size: 12px;
@@ -99,15 +103,16 @@ body {
#stats {
position: fixed;
- top: 30px;
- right: 30px;
+ top: 15px;
+ right: 10px;
font-size: 12px;
margin: 0;
color: #888;
}
#stats .progress {
- margin-bottom: 10px;
+ float: right;
+ padding-top: 0;
}
#stats em {
@@ -115,5 +120,14 @@ body {
}
#stats li {
+ display: inline-block;
+ margin: 0 5px;
list-style: none;
-}
+ padding-top: 11px;
+}
+
+code .comment { color: #ddd }
+code .init { color: #2F6FAD }
+code .string { color: #5890AD }
+code .keyword { color: #8A6343 }
+code .number { color: #2F6FAD }
View
341 test/vendor/mocha.js
@@ -52,7 +52,7 @@ require.register("browser/debug.js", function(module, exports, require){
module.exports = function(type){
return function(){
-
+ //console.log(arguments)
}
};
}); // module: browser/debug.js
@@ -242,6 +242,10 @@ require.register("browser/fs.js", function(module, exports, require){
}); // module: browser/fs.js
+require.register("browser/path.js", function(module, exports, require){
+
+}); // module: browser/path.js
+
require.register("browser/progress.js", function(module, exports, require){
/**
@@ -257,7 +261,7 @@ module.exports = Progress;
function Progress() {
this.percent = 0;
this.size(0);
- this.fontSize(12);
+ this.fontSize(11);
this.font('helvetica, arial, sans-serif');
}
@@ -575,9 +579,106 @@ require.register("interfaces/index.js", function(module, exports, require){
exports.bdd = require('./bdd');
exports.tdd = require('./tdd');
+exports.qunit = require('./qunit');
exports.exports = require('./exports');
+
}); // module: interfaces/index.js
+require.register("interfaces/qunit.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite')
+ , Test = require('../test');
+
+/**
+ * QUnit-style interface:
+ *
+ * suite('Array');
+ *
+ * test('#length', function(){
+ * var arr = [1,2,3];
+ * ok(arr.length == 3);
+ * });
+ *
+ * test('#indexOf()', function(){
+ * var arr = [1,2,3];
+ * ok(arr.indexOf(1) == 0);
+ * ok(arr.indexOf(2) == 1);
+ * ok(arr.indexOf(3) == 2);
+ * });
+ *
+ * suite('String');
+ *
+ * test('#length', function(){
+ * ok('foo'.length == 3);
+ * });
+ *
+ */
+
+module.exports = function(suite){
+ var suites = [suite];
+
+ suite.on('pre-require', function(context){
+
+ /**
+ * Execute before running tests.
+ */
+
+ context.before = function(fn){
+ suites[0].beforeAll(fn);
+ };
+
+ /**
+ * Execute after running tests.
+ */
+
+ context.after = function(fn){
+ suites[0].afterAll(fn);
+ };
+
+ /**
+ * Execute before each test case.
+ */
+
+ context.beforeEach = function(fn){
+ suites[0].beforeEach(fn);
+ };
+
+ /**
+ * Execute after each test case.
+ */
+
+ context.afterEach = function(fn){
+ suites[0].afterEach(fn);
+ };
+
+ /**
+ * Describe a "suite" with the given `title`.
+ */
+
+ context.suite = function(title){
+ if (suites.length > 1) suites.shift();
+ var suite = Suite.create(suites[0], title);
+ suites.unshift(suite);
+ };
+
+ /**
+ * Describe a specification or test-case
+ * with the given `title` and callback `fn`
+ * acting as a thunk.
+ */
+
+ context.test = function(title, fn){
+ suites[0].addTest(new Test(title, fn));
+ };
+ });
+};
+
+}); // module: interfaces/qunit.js
+
require.register("interfaces/tdd.js", function(module, exports, require){
/**
@@ -688,7 +789,7 @@ require.register("mocha.js", function(module, exports, require){
* Library version.
*/
-exports.version = '0.8.0';
+exports.version = '0.12.0';
exports.utils = require('./utils');
exports.interfaces = require('./interfaces');
@@ -698,7 +799,6 @@ exports.Runner = require('./runner');
exports.Suite = require('./suite');
exports.Hook = require('./hook');
exports.Test = require('./test');
-exports.watch = require('./watch');
}); // module: mocha.js
@@ -833,8 +933,8 @@ exports.list = function(failures){
// msg
var err = test.err
- , stack = err.stack || err.message
, message = err.message || ''
+ , stack = err.stack || message
, index = stack.indexOf(message) + message.length
, msg = stack.slice(0, index);
@@ -842,7 +942,7 @@ exports.list = function(failures){
stack = stack.slice(index + 1)
.replace(/^/gm, ' ');
- console.error(fmt, i, test.fullTitle(), msg, stack);
+ console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
});
};
@@ -872,7 +972,7 @@ function Base(runner) {
runner.on('suite', function(suite){
stats.suites = stats.suites || 0;
- stats.suites++;
+ suite.root || stats.suites++;
});
runner.on('test end', function(test){
@@ -1108,7 +1208,7 @@ exports = module.exports = HTML;
*/
var statsTemplate = '<ul id="stats">'
- + '<li class="progress"><canvas width="50" height="50"></canvas></li>'
+ + '<li class="progress"><canvas width="40" height="40"></canvas></li>'
+ '<li class="passes">passes: <em>0</em></li>'
+ '<li class="failures">failures: <em>0</em></li>'
+ '<li class="duration">duration: <em>0</em>s</li>'
@@ -1143,7 +1243,7 @@ function HTML(runner) {
if (!root.length) return error('#mocha div missing, add it to your document');
- if (progress) progress.size(50);
+ if (progress) progress.size(40);
runner.on('suite', function(suite){
if (suite.root) return;
@@ -1198,9 +1298,9 @@ function HTML(runner) {
// toggle code
el.find('h2').toggle(function(){
- pre.slideDown('fast');
+ pre && pre.slideDown('fast');
}, function(){
- pre.slideUp('fast');
+ pre && pre.slideUp('fast');
});
// code
@@ -1554,7 +1654,7 @@ function List(runner) {
runner.on('fail', function(test, err){
cursor.CR();
- console.log(color('fail', ' %d) %s'), n++, test.fullTitle());
+ console.log(color('fail', ' %d) %s'), ++n, test.fullTitle());
});
runner.on('end', self.epilogue.bind(self));
@@ -1738,7 +1838,7 @@ function Spec(runner) {
runner.on('fail', function(test, err){
cursor.CR();
- console.log(indent() + color('fail', ' %d) %s'), n++, test.title);
+ console.log(indent() + color('fail', ' %d) %s'), ++n, test.title);
});
runner.on('end', self.epilogue.bind(self));
@@ -1918,6 +2018,7 @@ function XUnit(runner) {
name: 'Mocha Tests'
, tests: stats.tests
, failures: stats.failures
+ , errors: stats.failures
, skip: stats.tests - stats.failures - stats.passes
, timestamp: (new Date).toUTCString()
, time: stats.duration / 1000
@@ -1942,7 +2043,7 @@ XUnit.prototype.constructor = XUnit;
function test(test) {
var attrs = {
- classname: test.fullTitle()
+ classname: test.parent.fullTitle()
, name: test.title
, time: test.duration / 1000
};
@@ -2015,6 +2116,8 @@ function Runnable(title, fn) {
this.async = fn && fn.length;
this.sync = ! this.async;
this._timeout = 2000;
+ this.timedOut = false;
+ this.context = this;
}
/**
@@ -2077,6 +2180,7 @@ Runnable.prototype.resetTimeout = function(){
if (ms) {
this.timer = setTimeout(function(){
self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
+ self.timedOut = true;
}, ms);
}
};
@@ -2092,6 +2196,7 @@ Runnable.prototype.run = function(fn){
var self = this
, ms = this.timeout()
, start = new Date
+ , ctx = this.context
, finished
, emitted;
@@ -2100,6 +2205,7 @@ Runnable.prototype.run = function(fn){
if (ms) {
this.timer = setTimeout(function(){
done(new Error('timeout of ' + ms + 'ms exceeded'));
+ self.timedOut = true;
}, ms);
}
}
@@ -2113,6 +2219,7 @@ Runnable.prototype.run = function(fn){
// finished
function done(err) {
+ if (self.timedOut) return;
if (finished) return multiple();
self.clearTimeout();
self.duration = new Date - start;
@@ -2126,7 +2233,7 @@ Runnable.prototype.run = function(fn){
// async
if (this.async) {
try {
- this.fn(function(err){
+ this.fn.call(ctx, function(err){
if (err instanceof Error) return done(err);
if (null != err) return done(new Error('done() invoked with non-Error: ' + err));
done();
@@ -2139,7 +2246,7 @@ Runnable.prototype.run = function(fn){
// sync
try {
- if (!this.pending) this.fn();
+ if (!this.pending) this.fn.call(ctx);
this.duration = new Date - start;
fn();
} catch (err) {
@@ -2229,6 +2336,7 @@ Runner.prototype.grep = function(re){
*/
Runner.prototype.globals = function(arr){
+ if (0 == arguments.length) return this._globals;
debug('globals %j', arr);
utils.forEach(arr, function(arr){
this._globals.push(arr);
@@ -2286,7 +2394,6 @@ Runner.prototype.fail = function(test, err){
*/
Runner.prototype.failHook = function(hook, err){
- ++this.failures;
this.fail(hook, err);
this.emit('end');
};
@@ -2310,6 +2417,7 @@ Runner.prototype.hook = function(name, fn){
var hook = hooks[i];
if (!hook) return fn();
self.currentRunnable = hook;
+ hook.context = self.test;
self.emit('hook', hook);
@@ -2442,6 +2550,9 @@ Runner.prototype.runTests = function(suite, fn){
, test;
function next(err) {
+ // if we bail after first err
+ if (self.failures && suite._bail) return fn();
+
// next test
test = tests.shift();
@@ -2459,9 +2570,12 @@ Runner.prototype.runTests = function(suite, fn){
}
// execute test and hook(s)
- self.emit('test', self.test = self.currentRunnable = test);
+ self.emit('test', self.test = test);
self.hookDown('beforeEach', function(){
+ self.currentRunnable = self.test;
self.runTest(function(err){
+ test = self.test;
+
if (err) {
self.fail(test, err);
self.emit('test end', test);
@@ -2516,6 +2630,32 @@ Runner.prototype.runSuite = function(suite, fn){
};
/**
+ * Handle uncaught exceptions.
+ *
+ * @param {Error} err
+ * @api private
+ */
+
+Runner.prototype.uncaught = function(err){
+ debug('uncaught exception');
+ var runnable = this.currentRunnable;
+ if (runnable.failed) return;
+ runnable.clearTimeout();
+ err.uncaught = true;
+ this.fail(runnable, err);
+
+ // recover from test
+ if ('test' == runnable.type) {
+ this.emit('test end', runnable);
+ this.hookUp('afterEach', this.next);
+ return;
+ }
+
+ // bail on hooks
+ this.emit('end');
+};
+
+/**
* Run the root suite and invoke `fn(failures)`
* on completion.
*
@@ -2531,9 +2671,9 @@ Runner.prototype.run = function(fn){
debug('start');
// callback
- self.on('end', function(){
+ this.on('end', function(){
debug('end');
- process.removeListener('uncaughtException', uncaught);
+ process.removeListener('uncaughtException', this.uncaught);
fn(self.failures);
});
@@ -2545,24 +2685,9 @@ Runner.prototype.run = function(fn){
});
// uncaught exception
- function uncaught(err){
- var runnable = self.currentRunnable;
- debug('uncaught exception');
- runnable.clearTimeout();
- err.uncaught = true;
- self.fail(runnable, err);
-
- // recover from test
- if ('test' == runnable.type) {
- self.emit('test end', runnable);
- self.hookUp('afterEach', self.next);
- // bail on hooks
- } else {
- self.emit('end');
- }
- }
-
- process.on('uncaughtException', uncaught);
+ process.on('uncaughtException', function(err){
+ self.uncaught(err);
+ });
return this;
};
@@ -2624,6 +2749,7 @@ function Suite(title) {
this._afterAll = [];
this.root = !title;
this._timeout = 2000;
+ this._bail = false;
}
/**
@@ -2645,6 +2771,7 @@ Suite.prototype.clone = function(){
var suite = new Suite(this.title);
debug('clone');
suite.timeout(this.timeout());
+ suite.bail(this.bail());
return suite;
};
@@ -2665,6 +2792,21 @@ Suite.prototype.timeout = function(ms){
};
/**
+ * Sets whether to bail after first error.
+ *
+ * @parma {Boolean} bail
+ * @return {Suite|Number} for chaining
+ * @api private
+ */
+
+Suite.prototype.bail = function(bail){
+ if (0 == arguments.length) return this._bail;
+ debug('bail %s', bail);
+ this._bail = bail;
+ return this;
+};
+
+/**
* Run `fn(test[, done])` before running tests.
*
* @param {Function} fn
@@ -2743,6 +2885,7 @@ Suite.prototype.afterEach = function(fn){
Suite.prototype.addSuite = function(suite){
suite.parent = this;
suite.timeout(this.timeout());
+ suite.bail(this.bail());
this.suites.push(suite);
this.emit('suite', suite);
return this;
@@ -2836,6 +2979,21 @@ Test.prototype.constructor = Test;
require.register("utils.js", function(module, exports, require){
/**
+ * Module dependencies.
+ */
+
+var fs = require('browser/fs')
+ , path = require('browser/path')
+ , join = path.join
+ , debug = require('browser/debug')('watch');
+
+/**
+ * Ignored directories.
+ */
+
+var ignore = ['node_modules', '.git'];
+
+/**
* Escape special characters in the given string of html.
*
* @param {String} html
@@ -2944,27 +3102,57 @@ exports.keys = Object.keys || function(obj) {
return keys;
};
-}); // module: utils.js
+/**
+ * Watch the given `files` for changes
+ * and invoke `fn(file)` on modification.
+ *
+ * @param {Array} files
+ * @param {Function} fn
+ * @api private
+ */
+
+exports.watch = function(files, fn){
+ var options = { interval: 100 };
+ files.forEach(function(file){
+ debug('file %s', file);
+ fs.watchFile(file, options, function(curr, prev){
+ if (prev.mtime < curr.mtime) fn(file);
+ });
+ });
+};
+
+/**
+ * Ignored files.
+ */
-require.register("watch.js", function(module, exports, require){
+function ignored(path){
+ return !~ignore.indexOf(path);
+}
/**
- * Module dependencies.
+ * Lookup files in the given `dir`.
+ *
+ * @return {Array}
+ * @api public
*/
-var fs = require('browser/fs')
- , debug = require('browser/debug')('watch');
+exports.files = function(dir, ret){
+ ret = ret || [];
-module.exports = function(paths, fn){
- var options = { interval: 100 };
- paths.forEach(function(path){
- debug('watch %s', path);
- fs.watchFile(path, options, function(curr, prev){
- if (prev.mtime < curr.mtime) fn(path);
- });
+ fs.readdirSync(dir)
+ .filter(ignored)
+ .forEach(function(path){
+ path = join(dir, path);
+ if (fs.statSync(path).isDirectory()) {
+ exports.files(path, ret);
+ } else if (path.match(/\.(js|coffee)$/)) {
+ ret.push(path);
+ }
});
+
+ return ret;
};
-}); // module: watch.js
+}); // module: utils.js
/**
* Node shims.
@@ -2980,6 +3168,10 @@ process.exit = function(status){};
process.stdout = {};
global = window;
+/**
+ * next tick implementation.
+ */
+
process.nextTick = (function(){
// postMessage behaves badly on IE8
if (window.ActiveXObject || !window.postMessage) {
@@ -3003,18 +3195,30 @@ process.nextTick = (function(){
}
})();
+/**
+ * Remove uncaughtException listener.
+ */
+
process.removeListener = function(e){
if ('uncaughtException' == e) {
window.onerror = null;
}
};
+/**
+ * Implements uncaughtException listener.
+ */
+
process.on = function(e, fn){
if ('uncaughtException' == e) {
window.onerror = fn;
}
};
+/**
+ * Expose mocha.
+ */
+
window.mocha = require('mocha');
// boot
@@ -3023,6 +3227,26 @@ window.mocha = require('mocha');
, utils = mocha.utils
, Reporter = mocha.reporters.HTML
+ /**
+ * Highlight the given string of `js`.
+ */
+
+ function highlight(js) {
+ return js
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
+ .replace(/('.*')/gm, '<span class="string">$1</span>')
+ .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
+ .replace(/(\d+)/gm, '<span class="number">$1</span>')
+ .replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
+ .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>')
+ }
+
+ /**
+ * Parse the given `qs`.
+ */
+
function parse(qs) {
return utils.reduce(qs.replace('?', '').split('&'), function(obj, pair){
var i = pair.indexOf('=')
@@ -3034,6 +3258,10 @@ window.mocha = require('mocha');
}, {});
}
+ /**
+ * Setup mocha with the give `ui` name.
+ */
+
mocha.setup = function(ui){
ui = mocha.interfaces[ui];
if (!ui) throw new Error('invalid mocha interface "' + ui + '"');
@@ -3041,13 +3269,22 @@ window.mocha = require('mocha');
suite.emit('pre-require', window);
};
+ /**
+ * Run mocha, returning the Runner.
+ */
+
mocha.run = function(){
suite.emit('run');
var runner = new mocha.Runner(suite);
var reporter = new Reporter(runner);
var query = parse(window.location.search || "");
if (query.grep) runner.grep(new RegExp(query.grep));
+ runner.on('end', function(){
+ $('code').each(function(){
+ $(this).html(highlight($(this).text()));
+ });
+ });
return runner.run();
};
})();
-})();
+})();
View
482 vendor/annotator.js
@@ -1,20 +1,39 @@
(function() {
- var $, Annotator, Delegator, Range, fn, functions, util, _Annotator, _i, _j, _len, _len2, _ref;
- var __slice = Array.prototype.slice, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
- for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
- function ctor() { this.constructor = child; }
- ctor.prototype = parent.prototype;
- child.prototype = new ctor;
- child.__super__ = parent.prototype;
- return child;
+ var $, Annotator, Delegator, Range, fn, functions, gettext, util, _Annotator, _gettext, _i, _j, _len, _len2, _ref, _t,
+ __slice = Array.prototype.slice,
+ __hasProp = Object.prototype.hasOwnProperty,
+ __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; };
+
+ gettext = null;
+
+ if (typeof Gettext !== "undefined" && Gettext !== null) {
+ _gettext = new Gettext({
+ domain: "annotator"
+ });
+ gettext = function(msgid) {
+ return _gettext.gettext(msgid);
+ };
+ } else {
+ gettext = function(msgid) {
+ return msgid;
+ };
+ }
+
+ _t = function(msgid) {
+ return gettext(msgid);
};
+
if (!(typeof jQuery !== "undefined" && jQuery !== null ? (_ref = jQuery.fn) != null ? _ref.jquery : void 0 : void 0)) {
- console.error("Annotator requires jQuery: have you included lib/vendor/jquery.js?");
+ console.error(_t("Annotator requires jQuery: have you included lib/vendor/jquery.js?"));
}
+
if (!(JSON && JSON.parse && JSON.stringify)) {
- console.error("Annotator requires a JSON implementation: have you included lib/vendor/json2.js?");
+ console.error(_t("Annotator requires a JSON implementation: have you included lib/vendor/json2.js?"));
}
+
$ = jQuery.sub();
+
$.flatten = function(array) {
var flatten;
flatten = function(ary) {
@@ -28,6 +47,7 @@
};
return flatten(array);
};
+
$.plugin = function(name, object) {
return jQuery.fn[name] = function(options) {
var args;
@@ -44,6 +64,7 @@
});
};
};
+
$.fn.textNodes = function() {
var getTextNodes;
getTextNodes = function(node) {
@@ -66,6 +87,7 @@
return $.flatten(getTextNodes(this));
});
};
+
$.fn.xpath = function(relativeRoot) {
var jq;
jq = this.map(function() {
@@ -82,30 +104,30 @@
});
return jq.get();
};
+
$.escape = function(html) {
return html.replace(/&(?!\w+;)/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
};
+
$.fn.escape = function(html) {
- if (arguments.length) {
- return this.html($.escape(html));
- }
+ if (arguments.length) return this.html($.escape(html));
return this.html();
};
+
functions = ["log", "debug", "info", "warn", "exception", "assert", "dir", "dirxml", "trace", "group", "groupEnd", "groupCollapsed", "time", "timeEnd", "profile", "profileEnd", "count", "clear", "table", "error", "notifyFirebug", "firebug", "userObjects"];
+
if (typeof console !== "undefined" && console !== null) {
if (!(console.group != null)) {
console.group = function(name) {
return console.log("GROUP: ", name);
};
}
- if (!(console.groupCollapsed != null)) {
- console.groupCollapsed = console.group;
- }
+ if (!(console.groupCollapsed != null)) console.groupCollapsed = console.group;
for (_i = 0, _len = functions.length; _i < _len; _i++) {
fn = functions[_i];
if (!(console[fn] != null)) {
console[fn] = function() {
- return console.log("Not implemented: console." + name);
+ return console.log(_t("Not implemented:") + (" console." + name));
};
}
}
@@ -126,16 +148,22 @@
return alert("WARNING: " + (args.join(', ')));
};
}
+
Delegator = (function() {
+
Delegator.prototype.events = {};
+
Delegator.prototype.options = {};
+
Delegator.prototype.element = null;
+
function Delegator(element, options) {
this.options = $.extend(true, {}, this.options, options);
this.element = $(element);
this.on = this.subscribe;
this.addEvents();
}
+
Delegator.prototype.addEvents = function() {
var event, functionName, sel, selector, _k, _ref2, _ref3, _results;
_ref2 = this.events;
@@ -147,15 +175,15 @@
}
return _results;
};
+
Delegator.prototype.addEvent = function(bindTo, event, functionName) {
- var closure, isBlankSelector;
- closure = __bind(function() {
- return this[functionName].apply(this, arguments);
- }, this);
+ var closure, isBlankSelector,
+ _this = this;
+ closure = function() {
+ return _this[functionName].apply(_this, arguments);
+ };
isBlankSelector = typeof bindTo === 'string' && bindTo.replace(/\s+/g, '') === '';
- if (isBlankSelector) {
- bindTo = this.element;
- }
+ if (isBlankSelector) bindTo = this.element;
if (typeof bindTo === 'string') {
this.element.delegate(bindTo, event, closure);
} else {
@@ -167,16 +195,17 @@
}
return this;
};
+
Delegator.prototype.isCustomEvent = function(event) {
- var natives;
- natives = "blur focus focusin focusout load resize scroll unload click dblclick\nmousedown mouseup mousemove mouseover mouseout mouseenter mouseleave\nchange select submit keydown keypress keyup error".split(/[^a-z]+/);
event = event.split('.')[0];
- return $.inArray(event, natives) === -1;
+ return $.inArray(event, Delegator.natives) === -1;
};
+
Delegator.prototype.publish = function() {
this.element.triggerHandler.apply(this.element, arguments);
return this;
};
+
Delegator.prototype.subscribe = function(event, callback) {
var closure;
closure = function() {
@@ -186,13 +215,34 @@
this.element.bind(event, closure);
return this;
};
+
Delegator.prototype.unsubscribe = function() {
this.element.unbind.apply(this.element, arguments);
return this;
};
+
return Delegator;
+
+ })();
+
+ Delegator.natives = (function() {
+ var key, specials, val;
+ specials = (function() {
+ var _ref2, _results;
+ _ref2 = jQuery.event.special;
+ _results = [];
+ for (key in _ref2) {
+ if (!__hasProp.call(_ref2, key)) continue;
+ val = _ref2[key];
+ _results.push(key);
+ }
+ return _results;
+ })();
+ return "blur focus focusin focusout load resize scroll unload click dblclick\nmousedown mouseup mousemove mouseover mouseout mouseenter mouseleave\nchange select submit keydown keypress keyup error".split(/[^a-z]+/).concat(specials);
})();
+
Range = {};
+
Range.sniff = function(r) {
if (r.commonAncestorContainer != null) {
return new Range.BrowserRange(r);
@@ -201,11 +251,13 @@
} else if (r.start && typeof r.start === "object") {
return new Range.NormalizedRange(r);
} else {
- console.error("Couldn't not sniff range type");
+ console.error(_t("Could not sniff range type"));
return false;
}
};
+
Range.BrowserRange = (function() {
+
function BrowserRange(obj) {
this.commonAncestorContainer = obj.commonAncestorContainer;
this.startContainer = obj.startContainer;
@@ -213,10 +265,11 @@
this.endContainer = obj.endContainer;
this.endOffset = obj.endOffset;
}
+
BrowserRange.prototype.normalize = function(root) {
var it, node, nr, offset, p, r, _k, _len3, _ref2;
if (this.tainted) {
- console.error("You may only call normalize() once on a BrowserRange!");
+ console.error(_t("You may only call normalize() once on a BrowserRange!"));
return false;
} else {
this.tainted = true;
@@ -246,9 +299,7 @@
}
nr.end = nr.start;
} else {
- if (r.endOffset < r.end.nodeValue.length) {
- r.end.splitText(r.endOffset);
- }
+ if (r.endOffset < r.end.nodeValue.length) r.end.splitText(r.endOffset);
nr.end = r.end;
}
nr.commonAncestor = this.commonAncestorContainer;
@@ -257,28 +308,33 @@
}
return new Range.NormalizedRange(nr);
};
+
BrowserRange.prototype.serialize = function(root, ignoreSelector) {
return this.normalize(root).serialize(root, ignoreSelector);
};
+
return BrowserRange;
+
})();
+
Range.NormalizedRange = (function() {
+
function NormalizedRange(obj) {
this.commonAncestor = obj.commonAncestor;
this.start = obj.start;
this.end = obj.end;
}
+
NormalizedRange.prototype.normalize = function(root) {
return this;
};
+
NormalizedRange.prototype.limit = function(bounds) {
var nodes, parent, startParents, _k, _len3, _ref2;
nodes = $.grep(this.textNodes(), function(node) {
return node.parentNode === bounds || $.contains(bounds, node.parentNode);
});
- if (!nodes.length) {
- return null;
- }
+ if (!nodes.length) return null;
this.start = nodes[0];
this.end = nodes[nodes.length - 1];
startParents = $(this.start).parents();
@@ -292,6 +348,7 @@
}
return this;
};
+
NormalizedRange.prototype.serialize = function(root, ignoreSelector) {
var end, serialization, start;
serialization = function(node, isEnd) {
@@ -324,6 +381,7 @@
endOffset: end[1]
});
};
+
NormalizedRange.prototype.text = function() {
var node;
return ((function() {
@@ -337,27 +395,39 @@
return _results;
}).call(this)).join('');
};
+
NormalizedRange.prototype.textNodes = function() {
var end, start, textNodes, _ref2;
textNodes = $(this.commonAncestor).textNodes();
_ref2 = [textNodes.index(this.start), textNodes.index(this.end)], start = _ref2[0], end = _ref2[1];
- return $.makeArray(textNodes.slice(start, (end + 1) || 9e9));
+ return $.makeArray(textNodes.slice(start, end + 1 || 9e9));
};
+
+ NormalizedRange.prototype.toRange = function() {
+ var range;
+ range = document.createRange();
+ range.setStartBefore(this.start);
+ range.setEndAfter(this.end);
+ return range;
+ };
+
return NormalizedRange;
+
})();
+
Range.SerializedRange = (function() {
+
function SerializedRange(obj) {
this.start = obj.start;
this.startOffset = obj.startOffset;
this.end = obj.end;
this.endOffset = obj.endOffset;
}
+
SerializedRange.prototype._nodeFromXPath = function(xpath) {
var customResolver, evaluateXPath, namespace, node, segment;
evaluateXPath = function(xp, nsResolver) {
- if (nsResolver == null) {
- nsResolver = null;
- }
+ if (nsResolver == null) nsResolver = null;
return document.evaluate(xp, document, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
};
if (!$.isXMLDoc(document.documentElement)) {
@@ -372,7 +442,11 @@
_results = [];
for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
segment = _ref2[_k];
- _results.push(segment && segment.indexOf(':') === -1 ? segment.replace(/^([a-z]+)/, 'xhtml:$1') : segment);
+ if (segment && segment.indexOf(':') === -1) {
+ _results.push(segment.replace(/^([a-z]+)/, 'xhtml:$1'));
+ } else {
+ _results.push(segment);
+ }
}
return _results;
})()).join('/');
@@ -389,6 +463,7 @@
return node;
}
};
+
SerializedRange.prototype.normalize = function(root) {
var cacXPath, common, endAncestry, i, length, p, parentXPath, range, startAncestry, tn, _k, _l, _len3, _len4, _ref2, _ref3, _ref4;
parentXPath = $(root).xpath()[0];
@@ -406,7 +481,7 @@
cacXPath = parentXPath + common.join("/");
range.commonAncestorContainer = this._nodeFromXPath(cacXPath);
if (!range.commonAncestorContainer) {
- console.error("Error deserializing range: can't find XPath '" + cacXPath + "'. Is this the right document?");
+ console.error(_t("Error deserializing range: can't find XPath '") + cacXPath + _t("'. Is this the right document?"));
return null;
}
_ref3 = ['start', 'end'];
@@ -427,9 +502,11 @@
}
return new Range.BrowserRange(range).normalize(root);
};
+
SerializedRange.prototype.serialize = function(root, ignoreSelector) {
return this.normalize(root).serialize(root, ignoreSelector);
};
+
SerializedRange.prototype.toObject = function() {
return {
start: this.start,
@@ -438,8 +515,11 @@
endOffset: this.endOffset
};
};
+
return SerializedRange;
+
})();
+
util = {
uuid: (function() {
var counter;
@@ -465,28 +545,42 @@
return event != null ? typeof event.preventDefault === "function" ? event.preventDefault() : void 0 : void 0;
}
};
+
_Annotator = this.Annotator;
- Annotator = (function() {
- __extends(Annotator, Delegator);
+
+ Annotator = (function(_super) {
+
+ __extends(Annotator, _super);
+
Annotator.prototype.events = {
".annotator-adder button click": "onAdderClick",
".annotator-adder button mousedown": "onAdderMousedown",
".annotator-hl mouseover": "onHighlightMouseover",
".annotator-hl mouseout": "startViewerHideTimer"
};
+
Annotator.prototype.html = {
hl: '<span class="annotator-hl"></span>',
- adder: '<div class="annotator-adder"><button>Annotate</button></div>',
+ adder: '<div class="annotator-adder"><button>' + _t('Annotate') + '</button></div>',
wrapper: '<div class="annotator-wrapper"></div>'
};
+
Annotator.prototype.options = {};
+
Annotator.prototype.plugins = {};
+
Annotator.prototype.editor = null;
+
Annotator.prototype.viewer = null;
+
Annotator.prototype.selectedRanges = null;
+
Annotator.prototype.mouseIsDown = false;
+
Annotator.prototype.ignoreMouseup = false;
+
Annotator.prototype.viewerHideTimer = null;
+
function Annotator(element, options) {
this.onDeleteAnnotation = __bind(this.onDeleteAnnotation, this);
this.onEditAnnotation = __bind(this.onEditAnnotation, this);
@@ -500,21 +594,19 @@
this.showViewer = __bind(this.showViewer, this);
this.onEditorSubmit = __bind(this.onEditorSubmit, this);
this.onEditorHide = __bind(this.onEditorHide, this);
- this.showEditor = __bind(this.showEditor, this); var name, src, _ref2;
+ this.showEditor = __bind(this.showEditor, this);
+ var name, src, _ref2;
Annotator.__super__.constructor.apply(this, arguments);
this.plugins = {};
- if (!Annotator.supported()) {
- return this;
- }
+ if (!Annotator.supported()) return this;
this._setupDocumentEvents()._setupWrapper()._setupViewer()._setupEditor();
_ref2 = this.html;
for (name in _ref2) {
src = _ref2[name];
- if (name !== 'wrapper') {
- this[name] = $(src).appendTo(this.wrapper).hide();
- }
+ if (name !== 'wrapper') this[name] = $(src).appendTo(this.wrapper).hide();
}
}
+
Annotator.prototype._setupWrapper = function() {
this.wrapper = $(this.html.wrapper);
this.element.find('script').remove();
@@ -522,24 +614,31 @@
this.wrapper = this.element.find('.annotator-wrapper');
return this;
};
+
Annotator.prototype._setupViewer = function() {
+ var _this = this;
this.viewer = new Annotator.Viewer();
this.viewer.hide().on("edit", this.onEditAnnotation).on("delete", this.onDeleteAnnotation).addField({
- load: __bind(function(field, annotation) {
- $(field).escape(annotation.text || '');
- return this.publish('annotationViewerTextField', [field, annotation]);
- }, this)
+ load: function(field, annotation) {
+ if (annotation.text) {
+ $(field).escape(annotation.text);
+ } else {
+ $(field).html("<i>" + (_t('No Comment')) + "</i>");
+ }
+ return _this.publish('annotationViewerTextField', [field, annotation]);
+ }
}).element.appendTo(this.wrapper).bind({
"mouseover": this.clearViewerHideTimer,
"mouseout": this.startViewerHideTimer
});
return this;
};
+
Annotator.prototype._setupEditor = function() {
this.editor = new Annotator.Editor();
this.editor.hide().on('hide', this.onEditorHide).on('save', this.onEditorSubmit).addField({
type: 'textarea',
- label: 'Comments\u2026',
+ label: _t('Comments') + '\u2026',
load: function(field, annotation) {
return $(field).find('textarea').val(annotation.text || '');
},
@@ -550,6 +649,7 @@
this.editor.element.appendTo(this.wrapper);
return this;
};
+
Annotator.prototype._setupDocumentEvents = function() {
$(document).bind({
"mouseup": this.checkForEndSelection,
@@ -557,6 +657,7 @@
});
return this;
};
+
Annotator.prototype.getSelectedRanges = function() {
var browserRange, i, ranges, selection;
selection = util.getGlobal().getSelection();
@@ -571,22 +672,24 @@
}
return _results;
}).call(this);
+ selection.removeAllRanges();
}
return $.grep(ranges, function(range) {
+ if (range) selection.addRange(range.toRange());
return range;
});
};
+
Annotator.prototype.createAnnotation = function() {
var annotation;
annotation = {};
this.publish('beforeAnnotationCreated', [annotation]);
return annotation;
};
+
Annotator.prototype.setupAnnotation = function(annotation, fireEvents) {
var normed, normedRanges, r, sniffed, _k, _len3;
- if (fireEvents == null) {
- fireEvents = true;
- }
+ if (fireEvents == null) fireEvents = true;
annotation.ranges || (annotation.ranges = this.selectedRanges);
normedRanges = (function() {
var _k, _len3, _ref2, _results;
@@ -613,16 +716,16 @@
}
annotation.quote = annotation.quote.join(' / ');
$(annotation.highlights).data('annotation', annotation);
- if (fireEvents) {
- this.publish('annotationCreated', [annotation]);
- }
+ if (fireEvents) this.publish('annotationCreated', [annotation]);
return annotation;
};
+
Annotator.prototype.updateAnnotation = function(annotation) {
this.publish('beforeAnnotationUpdated', [annotation]);
this.publish('annotationUpdated', [annotation]);
return annotation;
};
+
Annotator.prototype.deleteAnnotation = function(annotation) {
var h, _k, _len3, _ref2;
_ref2 = annotation.highlights;
@@ -633,60 +736,58 @@
this.publish('annotationDeleted', [annotation]);
return annotation;
};
+
Annotator.prototype.loadAnnotations = function(annotations) {
- var clone, loader;
- if (annotations == null) {
- annotations = [];
- }
- loader = __bind(function(annList) {
+ var clone, loader,
+ _this = this;
+ if (annotations == null) annotations = [];
+ loader = function(annList) {
var n, now, _k, _len3;
- if (annList == null) {
- annList = [];
- }
+ if (annList == null) annList = [];
now = annList.splice(0, 10);
for (_k = 0, _len3 = now.length; _k < _len3; _k++) {
n = now[_k];
- this.setupAnnotation(n, false);
+ _this.setupAnnotation(n, false);
}
if (annList.length > 0) {
return setTimeout((function() {
return loader(annList);
}), 100);
} else {
- return this.publish('annotationsLoaded', [clone]);
+ return _this.publish('annotationsLoaded', [clone]);
}
- }, this);
+ };
clone = annotations.slice();
- if (annotations.length) {
- loader(annotations);
- }
+ if (annotations.length) loader(annotations);
return this;
};
+
Annotator.prototype.dumpAnnotations = function() {
if (this.plugins['Store']) {
return this.plugins['Store'].dumpAnnotations();
} else {
- return console.warn("Can't dump annotations without Store plugin.");
+ return console.warn(_t("Can't dump annotations without Store plugin."));
}
};
+
Annotator.prototype.highlightRange = function(normedRange) {
- var elemList, node, wrapper;
- return elemList = (function() {
- var _k, _len3, _ref2, _results;
- _ref2 = normedRange.textNodes();
- _results = [];
- for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
- node = _ref2[_k];
- wrapper = this.hl.clone().show();
- _results.push($(node).wrap(wrapper).parent().get(0));
+ var node, white, _k, _len3, _ref2, _results;
+ white = /^\s*$/;
+ _ref2 = normedRange.textNodes();
+ _results = [];
+ for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
+ node = _ref2[_k];
+ if (!white.test(node.nodeValue)) {
+ _results.push($(node).wrapAll(this.hl).parent().show()[0]);
}
- return _results;
- }).call(this);
+ }
+ return _results;
};
+
Annotator.prototype.addPlugin = function(name, options) {
var klass, _base;
if (this.plugins[name]) {
- console.error("You cannot have more than one instance of any plugin.");
+ console.error(_t("You cannot have more than one instance of any plugin."));
} else {
klass = Annotator.Plugin[name];
if (typeof klass === 'function') {
@@ -696,20 +797,23 @@
_base.pluginInit();
}
} else {
- console.error("Could not load " + name + " plugin. Have you included the appropriate <script> tag?");
+ console.error(_t("Could not load ") + name + _t(" plugin. Have you included the appropriate <script> tag?"));
}
}
return this;
};
+
Annotator.prototype.showEditor = function(annotation, location) {
this.editor.element.css(location);
this.editor.load(annotation);
return this;
};
+
Annotator.prototype.onEditorHide = function() {
this.publish('annotationEditorHidden', [this.editor]);
return this.ignoreMouseup = false;
};
+
Annotator.prototype.onEditorSubmit = function(annotation) {
this.publish('annotationEditorSubmit', [this.editor, annotation]);
if (annotation.ranges === void 0) {
@@ -718,40 +822,41 @@
return this.updateAnnotation(annotation);
}
};
+
Annotator.prototype.showViewer = function(annotations, location) {
this.viewer.element.css(location);
this.viewer.load(annotations);
return this.publish('annotationViewerShown', [this.viewer, annotations]);
};
+
Annotator.prototype.startViewerHideTimer = function() {
if (!this.viewerHideTimer) {
return this.viewerHideTimer = setTimeout(this.viewer.hide, 250);
}
};
+
Annotator.prototype.clearViewerHideTimer = function() {
clearTimeout(this.viewerHideTimer);
return this.viewerHideTimer = false;
};
+
Annotator.prototype.checkForStartSelection = function(event) {
if (!(event && this.isAnnotator(event.target))) {
this.startViewerHideTimer();
return this.mouseIsDown = true;
}
};
+
Annotator.prototype.checkForEndSelection = function(event) {
var container, range, _k, _len3, _ref2;
this.mouseIsDown = false;
- if (this.ignoreMouseup) {
- return;
- }
+ if (this.ignoreMouseup) return;
this.selectedRanges = this.getSelectedRanges();
_ref2 = this.selectedRanges;
for (_k = 0, _len3 = _ref2.length; _k < _len3; _k++) {
range = _ref2[_k];
container = range.commonAncestor;
- if (this.isAnnotator(container)) {
- return;
- }
+ if (this.isAnnotator(container)) return;
}
if (event && this.selectedRanges.length) {
return this.adder.css(util.mousePosition(event, this.wrapper[0])).show();
@@ -759,69 +864,91 @@
return this.adder.hide();
}
};
+
Annotator.prototype.isAnnotator = function(element) {
return !!$(element).parents().andSelf().filter('[class^=annotator-]').not(this.wrapper).length;
};
+
Annotator.prototype.onHighlightMouseover = function(event) {
var annotations;
this.clearViewerHideTimer();
- if (this.mouseIsDown || this.viewer.isShown()) {
- return false;
- }
+ if (this.mouseIsDown || this.viewer.isShown()) return false;
annotations = $(event.target).parents('.annotator-hl').andSelf().map(function() {
return $(this).data("annotation");
});
return this.showViewer($.makeArray(annotations), util.mousePosition(event, this.wrapper[0]));
};
+
Annotator.prototype.onAdderMousedown = function(event) {
- if (event != null) {
- event.preventDefault();
- }
+ if (event != null) event.preventDefault();
return this.ignoreMouseup = true;
};
+
Annotator.prototype.onAdderClick = function(event) {
var position;
- if (event != null) {
- event.preventDefault();
- }
+ if (event != null) event.preventDefault();
position = this.adder.position();
this.adder.hide();
return this.showEditor(this.createAnnotation(), position);
};
+
Annotator.prototype.onEditAnnotation = function(annotation) {
var offset;
offset = this.viewer.element.position();
this.viewer.hide();
return this.showEditor(annotation, offset);
};
+
Annotator.prototype.onDeleteAnnotation = function(annotation) {
this.viewer.hide();
return this.deleteAnnotation(annotation);
};
+
return Annotator;
- })();
- Annotator.Plugin = (function() {
- __extends(Plugin, Delegator);
+
+ })(Delegator);
+
+ Annotator.Plugin = (function(_super) {
+
+ __extends(Plugin, _super);
+
function Plugin(element, options) {
Plugin.__super__.constructor.apply(this, arguments);
}
+
Plugin.prototype.pluginInit = function() {};
+
return Plugin;
- })();
+
+ })(Delegator);
+
Annotator.$ = $;
+
+ Annotator.Delegator = Delegator;
+
+ Annotator.Range = Range;
+
+ Annotator._t = _t;
+
Annotator.supported = function() {
return (function() {
return !!this.getSelection;
})();
};
+
Annotator.noConflict = function() {
util.getGlobal().Annotator = _Annotator;
return this;
};
+
$.plugin('annotator', Annotator);
+
this.Annotator = Annotator;
- Annotator.Widget = (function() {
- __extends(Widget, Delegator);
+
+ Annotator.Widget = (function(_super) {
+
+ __extends(Widget, _super);
+
Widget.prototype.classes = {
hide: 'annotator-hide',
invert: {
@@ -829,10 +956,12 @@
y: 'annotator-invert-y'
}
};
+
function Widget(element, options) {
Widget.__super__.constructor.apply(this, arguments);
this.classes = $.extend({}, Annotator.Widget.prototype.classes, this.classes);
}
+
Widget.prototype.checkOrientation = function() {
var current, offset, viewport, widget, window;
this.resetOrientation();
@@ -847,30 +976,42 @@
top: offset.top,
right: offset.left + widget.width()
};
- if ((current.top - viewport.top) < 0) {
- this.invertY();
- }
- if ((current.right - viewport.right) > 0) {
- this.invertX();
- }
+ if ((current.top - viewport.top) < 0) this.invertY();
+ if ((current.right - viewport.right) > 0) this.invertX();
return this;
};
+
Widget.prototype.resetOrientation = function() {
this.element.removeClass(this.classes.invert.x).removeClass(this.classes.invert.y);
return this;
};
+
Widget.prototype.invertX = function() {
this.element.addClass(this.classes.invert.x);
return this;
};
+
Widget.prototype.invertY = function() {
this.element.addClass(this.classes.invert.y);
return this;
};
+
+ Widget.prototype.isInvertedY = function() {
+ return this.element.hasClass(this.classes.invert.y);
+ };
+
+ Widget.prototype.isInvertedX = function() {
+ return this.element.hasClass(this.classes.invert.x);
+ };
+
return Widget;
- })();
- Annotator.Editor = (function() {
- __extends(Editor, Annotator.Widget);
+
+ })(Delegator);
+
+ Annotator.Editor = (function(_super) {
+
+ __extends(Editor, _super);
+
Editor.prototype.events = {
"form submit": "submit",
".annotator-save click": "submit",
@@ -878,12 +1019,16 @@
".annotator-cancel mouseover": "onCancelButtonMouseover",
"textarea keydown": "processKeypress"
};
+
Editor.prototype.classes = {
hide: 'annotator-hide',
focus: 'annotator-focus'
};
- Editor.prototype.html = "<div class=\"annotator-outer annotator-editor\">\n <form class=\"annotator-widget\">\n <ul class=\"annotator-listing\"></ul>\n <div class=\"annotator-controls\">\n <a href=\"#cancel\" class=\"annotator-cancel\">Cancel</a>\n <a href=\"#save\" class=\"annotator-save annotator-focus\">Save</a>\n </div>\n <span class=\"annotator-resize\"></span>\n </form>\n</div>";
+
+ Editor.prototype.html = "<div class=\"annotator-outer annotator-editor\">\n <form class=\"annotator-widget\">\n <ul class=\"annotator-listing\"></ul>\n <div class=\"annotator-controls\">\n <a href=\"#cancel\" class=\"annotator-cancel\">" + _t('Cancel') + "</a>\n<a href=\"#save\" class=\"annotator-save annotator-focus\">" + _t('Save') + "</a>\n </div>\n <span class=\"annotator-resize\"></span>\n </form>\n</div>";
+
Editor.prototype.options = {};
+
function Editor(options) {
this.onCancelButtonMouseover = __bind(this.onCancelButtonMouseover, this);
this.processKeypress = __bind(this.processKeypress, this);
@@ -893,20 +1038,26 @@
this.show = __bind(this.show, this); Editor.__super__.constructor.call(this, $(this.html)[0], options);
this.fields = [];
this.annotation = {};
- this.setupDragabbles();
+ this.setupDraggables();
}
+
Editor.prototype.show = function(event) {
+ var focusPos;
util.preventEventDefault(event);
this.element.removeClass(this.classes.hide);
this.element.find('.annotator-save').addClass(this.classes.focus);
- this.element.find(':input:first').focus();
- return this.checkOrientation().publish('show');
+ this.checkOrientation();
+ focusPos = this.isInvertedY() ? ':last' : ':first';
+ this.element.find(":input" + focusPos).focus();
+ return this.publish('show');
};
+
Editor.prototype.hide = function(event) {
util.preventEventDefault(event);
this.element.addClass(this.classes.hide);
return this.publish('hide');
};
+
Editor.prototype.load = function(annotation) {
var field, _k, _len3, _ref2;
this.annotation = annotation;
@@ -918,6 +1069,7 @@
}
return this.show();
};
+
Editor.prototype.submit = function(event) {
var field, _k, _len3, _ref2;
util.preventEventDefault(event);
@@ -929,6 +1081,7 @@
this.publish('save', [this.annotation]);
return this.hide();
};
+
Editor.prototype.addField = function(options) {
var element, field, input;
field = $.extend({
@@ -966,6 +1119,7 @@
this.fields.push(field);
return field.element;
};
+
Editor.prototype.checkOrientation = function() {
var controls, flipFields, list;
Editor.__super__.checkOrientation.apply(this, arguments);
@@ -985,6 +1139,7 @@
}
return this;
};
+
Editor.prototype.processKeypress = function(event) {
if (event.keyCode === 27) {
return this.hide();
@@ -992,11 +1147,14 @@
return this.submit();
}
};
+
Editor.prototype.onCancelButtonMouseover = function() {
return this.element.find('.' + this.classes.focus).removeClass(this.classes.focus);
};
- Editor.prototype.setupDragabbles = function() {
- var classes, controls, editor, mousedown, onMousedown, onMousemove, onMouseup, resize, textarea, throttle;
+
+ Editor.prototype.setupDraggables = function() {
+ var classes, controls, editor, mousedown, onMousedown, onMousemove, onMouseup, resize, textarea, throttle,
+ _this = this;