├── .czrc.json ├── nodemon.json ├── .prettierrc ├── changelog.config.js ├── src ├── img │ └── favicon-32x32.png ├── html │ └── index.html └── js │ └── app.js ├── docs └── images │ ├── cwrcwriter-high-level-diagram.png │ ├── oauth.svg │ └── cwrc-gitwriter-overview.svg ├── .env-cmdrc.json ├── .dockerignore ├── Dockerfile.dev ├── server ├── index.mjs ├── server.mjs └── dev │ └── dev.mjs ├── ecosystem.config.js ├── Dockerfile ├── .eslintrc ├── babel.config.json ├── .gitignore ├── issue_template.md ├── webpack.dev.js ├── webpack.prod.js ├── .github └── workflows │ ├── main.yml │ ├── next.yml │ └── development.yml ├── package.json ├── webpack.common.js ├── config └── config.json └── README.md /.czrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "git-cz" 3 | } -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["server"] 3 | } -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "singleQuote": true 4 | } -------------------------------------------------------------------------------- /changelog.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | maxMessageLength: 110, 3 | }; 4 | -------------------------------------------------------------------------------- /src/img/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cwrc/CWRC-GitWriter/HEAD/src/img/favicon-32x32.png -------------------------------------------------------------------------------- /docs/images/cwrcwriter-high-level-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cwrc/CWRC-GitWriter/HEAD/docs/images/cwrcwriter-high-level-diagram.png -------------------------------------------------------------------------------- /.env-cmdrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "development": { 3 | "NODE_ENV": "development" 4 | }, 5 | "production": { 6 | "NODE_ENV": "production" 7 | } 8 | } -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | 3 | # Coverage directory used by tools like istanbul 4 | coverage 5 | 6 | # Dependency directories 7 | node_modules 8 | 9 | # build 10 | -------------------------------------------------------------------------------- /Dockerfile.dev: -------------------------------------------------------------------------------- 1 | # CWRC-GitWriter 2 | 3 | FROM node:14.15.1 4 | 5 | WORKDIR /apps/CWRC-GitWriter 6 | 7 | COPY . . 8 | 9 | CMD ["npm", "run", "middleware-server-dev"] 10 | 11 | EXPOSE 3000 -------------------------------------------------------------------------------- /server/index.mjs: -------------------------------------------------------------------------------- 1 | import { app } from './server.mjs'; 2 | const port = process.env.PORT || 3000; 3 | 4 | // isDev(); 5 | 6 | app.listen(port, () => { 7 | console.log(`Server started on port ${port}`); 8 | }); 9 | -------------------------------------------------------------------------------- /ecosystem.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | apps: [{ 3 | name: 'cwrc-gitwriter', 4 | script: './server/index.mjs', 5 | args: '--no-daemon', 6 | env: { NODE_ENV: 'production' }, 7 | env_production: { NODE_ENV: 'production' }, 8 | }], 9 | }; 10 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # CWRC-GitWriter 2 | 3 | FROM node:14.15.1 4 | 5 | WORKDIR /apps/CWRC-GitWriter 6 | 7 | RUN npm install pm2 -g 8 | 9 | COPY . . 10 | 11 | RUN npm install && \ 12 | npm run build 13 | 14 | # CMD ["pm2", "start", "./server/server.js", "--no-daemon"] 15 | CMD ["pm2-runtime", "ecosystem.config.js"] 16 | 17 | EXPOSE 3000 18 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "jquery": true, 6 | "node": true 7 | }, 8 | "extends": ["eslint:recommended", "prettier"], 9 | "globals": { 10 | "Atomics": "readonly", 11 | "SharedArrayBuffer": "readonly" 12 | }, 13 | "parser": "@babel/eslint-parser", 14 | "parserOptions": { 15 | "allowImportExportEverywhere": true, 16 | "ecmaVersion": 2020, 17 | "sourceType": "module" 18 | }, 19 | "rules": { 20 | "no-unused-vars": 2 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /server/server.mjs: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { fileURLToPath } from 'url'; 3 | import express from 'express'; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = path.dirname(__filename); 7 | const publicPath = path.join(__dirname, '..', 'build'); 8 | 9 | export const app = express(); 10 | 11 | // export const isDev = async () => { 12 | // if (process.env.NODE_ENV === 'development') { 13 | // const { devTools } = await import('./dev/dev.mjs'); 14 | // devTools(app); 15 | // } 16 | // }; 17 | 18 | //make content available 19 | app.use(express.static(publicPath)); 20 | -------------------------------------------------------------------------------- /babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-react" 5 | ], 6 | "plugins": [ 7 | "@babel/plugin-proposal-class-properties" 8 | ], 9 | "overrides": [{ 10 | "include": [ 11 | "./node_modules/cwrc-writer-base/node_modules/tinymce/tinymce.js", 12 | "./node_modules/cwrc-writer-base/node_modules/react-dom/cjs/react-dom.development.js", 13 | "./node_modules/cwrc-writer-base/node_modules/openseadragon/build/openseadragon/openseadragon.js", 14 | "./node_modules/cwrc-git-dialogs/node_modules/react-dom/cjs/react-dom.development.js" 15 | ], 16 | "compact": true 17 | }] 18 | } -------------------------------------------------------------------------------- /src/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CWRC-Writer 7 | 8 | 9 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /server/dev/dev.mjs: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack'; 2 | import webpackDevMiddleware from 'webpack-dev-middleware'; 3 | import webpackHotMiddleware from 'webpack-hot-middleware'; 4 | 5 | import config from '../../webpack.dev.js'; 6 | 7 | export const devTools = (app) => { 8 | //webpack middleware and hot reload 9 | config.entry.app.unshift('webpack-hot-middleware/client?reload=true&timeout=1000'); //Auto-reloading when webpack detects any changes 10 | config.plugins.push(new webpack.HotModuleReplacementPlugin()); //Add HMR plugin 11 | const compiler = webpack(config); 12 | app.use( 13 | webpackDevMiddleware(compiler, { 14 | publicPath: config.output.publicPath, 15 | writeToDisk: true, 16 | }) 17 | ); 18 | 19 | // Enable "webpack-hot-middleware" 20 | app.use(webpackHotMiddleware(compiler)); 21 | 22 | console.log('Dev Server is online!'); 23 | }; 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | /dist 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | .idea 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # nyc test coverage 22 | .nyc_output 23 | 24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 25 | .grunt 26 | 27 | # node-waf configuration 28 | .lock-wscript 29 | 30 | # Compiled binary addons (http://nodejs.org/api/addons.html) 31 | build/Release 32 | 33 | # Dependency directories 34 | node_modules 35 | jspm_packages 36 | 37 | # Optional npm cache directory 38 | .npm 39 | 40 | # Optional REPL history 41 | .node_repl_history 42 | 43 | build 44 | /bin/ 45 | /classes/ 46 | .classpath 47 | .settings 48 | 49 | .DS_Store 50 | 51 | /config/config.json -------------------------------------------------------------------------------- /issue_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Expected Behaviour 4 | 5 | 6 | 7 | # Current Behaviour 8 | 9 | 10 | 11 | # Possible Solution 12 | 13 | 14 | 15 | # Steps to Reproduce (for bugs) 16 | 17 | 18 | 19 | 20 | 1. 21 | 2. 22 | 3. 23 | 4. 24 | 25 | ## Your Environment 26 | 27 | * URL: 28 | 29 | * Browser Name: 30 | 31 | * Operating System: 32 | 33 | * Attachements: 34 | 35 | 36 | * CWRC user name if submitting an issue for the CWRC research space, or the Github username if using GitWriter. 37 | -------------------------------------------------------------------------------- /webpack.dev.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const { merge } = require('webpack-merge'); 4 | 5 | const common = require('./webpack.common.js'); 6 | 7 | module.exports = merge(common, { 8 | // devtool: 'inline-cheap-module-source-map', 9 | devtool: false, 10 | cache: true, 11 | performance: { hints: false }, 12 | output: { pathinfo: true }, 13 | optimization: { 14 | namedModules: true, 15 | namedChunks: true, 16 | nodeEnv: 'development', 17 | flagIncludedChunks: false, 18 | occurrenceOrder: false, 19 | sideEffects: false, 20 | usedExports: false, 21 | concatenateModules: false, 22 | noEmitOnErrors: false, 23 | checkWasmTypes: false, 24 | minimize: false, 25 | removeAvailableModules: false, 26 | }, 27 | plugins: [ 28 | new webpack.NamedModulesPlugin(), 29 | new webpack.NamedChunksPlugin(), 30 | new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('development') }), 31 | new webpack.EvalSourceMapDevToolPlugin({ 32 | module: true, 33 | columns: true, 34 | exclude: [ 35 | // /jquery/, 36 | // /tinymce.js/, 37 | // /bootstrap/, 38 | /react/, 39 | /openseadragon/, 40 | /moment/, 41 | ], 42 | }), 43 | ], 44 | devServer: { 45 | contentBase: path.join(__dirname, 'build'), 46 | port: 3000, 47 | host: 'localhost', 48 | }, 49 | }); 50 | -------------------------------------------------------------------------------- /webpack.prod.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const { merge } = require('webpack-merge'); 3 | const TerserPlugin = require('terser-webpack-plugin'); 4 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); 5 | 6 | const common = require('./webpack.common.js'); 7 | 8 | module.exports = merge(common, { 9 | devtool: false, 10 | performance: { hints: 'warning' }, 11 | output: { pathinfo: false }, 12 | optimization: { 13 | namedModules: false, 14 | namedChunks: false, 15 | nodeEnv: 'production', 16 | flagIncludedChunks: true, 17 | occurrenceOrder: true, 18 | sideEffects: true, 19 | usedExports: true, 20 | concatenateModules: true, 21 | noEmitOnErrors: true, 22 | checkWasmTypes: true, 23 | minimize: true, 24 | minimizer: [ 25 | new TerserPlugin({ 26 | cache: true, //default 27 | parallel: true, // default 28 | sourceMap: true, //use sourceMapDevToolPlugin 29 | }), 30 | new OptimizeCSSAssetsPlugin({}), 31 | ], 32 | }, 33 | plugins: [ 34 | new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }), 35 | new webpack.optimize.ModuleConcatenationPlugin(), 36 | new webpack.NoEmitOnErrorsPlugin(), 37 | new webpack.SourceMapDevToolPlugin({ 38 | filename: 'js/app.js.map', 39 | module: true, 40 | columns: true, 41 | noSources: false, 42 | namespace: '', 43 | exclude: [/jquery/, /tinymce.js/, /bootstrap/, /react/, /openseadragon/, /moment/], 44 | }), 45 | ], 46 | }); 47 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI (main) 2 | 3 | # Controls when the workflow will run 4 | on: 5 | # Triggers the workflow on push or pull request events but only for the master branch 6 | push: 7 | branches: [ master, main ] 8 | tags: 9 | - 'v*.*.*' 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | jobs: 15 | docker: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - 19 | name: Checkout 20 | uses: actions/checkout@v2 21 | - 22 | name: Docker meta 23 | id: meta 24 | uses: docker/metadata-action@v3 25 | with: 26 | # list of Docker images to use as base name for tags 27 | # assumes image named after owner/repository 28 | images: | 29 | ${{ github.repository }} 30 | # generate Docker tags based on the following events/attributes 31 | tags: | 32 | type=raw,value=latest 33 | type=schedule 34 | type=ref,event=branch 35 | type=ref,event=pr 36 | type=semver,pattern={{version}} 37 | type=semver,pattern={{major}}.{{minor}} 38 | type=semver,pattern={{major}} 39 | type=sha 40 | - 41 | name: Set up QEMU 42 | uses: docker/setup-qemu-action@v1 43 | - 44 | name: Set up Docker Buildx 45 | uses: docker/setup-buildx-action@v1 46 | - 47 | name: Login to DockerHub 48 | if: github.event_name != 'pull_request' 49 | uses: docker/login-action@v1 50 | with: 51 | username: ${{ secrets.DOCKERHUB_USERNAME }} 52 | password: ${{ secrets.DOCKERHUB_TOKEN }} 53 | - 54 | name: Build and push 55 | uses: docker/build-push-action@v2 56 | with: 57 | context: . 58 | push: ${{ github.event_name != 'pull_request' }} 59 | tags: ${{ steps.meta.outputs.tags }} 60 | labels: ${{ steps.meta.outputs.labels }} 61 | 62 | -------------------------------------------------------------------------------- /.github/workflows/next.yml: -------------------------------------------------------------------------------- 1 | # Workflow to align with special naming of `next` branch to DockerHub `dev-next` convention 2 | # ToDo: stopgap - find better way to map Git branch to custom tag name (in ways not supported by docker/metadata-action) 3 | 4 | name: CI (next branch) 5 | 6 | # Controls when the workflow will run 7 | on: 8 | # Triggers the workflow on push or pull request events but only for the master branch 9 | push: 10 | branches: [ next ] 11 | tags: 12 | - 'v*.*.*' 13 | 14 | # Allows you to run this workflow manually from the Actions tab 15 | workflow_dispatch: 16 | 17 | jobs: 18 | docker: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - 22 | name: Checkout 23 | uses: actions/checkout@v2 24 | - 25 | name: Docker meta 26 | id: meta 27 | uses: docker/metadata-action@v3 28 | with: 29 | # list of Docker images to use as base name for tags 30 | # assumes image named after owner/repository 31 | images: | 32 | ${{ github.repository }} 33 | # generate Docker tags based on the following events/attributes 34 | tags: | 35 | type=raw,value=dev-next 36 | type=ref,event=branch 37 | type=sha 38 | - 39 | name: Set up QEMU 40 | uses: docker/setup-qemu-action@v1 41 | - 42 | name: Set up Docker Buildx 43 | uses: docker/setup-buildx-action@v1 44 | - 45 | name: Login to DockerHub 46 | if: github.event_name != 'pull_request' 47 | uses: docker/login-action@v1 48 | with: 49 | username: ${{ secrets.DOCKERHUB_USERNAME }} 50 | password: ${{ secrets.DOCKERHUB_TOKEN }} 51 | - 52 | name: Build and push 53 | uses: docker/build-push-action@v2 54 | with: 55 | context: . 56 | push: ${{ github.event_name != 'pull_request' }} 57 | tags: ${{ steps.meta.outputs.tags }} 58 | labels: ${{ steps.meta.outputs.labels }} 59 | 60 | -------------------------------------------------------------------------------- /.github/workflows/development.yml: -------------------------------------------------------------------------------- 1 | # Workflow to align with special naming of `development` branch to DockerHub `dev-latest` convention 2 | # ToDo: stopgap - find better way to map Git branch to custom tag name (in ways not supported by docker/metadata-action) 3 | 4 | name: CI (development branch) 5 | 6 | # Controls when the workflow will run 7 | on: 8 | # Triggers the workflow on push or pull request events but only for the master branch 9 | push: 10 | branches: [ development ] 11 | tags: 12 | - 'v*.*.*' 13 | 14 | # Allows you to run this workflow manually from the Actions tab 15 | workflow_dispatch: 16 | 17 | jobs: 18 | docker: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - 22 | name: Checkout 23 | uses: actions/checkout@v2 24 | - 25 | name: Docker meta 26 | id: meta 27 | uses: docker/metadata-action@v3 28 | with: 29 | # list of Docker images to use as base name for tags 30 | # assumes image named after owner/repository 31 | images: | 32 | ${{ github.repository }} 33 | # generate Docker tags based on the following events/attributes 34 | tags: | 35 | type=raw,value=dev-latest 36 | type=ref,event=branch 37 | type=sha 38 | - 39 | name: Set up QEMU 40 | uses: docker/setup-qemu-action@v1 41 | - 42 | name: Set up Docker Buildx 43 | uses: docker/setup-buildx-action@v1 44 | - 45 | name: Login to DockerHub 46 | if: github.event_name != 'pull_request' 47 | uses: docker/login-action@v1 48 | with: 49 | username: ${{ secrets.DOCKERHUB_USERNAME }} 50 | password: ${{ secrets.DOCKERHUB_TOKEN }} 51 | - 52 | name: Build and push 53 | uses: docker/build-push-action@v2 54 | with: 55 | context: . 56 | push: ${{ github.event_name != 'pull_request' }} 57 | tags: ${{ steps.meta.outputs.tags }} 58 | labels: ${{ steps.meta.outputs.labels }} 59 | 60 | -------------------------------------------------------------------------------- /src/js/app.js: -------------------------------------------------------------------------------- 1 | import dbpedia from 'dbpedia-entity-lookup'; 2 | import geonames from 'geonames-entity-lookup'; 3 | import getty from 'getty-entity-lookup'; 4 | import lgpn from 'lgpn-entity-lookup'; 5 | import viaf from 'viaf-entity-lookup'; 6 | import wikidata from 'wikidata-entity-lookup'; 7 | 8 | import GitStorageDialogs from 'cwrc-git-dialogs'; 9 | import EntityLookupDialogs from 'cwrc-public-entity-dialogs'; 10 | 11 | import CWRCWriter from 'cwrc-writer-base'; 12 | 13 | EntityLookupDialogs.showNoLinkButton(true); 14 | EntityLookupDialogs.showCreateNewButton(false); 15 | EntityLookupDialogs.showEditButton(false); 16 | EntityLookupDialogs.registerEntitySources({ 17 | rs: new Map().set('viaf', viaf).set('wikidata', wikidata).set('dbpedia', dbpedia), 18 | person: new Map() 19 | .set('viaf', viaf) 20 | .set('wikidata', wikidata) 21 | .set('getty', getty) 22 | .set('dbpedia', dbpedia) 23 | .set('lgpn', lgpn), 24 | place: new Map() 25 | .set('geonames', geonames) 26 | .set('viaf', viaf) 27 | .set('dbpedia', dbpedia) 28 | .set('wikidata', wikidata), 29 | organization: new Map().set('viaf', viaf).set('wikidata', wikidata).set('dbpedia', dbpedia), 30 | title: new Map().set('viaf', viaf).set('wikidata', wikidata).set('dbpedia', dbpedia), 31 | }); 32 | 33 | // if (process.env.NODE_ENV === 'development') { 34 | // GitStorageDialogs.setServerURL('http://localhost:3000/github'); 35 | // } else { 36 | GitStorageDialogs.setServerURL('./github'); 37 | // } 38 | 39 | const init = async () => { 40 | const configRequest = await fetch('./config/config.json').catch((err) => { 41 | console.log(err); 42 | }); 43 | const config = await configRequest.json(); 44 | 45 | // if (process.env.NODE_ENV === 'development') { 46 | // config.schema.schemaProxyUrl = 'http://localhost:3000'; 47 | // } 48 | 49 | config.container = 'cwrcWriterContainer'; 50 | config.modules = { 51 | west: [ 52 | { id: 'structure', title: 'Markup' }, 53 | { id: 'entities', title: 'Entities' }, 54 | { 55 | id: 'nerve', 56 | title: 'NERVE', 57 | config: { nerveUrl: config.nerveUrl }, 58 | }, 59 | ], 60 | south: [ 61 | { id: 'selection', title: 'Selection' }, 62 | { 63 | id: 'validation', 64 | title: 'Validation', 65 | config: { validationUrl: config.validationUrl }, 66 | }, 67 | ], 68 | east: [{ id: 'imageViewer', title: 'Image Viewer' }], 69 | }; 70 | config.entityLookupDialogs = EntityLookupDialogs; 71 | config.storageDialogs = GitStorageDialogs; 72 | 73 | //setup geonames 74 | if (config.lookups.geonames.username && config.lookups.geonames.username !== '') { 75 | geonames.credentials.username = config.lookups.geonames.username; 76 | } 77 | 78 | const writer = new CWRCWriter(config); 79 | 80 | window.writer = writer; 81 | 82 | writer.event('writerInitialized').subscribe(() => { 83 | writer.showLoadDialog(); 84 | }); 85 | }; 86 | 87 | init(); 88 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cwrc-git-writer", 3 | "version": "0.0.0", 4 | "description": "xml editing and rdf annotation using github as document store", 5 | "keywords": [ 6 | "xml", 7 | "rdf", 8 | "editor", 9 | "annotation" 10 | ], 11 | "homepage": "https://github.com/cwrc/CWRC-GitWriter", 12 | "bugs": { 13 | "url": "https://github.com/cwrc/CWRC-GitWriter/issues" 14 | }, 15 | "license": "GPL-2.0", 16 | "contributors": [ 17 | "Andrew MacDonald ", 18 | "James Chartrand ", 19 | "Luciano Frizzera " 20 | ], 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/cwrc/CWRC-GitWriter.git" 24 | }, 25 | "scripts": { 26 | "start": "env-cmd -e production node ./server/server.js", 27 | "middleware-server-dev": "env-cmd -e development nodemon -L ./server/index.mjs", 28 | "dev-server": "npm run cwrc-writer-editor-css-dev & webpack-dev-server --config webpack.dev.js", 29 | "webpack-dev": "npm run build-cwrc-writer-base && webpack --config webpack.dev.js --debug=true --display-error-details=true", 30 | "webpack-dev-watch": "env-cmd -e development npm run cwrc-writer-editor-css-dev & webpack --config webpack.dev.js --debug=true --display-error-details=true --watch", 31 | "cwrc-writer-editor-css-dev": "cd \"node_modules/cwrc-writer-base\" && npm run build-editor-css-dev", 32 | "build": "npm run build-cwrc-writer-base && npm run webpack-prod && npm run mockup-ui:copy-files", 33 | "build-cwrc-writer-base": "cd \"node_modules/cwrc-writer-base\" && npm run build", 34 | "webpack-prod": "webpack --config webpack.prod.js", 35 | "stats": "webpack --profile --json > stats.json", 36 | "analyzer": "webpack-bundle-analyzer stats.json", 37 | "mockup-ui:copy-files": "copyfiles -u 1 mockup-ui/* mockup-ui/**/* build/mockup-ui", 38 | "cm": "git-cz" 39 | }, 40 | "dependencies": { 41 | "cwrc-git-dialogs": "^4.0.0", 42 | "cwrc-public-entity-dialogs": "^4.0.0", 43 | "cwrc-writer-base": "^8.2.0", 44 | "dbpedia-entity-lookup": "^2.0.0", 45 | "env-cmd": "^10.1.0", 46 | "express": "^4.18.1", 47 | "geonames-entity-lookup": "^2.1.0", 48 | "getty-entity-lookup": "^2.3.2", 49 | "lgpn-entity-lookup": "^2.2.0", 50 | "viaf-entity-lookup": "^2.1.0", 51 | "wikidata-entity-lookup": "^2.1.0" 52 | }, 53 | "devDependencies": { 54 | "@babel/core": "^7.19.3", 55 | "@babel/eslint-parser": "^7.19.1", 56 | "@babel/plugin-proposal-class-properties": "^7.18.6", 57 | "@babel/plugin-syntax-dynamic-import": "^7.8.3", 58 | "@babel/plugin-transform-react-jsx": "^7.19.0", 59 | "@babel/plugin-transform-runtime": "^7.19.1", 60 | "@babel/preset-env": "^7.19.3", 61 | "@babel/preset-react": "^7.18.6", 62 | "@babel/runtime-corejs2": "^7.19.2", 63 | "babel-loader": "^8.2.5", 64 | "clean-webpack-plugin": "^3.0.0", 65 | "commitizen": "^4.2.5", 66 | "copy-webpack-plugin": "^6.4.1", 67 | "copyfiles": "^2.4.1", 68 | "css-loader": "^4.3.0", 69 | "eslint": "^7.32.0", 70 | "eslint-config-prettier": "^8.5.0", 71 | "eslint-plugin-prettier": "^3.4.1", 72 | "file-loader": "^6.2.0", 73 | "git-cz": "^4.9.0", 74 | "html-webpack-externals-plugin": "^3.8.0", 75 | "html-webpack-plugin": "^4.5.2", 76 | "image-webpack-loader": "^7.0.1", 77 | "less": "^4.1.3", 78 | "less-loader": "^7.3.0", 79 | "less-watch-compiler": "^1.16.3", 80 | "mini-css-extract-plugin": "^0.11.3", 81 | "nodemon": "^2.0.20", 82 | "optimize-css-assets-webpack-plugin": "^5.0.8", 83 | "prettier": "^2.7.1", 84 | "style-loader": "^1.3.0", 85 | "svg-inline-loader": "^0.8.2", 86 | "terser-webpack-plugin": "^4.2.3", 87 | "url-loader": "^4.1.1", 88 | "webpack": "^4.46.0", 89 | "webpack-bundle-analyzer": "^3.9.0", 90 | "webpack-cli": "^3.3.12", 91 | "webpack-dev-middleware": "^3.7.3", 92 | "webpack-dev-server": "^3.11.3", 93 | "webpack-hot-middleware": "^2.25.2", 94 | "webpack-merge": "^5.4.0", 95 | "webpackbar": "^4.0.0" 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /webpack.common.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 3 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 4 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin'); 6 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 7 | const WebpackBar = require('webpackbar'); 8 | 9 | module.exports = { 10 | entry: { 11 | app: ['./src/js/app.js'], 12 | }, 13 | mode: 'none', // all mode defaults for dev and prod and set in the respective configs 14 | output: { 15 | filename: 'js/[name].js', 16 | path: path.resolve(__dirname, 'build'), 17 | publicPath: './', 18 | }, 19 | plugins: [ 20 | new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }), 21 | new CopyWebpackPlugin({ 22 | patterns: [{ 23 | //copy config.json 24 | context: 'config/', 25 | from: '*', 26 | to: 'config', 27 | }, 28 | { 29 | //copy images for GitWriter (favicon) 30 | context: 'src/img', 31 | from: '*', 32 | to: 'img', 33 | }, 34 | { 35 | //copy images from Writer-Base 36 | context: 'node_modules/cwrc-writer-base/src/img', 37 | from: '*', 38 | to: 'img', 39 | }, 40 | { 41 | //Copy pre-compiled CSS required by tinyMCE 42 | context: 'node_modules/cwrc-writer-base/src/css/tinymce/', 43 | from: '*.css', 44 | to: 'css/tinymce', 45 | }, 46 | { 47 | //Copy pre-compiled CSS to stylize the editor (must be recompiled after each change) 48 | context: 'node_modules/cwrc-writer-base/src/css/build/', 49 | from: 'editor.css', 50 | to: 'css/editor.css', 51 | toType: 'file', 52 | }], 53 | }), 54 | new HtmlWebpackPlugin({ 55 | template: 'src/html/index.html', 56 | inject: 'body', 57 | }), 58 | new MiniCssExtractPlugin({ 59 | filename: '/css/[name].css', 60 | chunkFilename: '/css/[id].css', 61 | }), 62 | new HtmlWebpackExternalsPlugin({ 63 | externals: [{ 64 | module: 'rdflib', 65 | global: '$rdf', 66 | entry: { 67 | path: 'rdflib.min.js', 68 | cwpPatternConfig: { 69 | context: path.resolve( 70 | __dirname, 71 | 'node_modules/cwrc-writer-base/src/lib' 72 | ), 73 | }, 74 | }, 75 | }], 76 | outputPath: 'js', 77 | }), 78 | new WebpackBar({ color: '#0099ff' }), 79 | ], 80 | module: { 81 | rules: [ 82 | { 83 | test: /\.(js|jsx)$/, 84 | use: [{ 85 | loader: 'babel-loader', 86 | options: { 87 | sourceType: 'unambiguous', 88 | presets: ['@babel/preset-env', '@babel/preset-react'], 89 | plugins: [ 90 | '@babel/plugin-proposal-class-properties', [ 91 | '@babel/plugin-transform-runtime', { 92 | absoluteRuntime: false, 93 | corejs: false, 94 | helpers: false, 95 | regenerator: true, 96 | useESModules: false, 97 | }, 98 | ], 99 | ], 100 | }, 101 | }], 102 | }, 103 | { 104 | test: /\.(le|c)ss$/, 105 | use: [{ 106 | loader: MiniCssExtractPlugin.loader, 107 | options: { 108 | // you can specify a publicPath here 109 | // by default it uses publicPath in webpackOptions.output 110 | publicPath: '../', 111 | esModule: true, 112 | hmr: process.env.NODE_ENV === 'development', //allows to use this plugin in DEV 113 | }, 114 | }, 115 | { loader: 'css-loader' /* translates CSS into CommonJS*/ }, 116 | { 117 | loader: 'less-loader', // compiles Less to CSS //more: https://itnext.io/webpack-and-less-a75e04aaf528 118 | options: { 119 | lessOptions: { 120 | relativeUrls: 'local', //https://github.com/webpack-contrib/less-loader/issues/109, 121 | globalVars: { parentId: '#cwrcWriterContainer' }, 122 | }, 123 | }, 124 | }], 125 | }, 126 | { 127 | test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/, 128 | enforce: 'pre', // preload the jshint loader 129 | use: [{ 130 | loader: 'url-loader', 131 | options: { 132 | query: { limit: 25000 }, 133 | }, 134 | }], 135 | }, 136 | { 137 | test: /\.(png|jpg|jpeg|gif)$/i, 138 | enforce: 'pre', // preload the jshint loader 139 | // exclude: /node_modules/, // exclude any and all files in the node_modules folder 140 | use: [{ 141 | loader: 'file-loader', 142 | options: { 143 | name: '[name].[ext]', 144 | outputPath: 'img', 145 | }, 146 | }, 147 | { 148 | loader: 'image-webpack-loader', 149 | options: { disable: true /* webpack@2.x and newer */ }, 150 | }], 151 | }, 152 | { 153 | test: /\.svg$/, 154 | loader: 'svg-inline-loader', 155 | options: { 156 | removeSVGTagAttrs: false 157 | } 158 | }, 159 | ], 160 | }, 161 | optimization: { 162 | splitChunks: { 163 | cacheGroups: { 164 | commons: { 165 | // don't include cwrc or entity lookup modules in vendor bundle 166 | test: /[\\/]node_modules[\\/](?!.*(cwrc|entity-lookup))/, 167 | name: 'vendor', 168 | chunks: 'all', 169 | }, 170 | styles: { 171 | name: 'styles', 172 | test: /\.css$/, 173 | chunks: 'all', 174 | enforce: true, 175 | }, 176 | }, 177 | }, 178 | }, 179 | resolve: { 180 | extensions: ['*', '.js', '.jsx'], 181 | symlinks: false, 182 | }, 183 | node: { fs: 'empty' }, 184 | }; 185 | -------------------------------------------------------------------------------- /config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "cwrcRootUrl": "", 3 | "nerveUrl": "https://localhost/nerve/", 4 | "validationUrl": "https://localhost/validator/validate.html", 5 | "helpUrl": "https://cwrc.ca/CWRC-Writer_Documentation/", 6 | "lookups": { 7 | "geonames": { 8 | "username": "" 9 | } 10 | }, 11 | "schema": { 12 | "proxyXmlEndpoint": "./schema/xml/", 13 | "proxyCssEndpoint": "./schema/css/", 14 | "schemas": [{ 15 | "id": "cwrcTeiLite", 16 | "name": "CWRC TEI Lite", 17 | "schemaMappingsId": "tei", 18 | "xmlUrl": [ 19 | "https://cwrc.ca/schemas/cwrc_tei_lite.rng", 20 | "https://raw.githubusercontent.com/cwrc/CWRC-Schema/master/schemas/cwrc_tei_lite.rng" 21 | ], 22 | "cssUrl": [ 23 | "https://cwrc.ca/templates/css/tei.css", 24 | "https://raw.githubusercontent.com/cwrc/CWRC-Schema/master/templates/css/tei.css" 25 | ] 26 | }, 27 | { 28 | "id": "orlando", 29 | "name": "Orlando Schema", 30 | "schemaMappingsId": "orlando", 31 | "xmlUrl": [ 32 | "https://cwrc.ca/schemas/orlando_entry.rng", 33 | "https://raw.githubusercontent.com/cwrc/CWRC-Schema/master/schemas/orlando_entry.rng" 34 | ], 35 | "cssUrl": [ 36 | "https://cwrc.ca/templates/css/orlando_v2_cwrc-writer.css", 37 | "https://raw.githubusercontent.com/cwrc/CWRC-Schema/master/templates/css/orlando_v2_cwrc-writer.css" 38 | ] 39 | }, 40 | { 41 | "id": "event", 42 | "name": "Events Schema", 43 | "schemaMappingsId": "orlando", 44 | "xmlUrl": [ 45 | "https://cwrc.ca/schemas/orlando_event.rng", 46 | "https://raw.githubusercontent.com/cwrc/CWRC-Schema/master/schemas/orlando_event.rng" 47 | ], 48 | "cssUrl": [ 49 | "https://cwrc.ca/templates/css/orlando_v2_cwrc-writer.css", 50 | "https://raw.githubusercontent.com/cwrc/CWRC-Schema/master/templates/css/orlando_v2_cwrc-writer.css" 51 | ] 52 | }, 53 | { 54 | "id": "cwrcEntry", 55 | "name": "CWRC Entry Schema", 56 | "schemaMappingsId": "cwrcEntry", 57 | "xmlUrl": [ 58 | "https://cwrc.ca/schemas/cwrc_entry.rng", 59 | "https://raw.githubusercontent.com/cwrc/CWRC-Schema/master/schemas/cwrc_entry.rng" 60 | ], 61 | "cssUrl": [ 62 | "https://cwrc.ca/templates/css/cwrc.css", 63 | "https://raw.githubusercontent.com/cwrc/CWRC-Schema/master/templates/css/cwrc.css" 64 | ] 65 | }, 66 | { 67 | "id": "epidoc", 68 | "name": "EpiDoc Schema", 69 | "schemaMappingsId": "tei", 70 | "xmlUrl": [ 71 | "http://www.stoa.org/epidoc/schema/latest/tei-epidoc.rng", 72 | "https://cwrc.ca/epidoc/schema/latest/tei-epidoc.rng" 73 | ], 74 | "cssUrl": [ 75 | "https://cwrc.ca/templates/css/tei.css" 76 | ] 77 | }, 78 | { 79 | "id": "teiAll", 80 | "name": "TEI All Schema", 81 | "schemaMappingsId": "tei", 82 | "xmlUrl": [ 83 | "https://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng", 84 | "https://jenkins.tei-c.org/job/TEIP5/lastSuccessfulBuild/artifact/P5/release/xml/tei/custom/schema/relaxng/tei_all.rng" 85 | ], 86 | "cssUrl": [ 87 | "https://cwrc.ca/templates/css/tei.css" 88 | ] 89 | }, 90 | { 91 | "id": "teiDrama", 92 | "name": "TEI Drama Schema", 93 | "schemaMappingsId": "tei", 94 | "xmlUrl": [ 95 | "https://tei-c.org/release/xml/tei/custom/schema/relaxng/tei_drama.rng", 96 | "https://jenkins.tei-c.org/job/TEIP5/lastSuccessfulBuild/artifact/P5/release/xml/tei/custom/schema/relaxng/tei_drama.rng" 97 | ], 98 | "cssUrl": [ 99 | "https://cwrc.ca/templates/css/tei.css" 100 | ] 101 | }, 102 | { 103 | "id": "teiCorpus", 104 | "name": "TEI Corpus Schema", 105 | "schemaMappingsId": "tei", 106 | "xmlUrl": [ 107 | "https://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_corpus.rng", 108 | "https://jenkins.tei-c.org/job/TEIP5/lastSuccessfulBuild/artifact/P5/release/xml/tei/custom/schema/relaxng/tei_corpus.rng" 109 | ], 110 | "cssUrl": [ 111 | "https://cwrc.ca/templates/css/tei.css" 112 | ] 113 | }, 114 | { 115 | "id": "teiMs", 116 | "name": "TEI Manuscript Schema", 117 | "schemaMappingsId": "tei", 118 | "xmlUrl": [ 119 | "https://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_ms.rng", 120 | "https://jenkins.tei-c.org/job/TEIP5/lastSuccessfulBuild/artifact/P5/release/xml/tei/custom/schema/relaxng/tei_ms.rng" 121 | ], 122 | "cssUrl": [ 123 | "https://cwrc.ca/templates/css/tei.css" 124 | ] 125 | }, 126 | { 127 | "id": "teiSpeech", 128 | "name": "TEI Speech Schema", 129 | "schemaMappingsId": "tei", 130 | "xmlUrl": [ 131 | "https://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_speech.rng", 132 | "https://jenkins.tei-c.org/job/TEIP5/lastSuccessfulBuild/artifact/P5/release/xml/tei/custom/schema/relaxng/tei_speech.rng" 133 | ], 134 | "cssUrl": [ 135 | "https://cwrc.ca/templates/css/tei.css" 136 | ] 137 | }, 138 | { 139 | "id": "teiLite", 140 | "name": "TEI Lite Schema", 141 | "schemaMappingsId": "teiLite", 142 | "xmlUrl": [ 143 | "https://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_lite.rng", 144 | "https://jenkins.tei-c.org/job/TEIP5/lastSuccessfulBuild/artifact/P5/release/xml/tei/custom/schema/relaxng/tei_lite.rng" 145 | ], 146 | "cssUrl": [ 147 | "https://cwrc.ca/templates/css/tei.css" 148 | ] 149 | }, 150 | { 151 | "id": "moravian", 152 | "name": "Moravian Lives (TEI)", 153 | "schemaMappingsId": "tei", 154 | "xmlUrl": [ 155 | "https://raw.githubusercontent.com/moravianlives/ML/master/Projects/TEI_Memoirs/out/MoravianMemoirs.rng" 156 | ], 157 | "cssUrl": [ 158 | "https://cwrc.ca/templates/css/tei.css" 159 | ] 160 | }, 161 | { 162 | "id": "reed", 163 | "name": "Reed", 164 | "schemaMappingsId": "tei", 165 | "xmlUrl": [ 166 | "https://cwrc.ca/islandora/object/cwrc%3A5d5159ce-8710-4717-b977-cc528dedc25e/datastream/SCHEMA/view" 167 | ], 168 | "cssUrl": [ 169 | "https://cwrc.ca/templates/css/tei.css" 170 | ] 171 | } 172 | ] 173 | } 174 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CWRC-GitWriter 2 | 3 | ![Picture](http://cwrc.ca/logos/CWRC_logos_2016_versions/CWRCLogo-Horz-FullColour.png) 4 | 5 | [![experimental](http://badges.github.io/stability-badges/dist/experimental.svg)](http://github.com/badges/stability-badges) 6 | 7 | The code in this repository serves two purposes: 8 | 9 | 1. To back the sandbox deployment: [https://cwrc-writer.cwrc.ca/](https://cwrc-writer.cwrc.ca/) 10 | 11 | 2. To provide an example configuration of the CWRC-Writer for those who might like to substitute a different storage or lookup system. 12 | 13 | ## Table of Contents 14 | 15 | 1. [Overview](#overview) 16 | 2. [Use](#use) 17 | 3. [Installation](#installation) 18 | 4. [Development](#development) 19 | 5. [Authentication](#authentication) 20 | 6. [Contributing](#contributing) 21 | 7. [License](#license) 22 | 23 | ### Overview 24 | 25 | ![High Level Overview](/docs/images/cwrc-gitwriter-overview.svg) 26 | 27 | As you can see from the overview diagram, CWRC-GitWriter is the parent package which collects and configures the various child packages. While [CWRC-WriterBase](https://github.com/cwrc/CWRC-WriterBase) provides the primary editing functionality, it requires both storage and entity lookup packages, which in this case are [cwrc-git-dialogs](https://github.com/cwrc/cwrc-git-dialogs) and [CWRC-PublicEntityDialogs](https://github.com/cwrc/CWRC-PublicEntityDialogs). 28 | 29 | Although the sandbox version provides a freely usable instance, you may of course install an instance of the CWRC-GitWriter on your own server. CWRC-GitWriter also requires a running instance of [CWRC-GitServer](https://github.com/cwrc/CWRC-GitServer), which in turn interacts with GitHub through the [GitHub API](https://developer.github.com/v3/). 30 | 31 | Note that if you want to create a new version of the CWRC-Writer that is configured to work with your own document repository (e.g., a database), this repository still provides you with the best example to follow. You'll also want to look at the [cwrc-git-dialogs](https://www.npmjs.com/package/cwrc-git-dialogs) repository, which holds 32 | 33 | The javascript class that handles calls to the backend storage, in this case to Github via the CWRC-GitServer. This is the class you'd want to replace with your own. To replace the entity lookups you'd replace [cwrc-public-entity-dialogs](https://www.npmjs.com/package/cwrc-public-entity-dialogs) 34 | 35 | ## Use 36 | 37 | A running deployment of the code in this repository is available for anyone's use at: [https://cwrc-writer.cwrc.ca](https://cwrc-writer.cwrc.ca) 38 | 39 | ## Building 40 | 41 | There are two approached to install the [sandbox version of the CWRC-GitWriter](https://cwrc-writer.cwrc.ca). 42 | 43 | 1. Install the dockerized verion of Git-Server/Git-Writer (**recommended**). The instruction for this approach is descibed in the [CWRC-GitWriter-Docker repo](https://github.com/cwrc/CWRC-GitWriter-Docker). 44 | 2. Manually install each component. Instruction is down below: 45 | 46 | This repository contains a JS file — the [app file](src/js/app.js), and a JSON file — the [config file](config/config.json). The app file does not contain much code itself; it's main purpose to load/require other code bases, and then configure and instantiate the CWRC-Writer. It must first be built in order to be useable. To build: 47 | 48 | - Download the code for this repository, or clone the repository 49 | - Install all the NPM package dependencies: `npm install` 50 | - Check the `config.json file`. Provide the necessary information/customization. See below. 51 | - Use Webpack to package it up for deployment: `npm run build` 52 | 53 | The built code resides in the newly created build directory. It contains the app, along with all the necessary CSS, XML, and image files. To deploy the CWRC-GitWriter simply copy the build directory to your server, probably the same server from which you'd serve the [CWRC-GitServer](https://github.com/cwrc/CWRC-GitServer). You might choose to use ftp, scp, rsync, etc. An example rsync command might be: 54 | 55 | Alternately, if your server has Git and npm support you can clone and build this repository directly on your server. 56 | 57 | ### Config file 58 | 59 | #### cwrcRootUrl 60 | 61 | The path where CWRC-GitWriter is located on the server. Default `""` 62 | 63 | #### nerveUrl 64 | 65 | Nerve url. Default `"https://localhost/nerve/"` 66 | 67 | #### validationUrl 68 | 69 | Validator url. Default `"https://localhost/validator/validate.html"` 70 | 71 | #### helpUrl 72 | 73 | Help url. Default `"https://cwrc.ca/Documentation/CWRC-Writer"` 74 | 75 | #### lookups 76 | 77 | ##### geonames 78 | 79 | Provide a GeoNames username. Default `""` 80 | Note that if a username is not provided, CWRC-Git-Writer will throw an error when trying to access GeoNames. 81 | 82 | You can create a free user account here account: [https://www.geonames.org/login](https://www.geonames.org/login) 83 | 84 | #### schema 85 | 86 | #### proxyXmlEndpoint 87 | 88 | The endpoint path to make call request for schemas xml files. Default: `"./schema/xml/"` 89 | The schema is requested as the 'xml' parameter. eg. `"./schema/xml/:url"` 90 | 91 | #### proxyCssEndpoint 92 | 93 | The endpoint path to make call request for schemas css files. Default: `"./schema/css/"` 94 | The schema is requested as the 'css' parameter. eg. `"./schema/css/:url"` 95 | 96 | ##### schemas 97 | 98 | A list of schemas made available on CWRC-Writer. **Default list of schemas**: CWRC Basic TEI, Events, Biography, Writing, CWRC Entry, EpiDoc, TEI All, TEI Corpus, TEI Manuscript, TEI Speech, TEI Lite, Moravian Lives (TEI). 99 | 100 | Each schema is am object with the following information: 101 | 102 | ```js 103 | { 104 | id: `${uniqueID}`, 105 | name: `${name}`, 106 | schemaMappingsId: `${one_of_the_following['tei', 'orlando', 'cwrcEntry', 'teiLite']}`, 107 | xmlUrl: [`${list_of_URI}`], 108 | cssUrl: [`${list_of_URI}`] 109 | } 110 | ``` 111 | 112 | ## Development 113 | 114 | ### Using this code as an example to build a CWRC-Writer with a different backend 115 | 116 | The code in this repository brings together and configures code from other repositories and wouldn't in itself typically be usefully modified. You could, however, clone this repository as a base from which to create a new configuration of the CWRC-Writer, or simply use the code here as a guide in creating your own configuration. Your configuration might, for example, use Fedora to store documents, rather than GitHub. 117 | 118 | ### npm and webapack 119 | 120 | The code in this repository simply brings together and configures code from other repositories and wouldn't in itself typically be usefully modified. You could, however, clone this repository as a base from which to create a new configuration of the CWRC-Writer, or simply use the code here as a guide in creating your own configuration. Your configuration might, for example, use Fedora to store documents, rather than GitHub. 121 | 122 | CWRC-GitWriter uses [NPM](https://www.npmjs.com) both for dependency management and for running it's main build script. The build script in turn uses [Webpack](https://webpack.js.org/) to bundle all code into the single [build/js/app.js](build/js/app.js) file. The [package.json](package.json) file contains the script for invoking Webpack as well as the full list of NPM packages required. 123 | 124 | The entry point into the CWRC-GitWriter code, on which Webpack is invoked, is [src/js/app.js](src/js/app.js) which uses [node.js module loading](https://nodejs.org/api/modules.html) to 'require' - either from the [NPM public registry](https://www.npmjs.com) or from local files - the bits and pieces that make up the CWRC-GitWriter, and plug them together. [Webpack](https://webpack.js.org/) resolves all the 'require' statements, and bundles all the code, including NPM packages and local files, into a single javascript file that is loaded into the web browser. 125 | 126 | To develop a new configuration of the CWRC-Writer, you'll therefore need to understand NPM and Webpack. Then you can get into the CWRC-GitWriter NPM [package.json](package.json) file and [src/js/app.js](src/js/app.js) and adapt it to your own project. 127 | 128 | The [src/js/app.js](src/js/app.js) file imports the following npm CWRC packages: 129 | 130 | - [CWRC-WriterBase](https://www.npmjs.com/package/cwrc-writer-base) 131 | The CWRC-Writer editor 132 | 133 | - [cwrc-git-dialogs](https://www.npmjs.com/package/cwrc-git-dialogs) 134 | The javascript class that handles calls to the backend storage, in this case to Github via the CWRC-GitServer. This is the class you'd want to replace with your own. 135 | 136 | - [cwrc-public-entity-dialogs](https://www.npmjs.com/package/cwrc-public-entity-dialogs) 137 | The javascript class that handles lookups of named entities. You may want to replace this with your own entity lookup 138 | 139 | The app.js file also imports a config file: 140 | 141 | - [src/js/config/config.json](src/js/config/config.json) 142 | 143 | A JSON file that provides the basic configurations to CWRC-GitWriter. It also describes the XML schemas supported. 144 | 145 | - The [src/js/app.js](src/js/app.js) file ties all these together as you would for your own configuration of the CWRC-Writer. 146 | 147 | Note that the authentication for Github is invoked in app.js since it redirects to the GitHub site if the user isn't loaded. Better to redirect here at the outset before loading up all the other CWRC related code. Read more about authentication below in the [Authentication Section](#authentication) 148 | 149 | #### npm link 150 | 151 | If you are making changes to the npm packages that contribute to the CWRC-GitWriter (or more likely to some custom instance of the CWRC-GitWriter that you've built) and you find yourself repeatedly packaging and publishing the npm packages and re-importing the newly published packages (e.g.`npm i cwrc-writer-base@latest`) then you can instead use [npm link](https://docs.npmjs.com/cli/link) to point the package.json dependencies at the local instances. 152 | 153 | For example, when developing cwrc-git-dialogs you would use: 154 | 155 | ```bash 156 | cd ~/projects/cwrc-git-dialogs 157 | npm link 158 | cd ~/projects/CWRC-GitWriter 159 | npm link cwrc-git-dialogs 160 | ``` 161 | 162 | This creates a symbolic link between the two packages on your computer. Then, when you run `npm run watch` from CWRC-GitWriter, changes made to cwrc-git-dialogs will cause the CWRC-GitWriter build to update. 163 | 164 | Once finished making and testing local changes, publish the new NPM packages, including the local packages, and remove the dependencies from package.json: 165 | 166 | ```bash 167 | cd ~/projects/CWRC-GitWriter 168 | npm unlink cwrc-git-dialogs 169 | npm i cwrc-git-dialogs@latest 170 | ``` 171 | 172 | ## Authentication 173 | 174 | Authentication is with Github using OAuth, as described in the Github API docs: [Github - building oauth apps](https://developer.github.com/apps/building-oauth-apps/) 175 | 176 | The two relevant steps there are: 177 | 178 | 1. [Creating an OAuth App](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) 179 | 180 | 2. The section called Web Application Flow in [Authorizing OAuth Apps](https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/#web-application-flow) 181 | 182 | After authenticating with GitHub, GitHub returns an OAuth token, which is then submitted on every request to the GitHub API. 183 | 184 | We could store this token in a server side session, but instead we store it in a browser cookie that the CWRC-GitWriter submits in the request header (to help guard against [CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery)) for each request to the CWRC-GitServer. 185 | 186 | As explained in the development section you wouldn't typically usefully modify anything here for use by others. Nevertheless, if there is something we've missed, please submit an Issue. If you are interested, however, please take a look at our [Development Docs](https://github.com/cwrc/CWRC-Writer-Dev-Docs) 187 | 188 | ![Auththentication Process](https://github.com/cwrc/CWRC-GitWriter/blob/master/docs/images/oauth.svg) 189 | 190 | ## License 191 | 192 | [GNU GPL V2](LICENSE) 193 | -------------------------------------------------------------------------------- /docs/images/oauth.svg: -------------------------------------------------------------------------------- 1 | 2 |
cwrc-git-dialogs
[Not supported by viewer]
 yes 
