├── htmlrdfa-exporter ├── __init__.py └── static │ └── js │ └── es6_modules │ ├── plugins │ ├── editor │ │ └── htmlrdfa-exporter.js │ └── documents-overview │ │ └── htmlrdfa-exporter.js │ └── htmlrdfa-exporter │ ├── tags.js │ ├── index.js │ ├── templates.js │ └── base.js ├── MANIFEST.in ├── README.md ├── setup.py ├── .gitignore └── LICENSE /htmlrdfa-exporter/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.md 3 | recursive-include htmlrdfa-exporter/static * 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fiduswriter-htmlrdfa 2 | HTML RDFa export filter for Fidus Writer 3 | 4 | **NOTICE:** Plugin is in need of maintenance and is currently not in a working state. 5 | -------------------------------------------------------------------------------- /htmlrdfa-exporter/static/js/es6_modules/plugins/editor/htmlrdfa-exporter.js: -------------------------------------------------------------------------------- 1 | import {HTMLRDFaExporter} from "../../htmlrdfa-exporter" 2 | 3 | export class EditorHTMLRDFa { 4 | constructor(editor) { 5 | this.editor = editor 6 | } 7 | 8 | init() { 9 | let exportMenu = this.editor.menu.headerbarModel.content.find(menu => menu.id==='export') 10 | 11 | exportMenu.content.push( 12 | { 13 | title: gettext('HTML+RDFa'), 14 | type: 'action', 15 | tooltip: gettext('Export the document to a HTML+RDFa file. It can be imported by dokieli'), 16 | action: editor => { 17 | new HTMLRDFaExporter( 18 | this.editor.getDoc(), 19 | this.editor.mod.db.bibDB, 20 | this.editor.mod.db.imageDB, 21 | this.editor.mod.styles.citationStyles, 22 | this.editor.mod.styles.citationLocales 23 | ) 24 | } 25 | } 26 | ) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import find_packages, setup 3 | 4 | with open(os.path.join(os.path.dirname(__file__), 'README.md')) as readme: 5 | README = readme.read() 6 | 7 | os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) 8 | 9 | setup( 10 | name='fiduswriter-htmlrdfa', 11 | version='3.3.0-dev.0', 12 | packages=find_packages(), 13 | include_package_data=True, 14 | license='AGPL License', 15 | description='A Fidus Writer plugin to export HTML+RDFa files.', 16 | long_description=README, 17 | url='https://github.com/fiduswriter/fiduswriter-htmlrdfa', 18 | author='Afshin Sadeghi', 19 | author_email='sadeghi@cs.uni-bonn.de', 20 | classifiers=[ 21 | 'Environment :: Web Environment', 22 | 'Framework :: Django', 23 | 'Framework :: Django :: 1.11', 24 | 'Intended Audience :: Developers', 25 | 'License :: OSI Approved :: GNU Affero General Public License v3', 26 | 'Operating System :: OS Independent', 27 | 'Programming Language :: Python', 28 | 'Programming Language :: Python :: 2.7', 29 | 'Topic :: Internet :: WWW/HTTP', 30 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 31 | ], 32 | ) 33 | -------------------------------------------------------------------------------- /htmlrdfa-exporter/static/js/es6_modules/plugins/documents-overview/htmlrdfa-exporter.js: -------------------------------------------------------------------------------- 1 | import {getMissingDocumentListData} from "../../documents/tools" 2 | 3 | import {HTMLRDFaExporter} from "../../htmlrdfa-exporter" 4 | 5 | export class DocOverviewHTMLRDFa { 6 | constructor(documentOverview) { 7 | this.documentOverview = documentOverview 8 | } 9 | 10 | init() { 11 | let docSelectorMenu = this.documentOverview.menu.model.content.find(menu => menu.id==='doc_selector') 12 | 13 | docSelectorMenu.content.push( 14 | { 15 | title: gettext('Export selected as HTML+RDFa'), 16 | action: overview => { 17 | let ids = this.documentOverview.getSelected() 18 | if (ids.length) { 19 | getMissingDocumentListData( 20 | ids, 21 | this.documentOverview.documentList 22 | ).then( 23 | () => ids.forEach(id => { 24 | let doc = this.documentOverview.documentList.find(entry => entry.id===id) 25 | new HTMLRDFaExporter( 26 | doc, 27 | {db:doc.bibliography}, 28 | {db:doc.images}, 29 | this.documentOverview.citationStyles, 30 | this.documentOverview.citationLocales 31 | ) 32 | }) 33 | ) 34 | } 35 | } 36 | } 37 | ) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | 103 | #JS 104 | *~ 105 | -------------------------------------------------------------------------------- /htmlrdfa-exporter/static/js/es6_modules/htmlrdfa-exporter/tags.js: -------------------------------------------------------------------------------- 1 | export const TAGS = [ 2 | { 3 | tag: 'deo:Acknowledgements', 4 | texts: ['acknowledgement', 'acknowledgements'] 5 | }, 6 | { 7 | tag: 'deo:FutureWork', 8 | texts: ['outlook', 'futurework', 'roadmap', 'plan'] 9 | }, 10 | { 11 | tag: 'deo:Conclusion', 12 | texts: ['conclusion', 'conclusions'] 13 | }, 14 | { 15 | tag: 'deo:Results', 16 | texts: ['results'] 17 | }, 18 | { 19 | tag: 'deo:Discussion', 20 | texts: ['analysis', 'discussion', 'discussions'] 21 | }, 22 | { 23 | tag: 'deo:RelatedWork', 24 | texts: ['relatedwork', 'literaturereview'] 25 | }, 26 | { 27 | tag: 'deo:Evaluation', 28 | texts: ['validation', 'evaluation', 'experiments', 'comparison', 'experimental'] 29 | }, 30 | { 31 | tag: 'deo:Motivation', 32 | texts: ['motivation', 'casestudy'] 33 | }, 34 | { 35 | tag: 'deo:ProblemStatement', 36 | texts: ['problem', 'approach', 'casedescription'] 37 | }, 38 | { 39 | tag: 'deo:Abstract', 40 | texts: ['abstract', 'summary'] 41 | }, 42 | { 43 | tag: 'deo:Introduction', 44 | texts: ['introduction'] 45 | }, 46 | { 47 | tag: 'deo:Methods', 48 | texts: ['approach', 'methodology', 'methods', 'proposedsolution', 'proposedapproach'] 49 | }, 50 | { 51 | tag: 'ssn:System', 52 | texts: ['framework', 'structure', 'system', 'architecture', 'implementation', 'implementing', 'schema'] 53 | }, 54 | { 55 | tag: 'swrc:Keywords', 56 | texts: ['keywords'] 57 | }, 58 | { 59 | tag: 'deo:Background', 60 | texts: ['background', 'concepts'] 61 | }, 62 | { 63 | tag: 'deo:Model', 64 | texts: ['modeling', 'model', 'representation', 'modelling'] 65 | }, 66 | { 67 | tag: 'deo:Reference', 68 | texts: ['references', 'reference'] 69 | } 70 | ] 71 | -------------------------------------------------------------------------------- /htmlrdfa-exporter/static/js/es6_modules/htmlrdfa-exporter/index.js: -------------------------------------------------------------------------------- 1 | import {createSlug} from "../exporter/tools/file" 2 | import {findImages} from "../exporter/tools/html" 3 | import {ZipFileCreator} from "../exporter/tools/zip" 4 | import {htmlExportTemplate} from "./templates" 5 | import {addAlert} from "../common" 6 | import {katexRender} from "../katex" 7 | import {BaseHTMLRDFaExporter} from "./base" 8 | import download from "downloadjs" 9 | 10 | export class HTMLRDFaExporter extends BaseHTMLRDFaExporter { 11 | constructor(doc, bibDB, imageDB, citationStyles, citationLocales) { 12 | super() 13 | this.doc = doc 14 | this.citationStyles = citationStyles 15 | this.citationLocales = citationLocales 16 | this.bibDB = bibDB 17 | this.imageDB = imageDB 18 | this.exportOne() 19 | } 20 | 21 | exportOne() { 22 | addAlert('info', this.doc.title + ': ' + gettext( 23 | 'HTML export has been initiated.')) 24 | 25 | this.joinDocumentParts().then(() => this.exportTwo() 26 | ) 27 | 28 | 29 | } 30 | 31 | exportTwo() { 32 | 33 | let styleSheets = [], 34 | math = false 35 | 36 | let title = this.doc.title 37 | 38 | let contents = this.contents 39 | 40 | let equations = contents.querySelectorAll('.equation') 41 | 42 | let figureEquations = contents.querySelectorAll('.figure-equation') 43 | 44 | let comments = [] 45 | for (let comment in this.doc.comments) { 46 | comments.push(this.doc.comments[comment]) 47 | } 48 | 49 | if (equations.length > 0 || figureEquations.length > 0) { 50 | math = true 51 | styleSheets.push({ 52 | filename: 'katex.min.css' 53 | }) 54 | } 55 | 56 | for (let i = 0; i < equations.length; i++) { 57 | let node = equations[i] 58 | let formula = node.getAttribute('data-equation') 59 | katexRender(formula, node, { 60 | throwOnError: false 61 | }) 62 | } 63 | for (let i = 0; i < figureEquations.length; i++) { 64 | let node = figureEquations[i] 65 | let formula = node.getAttribute('data-equation') 66 | katexRender(formula, node, { 67 | displayMode: true, 68 | throwOnError: false 69 | }) 70 | } 71 | 72 | let includeZips = [] 73 | 74 | let httpOutputList = findImages(contents) 75 | 76 | contents = this.addSectionsTag(contents) 77 | 78 | contents = this.addFigureNumbers(contents) 79 | 80 | contents = this.converTitleToRDFa(contents) 81 | 82 | contents = this.convertAbstractToRDF(contents) 83 | 84 | contents = this.converAuthorsToRDFa(contents) 85 | 86 | contents = this.convertCommentsToRDFa(contents) 87 | 88 | let sidetagList = [] 89 | contents = this.convertSideCommentsToRDFa(contents,this.doc.comments, sidetagList) 90 | 91 | contents = this.adjustSections(contents,sidetagList) 92 | 93 | contents = this.addRefeneces(contents) 94 | 95 | contents = this.addRefeneceRDFa(contents) 96 | 97 | 98 | let contentsCode = this.replaceImgSrc(contents.innerHTML) 99 | 100 | let dom = htmlExportTemplate({ 101 | part: false, 102 | title, 103 | metadata: this.doc.metadata, 104 | settings: this.doc.settings, 105 | styleSheets, 106 | contents: contentsCode 107 | }) 108 | 109 | let outputList = [{ 110 | filename: 'document.html', 111 | contents: dom 112 | }] 113 | if (comments.length > 0) { 114 | for (let i = 0; i < comments.length; i++) { 115 | let node = comments[i] 116 | outputList.push(this.createComment(node)) 117 | } 118 | 119 | } 120 | 121 | for (let i = 0; i < styleSheets.length; i++) { 122 | let styleSheet = styleSheets[i] 123 | if (styleSheet.contents) { 124 | outputList.push(styleSheet) 125 | } 126 | } 127 | 128 | if (math) { 129 | includeZips.push({ 130 | 'directory': '', 131 | 'url': window.staticUrl + 'zip/katex-style.zip', 132 | }) 133 | } 134 | 135 | let zipper = new ZipFileCreator( 136 | outputList, 137 | httpOutputList, 138 | includeZips 139 | ) 140 | 141 | zipper.init().then( 142 | blob => download(blob, createSlug(title) + '.html.zip', 143 | 'application/zip') 144 | ) 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /htmlrdfa-exporter/static/js/es6_modules/htmlrdfa-exporter/templates.js: -------------------------------------------------------------------------------- 1 | import {escapeText} from "../common" 2 | /** A template for HTML+RDFa export of a document. Using dokieli template */ 3 | export let htmlExportTemplate = ({title, styleSheets, part, contents}) => 4 | ` 5 | 6 |
7 |${sidetags}` 209 | sidetagList.push(sideTagNode) 210 | } 211 | }) 212 | return htmlCode 213 | } 214 | 215 | adjustSections(htmlCode, sidetagList) { 216 | 217 | jQuery(htmlCode).find('section').each(function(index) { 218 | 219 | let next = this.nextSibling, 220 | divNode = jQuery(this).find( 221 | 'div[datatype="rdf:HTML"]')[0] 222 | if (divNode) { 223 | while (next && next.localName != 'section') { 224 | this.parentNode.removeChild(next) 225 | divNode.appendChild(next) 226 | next = this.nextSibling 227 | if (!next) { 228 | break 229 | } 230 | } 231 | } else { 232 | while (next && next.localName != 'section') { 233 | this.parentNode.removeChild(next) 234 | this.appendChild(next) 235 | next = this.nextSibling 236 | if (!next) { 237 | break 238 | } 239 | } 240 | } 241 | }) 242 | if (sidetagList.length > 0) { 243 | jQuery(htmlCode).find('section').each(function() { 244 | let tags = [] 245 | jQuery(this).find('span.comment').each(function() { 246 | for (let i = 0; i < sidetagList.length; i++) { 247 | if (sidetagList[i].innerHTML.includes( 248 | jQuery(this).attr('data-id') 249 | )) { 250 | tags.push(sidetagList[i]) 251 | } 252 | } 253 | }) 254 | if (tags.length > 0) { 255 | for (let i = 0; i < tags.length; i++) { 256 | this.appendChild(tags[i]) 257 | } 258 | } 259 | }) 260 | 261 | jQuery(htmlCode).each(function() { 262 | let script = document.createElement('script') 263 | script.innerHTML = 264 | `jQuery( document ).ready(function() { 265 | jQuery(this).find('span.comment').each(function () { 266 | var id=jQuery(this).attr('data-id'); 267 | var top=jQuery(this).offset().top - 40; 268 | jQuery(document).find('article[id="'+id+'"]').each(function () { 269 | jQuery(this).css('top',top); 270 | }); 271 | }); 272 | });` 273 | this.appendChild(script) 274 | }) 275 | 276 | } 277 | return htmlCode 278 | } 279 | 280 | addSectionsTag(dom) { 281 | let className, rdfaType 282 | 283 | jQuery(dom).find('h3').each(function(index) { 284 | if (this.classList !== null && this.innerHTML !== null) { 285 | className = this.innerText 286 | className = escapeText(className.replace(/\s+/g, '')) 287 | if (className !== null && className !== "") { 288 | this.classList.add(className) 289 | this.id = className 290 | this.outerHTML = 291 | `
Comment
97 |