Skip to content

Commit

Permalink
Merge branch 'citeproc-js'
Browse files Browse the repository at this point in the history
# Conflicts:
#	.gitignore
#	README.md
  • Loading branch information
deanishe committed Dec 24, 2017
2 parents 0445c7a + a11df7a commit c9fea8c
Show file tree
Hide file tree
Showing 22 changed files with 649 additions and 100 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/cpjs/node_modules/

# Created by https://www.gitignore.io/api/python,sublimetext,vim

Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ These are the workflow's default keywords in Alfred:
- `zotconf [<query>]` — View and edit workflow configuration.
- `An Update is Available` / `Workflow is Up To Date` — Whether a newer version of the workflow is available.
- `Default Style: …` — Choose a citation style for the `⌘↩` and `⌥↩` hotkeys (on search results).
- `Locale: …` — Choose a locale for the formatting of citations. If unset, US English is used.
- `Locale: …` — Choose a locale for the formatting of citations. If unset, the default for the style is used, or if none is set, US English.
- `Reload Zotero Cache` — Clear the workflow's cache of Zotero data. Useful if the workflow gets out of sync with Zotero.
- `Open Log File` — Open the workflows log file in the default app (usually Console.app). Useful for checking on indexing problems (the indexer output isn't visible in Alfred's debugger).
- `View Documentation` — Open this README in your browser.
Expand Down Expand Up @@ -108,7 +108,9 @@ For `⌘↩` and `⌥↩` to work on search results, you must first choose a def
<a name="locales"></a>
### Locales ###

[CSL][csl] and ZotHero support the following locales. The default locale is `en-US` (American English). Use the `zotconf` keyword to set a different locale.
[CSL][csl] and ZotHero support the following locales. The default behaviour is to use the locale specified in the style if there is one, and `en-US` (American English) if not. Setting a locale overrides the style's own locale.

Use the `zotconf` keyword to force a specific locale.

| Locale | Code |
|----------------------------------------------|---------|
Expand Down
Binary file removed ZotHero-0.1.5-beta.alfredworkflow
Binary file not shown.
Binary file added ZotHero-0.2-beta.alfredworkflow
Binary file not shown.
4 changes: 4 additions & 0 deletions cpjs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/node_modules/

# Generated script
/cite
6 changes: 6 additions & 0 deletions cpjs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
cpjs
====

A CSL citation generator based on `[citeproc-js][citeproc-js]`.

[citeproc-js]: https://github.com/Juris-M/citeproc-js
52 changes: 52 additions & 0 deletions cpjs/bench
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env python
# encoding: utf-8
#
# Copyright (c) 2017 Dean Jackson <[email protected]>
#
# MIT Licence. See http://opensource.org/licenses/MIT
#
# Created on 2017-12-24
#

"""Benchmark the speed of cite.js."""


from __future__ import print_function, absolute_import

from contextlib import contextmanager
import os
import subprocess
import sys
from time import time

REPS = 20
TIMES = []

HERE = os.path.dirname(__file__)
STYLE = os.path.expanduser('~/Zotero/styles/apa.csl')
LOCALES = os.path.join(HERE, 'locales')
DATA = os.path.join(HERE, 'test.json')


def log(s, *args):
"""Simple STDERR logger."""
if args:
s = s % args
print(s, file=sys.stderr)


@contextmanager
def timed(name):
start = time()
yield
d = time() - start
log('[%s] %0.2fs', name, d)
TIMES.append(d)


for i in range(REPS):
with timed('cite'):
subprocess.check_output(['./cite', '-L', LOCALES, STYLE, DATA])


log('[average] %0.3fs', sum(TIMES) / len(TIMES))
66 changes: 66 additions & 0 deletions cpjs/build
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/bin/zsh

set -e

here="$( cd "$( dirname "$0" )"; pwd )"
outfile="${here}/cite"
libfile="${here}/../src/lib/cite/cite"
minify=false

usage() {
cat <<EOS
build [-m|-h]
Build `cite` from citeproc-js and cite.js.
Usage:
build [-m]
build -h
Options:
-m Minify generated script
-h Show this help message and exit
EOS
}

while getopts ":hm" opt; do
case $opt in
h)
usage
exit 0
;;
m)
minify=true
;;
\?)
log "Invalid option: -$OPTARG"
exit 1
;;
esac
done
shift $((OPTIND-1))


echo '' > "$outfile"
echo '#!/usr/bin/osascript -l JavaScript' > "$outfile"
echo "\n" >> "$outfile"

echo "window = this;\n\n" >> "$outfile"

echo "// ======================== citeproc ==========================\n" >> "$outfile"