[Not supported by viewer]
 no 
[Not supported by viewer]
 cwrc-token cookie exists? 
[Not supported by viewer]
cwrc-token is added to
the HTTP header for each
request to CWRC-GitServer
[Not supported by viewer]
CWRC-GitServer gets the cwrc-token from the header and uses it to authenticate calls to GitHub
[Not supported by viewer]
User is sent to the
CWRC-GitServer /authenticate URL
[Not supported by viewer]
CWRC-GitServer redirects
to the GitHub OAuth authentication page
[Not supported by viewer]
User grants permission to
CWRC-GitWriter and is redirected to the CWRC-GitServer /callback URL
[Not supported by viewer]
CWRC-GitServer receives the OAuth token from GitHub and sets it as the cwrc-token cookie
[Not supported by viewer]
CWRC-GitWriter
[Not supported by viewer]
-------------------------------------------------------------------------------- /docs/images/cwrc-gitwriter-overview.svg: -------------------------------------------------------------------------------- 1 | 2 |
CWRC-GitWriter
<font style="font-size: 17px">CWRC-GitWriter</font>
CWRC-WriterBase
<font style="font-size: 17px">CWRC-WriterBase</font>
cwrc-git-dialogs
[Not supported by viewer]
CWRC-PublicEntityDialogs
<font style="font-size: 15px">CWRC-PublicEntityDialogs<br></font>
CWRC-GitServer
<font style="font-size: 17px">CWRC-GitServer</font>
CWRC-Git
[Not supported by viewer]
GitHub
[Not supported by viewer]
VIAF
[Not supported by viewer]
Wikidata
[Not supported by viewer]
DBPedia
[Not supported by viewer]
etc.
[Not supported by viewer]
NERVE
[Not supported by viewer]
CWRC XML Validator
[Not supported by viewer]
3 | --------------------------------------------------------------------------------