blash "
10 | ]
11 | },
12 | {
13 | "cell_type": "markdown",
14 | "metadata": {},
15 | "source": [
16 | " "
17 | ]
18 | },
19 | {
20 | "cell_type": "markdown",
21 | "metadata": {},
22 | "source": [
23 | "## Bibliography\n",
24 | "\n",
25 | ""
26 | ]
27 | }
28 | ],
29 | "metadata": {
30 | "cite2c": {
31 | "citations": {
32 | "29383/29XGSBTZ": {
33 | "DOI": "10.1038/250026a0",
34 | "URL": "http://dx.doi.org/10.1038/250026a0",
35 | "accessed": {
36 | "day": "8",
37 | "month": "3",
38 | "year": "2009"
39 | },
40 | "author": [
41 | {
42 | "family": "Grime",
43 | "given": "J. P."
44 | }
45 | ],
46 | "container-title": "Nature",
47 | "container-title-short": "Nature",
48 | "id": "29383/29XGSBTZ",
49 | "issue": "5461",
50 | "issued": {
51 | "day": 5,
52 | "month": "7",
53 | "year": "1974"
54 | },
55 | "journalAbbreviation": "Nature",
56 | "page": "26-31",
57 | "page-first": "26",
58 | "title": "Vegetation classification by reference to strategies",
59 | "type": "article-journal",
60 | "volume": "250"
61 | },
62 | "29383/44RMTN4V": {
63 | "author": [
64 | {
65 | "family": "Harlan",
66 | "given": "Jack R."
67 | }
68 | ],
69 | "container-title": "Archaeology",
70 | "id": "29383/44RMTN4V",
71 | "issue": "3",
72 | "issued": {
73 | "year": "1967"
74 | },
75 | "page": "197-201",
76 | "page-first": "197",
77 | "title": "A wild wheat harvest in Turkey",
78 | "type": "article-journal",
79 | "volume": "20"
80 | },
81 | "29383/QTCKJCDM": {
82 | "DOI": "10.2307/2406971",
83 | "URL": "http://www.jstor.org/stable/2406971",
84 | "accessed": {
85 | "day": "10",
86 | "month": "6",
87 | "year": "2013"
88 | },
89 | "author": [
90 | {
91 | "family": "Harlan",
92 | "given": "Jack R."
93 | },
94 | {
95 | "family": "Wet",
96 | "given": "J. M. J. de"
97 | },
98 | {
99 | "family": "Price",
100 | "given": "E. Glen"
101 | }
102 | ],
103 | "container-title": "Evolution",
104 | "container-title-short": "Evolution",
105 | "id": "29383/QTCKJCDM",
106 | "issue": "2",
107 | "issued": {
108 | "day": 1,
109 | "month": "6",
110 | "year": "1973"
111 | },
112 | "journalAbbreviation": "Evolution",
113 | "note": "ArticleType: research-article / Full publication date: Jun., 1973 / Copyright \u00a9 1973 Society for the Study of Evolution",
114 | "page": "311-325",
115 | "page-first": "311",
116 | "title": "Comparative Evolution of Cereals",
117 | "type": "article-journal",
118 | "volume": "27"
119 | },
120 | "29383/R7MVWURF": {
121 | "DOI": "10.1002/ece3.529",
122 | "URL": "http://onlinelibrary.wiley.com/doi/10.1002/ece3.529/abstract",
123 | "abstract": "Online databases of biological information offer tremendous potential for evolutionary and ecological discoveries, especially if data are combined in novel ways. However, the different names and varied spellings used for many species present major barriers to linking data. Taxonome is a software tool designed to solve this problem by quickly and reproducibly matching biological names to a given reference set. It is available both as a graphical user interface (GUI) for simple interactive use, and as a library for more advanced functionality with programs written in Python. Taxonome also includes functions to standardize distribution information to a well-defined set of regions, such as the TDWG World Geographical Scheme for Recording Plant Distributions. In combination, these tools will help biologists to rapidly synthesize disparate datasets, and to investigate large-scale patterns in species traits.",
124 | "accessed": {
125 | "day": "3",
126 | "month": "4",
127 | "year": "2013"
128 | },
129 | "author": [
130 | {
131 | "family": "Kluyver",
132 | "given": "Thomas A."
133 | },
134 | {
135 | "family": "Osborne",
136 | "given": "Colin P."
137 | }
138 | ],
139 | "container-title": "Ecology and Evolution",
140 | "id": "29383/R7MVWURF",
141 | "issue": "5",
142 | "issued": {
143 | "month": "5",
144 | "year": "2013"
145 | },
146 | "language": "en",
147 | "page": "1262-1265",
148 | "page-first": "1262",
149 | "shortTitle": "Taxonome",
150 | "title": "Taxonome: a software package for linking biological species data",
151 | "title-short": "Taxonome",
152 | "type": "article-journal",
153 | "volume": "3"
154 | },
155 | "allium_vavilovii": {
156 | "DOI": "10.1023/A:1012034931024",
157 | "ISSN": "0925-9864",
158 | "URL": "http://dx.doi.org/10.1023/A:1012034931024",
159 | "abstract": "A wild onion species from Karaj valley east of Tehran istaxonomically described as Allium asarense R. M.Fritsch et Matin. Sharing the bubble-like inflated lower scapewith A. vavilovii, the newspecies differs by semi-cylindrical leaves and small flowerswith translucent greenish-yellow tepals from all other knownspecies of Allium sect.Cepa. Molecular data suggest a closerelationship to A. cepa(but to a lesser degree than A.vavilovii) and indicate a still weakerphylogenetic connection of A.oschaninii to the common onion. The questionabout the possible wild ancestor of A.cepa is discussed against this background, and akey for determination of the Oschaninii-alliance of sect. Cepa is presented.",
160 | "author": [
161 | {
162 | "family": "Fritsch",
163 | "given": "Reinhard M."
164 | },
165 | {
166 | "family": "Matin",
167 | "given": "Farideh"
168 | },
169 | {
170 | "family": "Klaas",
171 | "given": "Manfred"
172 | }
173 | ],
174 | "container-title": "Genetic Resources and Crop Evolution",
175 | "container-title-short": "Genet Resour Crop Evol",
176 | "id": "allium_vavilovii",
177 | "issue": "4",
178 | "issued": {
179 | "day": 1,
180 | "month": 8,
181 | "year": 2001
182 | },
183 | "journalAbbreviation": "Genet Resour Crop Evol",
184 | "page": "401-408",
185 | "page-first": "401",
186 | "title": "Allium vavilovii M. Popov et Vved. and a new Iranian species are the closest among the known relatives of the common onion A. cepa L. (Alliaceae)",
187 | "type": "article-journal",
188 | "volume": "48"
189 | },
190 | "batpol": {
191 | "DOI": "10.1038/19648",
192 | "ISSN": "0028-0836",
193 | "URL": "http://dx.doi.org/10.1038/19648",
194 | "accessed": {
195 | "day": 31,
196 | "month": 8,
197 | "year": 2009
198 | },
199 | "author": [
200 | {
201 | "family": "von Helversen",
202 | "given": "Dagmar"
203 | },
204 | {
205 | "family": "von Helversen",
206 | "given": "Otto"
207 | }
208 | ],
209 | "container-title": "Nature",
210 | "container-title-short": "Nature",
211 | "id": "batpol",
212 | "issue": "6730",
213 | "issued": {
214 | "day": 29,
215 | "month": 4,
216 | "year": 1999
217 | },
218 | "journalAbbreviation": "Nature",
219 | "page": "759-760",
220 | "page-first": "759",
221 | "source": "Nature",
222 | "title": "Acoustic guide in bat-pollinated flower",
223 | "type": "article-journal",
224 | "volume": "398"
225 | }
226 | }
227 | },
228 | "kernelspec": {
229 | "display_name": "IPython (Python 3)",
230 | "name": "python3"
231 | },
232 | "language_info": {
233 | "codemirror_mode": {
234 | "name": "ipython",
235 | "version": 3
236 | },
237 | "mimetype": "text/x-python",
238 | "name": "python",
239 | "pygments_lexer": "ipython3"
240 | },
241 | "signature": "sha256:f5435fef05f9bd84be1023f8a8639d41f16dc6a6661905724f6a45d32e0d79d5"
242 | },
243 | "nbformat": 4,
244 | "nbformat_minor": 0
245 | }
--------------------------------------------------------------------------------
/bloodhound.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * typeahead.js 0.10.5
3 | * https://github.com/twitter/typeahead.js
4 | * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
5 | */
6 |
7 | (function($) {
8 | var _ = function() {
9 | "use strict";
10 | return {
11 | isMsie: function() {
12 | return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
13 | },
14 | isBlankString: function(str) {
15 | return !str || /^\s*$/.test(str);
16 | },
17 | escapeRegExChars: function(str) {
18 | return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
19 | },
20 | isString: function(obj) {
21 | return typeof obj === "string";
22 | },
23 | isNumber: function(obj) {
24 | return typeof obj === "number";
25 | },
26 | isArray: $.isArray,
27 | isFunction: $.isFunction,
28 | isObject: $.isPlainObject,
29 | isUndefined: function(obj) {
30 | return typeof obj === "undefined";
31 | },
32 | toStr: function toStr(s) {
33 | return _.isUndefined(s) || s === null ? "" : s + "";
34 | },
35 | bind: $.proxy,
36 | each: function(collection, cb) {
37 | $.each(collection, reverseArgs);
38 | function reverseArgs(index, value) {
39 | return cb(value, index);
40 | }
41 | },
42 | map: $.map,
43 | filter: $.grep,
44 | every: function(obj, test) {
45 | var result = true;
46 | if (!obj) {
47 | return result;
48 | }
49 | $.each(obj, function(key, val) {
50 | if (!(result = test.call(null, val, key, obj))) {
51 | return false;
52 | }
53 | });
54 | return !!result;
55 | },
56 | some: function(obj, test) {
57 | var result = false;
58 | if (!obj) {
59 | return result;
60 | }
61 | $.each(obj, function(key, val) {
62 | if (result = test.call(null, val, key, obj)) {
63 | return false;
64 | }
65 | });
66 | return !!result;
67 | },
68 | mixin: $.extend,
69 | getUniqueId: function() {
70 | var counter = 0;
71 | return function() {
72 | return counter++;
73 | };
74 | }(),
75 | templatify: function templatify(obj) {
76 | return $.isFunction(obj) ? obj : template;
77 | function template() {
78 | return String(obj);
79 | }
80 | },
81 | defer: function(fn) {
82 | setTimeout(fn, 0);
83 | },
84 | debounce: function(func, wait, immediate) {
85 | var timeout, result;
86 | return function() {
87 | var context = this, args = arguments, later, callNow;
88 | later = function() {
89 | timeout = null;
90 | if (!immediate) {
91 | result = func.apply(context, args);
92 | }
93 | };
94 | callNow = immediate && !timeout;
95 | clearTimeout(timeout);
96 | timeout = setTimeout(later, wait);
97 | if (callNow) {
98 | result = func.apply(context, args);
99 | }
100 | return result;
101 | };
102 | },
103 | throttle: function(func, wait) {
104 | var context, args, timeout, result, previous, later;
105 | previous = 0;
106 | later = function() {
107 | previous = new Date();
108 | timeout = null;
109 | result = func.apply(context, args);
110 | };
111 | return function() {
112 | var now = new Date(), remaining = wait - (now - previous);
113 | context = this;
114 | args = arguments;
115 | if (remaining <= 0) {
116 | clearTimeout(timeout);
117 | timeout = null;
118 | previous = now;
119 | result = func.apply(context, args);
120 | } else if (!timeout) {
121 | timeout = setTimeout(later, remaining);
122 | }
123 | return result;
124 | };
125 | },
126 | noop: function() {}
127 | };
128 | }();
129 | var VERSION = "0.10.5";
130 | var tokenizers = function() {
131 | "use strict";
132 | return {
133 | nonword: nonword,
134 | whitespace: whitespace,
135 | obj: {
136 | nonword: getObjTokenizer(nonword),
137 | whitespace: getObjTokenizer(whitespace)
138 | }
139 | };
140 | function whitespace(str) {
141 | str = _.toStr(str);
142 | return str ? str.split(/\s+/) : [];
143 | }
144 | function nonword(str) {
145 | str = _.toStr(str);
146 | return str ? str.split(/\W+/) : [];
147 | }
148 | function getObjTokenizer(tokenizer) {
149 | return function setKey() {
150 | var args = [].slice.call(arguments, 0);
151 | return function tokenize(o) {
152 | var tokens = [];
153 | _.each(args, function(k) {
154 | tokens = tokens.concat(tokenizer(_.toStr(o[k])));
155 | });
156 | return tokens;
157 | };
158 | };
159 | }
160 | }();
161 | var LruCache = function() {
162 | "use strict";
163 | function LruCache(maxSize) {
164 | this.maxSize = _.isNumber(maxSize) ? maxSize : 100;
165 | this.reset();
166 | if (this.maxSize <= 0) {
167 | this.set = this.get = $.noop;
168 | }
169 | }
170 | _.mixin(LruCache.prototype, {
171 | set: function set(key, val) {
172 | var tailItem = this.list.tail, node;
173 | if (this.size >= this.maxSize) {
174 | this.list.remove(tailItem);
175 | delete this.hash[tailItem.key];
176 | }
177 | if (node = this.hash[key]) {
178 | node.val = val;
179 | this.list.moveToFront(node);
180 | } else {
181 | node = new Node(key, val);
182 | this.list.add(node);
183 | this.hash[key] = node;
184 | this.size++;
185 | }
186 | },
187 | get: function get(key) {
188 | var node = this.hash[key];
189 | if (node) {
190 | this.list.moveToFront(node);
191 | return node.val;
192 | }
193 | },
194 | reset: function reset() {
195 | this.size = 0;
196 | this.hash = {};
197 | this.list = new List();
198 | }
199 | });
200 | function List() {
201 | this.head = this.tail = null;
202 | }
203 | _.mixin(List.prototype, {
204 | add: function add(node) {
205 | if (this.head) {
206 | node.next = this.head;
207 | this.head.prev = node;
208 | }
209 | this.head = node;
210 | this.tail = this.tail || node;
211 | },
212 | remove: function remove(node) {
213 | node.prev ? node.prev.next = node.next : this.head = node.next;
214 | node.next ? node.next.prev = node.prev : this.tail = node.prev;
215 | },
216 | moveToFront: function(node) {
217 | this.remove(node);
218 | this.add(node);
219 | }
220 | });
221 | function Node(key, val) {
222 | this.key = key;
223 | this.val = val;
224 | this.prev = this.next = null;
225 | }
226 | return LruCache;
227 | }();
228 | var PersistentStorage = function() {
229 | "use strict";
230 | var ls, methods;
231 | try {
232 | ls = window.localStorage;
233 | ls.setItem("~~~", "!");
234 | ls.removeItem("~~~");
235 | } catch (err) {
236 | ls = null;
237 | }
238 | function PersistentStorage(namespace) {
239 | this.prefix = [ "__", namespace, "__" ].join("");
240 | this.ttlKey = "__ttl__";
241 | this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));
242 | }
243 | if (ls && window.JSON) {
244 | methods = {
245 | _prefix: function(key) {
246 | return this.prefix + key;
247 | },
248 | _ttlKey: function(key) {
249 | return this._prefix(key) + this.ttlKey;
250 | },
251 | get: function(key) {
252 | if (this.isExpired(key)) {
253 | this.remove(key);
254 | }
255 | return decode(ls.getItem(this._prefix(key)));
256 | },
257 | set: function(key, val, ttl) {
258 | if (_.isNumber(ttl)) {
259 | ls.setItem(this._ttlKey(key), encode(now() + ttl));
260 | } else {
261 | ls.removeItem(this._ttlKey(key));
262 | }
263 | return ls.setItem(this._prefix(key), encode(val));
264 | },
265 | remove: function(key) {
266 | ls.removeItem(this._ttlKey(key));
267 | ls.removeItem(this._prefix(key));
268 | return this;
269 | },
270 | clear: function() {
271 | var i, key, keys = [], len = ls.length;
272 | for (i = 0; i < len; i++) {
273 | if ((key = ls.key(i)).match(this.keyMatcher)) {
274 | keys.push(key.replace(this.keyMatcher, ""));
275 | }
276 | }
277 | for (i = keys.length; i--; ) {
278 | this.remove(keys[i]);
279 | }
280 | return this;
281 | },
282 | isExpired: function(key) {
283 | var ttl = decode(ls.getItem(this._ttlKey(key)));
284 | return _.isNumber(ttl) && now() > ttl ? true : false;
285 | }
286 | };
287 | } else {
288 | methods = {
289 | get: _.noop,
290 | set: _.noop,
291 | remove: _.noop,
292 | clear: _.noop,
293 | isExpired: _.noop
294 | };
295 | }
296 | _.mixin(PersistentStorage.prototype, methods);
297 | return PersistentStorage;
298 | function now() {
299 | return new Date().getTime();
300 | }
301 | function encode(val) {
302 | return JSON.stringify(_.isUndefined(val) ? null : val);
303 | }
304 | function decode(val) {
305 | return JSON.parse(val);
306 | }
307 | }();
308 | var Transport = function() {
309 | "use strict";
310 | var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10);
311 | function Transport(o) {
312 | o = o || {};
313 | this.cancelled = false;
314 | this.lastUrl = null;
315 | this._send = o.transport ? callbackToDeferred(o.transport) : $.ajax;
316 | this._get = o.rateLimiter ? o.rateLimiter(this._get) : this._get;
317 | this._cache = o.cache === false ? new LruCache(0) : sharedCache;
318 | }
319 | Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
320 | maxPendingRequests = num;
321 | };
322 | Transport.resetCache = function resetCache() {
323 | sharedCache.reset();
324 | };
325 | _.mixin(Transport.prototype, {
326 | _get: function(url, o, cb) {
327 | var that = this, jqXhr;
328 | if (this.cancelled || url !== this.lastUrl) {
329 | return;
330 | }
331 | if (jqXhr = pendingRequests[url]) {
332 | jqXhr.done(done).fail(fail);
333 | } else if (pendingRequestsCount < maxPendingRequests) {
334 | pendingRequestsCount++;
335 | pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always);
336 | } else {
337 | this.onDeckRequestArgs = [].slice.call(arguments, 0);
338 | }
339 | function done(resp) {
340 | cb && cb(null, resp);
341 | that._cache.set(url, resp);
342 | }
343 | function fail() {
344 | cb && cb(true);
345 | }
346 | function always() {
347 | pendingRequestsCount--;
348 | delete pendingRequests[url];
349 | if (that.onDeckRequestArgs) {
350 | that._get.apply(that, that.onDeckRequestArgs);
351 | that.onDeckRequestArgs = null;
352 | }
353 | }
354 | },
355 | get: function(url, o, cb) {
356 | var resp;
357 | if (_.isFunction(o)) {
358 | cb = o;
359 | o = {};
360 | }
361 | this.cancelled = false;
362 | this.lastUrl = url;
363 | if (resp = this._cache.get(url)) {
364 | _.defer(function() {
365 | cb && cb(null, resp);
366 | });
367 | } else {
368 | this._get(url, o, cb);
369 | }
370 | return !!resp;
371 | },
372 | cancel: function() {
373 | this.cancelled = true;
374 | }
375 | });
376 | return Transport;
377 | function callbackToDeferred(fn) {
378 | return function customSendWrapper(url, o) {
379 | var deferred = $.Deferred();
380 | fn(url, o, onSuccess, onError);
381 | return deferred;
382 | function onSuccess(resp) {
383 | _.defer(function() {
384 | deferred.resolve(resp);
385 | });
386 | }
387 | function onError(err) {
388 | _.defer(function() {
389 | deferred.reject(err);
390 | });
391 | }
392 | };
393 | }
394 | }();
395 | var SearchIndex = function() {
396 | "use strict";
397 | function SearchIndex(o) {
398 | o = o || {};
399 | if (!o.datumTokenizer || !o.queryTokenizer) {
400 | $.error("datumTokenizer and queryTokenizer are both required");
401 | }
402 | this.datumTokenizer = o.datumTokenizer;
403 | this.queryTokenizer = o.queryTokenizer;
404 | this.reset();
405 | }
406 | _.mixin(SearchIndex.prototype, {
407 | bootstrap: function bootstrap(o) {
408 | this.datums = o.datums;
409 | this.trie = o.trie;
410 | },
411 | add: function(data) {
412 | var that = this;
413 | data = _.isArray(data) ? data : [ data ];
414 | _.each(data, function(datum) {
415 | var id, tokens;
416 | id = that.datums.push(datum) - 1;
417 | tokens = normalizeTokens(that.datumTokenizer(datum));
418 | _.each(tokens, function(token) {
419 | var node, chars, ch;
420 | node = that.trie;
421 | chars = token.split("");
422 | while (ch = chars.shift()) {
423 | node = node.children[ch] || (node.children[ch] = newNode());
424 | node.ids.push(id);
425 | }
426 | });
427 | });
428 | },
429 | get: function get(query) {
430 | var that = this, tokens, matches;
431 | tokens = normalizeTokens(this.queryTokenizer(query));
432 | _.each(tokens, function(token) {
433 | var node, chars, ch, ids;
434 | if (matches && matches.length === 0) {
435 | return false;
436 | }
437 | node = that.trie;
438 | chars = token.split("");
439 | while (node && (ch = chars.shift())) {
440 | node = node.children[ch];
441 | }
442 | if (node && chars.length === 0) {
443 | ids = node.ids.slice(0);
444 | matches = matches ? getIntersection(matches, ids) : ids;
445 | } else {
446 | matches = [];
447 | return false;
448 | }
449 | });
450 | return matches ? _.map(unique(matches), function(id) {
451 | return that.datums[id];
452 | }) : [];
453 | },
454 | reset: function reset() {
455 | this.datums = [];
456 | this.trie = newNode();
457 | },
458 | serialize: function serialize() {
459 | return {
460 | datums: this.datums,
461 | trie: this.trie
462 | };
463 | }
464 | });
465 | return SearchIndex;
466 | function normalizeTokens(tokens) {
467 | tokens = _.filter(tokens, function(token) {
468 | return !!token;
469 | });
470 | tokens = _.map(tokens, function(token) {
471 | return token.toLowerCase();
472 | });
473 | return tokens;
474 | }
475 | function newNode() {
476 | return {
477 | ids: [],
478 | children: {}
479 | };
480 | }
481 | function unique(array) {
482 | var seen = {}, uniques = [];
483 | for (var i = 0, len = array.length; i < len; i++) {
484 | if (!seen[array[i]]) {
485 | seen[array[i]] = true;
486 | uniques.push(array[i]);
487 | }
488 | }
489 | return uniques;
490 | }
491 | function getIntersection(arrayA, arrayB) {
492 | var ai = 0, bi = 0, intersection = [];
493 | arrayA = arrayA.sort(compare);
494 | arrayB = arrayB.sort(compare);
495 | var lenArrayA = arrayA.length, lenArrayB = arrayB.length;
496 | while (ai < lenArrayA && bi < lenArrayB) {
497 | if (arrayA[ai] < arrayB[bi]) {
498 | ai++;
499 | } else if (arrayA[ai] > arrayB[bi]) {
500 | bi++;
501 | } else {
502 | intersection.push(arrayA[ai]);
503 | ai++;
504 | bi++;
505 | }
506 | }
507 | return intersection;
508 | function compare(a, b) {
509 | return a - b;
510 | }
511 | }
512 | }();
513 | var oParser = function() {
514 | "use strict";
515 | return {
516 | local: getLocal,
517 | prefetch: getPrefetch,
518 | remote: getRemote
519 | };
520 | function getLocal(o) {
521 | return o.local || null;
522 | }
523 | function getPrefetch(o) {
524 | var prefetch, defaults;
525 | defaults = {
526 | url: null,
527 | thumbprint: "",
528 | ttl: 24 * 60 * 60 * 1e3,
529 | filter: null,
530 | ajax: {}
531 | };
532 | if (prefetch = o.prefetch || null) {
533 | prefetch = _.isString(prefetch) ? {
534 | url: prefetch
535 | } : prefetch;
536 | prefetch = _.mixin(defaults, prefetch);
537 | prefetch.thumbprint = VERSION + prefetch.thumbprint;
538 | prefetch.ajax.type = prefetch.ajax.type || "GET";
539 | prefetch.ajax.dataType = prefetch.ajax.dataType || "json";
540 | !prefetch.url && $.error("prefetch requires url to be set");
541 | }
542 | return prefetch;
543 | }
544 | function getRemote(o) {
545 | var remote, defaults;
546 | defaults = {
547 | url: null,
548 | cache: true,
549 | wildcard: "%QUERY",
550 | replace: null,
551 | rateLimitBy: "debounce",
552 | rateLimitWait: 300,
553 | send: null,
554 | filter: null,
555 | ajax: {}
556 | };
557 | if (remote = o.remote || null) {
558 | remote = _.isString(remote) ? {
559 | url: remote
560 | } : remote;
561 | remote = _.mixin(defaults, remote);
562 | remote.rateLimiter = /^throttle$/i.test(remote.rateLimitBy) ? byThrottle(remote.rateLimitWait) : byDebounce(remote.rateLimitWait);
563 | remote.ajax.type = remote.ajax.type || "GET";
564 | remote.ajax.dataType = remote.ajax.dataType || "json";
565 | delete remote.rateLimitBy;
566 | delete remote.rateLimitWait;
567 | !remote.url && $.error("remote requires url to be set");
568 | }
569 | return remote;
570 | function byDebounce(wait) {
571 | return function(fn) {
572 | return _.debounce(fn, wait);
573 | };
574 | }
575 | function byThrottle(wait) {
576 | return function(fn) {
577 | return _.throttle(fn, wait);
578 | };
579 | }
580 | }
581 | }();
582 | (function(root) {
583 | "use strict";
584 | var old, keys;
585 | old = root.Bloodhound;
586 | keys = {
587 | data: "data",
588 | protocol: "protocol",
589 | thumbprint: "thumbprint"
590 | };
591 | root.Bloodhound = Bloodhound;
592 | function Bloodhound(o) {
593 | if (!o || !o.local && !o.prefetch && !o.remote) {
594 | $.error("one of local, prefetch, or remote is required");
595 | }
596 | this.limit = o.limit || 5;
597 | this.sorter = getSorter(o.sorter);
598 | this.dupDetector = o.dupDetector || ignoreDuplicates;
599 | this.local = oParser.local(o);
600 | this.prefetch = oParser.prefetch(o);
601 | this.remote = oParser.remote(o);
602 | this.cacheKey = this.prefetch ? this.prefetch.cacheKey || this.prefetch.url : null;
603 | this.index = new SearchIndex({
604 | datumTokenizer: o.datumTokenizer,
605 | queryTokenizer: o.queryTokenizer
606 | });
607 | this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null;
608 | }
609 | Bloodhound.noConflict = function noConflict() {
610 | root.Bloodhound = old;
611 | return Bloodhound;
612 | };
613 | Bloodhound.tokenizers = tokenizers;
614 | _.mixin(Bloodhound.prototype, {
615 | _loadPrefetch: function loadPrefetch(o) {
616 | var that = this, serialized, deferred;
617 | if (serialized = this._readFromStorage(o.thumbprint)) {
618 | this.index.bootstrap(serialized);
619 | deferred = $.Deferred().resolve();
620 | } else {
621 | deferred = $.ajax(o.url, o.ajax).done(handlePrefetchResponse);
622 | }
623 | return deferred;
624 | function handlePrefetchResponse(resp) {
625 | that.clear();
626 | that.add(o.filter ? o.filter(resp) : resp);
627 | that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);
628 | }
629 | },
630 | _getFromRemote: function getFromRemote(query, cb) {
631 | var that = this, url, uriEncodedQuery;
632 | if (!this.transport) {
633 | return;
634 | }
635 | query = query || "";
636 | uriEncodedQuery = encodeURIComponent(query);
637 | url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);
638 | return this.transport.get(url, this.remote.ajax, handleRemoteResponse);
639 | function handleRemoteResponse(err, resp) {
640 | err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp);
641 | }
642 | },
643 | _cancelLastRemoteRequest: function cancelLastRemoteRequest() {
644 | this.transport && this.transport.cancel();
645 | },
646 | _saveToStorage: function saveToStorage(data, thumbprint, ttl) {
647 | if (this.storage) {
648 | this.storage.set(keys.data, data, ttl);
649 | this.storage.set(keys.protocol, location.protocol, ttl);
650 | this.storage.set(keys.thumbprint, thumbprint, ttl);
651 | }
652 | },
653 | _readFromStorage: function readFromStorage(thumbprint) {
654 | var stored = {}, isExpired;
655 | if (this.storage) {
656 | stored.data = this.storage.get(keys.data);
657 | stored.protocol = this.storage.get(keys.protocol);
658 | stored.thumbprint = this.storage.get(keys.thumbprint);
659 | }
660 | isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;
661 | return stored.data && !isExpired ? stored.data : null;
662 | },
663 | _initialize: function initialize() {
664 | var that = this, local = this.local, deferred;
665 | deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve();
666 | local && deferred.done(addLocalToIndex);
667 | this.transport = this.remote ? new Transport(this.remote) : null;
668 | return this.initPromise = deferred.promise();
669 | function addLocalToIndex() {
670 | that.add(_.isFunction(local) ? local() : local);
671 | }
672 | },
673 | initialize: function initialize(force) {
674 | return !this.initPromise || force ? this._initialize() : this.initPromise;
675 | },
676 | add: function add(data) {
677 | this.index.add(data);
678 | },
679 | get: function get(query, cb) {
680 | var that = this, matches = [], cacheHit = false;
681 | matches = this.index.get(query);
682 | matches = this.sorter(matches).slice(0, this.limit);
683 | matches.length < this.limit ? cacheHit = this._getFromRemote(query, returnRemoteMatches) : this._cancelLastRemoteRequest();
684 | if (!cacheHit) {
685 | (matches.length > 0 || !this.transport) && cb && cb(matches);
686 | }
687 | function returnRemoteMatches(remoteMatches) {
688 | var matchesWithBackfill = matches.slice(0);
689 | _.each(remoteMatches, function(remoteMatch) {
690 | var isDuplicate;
691 | isDuplicate = _.some(matchesWithBackfill, function(match) {
692 | return that.dupDetector(remoteMatch, match);
693 | });
694 | !isDuplicate && matchesWithBackfill.push(remoteMatch);
695 | return matchesWithBackfill.length < that.limit;
696 | });
697 | cb && cb(that.sorter(matchesWithBackfill));
698 | }
699 | },
700 | clear: function clear() {
701 | this.index.reset();
702 | },
703 | clearPrefetchCache: function clearPrefetchCache() {
704 | this.storage && this.storage.clear();
705 | },
706 | clearRemoteCache: function clearRemoteCache() {
707 | this.transport && Transport.resetCache();
708 | },
709 | ttAdapter: function ttAdapter() {
710 | return _.bind(this.get, this);
711 | }
712 | });
713 | return Bloodhound;
714 | function getSorter(sortFn) {
715 | return _.isFunction(sortFn) ? sort : noSort;
716 | function sort(array) {
717 | return array.sort(sortFn);
718 | }
719 | function noSort(array) {
720 | return array;
721 | }
722 | }
723 | function ignoreDuplicates() {
724 | return false;
725 | }
726 | })(this);
727 | })(window.jQuery);
728 |
--------------------------------------------------------------------------------
/cite2c/__init__.py:
--------------------------------------------------------------------------------
1 | """Citations for Jupyter Notebooks
2 | """
3 |
4 | __version__ = '0.2.1'
5 |
--------------------------------------------------------------------------------
/cite2c/handlers.py:
--------------------------------------------------------------------------------
1 | import glob
2 | import json
3 | import os
4 | from notebook.utils import url_path_join as ujoin
5 | from tornado.web import StaticFileHandler, RequestHandler
6 |
7 | from . import zotero_oauth
8 |
9 | def find_zotero_styles_dir():
10 | pattern = os.path.expanduser('~/.zotero/zotero/*/zotero/styles/')
11 | candidates = glob.glob(pattern)
12 | if not candidates:
13 | return None
14 | for c in candidates:
15 | if '.default' in c:
16 | return c
17 | return candidates[0]
18 |
19 | class ListStylesHandler(RequestHandler):
20 | def initialize(self, path):
21 | self.path = path
22 |
23 | def get(self):
24 | files = [f for f in os.listdir(self.path) if f.endswith('.csl')]
25 | self.finish(json.dumps(files))
26 |
27 | def load_jupyter_server_extension(nbapp):
28 | webapp = nbapp.web_app
29 | base_url = webapp.settings['base_url']
30 |
31 | zsd = find_zotero_styles_dir()
32 | if zsd:
33 | webapp.add_handlers(".*$", [
34 | (ujoin(base_url, r"/cite2c/styles/?"), ListStylesHandler,
35 | {'path': zsd}),
36 | (ujoin(base_url, r"/cite2c/styles/(.+)"), StaticFileHandler,
37 | {'path': zsd}),
38 | ])
39 | else:
40 | nbapp.log.warning('Could not find Zotero citation styles directory.')
41 |
42 | webapp.add_handlers(".*$", zotero_oauth.handlers(base_url))
43 |
--------------------------------------------------------------------------------
/cite2c/install.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from os.path import dirname, abspath, join as pjoin
3 | from notebook.nbextensions import install_nbextension, enable_nbextension
4 | from notebook.serverextensions import toggle_serverextension_python
5 |
6 | def install_nbext():
7 | print("Installing nbextension ...")
8 | c2cdir = pjoin(dirname(abspath(__file__)), 'nbext')
9 | install_nbextension(c2cdir, user=True, destination='cite2c')
10 |
11 | def enable_nbext():
12 | print("Enabling the nbextension ...")
13 | enable_nbextension('notebook', 'cite2c/main', user=True)
14 |
15 | def enable_server_ext():
16 | print("Enabling the server extension ...")
17 | toggle_serverextension_python('cite2c.handlers', enabled=True, user=True)
18 |
19 | def main():
20 | install_nbext()
21 | enable_nbext()
22 | enable_server_ext()
23 | print("Done.")
24 |
25 | if __name__ == '__main__':
26 | main()
27 |
--------------------------------------------------------------------------------
/cite2c/nbext/chicago-author-date.csl:
--------------------------------------------------------------------------------
1 |
2 |
558 |
--------------------------------------------------------------------------------
/cite2c/nbext/chicago-fullnote-bibliography.csl:
--------------------------------------------------------------------------------
1 |
2 |
1062 |
--------------------------------------------------------------------------------
/cite2c/nbext/main.js:
--------------------------------------------------------------------------------
1 | requirejs.config({
2 | shim: {
3 | 'nbextensions/cite2c/xmldom': {
4 | deps: [],
5 | exports: "CSL_CHROME"
6 | },
7 | 'nbextensions/cite2c/citeproc': {
8 | deps: ['nbextensions/cite2c/xmldom'],
9 | exports: "CSL"
10 | },
11 | 'nbextensions/cite2c/typeahead.bundle.min': {
12 | deps: ['jquery'],
13 | exports: "Bloodhound" // Doesn't actually work, because of the shenanigans typeahead does
14 | }
15 | }
16 | });
17 |
18 | define(['jquery',
19 | 'base/js/dialog',
20 | 'base/js/utils',
21 | 'services/config',
22 | 'nbextensions/cite2c/rendering',
23 | 'nbextensions/cite2c/typeahead.bundle.min',
24 | ],
25 | function($, dialog, utils, configmod, rendering) {
26 | "use strict";
27 |
28 | // There are two different jQuery typeahead plugins. This code uses one,
29 | // and the command palette uses the other. They both add the .typeahead()
30 | // method to jQuery objects. .noConflict() replaces the twitter .typeahead()
31 | // method we loaded with the jquery-typeahead one the command palette needs.
32 | // Then we reattach ours as .twitter_typeahead() so we can use it below.
33 | // Namespaces, anyone?
34 | $.fn.twitter_typeahead = $.fn.typeahead.noConflict();
35 |
36 | var make_author_string = function(authors) {
37 | // Make a simple string of the author surnames, to show in the
38 | // typeahead dropdown
39 | var surname = function(auth) { return auth.family || "?"; };
40 | if (!authors) return "";
41 | switch (authors.length) {
42 | case 0:
43 | return "";
44 | case 1:
45 | return surname(authors[0]);
46 | case 2:
47 | return surname(authors[0]) + " & " + surname(authors[1]);
48 | default:
49 | return surname(authors[0]) + " et al.";
50 | }
51 | };
52 |
53 |
54 | var csl_tokenize = function(item) {
55 | // Turn a CSL JSON object into an array of word tokens for Bloodhound
56 | var tokens = [];
57 | function add_splitted(value) {
58 | if (value) tokens = tokens.concat(value.toString().split(/\s+/));
59 | }
60 |
61 | add_splitted(item.title);
62 |
63 | if (item.author) {
64 | for (var i=0; i < item.author.length; i++) {
65 | add_splitted(item.author[i].family);
66 | add_splitted(item.author[i].literal);
67 | }
68 | }
69 |
70 | if (item.issued) {
71 | if (item.issued['date-parts'])
72 | add_splitted(item.issued['date-parts'][0]);
73 | add_splitted(item.issued.year);
74 | }
75 | return tokens;
76 | };
77 |
78 | var get_metadata_items = function() {
79 | // Get an array of citations from the metadata.
80 | var items = (IPython.notebook.metadata.cite2c || {}).citations || {};
81 | return $.map(items, function(obj, id) {return obj;}); // Flatten to array
82 | };
83 |
84 | var config = new configmod.ConfigSection('cite2c',
85 | {base_url: utils.get_body_data("baseUrl")});
86 | config.load();
87 |
88 | function get_zotero_access() {
89 | // Get the Zotero user ID, either from config, or by prompting the user
90 | // with a dialog. Returns a promise which resolves to the user ID.
91 | return config.loaded.then(function() {
92 | var zotero = (config.data.zotero || {});
93 | if (zotero.user_id && zotero.access_token) {
94 | return zotero;
95 | }
96 |
97 | var dialog_body = $("").append(
98 | "Opened a new tab to authenticate with Zotero. " +
99 | "Once you have done this, please click OK.
");
100 |
101 | // Open a new tab for the user to authorize cite2c on Zotero.
102 | window.open(utils.url_path_join(utils.get_body_data("baseUrl"),
103 | 'cite2c/zotero_oauth'));
104 |
105 | return new Promise(function(resolve, reject) {
106 | var clicked_ok = false;
107 | dialog.modal({
108 | notebook: IPython.notebook,
109 | keyboard_manager: IPython.keyboard_manager,
110 | title : "Zotero User ID",
111 | body : dialog_body,
112 | open: function() {
113 | var that = $(this);
114 | that.find('form').submit(function () {
115 | that.find('.btn-primary').first().click();
116 | return false;
117 | });
118 | },
119 | buttons : {
120 | "Cancel" : {
121 | click : function() { reject("Dialog cancelled"); }
122 | },
123 | "OK" : {
124 | class : "btn-primary",
125 | click: function() { clicked_ok = true; }
126 | }
127 | }
128 | }).on("hidden.bs.modal", function () {
129 | // Sigh. Because this ends up showing another dialog, if we
130 | // do it in the click handler, there's a race condition with
131 | // enabling/disabling the notebook keyboard shortcuts, which
132 | // leads to the shortcuts being active while the second
133 | // dialog is open. Waiting for this hidden event and doing
134 | // setTimeout should be enough to avoid the race.
135 | if (clicked_ok) {
136 | setTimeout(function () {
137 | config.load().then(function (data) {
138 | resolve(data.zotero);
139 | console.log("Authenticated Zotero user ID " + data.zotero.user_id);
140 | });
141 | }, 0);
142 | }
143 | });
144 | });
145 | });
146 | }
147 |
148 | var zot_bh_engine;
149 |
150 | function get_zot_bh_engine() {
151 | // Retrieve the existing Bloodhound engine for Zotero, or initialise a
152 | // new one. Returns a promise which resolves to the Bloodhound instance.
153 | // May prompt the user for their Zotero ID.
154 | if (zot_bh_engine) {
155 | // Engine already exists; resolve promise once it's initialised.
156 | return new Promise(function(resolve, reject) {
157 | zot_bh_engine.initialize()
158 | .done(function() { resolve(zot_bh_engine); })
159 | .fail(reject);
160 | });
161 | }
162 |
163 | return get_zotero_access().then(function(zotero_info) {
164 | zot_bh_engine = new Bloodhound({
165 | name: 'zotero',
166 | datumTokenizer: csl_tokenize,
167 | queryTokenizer: Bloodhound.tokenizers.whitespace,
168 | limit: 10,
169 | dupDetector: function(remoteMatch, localMatch) { return remoteMatch.id === localMatch.id; },
170 | local: get_metadata_items,
171 | remote: {
172 | url: "https://api.zotero.org/users/"+zotero_info.user_id+"/items?v=3&limit=10&format=csljson&q=%QUERY",
173 | filter: function(result) { return result.items; },
174 | ajax: {
175 | accepts: "application/vnd.citationstyles.csl+json",
176 | dataType: "json",
177 | headers: {
178 | "Zotero-API-Key": zotero_info.access_token
179 | }
180 | }
181 | }
182 | });
183 | return new Promise(function(resolve, reject) {
184 | zot_bh_engine.initialize()
185 | .done(function() { resolve(zot_bh_engine); })
186 | .fail(reject);
187 | });
188 | });
189 | }
190 |
191 | var store_citation = function(id, citation) {
192 | // Store citation data to notebook metadata & BH search index
193 | var metadata = IPython.notebook.metadata;
194 | if (!metadata.cite2c) metadata.cite2c = {};
195 | if (!metadata.cite2c.citations) metadata.cite2c.citations = {};
196 | if (!(id in metadata.cite2c.citations)) {
197 | metadata.cite2c.citations[id] = citation;
198 | zot_bh_engine.add(citation);
199 | }
200 | };
201 |
202 | function insert_citn() {
203 | // Show the user a dialog to choose and insert a citation
204 | var cell = IPython.notebook.get_selected_cell();
205 |
206 | var entry_box = $('');
207 | var dialog_body = $("")
208 | .append($("").text("Start typing below to search Zotero"))
209 | .append($('').append(entry_box));
210 | dialog_body.addClass("cite2c-dialog");
211 |
212 | get_zot_bh_engine().then(function(zot_bh_engine) {
213 | // Set up typeahead.js to search Zotero
214 | entry_box.twitter_typeahead({
215 | minLength: 3,
216 | hint: false,
217 | highlight: true,
218 | },
219 | {
220 | name: 'zotero',
221 | source: zot_bh_engine.ttAdapter(),
222 | displayKey: function(value) { return value.title || "Mystery item with no title"; },
223 | templates: {
224 | empty: "No matches",
225 | suggestion: function(value) {
226 | //console.log(value);
227 | return ""+value.title+"
" +
228 | '' + (value.type || "?") + "
" +
229 | ""+ make_author_string(value.author) + "
";
230 | }
231 | }
232 | });
233 |
234 | entry_box.on('typeahead:selected', function(ev, suggestion, dataset) {
235 | entry_box.data("csljson", suggestion);
236 | });
237 |
238 | // Display dialog
239 | dialog.modal({
240 | notebook: IPython.notebook,
241 | keyboard_manager: IPython.keyboard_manager,
242 | title : "Insert citation",
243 | body : dialog_body,
244 | open: function() {
245 | // Submit on pressing enter
246 | var that = $(this);
247 | that.find('form').submit(function () {
248 | that.find('.btn-primary').first().click();
249 | return false;
250 | });
251 | entry_box.focus();
252 | },
253 | buttons : {
254 | "Cancel" : {},
255 | "Insert" : {
256 | "class" : "btn-primary",
257 | "click" : function() {
258 | // Retrieve the selected citation, add to metadata,
259 | // and insert an HTML tag for it.
260 | var citation = entry_box.data("csljson");
261 | if (!citation) {return;}
262 | var id = citation.id;
263 | delete citation.id;
264 | store_citation(id, citation);
265 | var citn_html = '';
266 | cell.code_mirror.replaceSelection(citn_html);
267 | }
268 | }
269 | }
270 | });
271 | });
272 | }
273 |
274 | var insert_biblio = function() {
275 | // Insert HTML tag for bibliography
276 | var cell = IPython.notebook.get_selected_cell();
277 | cell.code_mirror.replaceSelection('');
278 | };
279 |
280 | var toolbar_buttons = function () {
281 | // Add toolbar buttons to insert citations and bibliographies
282 | if (!Jupyter.toolbar) {
283 | $([Jupyter.events]).on("app_initialized.NotebookApp", toolbar_buttons);
284 | return;
285 | }
286 |
287 | Jupyter.actions.register({
288 | icon: 'fa-mortar-board',
289 | help: 'Insert a citation',
290 | help_index: 'za',
291 | handler: insert_citn
292 | }, 'insert-citation', 'cite2c');
293 | Jupyter.actions.register({
294 | icon: 'fa-list',
295 | help: 'Insert bibliography',
296 | help_index: 'zb',
297 | handler: insert_biblio,
298 | }, 'insert-biblio', 'cite2c');
299 |
300 | Jupyter.toolbar.add_buttons_group([
301 | {
302 | 'label' : 'Cite',
303 | 'action' : 'cite2c:insert-citation'
304 | },
305 | 'cite2c:insert-biblio'
306 | ], 'cite2c-buttons');
307 | };
308 |
309 | function load_ipython_extension() {
310 | toolbar_buttons();
311 | rendering.init_rendering();
312 | $('head').append(
313 | $('')
314 | .attr('rel','stylesheet')
315 | .attr('type','text/css')
316 | .attr('href', utils.url_path_join(utils.get_body_data("baseUrl"),
317 | 'nbextensions/cite2c/styles.css'))
318 | );
319 | }
320 |
321 | return {load_ipython_extension: load_ipython_extension};
322 | });
323 |
--------------------------------------------------------------------------------
/cite2c/nbext/rendering.js:
--------------------------------------------------------------------------------
1 | define(['jquery',
2 | 'base/js/utils',
3 | 'nbextensions/cite2c/citeproc',
4 | ],
5 | function($, utils, CSL) {
6 | "use strict";
7 |
8 | /*
9 | * Part 1: Find and render citations using citeproc-js
10 | */
11 |
12 | var cpSys = {
13 | retrieveLocale: function(lang) {
14 | // Any locale you want, so long as it's en-US
15 | return " No. Doc. U.N. Sales No. No. \u201c \u201d \u2018 \u2019 st nd rd th first second third fourth fifth sixth seventh eighth ninth tenth at in ibid accessed retrieved from forthcoming reference references ref refs n.d. and et al. interview letter anonymous anon. and others in press online cited internet presented at the AD BC Spring Summer Autumn Winter with anthropology astronomy biology botany chemistry engineering generic base geography geology history humanities literature math medicine philosophy physics psychology sociology science political science social science theology zoology book books chapter chapters column columns figure figures folio folios number numbers line lines note notes opus opera page pages paragraph paragraph part parts section sections volume volumes edition editions verse verses sub verbo s.vv bk. chap. col. fig. f. no. op. p. pp. para. pt. sec. s.v. s.vv. v. vv. vol. vols. edition ed. ¶ ¶¶ § §§ editor editors translator translators ed. eds. tran. trans. edited by translated by to interview by ed. trans. January February March April May June July August September October November December Jan. Feb. Mar. Apr. May Jun. Jul. Aug. Sep. Oct. Nov. Dec. ";
16 | },
17 | retrieveItem: function(id) {
18 | var item = IPython.notebook.metadata.cite2c.citations[id];
19 | item.id = id; // Not documented, but citeproc breaks without this
20 | return item;
21 | }
22 | };
23 |
24 | var make_citeproc_pairs = function(citns) {
25 | return citns.map(function(citn) {
26 | return [citn.id, 0];
27 | });
28 | };
29 |
30 | var citeproc;
31 |
32 | function render_biblio() {
33 | var biblio_targets = $('.cite2c-biblio');
34 | if (biblio_targets.length === 0) {
35 | return;
36 | }
37 | var bibdata = citeproc.makeBibliography();
38 | var bibmetadata = bibdata[0];
39 | var bibhtml = bibmetadata.bibstart + bibdata[1].join('') + bibmetadata.bibend;
40 | biblio_targets.html(bibhtml);
41 | }
42 |
43 | function process_cell_citations(cell) {
44 | var i=0;
45 |
46 | // Gather citations before and after the current cell
47 | var all_cells = IPython.notebook.get_cells();
48 | var after_current = false;
49 | var citns_before = [];
50 | var citns_after = [];
51 | for (i=0; i < all_cells.length; i++) {
52 | if (all_cells[i] === cell) {
53 | after_current = true;
54 | continue;
55 | }
56 | if (after_current) {
57 | citns_after = citns_after.concat(all_cells[i]._cite2c_citns || []);
58 | } else {
59 | citns_before = citns_before.concat(all_cells[i]._cite2c_citns || []);
60 | }
61 | }
62 |
63 | var element = cell.element.find('div.text_cell_render');
64 | var citn_elements = element.find("[data-cite]");
65 | cell._cite2c_citns = [];
66 | var newbiblios = element.find(".cite2c-biblio");
67 |
68 | var bibchange = (newbiblios.length > 0);
69 | for (i=0; i < citn_elements.length; i++) {
70 | var citn_element = citn_elements[i];
71 | var id = citn_element.dataset.cite;
72 |
73 | var citeproc_citn = {citationItems: [{id: id}],
74 | properties: {noteIndex: 0}
75 | };
76 | var results = citeproc.processCitationCluster(citeproc_citn,
77 | make_citeproc_pairs(citns_before),
78 | make_citeproc_pairs(citns_after));
79 | var citn = {id: citeproc_citn.citationID, element: citn_element};
80 | cell._cite2c_citns.push(citn);
81 |
82 | bibchange = bibchange || results[0].bibchange;
83 | var updates = results[1];
84 | var all_citns = citns_before.concat([citn], citns_after);
85 |
86 | for (var j=0; j < updates.length; j++) {
87 | var idx = updates[j][0];
88 | var newcontent = updates[j][1];
89 | all_citns[idx].element.innerHTML = newcontent;
90 | }
91 | citns_before.push(citn);
92 | }
93 |
94 | // This is false when I would expect it to be true. For now,
95 | // just re-render the bibliography every time.
96 | //if (bibchange) {
97 | render_biblio();
98 | //}
99 | } // end process_cell_citations
100 |
101 | function md_cell_rendered(event, data) {
102 | // Event handler to process citations
103 | process_cell_citations(data.cell);
104 | }
105 |
106 | function reprocess_all() {
107 | // Process citations in all cells; used on load to render citations.
108 | var all_cells = IPython.notebook.get_cells();
109 | var i = 0;
110 | for (i = 0; i < all_cells.length; i++) {
111 | delete all_cells[i]._cite2c_citns;
112 | }
113 | for (i = 0; i < all_cells.length; i++) {
114 | var cell = all_cells[i];
115 | if (cell.cell_type === "markdown") {
116 | process_cell_citations(cell);
117 | }
118 | }
119 | }
120 |
121 | function init_rendering() {
122 | // Create a CSL engine, hook it up to the MarkdownCell rendered event,
123 | // and process all citations already in the document.
124 | $.ajax(utils.url_path_join(utils.get_body_data("baseUrl"),
125 | 'nbextensions/cite2c/chicago-author-date.csl'), {
126 | dataType: "text",
127 | success: function(styleAsText, textStatus, jqXHR) {
128 | citeproc = new CSL.Engine(cpSys, styleAsText);
129 |
130 | IPython.notebook.events.off("rendered.MarkdownCell", null, md_cell_rendered);
131 | IPython.notebook.events.on("rendered.MarkdownCell", md_cell_rendered);
132 |
133 | // Process all citations on load
134 | reprocess_all();
135 | }
136 | });
137 | }
138 |
139 | return {init_rendering: init_rendering};
140 | });
141 |
--------------------------------------------------------------------------------
/cite2c/nbext/styles.css:
--------------------------------------------------------------------------------
1 |
2 | .cite2c-dialog .twitter-typeahead {
3 | width: 90%;
4 | margin: 8px;
5 | }
6 |
7 | .cite2c-dialog .tt-input {
8 | width: 100%;
9 | }
10 |
11 | .cite2c-dialog .tt-dropdown-menu {
12 | background-color: #fff;
13 | border: 1px solid #ccc;
14 | border-radius: 4px;
15 | }
16 |
17 | .cite2c-dialog .tt-suggestion {
18 | padding: 4px;
19 | }
20 |
21 | .cite2c-dialog .tt-suggestion.tt-cursor {
22 | background-color: #eee;
23 | }
24 |
25 | .csl-entry {
26 | padding: 0.4em 0;
27 | }
28 |
--------------------------------------------------------------------------------
/cite2c/nbext/typeahead.bundle.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * typeahead.js 0.10.5
3 | * https://github.com/twitter/typeahead.js
4 | * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
5 | */
6 |
7 | !function(a){var b=function(){"use strict";return{isMsie:function(){return/(msie|trident)/i.test(navigator.userAgent)?navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2]:!1},isBlankString:function(a){return!a||/^\s*$/.test(a)},escapeRegExChars:function(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},isString:function(a){return"string"==typeof a},isNumber:function(a){return"number"==typeof a},isArray:a.isArray,isFunction:a.isFunction,isObject:a.isPlainObject,isUndefined:function(a){return"undefined"==typeof a},toStr:function(a){return b.isUndefined(a)||null===a?"":a+""},bind:a.proxy,each:function(b,c){function d(a,b){return c(b,a)}a.each(b,d)},map:a.map,filter:a.grep,every:function(b,c){var d=!0;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?void 0:!1}),!!d):d},some:function(b,c){var d=!1;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?!1:void 0}),!!d):d},mixin:a.extend,getUniqueId:function(){var a=0;return function(){return a++}}(),templatify:function(b){function c(){return String(b)}return a.isFunction(b)?b:c},defer:function(a){setTimeout(a,0)},debounce:function(a,b,c){var d,e;return function(){var f,g,h=this,i=arguments;return f=function(){d=null,c||(e=a.apply(h,i))},g=c&&!d,clearTimeout(d),d=setTimeout(f,b),g&&(e=a.apply(h,i)),e}},throttle:function(a,b){var c,d,e,f,g,h;return g=0,h=function(){g=new Date,e=null,f=a.apply(c,d)},function(){var i=new Date,j=b-(i-g);return c=this,d=arguments,0>=j?(clearTimeout(e),e=null,g=i,f=a.apply(c,d)):e||(e=setTimeout(h,j)),f}},noop:function(){}}}(),c="0.10.5",d=function(){"use strict";function a(a){return a=b.toStr(a),a?a.split(/\s+/):[]}function c(a){return a=b.toStr(a),a?a.split(/\W+/):[]}function d(a){return function(){var c=[].slice.call(arguments,0);return function(d){var e=[];return b.each(c,function(c){e=e.concat(a(b.toStr(d[c])))}),e}}}return{nonword:c,whitespace:a,obj:{nonword:d(c),whitespace:d(a)}}}(),e=function(){"use strict";function c(c){this.maxSize=b.isNumber(c)?c:100,this.reset(),this.maxSize<=0&&(this.set=this.get=a.noop)}function d(){this.head=this.tail=null}function e(a,b){this.key=a,this.val=b,this.prev=this.next=null}return b.mixin(c.prototype,{set:function(a,b){var c,d=this.list.tail;this.size>=this.maxSize&&(this.list.remove(d),delete this.hash[d.key]),(c=this.hash[a])?(c.val=b,this.list.moveToFront(c)):(c=new e(a,b),this.list.add(c),this.hash[a]=c,this.size++)},get:function(a){var b=this.hash[a];return b?(this.list.moveToFront(b),b.val):void 0},reset:function(){this.size=0,this.hash={},this.list=new d}}),b.mixin(d.prototype,{add:function(a){this.head&&(a.next=this.head,this.head.prev=a),this.head=a,this.tail=this.tail||a},remove:function(a){a.prev?a.prev.next=a.next:this.head=a.next,a.next?a.next.prev=a.prev:this.tail=a.prev},moveToFront:function(a){this.remove(a),this.add(a)}}),c}(),f=function(){"use strict";function a(a){this.prefix=["__",a,"__"].join(""),this.ttlKey="__ttl__",this.keyMatcher=new RegExp("^"+b.escapeRegExChars(this.prefix))}function c(){return(new Date).getTime()}function d(a){return JSON.stringify(b.isUndefined(a)?null:a)}function e(a){return JSON.parse(a)}var f,g;try{f=window.localStorage,f.setItem("~~~","!"),f.removeItem("~~~")}catch(h){f=null}return g=f&&window.JSON?{_prefix:function(a){return this.prefix+a},_ttlKey:function(a){return this._prefix(a)+this.ttlKey},get:function(a){return this.isExpired(a)&&this.remove(a),e(f.getItem(this._prefix(a)))},set:function(a,e,g){return b.isNumber(g)?f.setItem(this._ttlKey(a),d(c()+g)):f.removeItem(this._ttlKey(a)),f.setItem(this._prefix(a),d(e))},remove:function(a){return f.removeItem(this._ttlKey(a)),f.removeItem(this._prefix(a)),this},clear:function(){var a,b,c=[],d=f.length;for(a=0;d>a;a++)(b=f.key(a)).match(this.keyMatcher)&&c.push(b.replace(this.keyMatcher,""));for(a=c.length;a--;)this.remove(c[a]);return this},isExpired:function(a){var d=e(f.getItem(this._ttlKey(a)));return b.isNumber(d)&&c()>d?!0:!1}}:{get:b.noop,set:b.noop,remove:b.noop,clear:b.noop,isExpired:b.noop},b.mixin(a.prototype,g),a}(),g=function(){"use strict";function c(b){b=b||{},this.cancelled=!1,this.lastUrl=null,this._send=b.transport?d(b.transport):a.ajax,this._get=b.rateLimiter?b.rateLimiter(this._get):this._get,this._cache=b.cache===!1?new e(0):i}function d(c){return function(d,e){function f(a){b.defer(function(){h.resolve(a)})}function g(a){b.defer(function(){h.reject(a)})}var h=a.Deferred();return c(d,e,f,g),h}}var f=0,g={},h=6,i=new e(10);return c.setMaxPendingRequests=function(a){h=a},c.resetCache=function(){i.reset()},b.mixin(c.prototype,{_get:function(a,b,c){function d(b){c&&c(null,b),k._cache.set(a,b)}function e(){c&&c(!0)}function i(){f--,delete g[a],k.onDeckRequestArgs&&(k._get.apply(k,k.onDeckRequestArgs),k.onDeckRequestArgs=null)}var j,k=this;this.cancelled||a!==this.lastUrl||((j=g[a])?j.done(d).fail(e):h>f?(f++,g[a]=this._send(a,b).done(d).fail(e).always(i)):this.onDeckRequestArgs=[].slice.call(arguments,0))},get:function(a,c,d){var e;return b.isFunction(c)&&(d=c,c={}),this.cancelled=!1,this.lastUrl=a,(e=this._cache.get(a))?b.defer(function(){d&&d(null,e)}):this._get(a,c,d),!!e},cancel:function(){this.cancelled=!0}}),c}(),h=function(){"use strict";function c(b){b=b||{},b.datumTokenizer&&b.queryTokenizer||a.error("datumTokenizer and queryTokenizer are both required"),this.datumTokenizer=b.datumTokenizer,this.queryTokenizer=b.queryTokenizer,this.reset()}function d(a){return a=b.filter(a,function(a){return!!a}),a=b.map(a,function(a){return a.toLowerCase()})}function e(){return{ids:[],children:{}}}function f(a){for(var b={},c=[],d=0,e=a.length;e>d;d++)b[a[d]]||(b[a[d]]=!0,c.push(a[d]));return c}function g(a,b){function c(a,b){return a-b}var d=0,e=0,f=[];a=a.sort(c),b=b.sort(c);for(var g=a.length,h=b.length;g>d&&h>e;)a[d]b[e]?e++:(f.push(a[d]),d++,e++);return f}return b.mixin(c.prototype,{bootstrap:function(a){this.datums=a.datums,this.trie=a.trie},add:function(a){var c=this;a=b.isArray(a)?a:[a],b.each(a,function(a){var f,g;f=c.datums.push(a)-1,g=d(c.datumTokenizer(a)),b.each(g,function(a){var b,d,g;for(b=c.trie,d=a.split("");g=d.shift();)b=b.children[g]||(b.children[g]=e()),b.ids.push(f)})})},get:function(a){var c,e,h=this;return c=d(this.queryTokenizer(a)),b.each(c,function(a){var b,c,d,f;if(e&&0===e.length)return!1;for(b=h.trie,c=a.split("");b&&(d=c.shift());)b=b.children[d];return b&&0===c.length?(f=b.ids.slice(0),void(e=e?g(e,f):f)):(e=[],!1)}),e?b.map(f(e),function(a){return h.datums[a]}):[]},reset:function(){this.datums=[],this.trie=e()},serialize:function(){return{datums:this.datums,trie:this.trie}}}),c}(),i=function(){"use strict";function d(a){return a.local||null}function e(d){var e,f;return f={url:null,thumbprint:"",ttl:864e5,filter:null,ajax:{}},(e=d.prefetch||null)&&(e=b.isString(e)?{url:e}:e,e=b.mixin(f,e),e.thumbprint=c+e.thumbprint,e.ajax.type=e.ajax.type||"GET",e.ajax.dataType=e.ajax.dataType||"json",!e.url&&a.error("prefetch requires url to be set")),e}function f(c){function d(a){return function(c){return b.debounce(c,a)}}function e(a){return function(c){return b.throttle(c,a)}}var f,g;return g={url:null,cache:!0,wildcard:"%QUERY",replace:null,rateLimitBy:"debounce",rateLimitWait:300,send:null,filter:null,ajax:{}},(f=c.remote||null)&&(f=b.isString(f)?{url:f}:f,f=b.mixin(g,f),f.rateLimiter=/^throttle$/i.test(f.rateLimitBy)?e(f.rateLimitWait):d(f.rateLimitWait),f.ajax.type=f.ajax.type||"GET",f.ajax.dataType=f.ajax.dataType||"json",delete f.rateLimitBy,delete f.rateLimitWait,!f.url&&a.error("remote requires url to be set")),f}return{local:d,prefetch:e,remote:f}}();!function(c){"use strict";function e(b){b&&(b.local||b.prefetch||b.remote)||a.error("one of local, prefetch, or remote is required"),this.limit=b.limit||5,this.sorter=j(b.sorter),this.dupDetector=b.dupDetector||k,this.local=i.local(b),this.prefetch=i.prefetch(b),this.remote=i.remote(b),this.cacheKey=this.prefetch?this.prefetch.cacheKey||this.prefetch.url:null,this.index=new h({datumTokenizer:b.datumTokenizer,queryTokenizer:b.queryTokenizer}),this.storage=this.cacheKey?new f(this.cacheKey):null}function j(a){function c(b){return b.sort(a)}function d(a){return a}return b.isFunction(a)?c:d}function k(){return!1}var l,m;return l=c.Bloodhound,m={data:"data",protocol:"protocol",thumbprint:"thumbprint"},c.Bloodhound=e,e.noConflict=function(){return c.Bloodhound=l,e},e.tokenizers=d,b.mixin(e.prototype,{_loadPrefetch:function(b){function c(a){f.clear(),f.add(b.filter?b.filter(a):a),f._saveToStorage(f.index.serialize(),b.thumbprint,b.ttl)}var d,e,f=this;return(d=this._readFromStorage(b.thumbprint))?(this.index.bootstrap(d),e=a.Deferred().resolve()):e=a.ajax(b.url,b.ajax).done(c),e},_getFromRemote:function(a,b){function c(a,c){b(a?[]:f.remote.filter?f.remote.filter(c):c)}var d,e,f=this;if(this.transport)return a=a||"",e=encodeURIComponent(a),d=this.remote.replace?this.remote.replace(this.remote.url,a):this.remote.url.replace(this.remote.wildcard,e),this.transport.get(d,this.remote.ajax,c)},_cancelLastRemoteRequest:function(){this.transport&&this.transport.cancel()},_saveToStorage:function(a,b,c){this.storage&&(this.storage.set(m.data,a,c),this.storage.set(m.protocol,location.protocol,c),this.storage.set(m.thumbprint,b,c))},_readFromStorage:function(a){var b,c={};return this.storage&&(c.data=this.storage.get(m.data),c.protocol=this.storage.get(m.protocol),c.thumbprint=this.storage.get(m.thumbprint)),b=c.thumbprint!==a||c.protocol!==location.protocol,c.data&&!b?c.data:null},_initialize:function(){function c(){e.add(b.isFunction(f)?f():f)}var d,e=this,f=this.local;return d=this.prefetch?this._loadPrefetch(this.prefetch):a.Deferred().resolve(),f&&d.done(c),this.transport=this.remote?new g(this.remote):null,this.initPromise=d.promise()},initialize:function(a){return!this.initPromise||a?this._initialize():this.initPromise},add:function(a){this.index.add(a)},get:function(a,c){function d(a){var d=f.slice(0);b.each(a,function(a){var c;return c=b.some(d,function(b){return e.dupDetector(a,b)}),!c&&d.push(a),d.length0||!this.transport)&&c&&c(f)},clear:function(){this.index.reset()},clearPrefetchCache:function(){this.storage&&this.storage.clear()},clearRemoteCache:function(){this.transport&&g.resetCache()},ttAdapter:function(){return b.bind(this.get,this)}}),e}(this);var j=function(){return{wrapper:'',dropdown:'',dataset:'',suggestions:'',suggestion:''}}(),k=function(){"use strict";var a={wrapper:{position:"relative",display:"inline-block"},hint:{position:"absolute",top:"0",left:"0",borderColor:"transparent",boxShadow:"none",opacity:"1"},input:{position:"relative",verticalAlign:"top",backgroundColor:"transparent"},inputWithNoHint:{position:"relative",verticalAlign:"top"},dropdown:{position:"absolute",top:"100%",left:"0",zIndex:"100",display:"none"},suggestions:{display:"block"},suggestion:{whiteSpace:"nowrap",cursor:"pointer"},suggestionChild:{whiteSpace:"normal"},ltr:{left:"0",right:"auto"},rtl:{left:"auto",right:" 0"}};return b.isMsie()&&b.mixin(a.input,{backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"}),b.isMsie()&&b.isMsie()<=7&&b.mixin(a.input,{marginTop:"-1px"}),a}(),l=function(){"use strict";function c(b){b&&b.el||a.error("EventBus initialized without el"),this.$el=a(b.el)}var d="typeahead:";return b.mixin(c.prototype,{trigger:function(a){var b=[].slice.call(arguments,1);this.$el.trigger(d+a,b)}}),c}(),m=function(){"use strict";function a(a,b,c,d){var e;if(!c)return this;for(b=b.split(i),c=d?h(c,d):c,this._callbacks=this._callbacks||{};e=b.shift();)this._callbacks[e]=this._callbacks[e]||{sync:[],async:[]},this._callbacks[e][a].push(c);return this}function b(b,c,d){return a.call(this,"async",b,c,d)}function c(b,c,d){return a.call(this,"sync",b,c,d)}function d(a){var b;if(!this._callbacks)return this;for(a=a.split(i);b=a.shift();)delete this._callbacks[b];return this}function e(a){var b,c,d,e,g;if(!this._callbacks)return this;for(a=a.split(i),d=[].slice.call(arguments,1);(b=a.shift())&&(c=this._callbacks[b]);)e=f(c.sync,this,[b].concat(d)),g=f(c.async,this,[b].concat(d)),e()&&j(g);return this}function f(a,b,c){function d(){for(var d,e=0,f=a.length;!d&&f>e;e+=1)d=a[e].apply(b,c)===!1;return!d}return d}function g(){var a;return a=window.setImmediate?function(a){setImmediate(function(){a()})}:function(a){setTimeout(function(){a()},0)}}function h(a,b){return a.bind?a.bind(b):function(){a.apply(b,[].slice.call(arguments,0))}}var i=/\s+/,j=g();return{onSync:c,onAsync:b,off:d,trigger:e}}(),n=function(a){"use strict";function c(a,c,d){for(var e,f=[],g=0,h=a.length;h>g;g++)f.push(b.escapeRegExChars(a[g]));return e=d?"\\b("+f.join("|")+")\\b":"("+f.join("|")+")",c?new RegExp(e):new RegExp(e,"i")}var d={node:null,pattern:null,tagName:"strong",className:null,wordsOnly:!1,caseSensitive:!1};return function(e){function f(b){var c,d,f;return(c=h.exec(b.data))&&(f=a.createElement(e.tagName),e.className&&(f.className=e.className),d=b.splitText(c.index),d.splitText(c[0].length),f.appendChild(d.cloneNode(!0)),b.parentNode.replaceChild(f,d)),!!c}function g(a,b){for(var c,d=3,e=0;e').css({position:"absolute",visibility:"hidden",whiteSpace:"pre",fontFamily:b.css("font-family"),fontSize:b.css("font-size"),fontStyle:b.css("font-style"),fontVariant:b.css("font-variant"),fontWeight:b.css("font-weight"),wordSpacing:b.css("word-spacing"),letterSpacing:b.css("letter-spacing"),textIndent:b.css("text-indent"),textRendering:b.css("text-rendering"),textTransform:b.css("text-transform")}).insertAfter(b)}function e(a,b){return c.normalizeQuery(a)===c.normalizeQuery(b)}function f(a){return a.altKey||a.ctrlKey||a.metaKey||a.shiftKey}var g;return g={9:"tab",27:"esc",37:"left",39:"right",13:"enter",38:"up",40:"down"},c.normalizeQuery=function(a){return(a||"").replace(/^\s*/g,"").replace(/\s{2,}/g," ")},b.mixin(c.prototype,m,{_onBlur:function(){this.resetInputValue(),this.trigger("blurred")},_onFocus:function(){this.trigger("focused")},_onKeydown:function(a){var b=g[a.which||a.keyCode];this._managePreventDefault(b,a),b&&this._shouldTrigger(b,a)&&this.trigger(b+"Keyed",a)},_onInput:function(){this._checkInputValue()},_managePreventDefault:function(a,b){var c,d,e;switch(a){case"tab":d=this.getHint(),e=this.getInputValue(),c=d&&d!==e&&!f(b);break;case"up":case"down":c=!f(b);break;default:c=!1}c&&b.preventDefault()},_shouldTrigger:function(a,b){var c;switch(a){case"tab":c=!f(b);break;default:c=!0}return c},_checkInputValue:function(){var a,b,c;a=this.getInputValue(),b=e(a,this.query),c=b?this.query.length!==a.length:!1,this.query=a,b?c&&this.trigger("whitespaceChanged",this.query):this.trigger("queryChanged",this.query)},focus:function(){this.$input.focus()},blur:function(){this.$input.blur()},getQuery:function(){return this.query},setQuery:function(a){this.query=a},getInputValue:function(){return this.$input.val()},setInputValue:function(a,b){this.$input.val(a),b?this.clearHint():this._checkInputValue()},resetInputValue:function(){this.setInputValue(this.query,!0)},getHint:function(){return this.$hint.val()},setHint:function(a){this.$hint.val(a)},clearHint:function(){this.setHint("")},clearHintIfInvalid:function(){var a,b,c,d;a=this.getInputValue(),b=this.getHint(),c=a!==b&&0===b.indexOf(a),d=""!==a&&c&&!this.hasOverflow(),!d&&this.clearHint()},getLanguageDirection:function(){return(this.$input.css("direction")||"ltr").toLowerCase()},hasOverflow:function(){var a=this.$input.width()-2;return this.$overflowHelper.text(this.getInputValue()),this.$overflowHelper.width()>=a},isCursorAtEnd:function(){var a,c,d;return a=this.$input.val().length,c=this.$input[0].selectionStart,b.isNumber(c)?c===a:document.selection?(d=document.selection.createRange(),d.moveStart("character",-a),a===d.text.length):!0},destroy:function(){this.$hint.off(".tt"),this.$input.off(".tt"),this.$hint=this.$input=this.$overflowHelper=null}}),c}(),p=function(){"use strict";function c(c){c=c||{},c.templates=c.templates||{},c.source||a.error("missing source"),c.name&&!f(c.name)&&a.error("invalid dataset name: "+c.name),this.query=null,this.highlight=!!c.highlight,this.name=c.name||b.getUniqueId(),this.source=c.source,this.displayFn=d(c.display||c.displayKey),this.templates=e(c.templates,this.displayFn),this.$el=a(j.dataset.replace("%CLASS%",this.name))}function d(a){function c(b){return b[a]}return a=a||"value",b.isFunction(a)?a:c}function e(a,c){function d(a){return""+c(a)+"
"}return{empty:a.empty&&b.templatify(a.empty),header:a.header&&b.templatify(a.header),footer:a.footer&&b.templatify(a.footer),suggestion:a.suggestion||d}}function f(a){return/^[_a-zA-Z0-9-]+$/.test(a)}var g="ttDataset",h="ttValue",i="ttDatum";return c.extractDatasetName=function(b){return a(b).data(g)},c.extractValue=function(b){return a(b).data(h)},c.extractDatum=function(b){return a(b).data(i)},b.mixin(c.prototype,m,{_render:function(c,d){function e(){return p.templates.empty({query:c,isEmpty:!0})}function f(){function e(b){var c;return c=a(j.suggestion).append(p.templates.suggestion(b)).data(g,p.name).data(h,p.displayFn(b)).data(i,b),c.children().each(function(){a(this).css(k.suggestionChild)}),c}var f,l;return f=a(j.suggestions).css(k.suggestions),l=b.map(d,e),f.append.apply(f,l),p.highlight&&n({className:"tt-highlight",node:f[0],pattern:c}),f}function l(){return p.templates.header({query:c,isEmpty:!o})}function m(){return p.templates.footer({query:c,isEmpty:!o})}if(this.$el){var o,p=this;this.$el.empty(),o=d&&d.length,!o&&this.templates.empty?this.$el.html(e()).prepend(p.templates.header?l():null).append(p.templates.footer?m():null):o&&this.$el.html(f()).prepend(p.templates.header?l():null).append(p.templates.footer?m():null),this.trigger("rendered")}},getRoot:function(){return this.$el},update:function(a){function b(b){c.canceled||a!==c.query||c._render(a,b)}var c=this;this.query=a,this.canceled=!1,this.source(a,b)},cancel:function(){this.canceled=!0},clear:function(){this.cancel(),this.$el.empty(),this.trigger("rendered")},isEmpty:function(){return this.$el.is(":empty")},destroy:function(){this.$el=null}}),c}(),q=function(){"use strict";function c(c){var e,f,g,h=this;c=c||{},c.menu||a.error("menu is required"),this.isOpen=!1,this.isEmpty=!0,this.datasets=b.map(c.datasets,d),e=b.bind(this._onSuggestionClick,this),f=b.bind(this._onSuggestionMouseEnter,this),g=b.bind(this._onSuggestionMouseLeave,this),this.$menu=a(c.menu).on("click.tt",".tt-suggestion",e).on("mouseenter.tt",".tt-suggestion",f).on("mouseleave.tt",".tt-suggestion",g),b.each(this.datasets,function(a){h.$menu.append(a.getRoot()),a.onSync("rendered",h._onRendered,h)})}function d(a){return new p(a)}return b.mixin(c.prototype,m,{_onSuggestionClick:function(b){this.trigger("suggestionClicked",a(b.currentTarget))},_onSuggestionMouseEnter:function(b){this._removeCursor(),this._setCursor(a(b.currentTarget),!0)},_onSuggestionMouseLeave:function(){this._removeCursor()},_onRendered:function(){function a(a){return a.isEmpty()}this.isEmpty=b.every(this.datasets,a),this.isEmpty?this._hide():this.isOpen&&this._show(),this.trigger("datasetRendered")},_hide:function(){this.$menu.hide()},_show:function(){this.$menu.css("display","block")},_getSuggestions:function(){return this.$menu.find(".tt-suggestion")},_getCursor:function(){return this.$menu.find(".tt-cursor").first()},_setCursor:function(a,b){a.first().addClass("tt-cursor"),!b&&this.trigger("cursorMoved")},_removeCursor:function(){this._getCursor().removeClass("tt-cursor")},_moveCursor:function(a){var b,c,d,e;if(this.isOpen){if(c=this._getCursor(),b=this._getSuggestions(),this._removeCursor(),d=b.index(c)+a,d=(d+1)%(b.length+1)-1,-1===d)return void this.trigger("cursorRemoved");-1>d&&(d=b.length-1),this._setCursor(e=b.eq(d)),this._ensureVisible(e)}},_ensureVisible:function(a){var b,c,d,e;b=a.position().top,c=b+a.outerHeight(!0),d=this.$menu.scrollTop(),e=this.$menu.height()+parseInt(this.$menu.css("paddingTop"),10)+parseInt(this.$menu.css("paddingBottom"),10),0>b?this.$menu.scrollTop(d+b):c>e&&this.$menu.scrollTop(d+(c-e))},close:function(){this.isOpen&&(this.isOpen=!1,this._removeCursor(),this._hide(),this.trigger("closed"))},open:function(){this.isOpen||(this.isOpen=!0,!this.isEmpty&&this._show(),this.trigger("opened"))},setLanguageDirection:function(a){this.$menu.css("ltr"===a?k.ltr:k.rtl)},moveCursorUp:function(){this._moveCursor(-1)},moveCursorDown:function(){this._moveCursor(1)},getDatumForSuggestion:function(a){var b=null;return a.length&&(b={raw:p.extractDatum(a),value:p.extractValue(a),datasetName:p.extractDatasetName(a)}),b},getDatumForCursor:function(){return this.getDatumForSuggestion(this._getCursor().first())},getDatumForTopSuggestion:function(){return this.getDatumForSuggestion(this._getSuggestions().first())},update:function(a){function c(b){b.update(a)}b.each(this.datasets,c)},empty:function(){function a(a){a.clear()}b.each(this.datasets,a),this.isEmpty=!0},isVisible:function(){return this.isOpen&&!this.isEmpty},destroy:function(){function a(a){a.destroy()}this.$menu.off(".tt"),this.$menu=null,b.each(this.datasets,a)}}),c}(),r=function(){"use strict";function c(c){var e,f,g;c=c||{},c.input||a.error("missing input"),this.isActivated=!1,this.autoselect=!!c.autoselect,this.minLength=b.isNumber(c.minLength)?c.minLength:1,this.$node=d(c.input,c.withHint),e=this.$node.find(".tt-dropdown-menu"),f=this.$node.find(".tt-input"),g=this.$node.find(".tt-hint"),f.on("blur.tt",function(a){var c,d,g;c=document.activeElement,d=e.is(c),g=e.has(c).length>0,b.isMsie()&&(d||g)&&(a.preventDefault(),a.stopImmediatePropagation(),b.defer(function(){f.focus()}))}),e.on("mousedown.tt",function(a){a.preventDefault()}),this.eventBus=c.eventBus||new l({el:f}),this.dropdown=new q({menu:e,datasets:c.datasets}).onSync("suggestionClicked",this._onSuggestionClicked,this).onSync("cursorMoved",this._onCursorMoved,this).onSync("cursorRemoved",this._onCursorRemoved,this).onSync("opened",this._onOpened,this).onSync("closed",this._onClosed,this).onAsync("datasetRendered",this._onDatasetRendered,this),this.input=new o({input:f,hint:g}).onSync("focused",this._onFocused,this).onSync("blurred",this._onBlurred,this).onSync("enterKeyed",this._onEnterKeyed,this).onSync("tabKeyed",this._onTabKeyed,this).onSync("escKeyed",this._onEscKeyed,this).onSync("upKeyed",this._onUpKeyed,this).onSync("downKeyed",this._onDownKeyed,this).onSync("leftKeyed",this._onLeftKeyed,this).onSync("rightKeyed",this._onRightKeyed,this).onSync("queryChanged",this._onQueryChanged,this).onSync("whitespaceChanged",this._onWhitespaceChanged,this),this._setLanguageDirection()}function d(b,c){var d,f,h,i;d=a(b),f=a(j.wrapper).css(k.wrapper),h=a(j.dropdown).css(k.dropdown),i=d.clone().css(k.hint).css(e(d)),i.val("").removeData().addClass("tt-hint").removeAttr("id name placeholder required").prop("readonly",!0).attr({autocomplete:"off",spellcheck:"false",tabindex:-1}),d.data(g,{dir:d.attr("dir"),autocomplete:d.attr("autocomplete"),spellcheck:d.attr("spellcheck"),style:d.attr("style")}),d.addClass("tt-input").attr({autocomplete:"off",spellcheck:!1}).css(c?k.input:k.inputWithNoHint);try{!d.attr("dir")&&d.attr("dir","auto")}catch(l){}return d.wrap(f).parent().prepend(c?i:null).append(h)}function e(a){return{backgroundAttachment:a.css("background-attachment"),backgroundClip:a.css("background-clip"),backgroundColor:a.css("background-color"),backgroundImage:a.css("background-image"),backgroundOrigin:a.css("background-origin"),backgroundPosition:a.css("background-position"),backgroundRepeat:a.css("background-repeat"),backgroundSize:a.css("background-size")}}function f(a){var c=a.find(".tt-input");b.each(c.data(g),function(a,d){b.isUndefined(a)?c.removeAttr(d):c.attr(d,a)}),c.detach().removeData(g).removeClass("tt-input").insertAfter(a),a.remove()}var g="ttAttrs";return b.mixin(c.prototype,{_onSuggestionClicked:function(a,b){var c;(c=this.dropdown.getDatumForSuggestion(b))&&this._select(c)},_onCursorMoved:function(){var a=this.dropdown.getDatumForCursor();this.input.setInputValue(a.value,!0),this.eventBus.trigger("cursorchanged",a.raw,a.datasetName)},_onCursorRemoved:function(){this.input.resetInputValue(),this._updateHint()},_onDatasetRendered:function(){this._updateHint()},_onOpened:function(){this._updateHint(),this.eventBus.trigger("opened")},_onClosed:function(){this.input.clearHint(),this.eventBus.trigger("closed")},_onFocused:function(){this.isActivated=!0,this.dropdown.open()},_onBlurred:function(){this.isActivated=!1,this.dropdown.empty(),this.dropdown.close()},_onEnterKeyed:function(a,b){var c,d;c=this.dropdown.getDatumForCursor(),d=this.dropdown.getDatumForTopSuggestion(),c?(this._select(c),b.preventDefault()):this.autoselect&&d&&(this._select(d),b.preventDefault())},_onTabKeyed:function(a,b){var c;(c=this.dropdown.getDatumForCursor())?(this._select(c),b.preventDefault()):this._autocomplete(!0)},_onEscKeyed:function(){this.dropdown.close(),this.input.resetInputValue()},_onUpKeyed:function(){var a=this.input.getQuery();this.dropdown.isEmpty&&a.length>=this.minLength?this.dropdown.update(a):this.dropdown.moveCursorUp(),this.dropdown.open()},_onDownKeyed:function(){var a=this.input.getQuery();this.dropdown.isEmpty&&a.length>=this.minLength?this.dropdown.update(a):this.dropdown.moveCursorDown(),this.dropdown.open()},_onLeftKeyed:function(){"rtl"===this.dir&&this._autocomplete()},_onRightKeyed:function(){"ltr"===this.dir&&this._autocomplete()},_onQueryChanged:function(a,b){this.input.clearHintIfInvalid(),b.length>=this.minLength?this.dropdown.update(b):this.dropdown.empty(),this.dropdown.open(),this._setLanguageDirection()},_onWhitespaceChanged:function(){this._updateHint(),this.dropdown.open()},_setLanguageDirection:function(){var a;this.dir!==(a=this.input.getLanguageDirection())&&(this.dir=a,this.$node.css("direction",a),this.dropdown.setLanguageDirection(a))},_updateHint:function(){var a,c,d,e,f,g;a=this.dropdown.getDatumForTopSuggestion(),a&&this.dropdown.isVisible()&&!this.input.hasOverflow()?(c=this.input.getInputValue(),d=o.normalizeQuery(c),e=b.escapeRegExChars(d),f=new RegExp("^(?:"+e+")(.+$)","i"),g=f.exec(a.value),g?this.input.setHint(c+g[1]):this.input.clearHint()):this.input.clearHint()},_autocomplete:function(a){var b,c,d,e;b=this.input.getHint(),c=this.input.getQuery(),d=a||this.input.isCursorAtEnd(),b&&c!==b&&d&&(e=this.dropdown.getDatumForTopSuggestion(),e&&this.input.setInputValue(e.value),this.eventBus.trigger("autocompleted",e.raw,e.datasetName))},_select:function(a){this.input.setQuery(a.value),this.input.setInputValue(a.value,!0),this._setLanguageDirection(),this.eventBus.trigger("selected",a.raw,a.datasetName),this.dropdown.close(),b.defer(b.bind(this.dropdown.empty,this.dropdown))},open:function(){this.dropdown.open()},close:function(){this.dropdown.close()},setVal:function(a){a=b.toStr(a),this.isActivated?this.input.setInputValue(a):(this.input.setQuery(a),this.input.setInputValue(a,!0)),this._setLanguageDirection()},getVal:function(){return this.input.getQuery()},destroy:function(){this.input.destroy(),this.dropdown.destroy(),f(this.$node),this.$node=null}}),c}();!function(){"use strict";var c,d,e;c=a.fn.typeahead,d="ttTypeahead",e={initialize:function(c,e){function f(){var f,g,h=a(this);b.each(e,function(a){a.highlight=!!c.highlight}),g=new r({input:h,eventBus:f=new l({el:h}),withHint:b.isUndefined(c.hint)?!0:!!c.hint,minLength:c.minLength,autoselect:c.autoselect,datasets:e}),h.data(d,g)}return e=b.isArray(e)?e:[].slice.call(arguments,1),c=c||{},this.each(f)},open:function(){function b(){var b,c=a(this);(b=c.data(d))&&b.open()}return this.each(b)},close:function(){function b(){var b,c=a(this);(b=c.data(d))&&b.close()}return this.each(b)},val:function(b){function c(){var c,e=a(this);(c=e.data(d))&&c.setVal(b)}function e(a){var b,c;return(b=a.data(d))&&(c=b.getVal()),c}return arguments.length?this.each(c):e(this.first())},destroy:function(){function b(){var b,c=a(this);(b=c.data(d))&&(b.destroy(),c.removeData(d))}return this.each(b)}},a.fn.typeahead=function(b){var c;return e[b]&&"initialize"!==b?(c=this.filter(function(){return!!a(this).data(d)}),e[b].apply(c,[].slice.call(arguments,1))):e.initialize.apply(this,arguments)},a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this}}()}(window.jQuery);
--------------------------------------------------------------------------------
/cite2c/nbext/xmldom.js:
--------------------------------------------------------------------------------
1 | if ("undefined" === typeof CSL_IS_IE) {
2 | var CSL_IS_IE;
3 | };
4 | var CSL_CHROME = function () {
5 | if ("undefined" == typeof DOMParser || CSL_IS_IE) {
6 | CSL_IS_IE = true;
7 | DOMParser = function() {};
8 | DOMParser.prototype.parseFromString = function(str, contentType) {
9 | if ("undefined" != typeof ActiveXObject) {
10 | var xmldata = new ActiveXObject('MSXML.DomDocument');
11 | xmldata.async = false;
12 | xmldata.loadXML(str);
13 | return xmldata;
14 | } else if ("undefined" != typeof XMLHttpRequest) {
15 | var xmldata = new XMLHttpRequest;
16 | if (!contentType) {
17 | contentType = 'text/xml';
18 | }
19 | xmldata.open('GET', 'data:' + contentType + ';charset=utf-8,' + encodeURIComponent(str), false);
20 | if(xmldata.overrideMimeType) {
21 | xmldata.overrideMimeType(contentType);
22 | }
23 | xmldata.send(null);
24 | return xmldata.responseXML;
25 | }
26 | };
27 | this.hasAttributes = function (node) {
28 | var ret;
29 | if (node.attributes && node.attributes.length) {
30 | ret = true;
31 | } else {
32 | ret = false;
33 | }
34 | return ret;
35 | };
36 | } else {
37 | this.hasAttributes = function (node) {
38 | var ret;
39 | if (node.attributes && node.attributes.length) {
40 | ret = true;
41 | } else {
42 | ret = false;
43 | }
44 | return ret;
45 | };
46 | }
47 | this.importNode = function (doc, srcElement) {
48 | if ("undefined" == typeof doc.importNode) {
49 | var ret = this._importNode(doc, srcElement, true);
50 | } else {
51 | var ret = doc.importNode(srcElement, true);
52 | }
53 | return ret;
54 | };
55 | this._importNode = function(doc, node, allChildren) {
56 | switch (node.nodeType) {
57 | case 1:
58 | var newNode = doc.createElement(node.nodeName);
59 | if (node.attributes && node.attributes.length > 0)
60 | for (var i = 0, il = node.attributes.length; i < il;)
61 | newNode.setAttribute(node.attributes[i].nodeName, node.getAttribute(node.attributes[i++].nodeName));
62 | if (allChildren && node.childNodes && node.childNodes.length > 0)
63 | for (var i = 0, il = node.childNodes.length; i < il;)
64 | newNode.appendChild(this._importNode(doc, node.childNodes[i++], allChildren));
65 | return newNode;
66 | break;
67 | case 3:
68 | case 4:
69 | case 8:
70 | }
71 | };
72 | this.parser = new DOMParser();
73 | var str = "";
74 | var inst_doc = this.parser.parseFromString(str, "text/xml");
75 | var inst_node = inst_doc.getElementsByTagName("institution");
76 | this.institution = inst_node.item(0);
77 | var inst_part_node = inst_doc.getElementsByTagName("institution-part");
78 | this.institutionpart = inst_part_node.item(0);
79 | this.ns = "http://purl.org/net/xbiblio/csl";
80 | };
81 | CSL_CHROME.prototype.clean = function (xml) {
82 | xml = xml.replace(/<\?[^?]+\?>/g, "");
83 | xml = xml.replace(/]+>/g, "");
84 | xml = xml.replace(/^\s+/, "");
85 | xml = xml.replace(/\s+$/, "");
86 | xml = xml.replace(/^\n*/, "");
87 | return xml;
88 | };
89 | CSL_CHROME.prototype.getStyleId = function (myxml) {
90 | var text = "";
91 | var node = myxml.getElementsByTagName("id");
92 | if (node && node.length) {
93 | node = node.item(0);
94 | }
95 | if (node) {
96 | text = node.textContent;
97 | }
98 | if (!text) {
99 | text = node.innerText;
100 | }
101 | if (!text) {
102 | text = node.innerHTML;
103 | }
104 | return text;
105 | };
106 | CSL_CHROME.prototype.children = function (myxml) {
107 | var children, pos, len, ret;
108 | if (myxml) {
109 | ret = [];
110 | children = myxml.childNodes;
111 | for (pos = 0, len = children.length; pos < len; pos += 1) {
112 | if (children[pos].nodeName != "#text") {
113 | ret.push(children[pos]);
114 | }
115 | }
116 | return ret;
117 | } else {
118 | return [];
119 | }
120 | };
121 | CSL_CHROME.prototype.nodename = function (myxml) {
122 | var ret = myxml.nodeName;
123 | return ret;
124 | };
125 | CSL_CHROME.prototype.attributes = function (myxml) {
126 | var ret, attrs, attr, key, xml, pos, len;
127 | ret = new Object();
128 | if (myxml && this.hasAttributes(myxml)) {
129 | attrs = myxml.attributes;
130 | for (pos = 0, len=attrs.length; pos < len; pos += 1) {
131 | attr = attrs[pos];
132 | ret["@" + attr.name] = attr.value;
133 | }
134 | }
135 | return ret;
136 | };
137 | CSL_CHROME.prototype.content = function (myxml) {
138 | var ret;
139 | if ("undefined" != typeof myxml.textContent) {
140 | ret = myxml.textContent;
141 | } else if ("undefined" != typeof myxml.innerText) {
142 | ret = myxml.innerText;
143 | } else {
144 | ret = myxml.txt;
145 | }
146 | return ret;
147 | };
148 | CSL_CHROME.prototype.namespace = {
149 | "xml":"http://www.w3.org/XML/1998/namespace"
150 | }
151 | CSL_CHROME.prototype.numberofnodes = function (myxml) {
152 | if (myxml) {
153 | return myxml.length;
154 | } else {
155 | return 0;
156 | }
157 | };
158 | CSL_CHROME.prototype.getAttributeName = function (attr) {
159 | var ret = attr.name;
160 | return ret;
161 | }
162 | CSL_CHROME.prototype.getAttributeValue = function (myxml,name,namespace) {
163 | var ret = "";
164 | if (namespace) {
165 | name = namespace+":"+name;
166 | }
167 | if (myxml && this.hasAttributes(myxml) && myxml.getAttribute(name)) {
168 | ret = myxml.getAttribute(name);
169 | }
170 | return ret;
171 | }
172 | CSL_CHROME.prototype.getNodeValue = function (myxml,name) {
173 | var ret = "";
174 | if (name){
175 | var vals = myxml.getElementsByTagName(name);
176 | if (vals.length > 0) {
177 | if ("undefined" != typeof vals[0].textContent) {
178 | ret = vals[0].textContent;
179 | } else if ("undefined" != typeof vals[0].innerText) {
180 | ret = vals[0].innerText;
181 | } else {
182 | ret = vals[0].text;
183 | }
184 | }
185 | } else {
186 | ret = myxml;
187 | }
188 | if (ret && ret.childNodes && (ret.childNodes.length == 0 || (ret.childNodes.length == 1 && ret.firstChild.nodeName == "#text"))) {
189 | if ("undefined" != typeof ret.textContent) {
190 | ret = ret.textContent;
191 | } else if ("undefined" != typeof ret.innerText) {
192 | ret = ret.innerText;
193 | } else {
194 | ret = ret.text;
195 | }
196 | }
197 | return ret;
198 | }
199 | CSL_CHROME.prototype.setAttributeOnNodeIdentifiedByNameAttribute = function (myxml,nodename,partname,attrname,val) {
200 | var pos, len, xml, nodes, node;
201 | if (attrname.slice(0,1) === '@'){
202 | attrname = attrname.slice(1);
203 | }
204 | nodes = myxml.getElementsByTagName(nodename);
205 | for (pos = 0, len = nodes.length; pos < len; pos += 1) {
206 | node = nodes[pos];
207 | if (node.getAttribute("name") != partname) {
208 | continue;
209 | }
210 | node.setAttribute(attrname, val);
211 | }
212 | }
213 | CSL_CHROME.prototype.deleteNodeByNameAttribute = function (myxml,val) {
214 | var pos, len, node, nodes;
215 | nodes = myxml.childNodes;
216 | for (pos = 0, len = nodes.length; pos < len; pos += 1) {
217 | node = nodes[pos];
218 | if (!node || node.nodeType == node.TEXT_NODE) {
219 | continue;
220 | }
221 | if (this.hasAttributes(node) && node.getAttribute("name") == val) {
222 | myxml.removeChild(nodes[pos]);
223 | }
224 | }
225 | }
226 | CSL_CHROME.prototype.deleteAttribute = function (myxml,attr) {
227 | myxml.removeAttribute(attr);
228 | }
229 | CSL_CHROME.prototype.setAttribute = function (myxml,attr,val) {
230 | if (!myxml.ownerDocument) {
231 | myxml = myxml.firstChild;
232 | }
233 | if (["function", "unknown"].indexOf(typeof myxml.setAttribute) > -1) {
234 | myxml.setAttribute(attr, val);
235 | }
236 | return false;
237 | }
238 | CSL_CHROME.prototype.nodeCopy = function (myxml) {
239 | var cloned_node = myxml.cloneNode(true);
240 | return cloned_node;
241 | }
242 | CSL_CHROME.prototype.getNodesByName = function (myxml,name,nameattrval) {
243 | var ret, nodes, node, pos, len;
244 | ret = [];
245 | nodes = myxml.getElementsByTagName(name);
246 | for (pos = 0, len = nodes.length; pos < len; pos += 1) {
247 | node = nodes.item(pos);
248 | if (nameattrval && !(this.hasAttributes(node) && node.getAttribute("name") == nameattrval)) {
249 | continue;
250 | }
251 | ret.push(node);
252 | }
253 | return ret;
254 | }
255 | CSL_CHROME.prototype.nodeNameIs = function (myxml,name) {
256 | if (name == myxml.nodeName) {
257 | return true;
258 | }
259 | return false;
260 | }
261 | CSL_CHROME.prototype.makeXml = function (myxml) {
262 | var ret, topnode;
263 | if (!myxml) {
264 | myxml = "";
265 | }
266 | myxml = myxml.replace(/\s*<\?[^>]*\?>\s*\n*/g, "");
267 | var nodetree = this.parser.parseFromString(myxml, "application/xml");
268 | return nodetree.firstChild;
269 | };
270 | CSL_CHROME.prototype.insertChildNodeAfter = function (parent,node,pos,datexml) {
271 | var myxml, xml;
272 | myxml = this.importNode(node.ownerDocument, datexml);
273 | parent.replaceChild(myxml, node);
274 | return parent;
275 | };
276 | CSL_CHROME.prototype.insertPublisherAndPlace = function(myxml) {
277 | var group = myxml.getElementsByTagName("group");
278 | for (var i = 0, ilen = group.length; i < ilen; i += 1) {
279 | var node = group.item(i);
280 | var skippers = [];
281 | for (var j = 0, jlen = node.childNodes.length; j < jlen; j += 1) {
282 | if (node.childNodes.item(j).nodeType !== 1) {
283 | skippers.push(j);
284 | }
285 | }
286 | if (node.childNodes.length - skippers.length === 2) {
287 | var twovars = [];
288 | for (var j = 0, jlen = 2; j < jlen; j += 1) {
289 | if (skippers.indexOf(j) > -1) {
290 | continue;
291 | }
292 | var child = node.childNodes.item(j);
293 | var subskippers = [];
294 | for (var k = 0, klen = child.childNodes.length; k < klen; k += 1) {
295 | if (child.childNodes.item(k).nodeType !== 1) {
296 | subskippers.push(k);
297 | }
298 | }
299 | if (child.childNodes.length - subskippers.length === 0) {
300 | twovars.push(child.getAttribute('variable'));
301 | if (child.getAttribute('suffix')
302 | || child.getAttribute('prefix')) {
303 | twovars = [];
304 | break;
305 | }
306 | }
307 | }
308 | if (twovars.indexOf("publisher") > -1 && twovars.indexOf("publisher-place") > -1) {
309 | node.setAttribute('has-publisher-and-publisher-place', true);
310 | }
311 | }
312 | }
313 | };
314 | CSL_CHROME.prototype.addMissingNameNodes = function(myxml) {
315 | var nameslist = myxml.getElementsByTagName("names");
316 | for (var i = 0, ilen = nameslist.length; i < ilen; i += 1) {
317 | var names = nameslist.item(i);
318 | var namelist = names.getElementsByTagName("name");
319 | if ((!namelist || namelist.length === 0)
320 | && names.parentNode.tagName.toLowerCase() !== "substitute") {
321 | var doc = names.ownerDocument;
322 | var name = doc.createElement("name");
323 | names.appendChild(name);
324 | }
325 | }
326 | };
327 | CSL_CHROME.prototype.addInstitutionNodes = function(myxml) {
328 | var names, thenames, institution, theinstitution, name, thename, xml, pos, len;
329 | names = myxml.getElementsByTagName("names");
330 | for (pos = 0, len = names.length; pos < len; pos += 1) {
331 | thenames = names.item(pos);
332 | name = thenames.getElementsByTagName("name");
333 | if (name.length == 0) {
334 | continue;
335 | }
336 | institution = thenames.getElementsByTagName("institution");
337 | if (institution.length == 0) {
338 | theinstitution = this.importNode(myxml.ownerDocument, this.institution);
339 | theinstitutionpart = theinstitution.getElementsByTagName("institution-part").item(0);
340 | thename = name.item(0);
341 | thenames.insertBefore(theinstitution, thename.nextSibling);
342 | for (var j = 0, jlen = CSL.INSTITUTION_KEYS.length; j < jlen; j += 1) {
343 | var attrname = CSL.INSTITUTION_KEYS[j];
344 | var attrval = thename.getAttribute(attrname);
345 | if (attrval) {
346 | theinstitutionpart.setAttribute(attrname, attrval);
347 | }
348 | }
349 | var nameparts = thename.getElementsByTagName("name-part");
350 | for (var j = 0, jlen = nameparts.length; j < jlen; j += 1) {
351 | if ('family' === nameparts[j].getAttribute('name')) {
352 | for (var k = 0, klen = CSL.INSTITUTION_KEYS.length; k < klen; k += 1) {
353 | var attrname = CSL.INSTITUTION_KEYS[k];
354 | var attrval = nameparts[j].getAttribute(attrname);
355 | if (attrval) {
356 | theinstitutionpart.setAttribute(attrname, attrval);
357 | }
358 | }
359 | }
360 | }
361 | }
362 | }
363 | };
364 | CSL_CHROME.prototype.flagDateMacros = function(myxml) {
365 | var pos, len, thenode, thedate;
366 | nodes = myxml.getElementsByTagName("macro");
367 | for (pos = 0, len = nodes.length; pos < len; pos += 1) {
368 | thenode = nodes.item(pos);
369 | thedate = thenode.getElementsByTagName("date");
370 | if (thedate.length) {
371 | thenode.setAttribute('macro-has-date', 'true');
372 | }
373 | }
374 | };
375 |
--------------------------------------------------------------------------------
/cite2c/oauth_success.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | OAuth Success
6 |
7 |
8 | Authenticated successfully. You can now close this tab.
9 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/cite2c/zotero_oauth.py:
--------------------------------------------------------------------------------
1 | """Get an API token to access a user's Zotero library, using OAuth 1.0a
2 | """
3 | from notebook.base.handlers import IPythonHandler
4 | from notebook.services.config.manager import ConfigManager
5 | from notebook.utils import url_path_join as ujoin
6 | import os
7 | from rauth import OAuth1Service
8 | from rauth.utils import parse_utf8_qsl
9 | from tornado.web import HTTPError
10 |
11 | # If you copy this code, please get your own key at:
12 | # https://www.zotero.org/oauth/apps
13 | CITE2C_ZOTERO_CLIENT_KEY = "8cc04771a4e2ef9c9c4d"
14 | CITE2C_ZOTERO_CLIENT_SECRET = "9270b1ed6762a87eb253"
15 |
16 | def zotero_oauth_service():
17 | return OAuth1Service(
18 | name='zotero',
19 | consumer_key=CITE2C_ZOTERO_CLIENT_KEY,
20 | consumer_secret=CITE2C_ZOTERO_CLIENT_SECRET,
21 | request_token_url='https://www.zotero.org/oauth/request',
22 | access_token_url='https://www.zotero.org/oauth/access',
23 | authorize_url='https://www.zotero.org/oauth/authorize',
24 | base_url='https://api.zotero.org')
25 |
26 | # These are stored as globals while we wait for the callback.
27 | # We're only trying to handle one user authenticating, so this should be OK.
28 | request_token = ''
29 | request_token_secret = ''
30 |
31 | class ZoteroOauthHandler(IPythonHandler):
32 | """Part 1: Get a request token, send the user to authorize it.
33 | """
34 | def get(self):
35 | global request_token, request_token_secret
36 |
37 | callback = '%s://%s%scite2c/zotero_oauth_cb' % (
38 | self.request.protocol, self.request.host, self.settings['base_url']
39 | )
40 | oauth_svc = zotero_oauth_service()
41 | request_token, request_token_secret = oauth_svc.get_request_token(
42 | params={'oauth_callback': callback}
43 | )
44 | authorize_url = oauth_svc.get_authorize_url(request_token)
45 | self.log.info("Zotero OAuth, redirecting to: %s", authorize_url)
46 | self.redirect(authorize_url)
47 |
48 | # HTML+JS to close the tab after OAuth succeeded.
49 | oauth_success = os.path.join(os.path.dirname(__file__), 'oauth_success.html')
50 |
51 | class ZoteroOauthCallbackHandler(IPythonHandler):
52 | """Part 2: Zotero redirects back to here after authorization.
53 |
54 | Get the access token and user info, store them in cite2c's frontend config.
55 | """
56 | def get(self):
57 | if not (request_token and request_token_secret):
58 | raise HTTPError(log_message='OAuth callback, no request token')
59 | verifier = self.get_query_argument('oauth_verifier')
60 |
61 | access_token_response = zotero_oauth_service().get_raw_access_token(
62 | request_token, request_token_secret,
63 | data={'oauth_verifier': verifier}
64 | )
65 | access_token_response.raise_for_status()
66 | access_info = parse_utf8_qsl(access_token_response.content)
67 | if 'oauth_token' not in access_info:
68 | raise HTTPError(log_message="Missing oauth_token. Response content: %r"
69 | % access_token_response.content)
70 |
71 | # We have successfully authenticated.
72 | cm = ConfigManager()
73 | cm.update('cite2c', {'zotero': {
74 | 'user_id': access_info['userID'],
75 | 'username': access_info['username'],
76 | 'access_token': access_info['oauth_token'],
77 | }})
78 | self.log.info("OAuth completed for Zotero user %s", access_info['userID'])
79 | with open(oauth_success) as f:
80 | self.finish(f.read())
81 |
82 | def handlers(base_url):
83 | return [
84 | (ujoin(base_url, r"/cite2c/zotero_oauth"), ZoteroOauthHandler),
85 | (ujoin(base_url, r"/cite2c/zotero_oauth_cb"), ZoteroOauthCallbackHandler),
86 | ]
87 |
--------------------------------------------------------------------------------
/flit.ini:
--------------------------------------------------------------------------------
1 | [metadata]
2 | module = cite2c
3 | author = Thomas Kluyver
4 | author-email = thomas@kluyver.me.uk
5 | home-page = https://github.com/takluyver/cite2c
6 | description-file = README.md
7 | classifiers = License :: OSI Approved :: MIT License
8 | requires = notebook
9 | tornado
10 | rauth
11 |
12 |
--------------------------------------------------------------------------------
/search_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/takluyver/cite2c/55b5f10288ad557a014e1ee10cb54c86d97ea166/search_screenshot.png
--------------------------------------------------------------------------------
/toolbar_buttons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/takluyver/cite2c/55b5f10288ad557a014e1ee10cb54c86d97ea166/toolbar_buttons.png
--------------------------------------------------------------------------------