├── .gitignore ├── static ├── mirador │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ ├── MaterialIcons-Regular.eot │ │ ├── MaterialIcons-Regular.ttf │ │ ├── MaterialIcons-Regular.woff │ │ ├── MaterialIcons-Regular.woff2 │ │ └── fontawesome-webfont.woff2 │ ├── images │ │ ├── debut_dark.png │ │ ├── border_type_1.png │ │ ├── border_type_2.png │ │ ├── border_type_3.png │ │ ├── border_type_4.png │ │ └── border_type_5.png │ ├── plugins │ │ ├── help │ │ │ ├── img │ │ │ │ └── logo.png │ │ │ └── index.js │ │ ├── emoticons │ │ │ ├── img │ │ │ │ ├── smiley-cool.gif │ │ │ │ ├── smiley-cry.gif │ │ │ │ ├── smiley-frown.gif │ │ │ │ ├── smiley-kiss.gif │ │ │ │ ├── smiley-smile.gif │ │ │ │ ├── smiley-wink.gif │ │ │ │ ├── smiley-yell.gif │ │ │ │ ├── smiley-sealed.gif │ │ │ │ ├── smiley-embarassed.gif │ │ │ │ ├── smiley-innocent.gif │ │ │ │ ├── smiley-laughing.gif │ │ │ │ ├── smiley-surprised.gif │ │ │ │ ├── smiley-tongue-out.gif │ │ │ │ ├── smiley-undecided.gif │ │ │ │ ├── smiley-money-mouth.gif │ │ │ │ └── smiley-foot-in-mouth.gif │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── hr │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── toc │ │ │ ├── index.js │ │ │ └── plugin.min.js │ │ ├── code │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── link │ │ │ └── index.js │ │ ├── save │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── image │ │ │ └── index.js │ │ ├── lists │ │ │ └── index.js │ │ ├── media │ │ │ └── index.js │ │ ├── paste │ │ │ └── index.js │ │ ├── print │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── table │ │ │ └── index.js │ │ ├── advlist │ │ │ ├── index.js │ │ │ └── plugin.min.js │ │ ├── anchor │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── bbcode │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── charmap │ │ │ └── index.js │ │ ├── preview │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── autolink │ │ │ ├── index.js │ │ │ └── plugin.min.js │ │ ├── autosave │ │ │ ├── index.js │ │ │ └── plugin.min.js │ │ ├── fullpage │ │ │ └── index.js │ │ ├── tabfocus │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── template │ │ │ ├── index.js │ │ │ └── plugin.min.js │ │ ├── importcss │ │ │ ├── index.js │ │ │ └── plugin.min.js │ │ ├── pagebreak │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── textcolor │ │ │ ├── index.js │ │ │ └── plugin.min.js │ │ ├── wordcount │ │ │ └── index.js │ │ ├── autoresize │ │ │ ├── index.js │ │ │ └── plugin.min.js │ │ ├── codesample │ │ │ ├── index.js │ │ │ └── css │ │ │ │ └── prism.css │ │ ├── fullscreen │ │ │ ├── index.js │ │ │ └── plugin.min.js │ │ ├── imagetools │ │ │ └── index.js │ │ ├── colorpicker │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── contextmenu │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── legacyoutput │ │ │ ├── index.js │ │ │ └── plugin.min.js │ │ ├── nonbreaking │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── noneditable │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── spellchecker │ │ │ └── index.js │ │ ├── textpattern │ │ │ ├── index.js │ │ │ └── plugin.min.js │ │ ├── visualblocks │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ ├── visualchars │ │ │ ├── index.js │ │ │ └── plugin.min.js │ │ ├── searchreplace │ │ │ └── index.js │ │ ├── directionality │ │ │ ├── index.js │ │ │ ├── plugin.min.js │ │ │ └── plugin.js │ │ └── insertdatetime │ │ │ ├── index.js │ │ │ └── plugin.min.js │ ├── skins │ │ └── lightgray │ │ │ ├── img │ │ │ ├── anchor.gif │ │ │ ├── loader.gif │ │ │ ├── object.gif │ │ │ └── trans.gif │ │ │ ├── fonts │ │ │ ├── tinymce.eot │ │ │ ├── tinymce.ttf │ │ │ ├── tinymce.woff │ │ │ ├── tinymce-small.eot │ │ │ ├── tinymce-small.ttf │ │ │ ├── tinymce-small.woff │ │ │ └── tinymce-mobile.woff │ │ │ ├── content.mobile.min.css │ │ │ ├── content.inline.min.css │ │ │ └── content.min.css │ ├── themes │ │ ├── inlite │ │ │ └── index.js │ │ ├── mobile │ │ │ └── index.js │ │ └── modern │ │ │ └── index.js │ └── locales │ │ ├── nl │ │ └── translation.json │ │ ├── zh │ │ └── translation.json │ │ ├── zh-CN │ │ └── translation.json │ │ ├── zh-TW │ │ └── translation.json │ │ ├── ko │ │ └── translation.json │ │ ├── ja │ │ └── translation.json │ │ ├── es │ │ └── translation.json │ │ ├── ga │ │ └── translation.json │ │ ├── en │ │ └── translation.json │ │ ├── ar │ │ └── translation.json │ │ ├── de │ │ └── translation.json │ │ └── fr │ │ └── translation.json ├── index.html └── annotationEndpoint.js ├── Makefile ├── go.mod ├── db.go ├── annotation.go ├── go.sum ├── main.go ├── README.md └── handlers.go /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | bindata.go 3 | vendor 4 | build/macos/IIIF\ Annotation\ Studio.app/Contents/MacOS/IIIF\ Annotation\ Studio.app 5 | -------------------------------------------------------------------------------- /static/mirador/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /static/mirador/images/debut_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/images/debut_dark.png -------------------------------------------------------------------------------- /static/mirador/images/border_type_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/images/border_type_1.png -------------------------------------------------------------------------------- /static/mirador/images/border_type_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/images/border_type_2.png -------------------------------------------------------------------------------- /static/mirador/images/border_type_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/images/border_type_3.png -------------------------------------------------------------------------------- /static/mirador/images/border_type_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/images/border_type_4.png -------------------------------------------------------------------------------- /static/mirador/images/border_type_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/images/border_type_5.png -------------------------------------------------------------------------------- /static/mirador/plugins/help/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/help/img/logo.png -------------------------------------------------------------------------------- /static/mirador/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /static/mirador/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /static/mirador/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/mirador/skins/lightgray/img/anchor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/skins/lightgray/img/anchor.gif -------------------------------------------------------------------------------- /static/mirador/skins/lightgray/img/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/skins/lightgray/img/loader.gif -------------------------------------------------------------------------------- /static/mirador/skins/lightgray/img/object.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/skins/lightgray/img/object.gif -------------------------------------------------------------------------------- /static/mirador/skins/lightgray/img/trans.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/skins/lightgray/img/trans.gif -------------------------------------------------------------------------------- /static/mirador/fonts/MaterialIcons-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/fonts/MaterialIcons-Regular.eot -------------------------------------------------------------------------------- /static/mirador/fonts/MaterialIcons-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/fonts/MaterialIcons-Regular.ttf -------------------------------------------------------------------------------- /static/mirador/fonts/MaterialIcons-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/fonts/MaterialIcons-Regular.woff -------------------------------------------------------------------------------- /static/mirador/fonts/MaterialIcons-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/fonts/MaterialIcons-Regular.woff2 -------------------------------------------------------------------------------- /static/mirador/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /static/mirador/skins/lightgray/fonts/tinymce.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/skins/lightgray/fonts/tinymce.eot -------------------------------------------------------------------------------- /static/mirador/skins/lightgray/fonts/tinymce.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/skins/lightgray/fonts/tinymce.ttf -------------------------------------------------------------------------------- /static/mirador/skins/lightgray/fonts/tinymce.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/skins/lightgray/fonts/tinymce.woff -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | bindata: 2 | go-bindata-assetfs static/... 3 | 4 | build-macos: 5 | go build -o "build/macos/IIIF Annotation Studio.app/Contents/MacOS/IIIF Annotation Studio.app" -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-cool.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-cool.gif -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-cry.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-cry.gif -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-frown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-frown.gif -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-kiss.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-kiss.gif -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-smile.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-smile.gif -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-wink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-wink.gif -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-yell.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-yell.gif -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-sealed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-sealed.gif -------------------------------------------------------------------------------- /static/mirador/skins/lightgray/fonts/tinymce-small.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/skins/lightgray/fonts/tinymce-small.eot -------------------------------------------------------------------------------- /static/mirador/skins/lightgray/fonts/tinymce-small.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/skins/lightgray/fonts/tinymce-small.ttf -------------------------------------------------------------------------------- /static/mirador/skins/lightgray/fonts/tinymce-small.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/skins/lightgray/fonts/tinymce-small.woff -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-embarassed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-embarassed.gif -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-innocent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-innocent.gif -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-laughing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-laughing.gif -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-surprised.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-surprised.gif -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-tongue-out.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-tongue-out.gif -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-undecided.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-undecided.gif -------------------------------------------------------------------------------- /static/mirador/skins/lightgray/fonts/tinymce-mobile.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/skins/lightgray/fonts/tinymce-mobile.woff -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-money-mouth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-money-mouth.gif -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/img/smiley-foot-in-mouth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atomotic/iiif-annotation-studio/HEAD/static/mirador/plugins/emoticons/img/smiley-foot-in-mouth.gif -------------------------------------------------------------------------------- /static/mirador/plugins/hr/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "hr" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/hr') 5 | // ES2015: 6 | // import 'tinymce/plugins/hr' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/toc/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "toc" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/toc') 5 | // ES2015: 6 | // import 'tinymce/plugins/toc' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/code/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "code" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/code') 5 | // ES2015: 6 | // import 'tinymce/plugins/code' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/help/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "help" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/help') 5 | // ES2015: 6 | // import 'tinymce/plugins/help' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/link/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "link" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/link') 5 | // ES2015: 6 | // import 'tinymce/plugins/link' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/save/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "save" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/save') 5 | // ES2015: 6 | // import 'tinymce/plugins/save' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/image/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "image" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/image') 5 | // ES2015: 6 | // import 'tinymce/plugins/image' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/lists/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "lists" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/lists') 5 | // ES2015: 6 | // import 'tinymce/plugins/lists' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/media/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "media" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/media') 5 | // ES2015: 6 | // import 'tinymce/plugins/media' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/paste/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "paste" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/paste') 5 | // ES2015: 6 | // import 'tinymce/plugins/paste' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/print/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "print" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/print') 5 | // ES2015: 6 | // import 'tinymce/plugins/print' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/table/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "table" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/table') 5 | // ES2015: 6 | // import 'tinymce/plugins/table' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/themes/inlite/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "inlite" theme for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/themes/inlite') 5 | // ES2015: 6 | // import 'tinymce/themes/inlite' 7 | require('./theme.js'); -------------------------------------------------------------------------------- /static/mirador/themes/mobile/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "mobile" theme for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/themes/mobile') 5 | // ES2015: 6 | // import 'tinymce/themes/mobile' 7 | require('./theme.js'); -------------------------------------------------------------------------------- /static/mirador/themes/modern/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "modern" theme for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/themes/modern') 5 | // ES2015: 6 | // import 'tinymce/themes/modern' 7 | require('./theme.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/advlist/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "advlist" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/advlist') 5 | // ES2015: 6 | // import 'tinymce/plugins/advlist' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/anchor/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "anchor" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/anchor') 5 | // ES2015: 6 | // import 'tinymce/plugins/anchor' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/bbcode/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "bbcode" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/bbcode') 5 | // ES2015: 6 | // import 'tinymce/plugins/bbcode' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/charmap/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "charmap" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/charmap') 5 | // ES2015: 6 | // import 'tinymce/plugins/charmap' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/preview/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "preview" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/preview') 5 | // ES2015: 6 | // import 'tinymce/plugins/preview' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/autolink/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "autolink" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/autolink') 5 | // ES2015: 6 | // import 'tinymce/plugins/autolink' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/autosave/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "autosave" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/autosave') 5 | // ES2015: 6 | // import 'tinymce/plugins/autosave' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/fullpage/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "fullpage" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/fullpage') 5 | // ES2015: 6 | // import 'tinymce/plugins/fullpage' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/tabfocus/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "tabfocus" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/tabfocus') 5 | // ES2015: 6 | // import 'tinymce/plugins/tabfocus' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/template/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "template" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/template') 5 | // ES2015: 6 | // import 'tinymce/plugins/template' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/emoticons/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "emoticons" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/emoticons') 5 | // ES2015: 6 | // import 'tinymce/plugins/emoticons' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/importcss/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "importcss" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/importcss') 5 | // ES2015: 6 | // import 'tinymce/plugins/importcss' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/pagebreak/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "pagebreak" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/pagebreak') 5 | // ES2015: 6 | // import 'tinymce/plugins/pagebreak' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/textcolor/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "textcolor" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/textcolor') 5 | // ES2015: 6 | // import 'tinymce/plugins/textcolor' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/wordcount/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "wordcount" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/wordcount') 5 | // ES2015: 6 | // import 'tinymce/plugins/wordcount' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/autoresize/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "autoresize" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/autoresize') 5 | // ES2015: 6 | // import 'tinymce/plugins/autoresize' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/codesample/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "codesample" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/codesample') 5 | // ES2015: 6 | // import 'tinymce/plugins/codesample' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/fullscreen/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "fullscreen" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/fullscreen') 5 | // ES2015: 6 | // import 'tinymce/plugins/fullscreen' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/imagetools/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "imagetools" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/imagetools') 5 | // ES2015: 6 | // import 'tinymce/plugins/imagetools' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/colorpicker/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "colorpicker" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/colorpicker') 5 | // ES2015: 6 | // import 'tinymce/plugins/colorpicker' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/contextmenu/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "contextmenu" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/contextmenu') 5 | // ES2015: 6 | // import 'tinymce/plugins/contextmenu' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/legacyoutput/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "legacyoutput" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/legacyoutput') 5 | // ES2015: 6 | // import 'tinymce/plugins/legacyoutput' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/nonbreaking/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "nonbreaking" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/nonbreaking') 5 | // ES2015: 6 | // import 'tinymce/plugins/nonbreaking' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/noneditable/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "noneditable" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/noneditable') 5 | // ES2015: 6 | // import 'tinymce/plugins/noneditable' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/spellchecker/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "spellchecker" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/spellchecker') 5 | // ES2015: 6 | // import 'tinymce/plugins/spellchecker' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/textpattern/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "textpattern" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/textpattern') 5 | // ES2015: 6 | // import 'tinymce/plugins/textpattern' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/visualblocks/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "visualblocks" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/visualblocks') 5 | // ES2015: 6 | // import 'tinymce/plugins/visualblocks' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/visualchars/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "visualchars" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/visualchars') 5 | // ES2015: 6 | // import 'tinymce/plugins/visualchars' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/skins/lightgray/content.mobile.min.css: -------------------------------------------------------------------------------- 1 | .tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection{position:absolute;display:inline-block;background-color:green;opacity:.5}body{-webkit-text-size-adjust:none}body img{max-width:96vw}body table img{max-width:95%} -------------------------------------------------------------------------------- /static/mirador/plugins/searchreplace/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "searchreplace" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/searchreplace') 5 | // ES2015: 6 | // import 'tinymce/plugins/searchreplace' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/directionality/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "directionality" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/directionality') 5 | // ES2015: 6 | // import 'tinymce/plugins/directionality' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/insertdatetime/index.js: -------------------------------------------------------------------------------- 1 | // Exports the "insertdatetime" plugin for usage with module loaders 2 | // Usage: 3 | // CommonJS: 4 | // require('tinymce/plugins/insertdatetime') 5 | // ES2015: 6 | // import 'tinymce/plugins/insertdatetime' 7 | require('./plugin.js'); -------------------------------------------------------------------------------- /static/mirador/plugins/print/plugin.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),n=function(t){t.addCommand("mcePrint",function(){t.getWin().print()})},i=function(t){t.addButton("print",{title:"Print",cmd:"mcePrint"}),t.addMenuItem("print",{text:"Print",cmd:"mcePrint",icon:"print"})};t.add("print",function(t){n(t),i(t),t.addShortcut("Meta+P","","mcePrint")})}(); -------------------------------------------------------------------------------- /static/mirador/plugins/hr/plugin.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=function(n){n.addCommand("InsertHorizontalRule",function(){n.execCommand("mceInsertContent",!1,"
")})},o=function(n){n.addButton("hr",{icon:"hr",tooltip:"Horizontal line",cmd:"InsertHorizontalRule"}),n.addMenuItem("hr",{icon:"hr",text:"Horizontal line",cmd:"InsertHorizontalRule",context:"insert"})};n.add("hr",function(n){t(n),o(n)})}(); -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/atomotic/iiif-annotation-studio 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/elazarl/go-bindata-assetfs v1.0.0 7 | github.com/google/uuid v1.1.1 // indirect 8 | github.com/julienschmidt/httprouter v1.2.0 9 | github.com/lithammer/shortuuid v3.0.0+incompatible 10 | github.com/mattn/go-sqlite3 v1.10.0 11 | github.com/mitchellh/go-homedir v1.1.0 12 | github.com/rs/zerolog v1.12.0 13 | github.com/zserge/webview v0.0.0-20190123072648-16c93bcaeaeb 14 | ) 15 | -------------------------------------------------------------------------------- /db.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | 6 | "github.com/rs/zerolog/log" 7 | ) 8 | 9 | // InitDB create the database table and indexes 10 | func InitDB(dsn string) *sql.DB { 11 | db, err := sql.Open("sqlite3", dsn) 12 | if err != nil { 13 | log.Fatal().Msg("database init error") 14 | } 15 | statement, _ := db.Prepare(`CREATE TABLE IF NOT EXISTS annotations ( 16 | id INTEGER PRIMARY KEY, 17 | annoid VARCHAR, 18 | created_at DATETIME, 19 | target VARCHAR, 20 | manifest VARCHAR, 21 | body TEXT)`) 22 | statement.Exec() 23 | 24 | statement, _ = db.Prepare("CREATE UNIQUE INDEX IF NOT EXISTS annotation_id ON annotations (annoid);") 25 | statement.Exec() 26 | return db 27 | } 28 | -------------------------------------------------------------------------------- /static/mirador/plugins/directionality/plugin.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),c=tinymce.util.Tools.resolve("tinymce.util.Tools"),e=function(t,e){var i,n=t.dom,o=t.selection.getSelectedBlocks();o.length&&(i=n.getAttrib(o[0],"dir"),c.each(o,function(t){n.getParent(t.parentNode,'*[dir="'+e+'"]',n.getRoot())||n.setAttrib(t,"dir",i!==e?e:null)}),t.nodeChanged())},i=function(t){t.addCommand("mceDirectionLTR",function(){e(t,"ltr")}),t.addCommand("mceDirectionRTL",function(){e(t,"rtl")})},n=function(e){var i=[];return c.each("h1 h2 h3 h4 h5 h6 div p".split(" "),function(t){i.push(t+"[dir="+e+"]")}),i.join(",")},o=function(t){t.addButton("ltr",{title:"Left to right",cmd:"mceDirectionLTR",stateSelector:n("ltr")}),t.addButton("rtl",{title:"Right to left",cmd:"mceDirectionRTL",stateSelector:n("rtl")})};t.add("directionality",function(t){i(t),o(t)})}(); -------------------------------------------------------------------------------- /static/mirador/plugins/nonbreaking/plugin.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager"),i=function(n,e){var t,i=(t=n).plugins.visualchars&&t.plugins.visualchars.isEnabled()?' ':" ";n.insertContent(function(n,e){for(var t="",i=0;i'}),o+=""}),o+=""},o=function(a,t){var e=i(t);a.addButton("emoticons",{type:"panelbutton",panel:{role:"application",autohide:!0,html:e,onclick:function(t){var e,i,o,n=a.dom.getParent(t.target,"a");n&&(e=a,i=n.getAttribute("data-mce-url"),o=n.getAttribute("data-mce-alt"),e.insertContent(e.dom.createHTML("img",{src:i,alt:o})),this.hide())}},tooltip:"Emoticons"})};t.add("emoticons",function(t,e){o(t,e)})}(); -------------------------------------------------------------------------------- /static/mirador/plugins/hr/plugin.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var hr = (function () { 3 | 'use strict'; 4 | 5 | var global = tinymce.util.Tools.resolve('tinymce.PluginManager'); 6 | 7 | var register = function (editor) { 8 | editor.addCommand('InsertHorizontalRule', function () { 9 | editor.execCommand('mceInsertContent', false, '
'); 10 | }); 11 | }; 12 | var $_598wgdc0jfuw8p00 = { register: register }; 13 | 14 | var register$1 = function (editor) { 15 | editor.addButton('hr', { 16 | icon: 'hr', 17 | tooltip: 'Horizontal line', 18 | cmd: 'InsertHorizontalRule' 19 | }); 20 | editor.addMenuItem('hr', { 21 | icon: 'hr', 22 | text: 'Horizontal line', 23 | cmd: 'InsertHorizontalRule', 24 | context: 'insert' 25 | }); 26 | }; 27 | var $_7oq7jyc1jfuw8p02 = { register: register$1 }; 28 | 29 | global.add('hr', function (editor) { 30 | $_598wgdc0jfuw8p00.register(editor); 31 | $_7oq7jyc1jfuw8p02.register(editor); 32 | }); 33 | function Plugin () { 34 | } 35 | 36 | return Plugin; 37 | 38 | }()); 39 | })(); 40 | -------------------------------------------------------------------------------- /static/mirador/plugins/colorpicker/plugin.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),l=tinymce.util.Tools.resolve("tinymce.util.Color"),a=function(e,n){e.find("#preview")[0].getEl().style.background=n},o=function(e,n){var i=l(n),t=i.toRgb();e.fromJSON({r:t.r,g:t.g,b:t.b,hex:i.toHex().substr(1)}),a(e,i.toHex())},t=function(e,n,i){var t=e.windowManager.open({title:"Color",items:{type:"container",layout:"flex",direction:"row",align:"stretch",padding:5,spacing:10,items:[{type:"colorpicker",value:i,onchange:function(){var e=this.rgb();t&&(t.find("#r").value(e.r),t.find("#g").value(e.g),t.find("#b").value(e.b),t.find("#hex").value(this.value().substr(1)),a(t,this.value()))}},{type:"form",padding:0,labelGap:5,defaults:{type:"textbox",size:7,value:"0",flex:1,spellcheck:!1,onchange:function(){var e,n,i=t.find("colorpicker")[0];if(e=this.name(),n=this.value(),"hex"===e)return o(t,n="#"+n),void i.value(n);n={r:t.find("#r").value(),g:t.find("#g").value(),b:t.find("#b").value()},i.value(n),o(t,n)}},items:[{name:"r",label:"R",autofocus:1},{name:"g",label:"G"},{name:"b",label:"B"},{name:"hex",label:"#",value:"000000"},{name:"preview",type:"container",border:1}]}]},onSubmit:function(){n("#"+t.toJSON().hex)}});o(t,i)};e.add("colorpicker",function(i){i.settings.color_picker_callback||(i.settings.color_picker_callback=function(e,n){t(i,e,n)})})}(); -------------------------------------------------------------------------------- /static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | IIIF Annotation Studio 12 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /static/mirador/plugins/save/plugin.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),a=tinymce.util.Tools.resolve("tinymce.util.Tools"),o=function(n){return n.getParam("save_enablewhendirty",!0)},c=function(n){return!!n.getParam("save_onsavecallback")},i=function(n){return!!n.getParam("save_oncancelcallback")},r=function(n,e){n.notificationManager.open({text:n.translate(e),type:"error"})},e=function(n){var e;if(e=t.DOM.getParent(n.id,"form"),!o(n)||n.isDirty()){if(n.save(),c(n))return n.execCallback("save_onsavecallback",n),void n.nodeChanged();e?(n.setDirty(!1),e.onsubmit&&!e.onsubmit()||("function"==typeof e.submit?e.submit():r(n,"Error: Form submit field collision.")),n.nodeChanged()):r(n,"Error: No form element found.")}},l=function(n){var e=a.trim(n.startContent);i(n)?n.execCallback("save_oncancelcallback",n):(n.setContent(e),n.undoManager.clear(),n.nodeChanged())},d=function(n){n.addCommand("mceSave",function(){e(n)}),n.addCommand("mceCancel",function(){l(n)})},s=function(t){return function(n){var e=n.control;t.on("nodeChange dirty",function(){e.disabled(o(t)&&!t.isDirty())})}},u=function(n){n.addButton("save",{icon:"save",text:"Save",cmd:"mceSave",disabled:!0,onPostRender:s(n)}),n.addButton("cancel",{text:"Cancel",icon:!1,cmd:"mceCancel",disabled:!0,onPostRender:s(n)}),n.addShortcut("Meta+S","","mceSave")};n.add("save",function(n){u(n),d(n)})}(); -------------------------------------------------------------------------------- /static/mirador/plugins/anchor/plugin.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=function(t){return/^[A-Za-z][A-Za-z0-9\-:._]*$/.test(t)},e=function(t){var e=t.selection.getNode();return"A"===e.tagName&&""===t.dom.getAttrib(e,"href")?e.id||e.name:""},i=function(t,e){var n=t.selection.getNode();"A"===n.tagName&&""===t.dom.getAttrib(n,"href")?(n.removeAttribute("name"),n.id=e):(t.focus(),t.selection.collapse(!0),t.execCommand("mceInsertContent",!1,t.dom.createHTML("a",{id:e})))},n=function(r){var t=e(r);r.windowManager.open({title:"Anchor",body:{type:"textbox",name:"id",size:40,label:"Id",value:t},onsubmit:function(t){var e,n,o=t.data.id;e=r,(a(n=o)?(i(e,n),0):(e.windowManager.alert("Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores."),1))&&t.preventDefault()}})},o=function(t){t.addCommand("mceAnchor",function(){n(t)})},r=function(o){return function(t){for(var e=0;e'},c=function(c){var o=n(c),a=new RegExp(o.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,function(e){return"\\"+e}),"gi");c.on("BeforeSetContent",function(e){e.content=e.content.replace(a,r())}),c.on("PreInit",function(){c.serializer.addNodeFilter("img",function(e){for(var a,n,t=e.length;t--;)if((n=(a=e[t]).attr("class"))&&-1!==n.indexOf("mce-pagebreak")){var r=a.parent;if(c.schema.getBlockElements()[r.name]&&i(c)){r.type=3,r.value=o,r.raw=!0,a.remove();continue}a.type=3,a.value=o,a.raw=!0}})})},o=r,g=t,u=function(e){e.addCommand("mcePageBreak",function(){e.settings.pagebreak_split_block?e.insertContent("

"+o()+"

"):e.insertContent(o())})},m=function(a){a.on("ResolveName",function(e){"IMG"===e.target.nodeName&&a.dom.hasClass(e.target,g())&&(e.name="pagebreak")})},s=function(e){e.addButton("pagebreak",{title:"Page break",cmd:"mcePageBreak"}),e.addMenuItem("pagebreak",{text:"Page break",icon:"pagebreak",cmd:"mcePageBreak",context:"insert"})};e.add("pagebreak",function(e){u(e),s(e),c(e),m(e)})}(); -------------------------------------------------------------------------------- /static/mirador/locales/nl/translation.json: -------------------------------------------------------------------------------- 1 | { 2 | "addItem": "Voeg item toe", 3 | "changeLayout": "Pas layout aan", 4 | "selectGrid": "Kies een grid hieronder", 5 | "bookmark": "Favoriet", 6 | "close": "Sluiten", 7 | "bookmarkTitle": "Favoriet of deel uw werkset", 8 | "filterObjects": "Filter objecten", 9 | "addNewObject": "Voeg nieuw object toe via URL", 10 | "more": "meer", 11 | "item": "item", 12 | "items": "items", 13 | "details": "Details", 14 | "rights": "Copyright", 15 | "rightsStatus": "Copyright Status", 16 | "unspecified": "Niet gespecifieerd", 17 | "links": "Links", 18 | "addSlotRight": "Voeg Slot toe rechts", 19 | "addSlotLeft": "Voeg Slot toe links", 20 | "addSlotAbove": "Voeg Slot toe bovenaan", 21 | "addSlotBelow": "Voeg Slot toe onderaan", 22 | "imageView": "Beeld presentatie", 23 | "bookView": "Boek presentatie", 24 | "scrollView": "Scroll view", 25 | "thumbnailsView": "Bekijk thumbnail", 26 | "comments": "Commentaar", 27 | "addTagsHere": "Voeg hier tags toe", 28 | "save": "Opslaan", 29 | "cancel": "Annuleren", 30 | "edit": "Bewerken", 31 | "delete": "Verwijderen", 32 | "url": "URL", 33 | "newObject": "Nieuw Object", 34 | "objectMetadata": "Object Metadata", 35 | "fullScreen": "Volledig scherm", 36 | "logo": "Logo", 37 | "load": "Laad", 38 | "dropToLoad": "Drop hier om the laden" 39 | } 40 | -------------------------------------------------------------------------------- /annotation.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "encoding/json" 4 | 5 | // Annotation struct 6 | type Annotation struct { 7 | Context string `json:"@context"` 8 | Type string `json:"@type"` 9 | ID string `json:"@id"` 10 | Motivation []string `json:"motivation"` 11 | On []struct { 12 | Type string `json:"@type"` 13 | Full string `json:"full"` 14 | Selector struct { 15 | Type string `json:"@type"` 16 | Default struct { 17 | Type string `json:"@type"` 18 | Value string `json:"value"` 19 | } `json:"default"` 20 | Item struct { 21 | Type string `json:"@type"` 22 | Value string `json:"value"` 23 | } `json:"item"` 24 | } `json:"selector"` 25 | Within struct { 26 | ID string `json:"@id"` 27 | Type string `json:"@type"` 28 | } `json:"within"` 29 | } `json:"on"` 30 | Resource []struct { 31 | Type string `json:"@type"` 32 | Chars string `json:"chars"` 33 | 34 | Format string `json:"format"` 35 | } `json:"resource"` 36 | } 37 | 38 | // Manifest of the annotation 39 | func (a *Annotation) Manifest() string { 40 | return a.On[0].Within.ID 41 | } 42 | 43 | // Canvas of the annotation 44 | func (a *Annotation) Canvas() string { 45 | return a.On[0].Full 46 | } 47 | 48 | // AnnotationList is a list of annotation 49 | type AnnotationList struct { 50 | Context string `json:"@context"` 51 | ID string `json:"@id"` 52 | Type string `json:"@type"` 53 | Resources []json.RawMessage `json:"resources"` 54 | } 55 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= 2 | github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= 3 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= 4 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 5 | github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g= 6 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 7 | github.com/lithammer/shortuuid v3.0.0+incompatible h1:NcD0xWW/MZYXEHa6ITy6kaXN5nwm/V115vj2YXfhS0w= 8 | github.com/lithammer/shortuuid v3.0.0+incompatible/go.mod h1:FR74pbAuElzOUuenUHTK2Tciko1/vKuIKS9dSkDrA4w= 9 | github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= 10 | github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 11 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 12 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 13 | github.com/rs/zerolog v1.12.0 h1:aqZ1XRadoS8IBknR5IDFvGzbHly1X9ApIqOroooQF/c= 14 | github.com/rs/zerolog v1.12.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= 15 | github.com/zserge/webview v0.0.0-20190123072648-16c93bcaeaeb h1:zVjnyZIM7UtkG3dNckiudIm+TUHkZqi5xlVQPd3J6/c= 16 | github.com/zserge/webview v0.0.0-20190123072648-16c93bcaeaeb/go.mod h1:a1CV8KR4Dd1eP2g+mEijGOp+HKczwdKHWyx0aPHKvo4= 17 | -------------------------------------------------------------------------------- /static/mirador/plugins/noneditable/plugin.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),c=tinymce.util.Tools.resolve("tinymce.util.Tools"),l=function(t){return t.getParam("noneditable_noneditable_class","mceNonEditable")},u=function(t){return t.getParam("noneditable_editable_class","mceEditable")},f=function(t){var n=t.getParam("noneditable_regexp",[]);return n&&n.constructor===RegExp?[n]:n},s=function(n){return function(t){return-1!==(" "+t.attr("class")+" ").indexOf(n)}},d=function(i,o,c){return function(t){var n=arguments,e=n[n.length-2],r=0"===r){var a=o.lastIndexOf("<",e);if(-1!==a&&-1!==o.substring(a,e).indexOf('contenteditable="false"'))return t}return''+i.dom.encode("string"==typeof n[1]?n[1]:n[0])+""}},n=function(n){var t,e,r="contenteditable";t=" "+c.trim(u(n))+" ",e=" "+c.trim(l(n))+" ";var a=s(t),i=s(e),o=f(n);n.on("PreInit",function(){0',e&&(n+='"),d.each(t.contentCSS,function(e){n+=''});var o=t.settings.body_id||"tinymce";-1!==o.indexOf("=")&&(o=(o=t.getParam("body_id","","hash"))[t.id]||o);var r=t.settings.body_class||"";-1!==r.indexOf("=")&&(r=(r=t.getParam("body_class","","hash"))[t.id]||"");var c=t.settings.directionality?' dir="'+t.settings.directionality+'"':"";return""+n+'"+t.getContent()+' '; 49 | var dirAttr = editor.settings.directionality ? ' dir="' + editor.settings.directionality + '"' : ''; 50 | previewHtml = '' + '' + '' + headHtml + '' + '' + editor.getContent() + preventClicksOnLinksScript + '' + ''; 51 | return previewHtml; 52 | }; 53 | var injectIframeContent = function (editor, iframe, sandbox) { 54 | var previewHtml = getPreviewHtml(editor); 55 | if (!sandbox) { 56 | var doc = iframe.contentWindow.document; 57 | doc.open(); 58 | doc.write(previewHtml); 59 | doc.close(); 60 | } else { 61 | iframe.src = 'data:text/html;charset=utf-8,' + encodeURIComponent(previewHtml); 62 | } 63 | }; 64 | var $_fzmri3imjfuw8pxx = { 65 | getPreviewHtml: getPreviewHtml, 66 | injectIframeContent: injectIframeContent 67 | }; 68 | 69 | var open = function (editor) { 70 | var sandbox = !global$1.ie; 71 | var dialogHtml = ''; 72 | var dialogWidth = $_1grwcliljfuw8pxt.getPreviewDialogWidth(editor); 73 | var dialogHeight = $_1grwcliljfuw8pxt.getPreviewDialogHeight(editor); 74 | editor.windowManager.open({ 75 | title: 'Preview', 76 | width: dialogWidth, 77 | height: dialogHeight, 78 | html: dialogHtml, 79 | buttons: { 80 | text: 'Close', 81 | onclick: function (e) { 82 | e.control.parent().parent().close(); 83 | } 84 | }, 85 | onPostRender: function (e) { 86 | var iframeElm = e.control.getEl('body').firstChild; 87 | $_fzmri3imjfuw8pxx.injectIframeContent(editor, iframeElm, sandbox); 88 | } 89 | }); 90 | }; 91 | var $_e6srydijjfuw8pxr = { open: open }; 92 | 93 | var register = function (editor) { 94 | editor.addCommand('mcePreview', function () { 95 | $_e6srydijjfuw8pxr.open(editor); 96 | }); 97 | }; 98 | var $_dnevifiijfuw8pxq = { register: register }; 99 | 100 | var register$1 = function (editor) { 101 | editor.addButton('preview', { 102 | title: 'Preview', 103 | cmd: 'mcePreview' 104 | }); 105 | editor.addMenuItem('preview', { 106 | text: 'Preview', 107 | cmd: 'mcePreview', 108 | context: 'view' 109 | }); 110 | }; 111 | var $_8qveptiojfuw8py0 = { register: register$1 }; 112 | 113 | global.add('preview', function (editor) { 114 | $_dnevifiijfuw8pxq.register(editor); 115 | $_8qveptiojfuw8py0.register(editor); 116 | }); 117 | function Plugin () { 118 | } 119 | 120 | return Plugin; 121 | 122 | }()); 123 | })(); 124 | -------------------------------------------------------------------------------- /static/mirador/plugins/template/plugin.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=function(e){return function(){return e}},n=(t(!1),t(!0),function(l){for(var e=[],t=1;t")){var a="";o.each(t.contentCSS,function(e){a+=''});var r=t.settings.body_class||"";-1!==r.indexOf("=")&&(r=(r=t.getParam("body_class","","hash"))[t.id]||""),n=""+a+''+n+""}n=T(t,n,p(t));var l=e.find("iframe")[0].getEl().contentWindow.document;l.open(),l.write(n),l.close()},H=function(n,e){var a,r,t=[];if(e&&0!==e.length)o.each(e,function(e){t.push({selected:!t.length,text:e.title,value:{url:e.url,content:e.content,description:e.description}})}),(a=n.windowManager.open({title:"Insert template",layout:"flex",direction:"column",align:"stretch",padding:15,spacing:10,items:[{type:"form",flex:0,padding:0,items:[{type:"container",label:"Templates",items:{type:"listbox",label:"Templates",name:"template",values:t,onselect:function(e){var t=e.control.value();t.url?c.send({url:t.url,success:function(e){D(n,a,r=e)}}):(r=t.content,D(n,a,r)),a.find("#description")[0].text(e.control.value().description)}}}]},{type:"label",name:"description",label:"Description",text:"\xa0"},{type:"iframe",flex:1,border:1}],onsubmit:function(){P(n,!1,r)},minWidth:g(n),minHeight:h(n)})).find("listbox")[0].fire("select");else{var l=n.translate("No templates defined.");n.notificationManager.open({text:l,type:"info"})}},C=function(t){return function(e){H(t,e)}},A=function(e){e.addButton("template",{title:"Insert template",onclick:l(e.settings,C(e))}),e.addMenuItem("template",{text:"Template",onclick:l(e.settings,C(e)),icon:"template",context:"insert"})};e.add("template",function(e){A(e),S(e),w(e)})}(); -------------------------------------------------------------------------------- /static/mirador/plugins/contextmenu/plugin.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var contextmenu = (function () { 3 | 'use strict'; 4 | 5 | var Cell = function (initial) { 6 | var value = initial; 7 | var get = function () { 8 | return value; 9 | }; 10 | var set = function (v) { 11 | value = v; 12 | }; 13 | var clone = function () { 14 | return Cell(get()); 15 | }; 16 | return { 17 | get: get, 18 | set: set, 19 | clone: clone 20 | }; 21 | }; 22 | 23 | var global = tinymce.util.Tools.resolve('tinymce.PluginManager'); 24 | 25 | var get = function (visibleState) { 26 | var isContextMenuVisible = function () { 27 | return visibleState.get(); 28 | }; 29 | return { isContextMenuVisible: isContextMenuVisible }; 30 | }; 31 | var $_9t541la6jfuw8osw = { get: get }; 32 | 33 | var shouldNeverUseNative = function (editor) { 34 | return editor.settings.contextmenu_never_use_native; 35 | }; 36 | var getContextMenu = function (editor) { 37 | return editor.getParam('contextmenu', 'link openlink image inserttable | cell row column deletetable'); 38 | }; 39 | var $_aohegpa8jfuw8osy = { 40 | shouldNeverUseNative: shouldNeverUseNative, 41 | getContextMenu: getContextMenu 42 | }; 43 | 44 | var global$1 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils'); 45 | 46 | var getUiContainer = function (editor) { 47 | return global$1.DOM.select(editor.settings.ui_container)[0]; 48 | }; 49 | 50 | var nu = function (x, y) { 51 | return { 52 | x: x, 53 | y: y 54 | }; 55 | }; 56 | var transpose = function (pos, dx, dy) { 57 | return nu(pos.x + dx, pos.y + dy); 58 | }; 59 | var fromPageXY = function (e) { 60 | return nu(e.pageX, e.pageY); 61 | }; 62 | var fromClientXY = function (e) { 63 | return nu(e.clientX, e.clientY); 64 | }; 65 | var transposeUiContainer = function (element, pos) { 66 | if (element && global$1.DOM.getStyle(element, 'position', true) !== 'static') { 67 | var containerPos = global$1.DOM.getPos(element); 68 | var dx = containerPos.x - element.scrollLeft; 69 | var dy = containerPos.y - element.scrollTop; 70 | return transpose(pos, -dx, -dy); 71 | } else { 72 | return transpose(pos, 0, 0); 73 | } 74 | }; 75 | var transposeContentAreaContainer = function (element, pos) { 76 | var containerPos = global$1.DOM.getPos(element); 77 | return transpose(pos, containerPos.x, containerPos.y); 78 | }; 79 | var getPos = function (editor, e) { 80 | if (editor.inline) { 81 | return transposeUiContainer(getUiContainer(editor), fromPageXY(e)); 82 | } else { 83 | var iframePos = transposeContentAreaContainer(editor.getContentAreaContainer(), fromClientXY(e)); 84 | return transposeUiContainer(getUiContainer(editor), iframePos); 85 | } 86 | }; 87 | var $_14s918a9jfuw8ot0 = { getPos: getPos }; 88 | 89 | var global$2 = tinymce.util.Tools.resolve('tinymce.ui.Factory'); 90 | 91 | var global$3 = tinymce.util.Tools.resolve('tinymce.util.Tools'); 92 | 93 | var renderMenu = function (editor, visibleState) { 94 | var menu, contextmenu; 95 | var items = []; 96 | contextmenu = $_aohegpa8jfuw8osy.getContextMenu(editor); 97 | global$3.each(contextmenu.split(/[ ,]/), function (name) { 98 | var item = editor.menuItems[name]; 99 | if (name === '|') { 100 | item = { text: name }; 101 | } 102 | if (item) { 103 | item.shortcut = ''; 104 | items.push(item); 105 | } 106 | }); 107 | for (var i = 0; i < items.length; i++) { 108 | if (items[i].text === '|') { 109 | if (i === 0 || i === items.length - 1) { 110 | items.splice(i, 1); 111 | } 112 | } 113 | } 114 | menu = global$2.create('menu', { 115 | items: items, 116 | context: 'contextmenu', 117 | classes: 'contextmenu' 118 | }); 119 | menu.uiContainer = getUiContainer(editor); 120 | menu.renderTo(getUiContainer(editor)); 121 | menu.on('hide', function (e) { 122 | if (e.control === this) { 123 | visibleState.set(false); 124 | } 125 | }); 126 | editor.on('remove', function () { 127 | menu.remove(); 128 | menu = null; 129 | }); 130 | return menu; 131 | }; 132 | var show = function (editor, pos, visibleState, menu) { 133 | if (menu.get() === null) { 134 | menu.set(renderMenu(editor, visibleState)); 135 | } else { 136 | menu.get().show(); 137 | } 138 | menu.get().moveTo(pos.x, pos.y); 139 | visibleState.set(true); 140 | }; 141 | var $_8rgmaiacjfuw8ot4 = { show: show }; 142 | 143 | var isNativeOverrideKeyEvent = function (editor, e) { 144 | return e.ctrlKey && !$_aohegpa8jfuw8osy.shouldNeverUseNative(editor); 145 | }; 146 | var setup = function (editor, visibleState, menu) { 147 | editor.on('contextmenu', function (e) { 148 | if (isNativeOverrideKeyEvent(editor, e)) { 149 | return; 150 | } 151 | e.preventDefault(); 152 | $_8rgmaiacjfuw8ot4.show(editor, $_14s918a9jfuw8ot0.getPos(editor, e), visibleState, menu); 153 | }); 154 | }; 155 | var $_9ravlwa7jfuw8osx = { setup: setup }; 156 | 157 | global.add('contextmenu', function (editor) { 158 | var menu = Cell(null), visibleState = Cell(false); 159 | $_9ravlwa7jfuw8osx.setup(editor, visibleState, menu); 160 | return $_9t541la6jfuw8osw.get(visibleState); 161 | }); 162 | function Plugin () { 163 | } 164 | 165 | return Plugin; 166 | 167 | }()); 168 | })(); 169 | -------------------------------------------------------------------------------- /handlers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strconv" 9 | "time" 10 | 11 | "hash/fnv" 12 | 13 | "github.com/julienschmidt/httprouter" 14 | "github.com/lithammer/shortuuid" 15 | "github.com/rs/zerolog/log" 16 | ) 17 | 18 | // Simple hash function used to generate a string hash of the canvas uri 19 | // to have a unique stable annotation list id 20 | func hash(s string) string { 21 | h := fnv.New64a() 22 | h.Write([]byte(s)) 23 | return strconv.FormatUint(h.Sum64(), 16) 24 | } 25 | 26 | // List display the annotation list 27 | func List(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 28 | var body json.RawMessage 29 | canvas, _ := r.URL.Query()["canvas"] 30 | 31 | annotationlisthash := hash(canvas[0]) 32 | 33 | list := AnnotationList{ 34 | Context: "http://iiif.io/api/presentation/2/context.json", 35 | ID: "https://docuver.se/iiif/annotation/list" + annotationlisthash, 36 | Type: "sc:AnnotationList", 37 | } 38 | 39 | rows, err := db.Query("SELECT body FROM annotations where target=?", canvas[0]) 40 | if err != nil { 41 | log.Error().Err(err).Str("action", "list").Msg("db error") 42 | w.WriteHeader(http.StatusInternalServerError) 43 | w.Write([]byte("500")) 44 | return 45 | } 46 | defer rows.Close() 47 | for rows.Next() { 48 | err := rows.Scan(&body) 49 | if err != nil { 50 | log.Error().Err(err).Str("action", "list").Msg("db error") 51 | w.WriteHeader(http.StatusInternalServerError) 52 | w.Write([]byte("500")) 53 | return 54 | } 55 | list.Resources = append(list.Resources, body) 56 | } 57 | 58 | if len(list.Resources) == 0 { 59 | list.Resources = append(list.Resources, json.RawMessage("{}")) 60 | } 61 | 62 | w.Header().Set("Content-Type", "application/json") 63 | enc := json.NewEncoder(w) 64 | if err := enc.Encode(list); err != nil { 65 | log.Error().Err(err).Str("action", "list").Str("canvas", canvas[0]).Msg("annotation list error") 66 | w.WriteHeader(http.StatusInternalServerError) 67 | w.Write([]byte("500")) 68 | return 69 | } 70 | 71 | } 72 | 73 | // Get retrieve a single annotation with database id 74 | // NOTE: just for test, not used by mirador 75 | func Get(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 76 | w.Header().Set("Content-Type", "application/json") 77 | 78 | var body string 79 | err := db.QueryRow("SELECT body FROM annotations where id=?", ps.ByName("id")).Scan(&body) 80 | 81 | if err != nil { 82 | log.Error().Err(err).Str("action", "get").Msg("db error") 83 | w.WriteHeader(http.StatusInternalServerError) 84 | w.Write([]byte("500")) 85 | return 86 | } 87 | 88 | w.Header().Set("Content-Type", "application/json") 89 | fmt.Fprintf(w, body) 90 | } 91 | 92 | // Delete an annotation 93 | // the output of this controller is the annotation body that is being deleted 94 | func Delete(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 95 | 96 | var anno string 97 | err := db.QueryRow("SELECT body FROM annotations where annoid = ?", ps.ByName("id")).Scan(&anno) 98 | if err != nil { 99 | log.Error().Err(err).Str("action", "delete").Msg("db error") 100 | w.WriteHeader(http.StatusInternalServerError) 101 | w.Write([]byte("500")) 102 | return 103 | } 104 | 105 | _, err = db.Exec("DELETE FROM annotations where annoid=?", ps.ByName("id")) 106 | if err != nil { 107 | log.Error().Err(err).Str("action", "delete").Msg("db error") 108 | w.WriteHeader(http.StatusInternalServerError) 109 | w.Write([]byte("500")) 110 | return 111 | } 112 | log.Info().Str("annotation_id", ps.ByName("id")).Str("action", "delete").Msg("") 113 | w.Header().Set("Content-Type", "application/json") 114 | fmt.Fprintf(w, anno) 115 | } 116 | 117 | // Create an annotation 118 | func Create(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 119 | body, err := ioutil.ReadAll(r.Body) 120 | defer r.Body.Close() 121 | if err != nil { 122 | log.Error().Err(err).Str("action", "create").Msg("") 123 | w.WriteHeader(http.StatusInternalServerError) 124 | w.Write([]byte("500")) 125 | return 126 | } 127 | 128 | var annotation Annotation 129 | err = json.Unmarshal(body, &annotation) 130 | if err != nil { 131 | log.Error().Err(err).Str("action", "create").Msg("") 132 | w.WriteHeader(http.StatusInternalServerError) 133 | w.Write([]byte("500")) 134 | return 135 | } 136 | 137 | annoid := shortuuid.New() 138 | annotation.ID = "https://docuver.se/iiif/annotation/" + annoid 139 | AnnotationWithID, _ := json.Marshal(annotation) 140 | statement, _ := db.Prepare("INSERT INTO annotations (annoid, created_at, target, manifest, body) VALUES (?, ?, ?, ?, ?)") 141 | statement.Exec(annoid, time.Now(), annotation.Canvas(), annotation.Manifest(), AnnotationWithID) 142 | log.Info().Str("annotation_id", annoid).Str("action", "create").Msg("") 143 | 144 | fmt.Fprintf(w, string(AnnotationWithID)) 145 | } 146 | 147 | // Update an annotation 148 | func Update(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 149 | 150 | annoid := ps.ByName("id") 151 | 152 | body, err := ioutil.ReadAll(r.Body) 153 | defer r.Body.Close() 154 | if err != nil { 155 | log.Error().Err(err).Str("action", "update").Msg("db error") 156 | w.WriteHeader(http.StatusInternalServerError) 157 | w.Write([]byte("500")) 158 | return 159 | } 160 | 161 | _, err = db.Exec("UPDATE annotations SET body=? WHERE annoid=?", body, annoid) 162 | if err != nil { 163 | log.Error().Err(err).Str("action", "update").Msg("db error") 164 | w.WriteHeader(http.StatusInternalServerError) 165 | w.Write([]byte("500")) 166 | return 167 | } 168 | 169 | log.Info().Str("annotation_id", annoid).Str("action", "update").Msg("") 170 | 171 | fmt.Fprintf(w, string(body)) 172 | } 173 | -------------------------------------------------------------------------------- /static/mirador/plugins/visualchars/plugin.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var n,e,t,r,o=function(n){var e=n,t=function(){return e};return{get:t,set:function(n){e=n},clone:function(){return o(t())}}},u=tinymce.util.Tools.resolve("tinymce.PluginManager"),i=function(n){return{isEnabled:function(){return n.get()}}},c=function(n,e){return n.fire("VisualChars",{state:e})},a={"\xa0":"nbsp","\xad":"shy"},f=function(n,e){var t,r="";for(t in n)r+=t;return new RegExp("["+r+"]",e?"g":"")},l=function(n){var e,t="";for(e in n)t&&(t+=","),t+="span.mce-"+n[e];return t},s={charMap:a,regExp:f(a),regExpGlobal:f(a,!0),selector:l(a),charMapToRegExp:f,charMapToSelector:l},d=function(n){return function(){return n}},m={noop:function(){for(var n=[],e=0;e'+n+""},R=function(n,e){var t=[],r=n.dom(),o=N(r.childNodes,O.fromDom);return k(o,function(n){e(n)&&(t=t.concat([n])),t=t.concat(R(n,e))}),t},_={isMatch:function(n){return H.isText(n)&&H.value(n)!==undefined&&s.regExp.test(H.value(n))},filterDescendants:R,findParentElm:function(n,e){for(;n.parentNode;){if(n.parentNode===e)return n;n=n.parentNode}},replaceWithSpans:function(n){return n.replace(s.regExpGlobal,L)}},F=function(t,n){var r,o,e=_.filterDescendants(O.fromDom(n),_.isMatch);k(e,function(n){var e=_.replaceWithSpans(H.value(n));for(o=t.dom.create("div",null,e);r=o.lastChild;)t.dom.insertAfter(r,n.dom());t.dom.remove(n.dom())})},z=function(e,n){var t=e.dom.select(s.selector,n);k(t,function(n){e.dom.remove(n,1)})},G=F,W=z,I=function(n){var e=n.getBody(),t=n.selection.getBookmark(),r=_.findParentElm(n.selection.getNode(),e);r=r!==undefined?r:e,z(n,r),F(n,r),n.selection.moveToBookmark(t)},U=function(n,e){var t,r=n.getBody(),o=n.selection;e.set(!e.get()),c(n,e.get()),t=o.getBookmark(),!0===e.get()?G(n,r):W(n,r),o.moveToBookmark(t)},J=function(n,e){n.addCommand("mceVisualChars",function(){U(n,e)})},K=tinymce.util.Tools.resolve("tinymce.util.Delay"),Q=function(e,t){var r=K.debounce(function(){I(e)},300);!1!==e.settings.forced_root_block&&e.on("keydown",function(n){!0===t.get()&&(13===n.keyCode?I(e):r())})},X=function(t){return function(n){var e=n.control;t.on("VisualChars",function(n){e.active(n.state)})}};u.add("visualchars",function(n){var e,t=o(!1);return J(n,t),(e=n).addButton("visualchars",{active:!1,title:"Show invisible characters",cmd:"mceVisualChars",onPostRender:X(e)}),e.addMenuItem("visualchars",{text:"Show invisible characters",cmd:"mceVisualChars",onPostRender:X(e),selectable:!0,context:"view",prependToContext:!0}),Q(n,t),i(t)})}(); --------------------------------------------------------------------------------