$minify && {
browserify -r citeproc -s CSL | uglifyjs -c -m -r CSL >> "$outfile"
} || {
browserify -r citeproc -s CSL >> "$outfile"
}


echo "\n\n// ======================== /citeproc =========================\n" >> "$outfile"


cat "${here}/cite.js" >> "$outfile"

chmod +x "$outfile"

command cp -vf "$outfile" "$libfile"
190 changes: 190 additions & 0 deletions cpjs/cite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@

ObjC.import('stdlib')
ObjC.import('Foundation')
var fm = $.NSFileManager.defaultManager


Array.prototype.contains = function(val) {
for (var i; i < this.length; i++) {
if (this[i] === val)
return true
}
return false
}

var usage = `cite [options] <style.csl> <csl.json>
Generate an HTML CSL citation for item defined in <csl.json> using
the stylesheet specified by <style.csl>.
Usage:
cite [-b] [-v] [-l <lang>] [-L <dir>] <style.csl> <csl.json>
cite (-h|--help)
Options:
-b, --bibliography Generate bibliography-style citation
-l <lang>, --locale <lang> Locale for citation
-L <dir>, --locale-dir <dir> Directory locale files are in
-v, --verbose Show status messages
-h, --help Show this message and exit
`

// Show CLI help and exit.
function showHelp(errMsg) {
var status = 0
if (errMsg) {
console.log(`error: ${errMsg}`)
status = 1
}
console.log(usage)
$.exit(status)
}

// Parse command-line flags.
function parseArgs(argv) {
argv.forEach(function(s) {
if (s == '-h' || s == '--help')
showHelp()
})
if (argv.length == 0)
showHelp()

var args = [],
opts = {
locale: null,
localeDir: './locales',
style: null,
csl: null,
bibliography: false,
verbose: false
}

// Extract flags and collect arguments
for (var i=0; i < argv.length; i++) {
var s = argv[i]

if (s.startsWith('-')) {

if (s == '--locale' || s == '-l') {
opts.locale = argv[i+1]
i++
}

else if (s == '--locale-dir' || s == '-L') {
opts.localeDir = argv[i+1]
i++
}

else if (s == '--bibliography' || s == '-b')
opts.bibliography = true

else if (s == '--verbose' || s == '-v')
opts.verbose = true

else
showHelp('unknown option: ' + s)

} else {
args.push(s)
}
}

// Arguments
if (args.length > 2)
showHelp('script takes 2 arguments')

if (args.length > 0)
opts.style = args[0]

if (args.length > 1)
opts.csl = args[1]

return opts
}

// Read file at `path` and return its contents as a string.
function readFile(path) {
var contents = $.NSString.alloc.initWithDataEncoding(fm.contentsAtPath(path), $.NSUTF8StringEncoding)
return ObjC.unwrap(contents)
}


function stripOuterDiv(html) {
var match = new RegExp('^<div.*?>(.+)</div>$').exec(html)
if (match != null)
return match[1]

return html
}


var Citer = function(opts) {
this.opts = opts
this.item = JSON.parse(readFile(opts.csl))
this.style = readFile(opts.style)
this.id = this.item.id

var locale = 'en',
force = false

if (opts.locale) {
locale = opts.locale
force = true
}

this.citer = new CSL.Engine(this, this.style, locale, force)
}


Citer.prototype.retrieveItem = function(id) {
return this.item
}

Citer.prototype.retrieveLocale = function(lang) {
if (this.opts.verbose) {
console.log(`locale=${lang}`)
console.log(`localeDir=${this.opts.localeDir}`)
}

return readFile(`${this.opts.localeDir}/locales-${lang}.xml`)
}

Citer.prototype.cite = function() {
var data = {html: '', rtf: ''}
this.citer.updateItems([this.id])

if (this.opts.bibliography) {

// -----------------------------------------------------
// HTML
var html = this.citer.makeBibliography()[1].join('\n').trim()
data.html = stripOuterDiv(html)

// -----------------------------------------------------
// RTF
this.citer.setOutputFormat('rtf')
data.rtf = this.citer.makeBibliography()[1].join('\n')

} else {
data.html = this.citer.makeCitationCluster([this.id])
this.citer.setOutputFormat('rtf')
data.rtf = this.citer.makeCitationCluster([this.id])
}

return data
}


function run(argv) {

var opts = parseArgs(argv)

if (opts.verbose) {
console.log(`bibliography=${opts.bibliography}`)
console.log(`csl=${opts.csl}`)
console.log(`style=${opts.style}`)
}

return JSON.stringify(new Citer(opts).cite())
}
1 change: 1 addition & 0 deletions cpjs/locales
45 changes: 45 additions & 0 deletions cpjs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c9fea8c

Please sign in to comment.