├── .gitignore ├── .nvmrc ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── config.js ├── etherpad-editor.js ├── index.html ├── index.js ├── plantuml-rendered.js └── style.css └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v16.7.0 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Alexis Hernandez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | CollabUML is a PlantUML based app for online collaborative design on UML 4 | 5 | 6 | ## How it works? 7 | 8 | CollabUML is a super-simple client only app that wires existing technology, in this case, it uses an https://etherpad.org to handle the collaborative text editor and https://plantuml.com/ public server to render the editor's content. 9 | 10 | There is a timer that takes the etherpad content to render it with plantuml on every tick. 11 | 12 | 13 | ## Run it 14 | 15 | An Etherpad instance is required, host/apikey must be configured at [config.js](./src/config.js) 16 | 17 | Then, run `npm install` to download the js dependencies, then, `npm run start` will allow you to use the app at `localhost:8080` 18 | 19 | ## Project state 20 | 21 | The project was created in 2020, there haven't been much changes since then, I plan to keep the server running for as long as it doesn't require much maintenance (the case for 3 years). 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "collabuml-web", 3 | "version": "1.0.0", 4 | "description": "", 5 | "private": true, 6 | "scripts": { 7 | "build": "webpack --mode=development", 8 | "watch": "webpack --watch", 9 | "start": "webpack-dev-server --history-api-fallback", 10 | "dist": "webpack --mode=production", 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "bootswatch": "^4.4.1", 17 | "jquery": "^3.5.0", 18 | "lodash": "^4.17.15", 19 | "pako": "^1.0.11", 20 | "plantuml-encoder": "^1.4.0" 21 | }, 22 | "devDependencies": { 23 | "clean-webpack-plugin": "^3.0.0", 24 | "css-loader": "^3.5.3", 25 | "file-loader": "^6.0.0", 26 | "html-webpack-plugin": "^4.2.0", 27 | "style-loader": "^1.2.0", 28 | "webpack": "^4.43.0", 29 | "webpack-cli": "^3.3.11", 30 | "webpack-dev-server": "^3.10.3" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | function promptForSessionName() { 2 | var input = prompt('Choose the session name, your peers need to use this to collaborate with you, or ignore this to go to the test session') || ''; 3 | input = input.trim(); 4 | if (input.length == 0) { 5 | return 'test'; 6 | } else { 7 | return input; 8 | } 9 | } 10 | 11 | function getSessionName() { 12 | var currentPath = window.location.pathname; 13 | if (currentPath.startsWith('/')) { 14 | var session = currentPath.substr(1).trim(); 15 | if (session !== '') { 16 | return session; 17 | } 18 | } 19 | 20 | var session = promptForSessionName(); 21 | var newPath = '/' + session; 22 | window.location.pathname = newPath; 23 | } 24 | 25 | function getUserName() { 26 | return 'unnamed'; 27 | } 28 | 29 | export const collabuml = { 30 | padId: getSessionName(), 31 | userName: getUserName(), 32 | host: 'https://pad.collabuml.com', 33 | apikey: 'd73bfbe04a31195082be48dfd9dc22cb17bcedeedea0be2404be6cbe290440e6' 34 | }; 35 | -------------------------------------------------------------------------------- /src/etherpad-editor.js: -------------------------------------------------------------------------------- 1 | import jQuery from 'jquery'; 2 | import { collabuml } from './config'; 3 | 4 | export const getText = (callback) => { 5 | jQuery.ajax({ 6 | 'url': collabuml.host + '/api/1/getText?apikey=' + collabuml.apikey + '&padID=' + collabuml.padId + '&jsonp=?', 7 | 'type': 'GET', 8 | 'dataType': "jsonp", 9 | 'success': function (response) { 10 | callback(response.data.text); 11 | } 12 | }); 13 | }; 14 | 15 | export const renderPad = (selector, padId) => { 16 | jQuery(selector).pad({ 'padId': padId, 'showChat': 'false' }); 17 | }; 18 | 19 | (function (jQuery) { 20 | jQuery.fn.pad = function (options) { 21 | var settings = { 22 | 'host': collabuml.host, 23 | 'baseUrl': '/p/', 24 | 'showControls': false, 25 | 'showChat': false, 26 | 'showLineNumbers': true, 27 | 'userName': collabuml.userName, 28 | 'lang': '', 29 | 'useMonospaceFont': false, 30 | 'noColors': false, 31 | 'userColor': false, 32 | 'hideQRCode': false, 33 | 'alwaysShowChat': false, 34 | 'width': 100, 35 | 'height': 300, 36 | 'border': 1, 37 | 'borderStyle': 'solid', 38 | 'toggleTextOn': 'Disable Rich-text', 39 | 'toggleTextOff': 'Enable Rich-text', 40 | 'plugins': {}, 41 | 'rtl': false 42 | }; 43 | var $self = this; 44 | if (!$self.length) return; 45 | if (!$self.attr('id')) throw new Error('No "id" attribute'); 46 | 47 | var useValue = $self[0].tagName.toLowerCase() == 'textarea'; 48 | var selfId = $self.attr('id'); 49 | var epframeId = 'epframe' + selfId; 50 | // This writes a new frame if required 51 | if (options) { 52 | jQuery.extend(settings, options); 53 | } 54 | 55 | var pluginParams = ''; 56 | for (var option in settings.plugins) { 57 | pluginParams += '&' + option + '=' + settings.plugins[option] 58 | } 59 | 60 | var iFrameLink = ''; 82 | 83 | 84 | var $iFrameLink = jQuery(iFrameLink); 85 | 86 | if (useValue) { 87 | var $toggleLink = jQuery('' + settings.toggleTextOn + '').click(function () { 88 | var $this = jQuery(this); 89 | $this.toggleClass('active'); 90 | if ($this.hasClass('active')) $this.text(settings.toggleTextOff); 91 | $self.pad({ getContents: true }); 92 | return false; 93 | }); 94 | $self 95 | .hide() 96 | .after($toggleLink) 97 | .after($iFrameLink) 98 | ; 99 | } 100 | else { 101 | $self.html(iFrameLink); 102 | } 103 | 104 | return $self; 105 | }; 106 | })(jQuery); 107 | 108 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 |If you liked this app, you can support me by purchasing/sharing codepreview.io
48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import './style.css'; 3 | import '../node_modules/bootswatch/dist/flatly/bootstrap.min.css'; 4 | import jQuery from 'jquery'; 5 | import { collabuml } from './config'; 6 | import { getText, renderPad } from './etherpad-editor'; 7 | import { scheduledRendering } from './plantuml-rendered'; 8 | 9 | jQuery(function () { 10 | renderPad('#etherpad-input', collabuml.padId); 11 | jQuery('#session-name').append('Session: ' + collabuml.padId); 12 | scheduledRendering(2000, getText); 13 | }); 14 | -------------------------------------------------------------------------------- /src/plantuml-rendered.js: -------------------------------------------------------------------------------- 1 | import jQuery from 'jquery'; 2 | 3 | const plantumlEncoder = require('plantuml-encoder') 4 | 5 | function renderDiagram(ms, getText) { 6 | scheduledRendering(ms, getText); 7 | getText(function (text) { 8 | var encoded = plantumlEncoder.encode(text); 9 | var div = jQuery('#diagram-view') 10 | var sourceUrl = "https://www.plantuml.com/plantuml/img/" + encoded; 11 | var item = '