Cache/CacheClassExplorer-vX.X.X.xml file.
35 |
36 | ###### Web application
37 |
38 | Note that importing ClassExplorer.WebAppInstaller class will also create a /ClassExplorer application.
39 | If you want to create WEB application manually, please, do not import this class. Anyway,
40 | importing this class requires %SYS permission.
41 |
42 | ## Usage
43 |
44 | Visit [server domain and port]/ClassExplorer/ (slash at end required) to enter
45 | application.
46 |
47 | ## Development
48 |
49 | ### Local
50 |
51 | To build project, you need [NodeJS](https://nodejs.org) platform to be installed. Then, clone source
52 | code and run npm install from the root of the project. This will install all necessary
53 | modules from NPM for the project.
54 |
55 | After that and each next time just run npm run gulp command from the project root.
56 | This will generate build directory, where you will find XML file ready to import.
57 |
58 | One can import/export the built source to the local Cache/URIS instance (see `import.bat`):
59 |
60 | ```
61 | ./import.bat
62 | ```
63 |
64 | This will bring `ClassExplorer-v*.*.*.xml` to the `build` directory, which you can then package with `npm run zip`.
65 |
66 | ### Using docker
67 |
68 | :warning: The following is a rather naive way of building the web app for ZPM packaging using an [nvm docker script](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-in-docker), starting the image as a daemon, and then manually copying the files back out.
69 |
70 | ```Shell
71 | docker build -f ./Dockerfile-build-npm -t build-npm .
72 | docker run --rm -d --name build-npm build-npm /bin/bash -c 'while true; do sleep 30; done'
73 | docker cp build-npm:/opt/irisapp/build/cls/ClassExplorer.ClassView.cls ./build-for-zpm/ClassExplorer/ClassView.cls
74 | docker cp build-npm:/opt/irisapp/build/cls/ClassExplorer.Router.cls ./build-for-zpm/ClassExplorer/Router.cls
75 | docker cp build-npm:/opt/irisapp/build/cls/ClassExplorer.StaticContent.cls ./build-for-zpm/ClassExplorer/StaticContent.cls
76 | docker stop build-npm
77 | ```
78 |
79 | ### ZPM
80 |
81 | [ZPM](https://github.com/intersystems-community/zpm) is the package manager for InterSystems products. Currently,
82 | the release pipeline for it is manual. The ZPM release should happen once the package is uploaded
83 | to [InterSystems OpenExchange](https://openexchange.intersystems.com/) with the "ZPM" option checked in. This
84 | should grab **manually moved** files from `build-for-zpm/ClassExplorer` directory for the release.
85 |
86 | Locally, one can run and test the application using Docker:
87 |
88 | 0. Before each release, **manually** patch the version in the `module.xml` file.
89 | 1. Run `docker-compose up -d --build` in the repository root to bring up ClassExplorer to a docker container.
90 | 2. Check `localhost:52773/ClassExplorer/` in a little while - it should have the app already.
91 | 3. Run `docker-compose exec iris iris session iris` and then type `zn "IRISAPP" zpm` to start ZPM session in the "IRISAPP" namespace.
92 | 4. Type `load /irisdev/app` to test whether ZPM can parse the repository root.
93 | 5. Type `classexplorer package` to try to compile the package. It should say something like `Module package generated: /tmp/dirymgtBA/classexplorer-1.20.0.tgz`.
94 | 6. Configure the test registry to publish the package `repo -n registry -r -url https://test.pm.community.intersystems.com/registry/ -user test -pass test` (type `search` to see the registries list).
95 | 7. Finally publish the package `classexplorer publish`.
96 | 8. Further steps to test it: [https://community.intersystems.com/post/testing-packages-zpm](https://community.intersystems.com/post/testing-packages-zpm)
97 |
98 | ## Related Discussion
99 |
100 | See the detailed description and discussion [in this article](https://community.intersystems.com/node/407056).
101 | Have a look at [InterSystems Developer Community](community.intersystems.com) to learn about InterSystems technology, sharing solutions and staying up-to-date on the latest developments.
102 |
103 | ## License
104 |
105 | [MIT](LICENSE) © [Nikita Savchenko](https://nikita.tk)
106 |
--------------------------------------------------------------------------------
/src/web/jsLib/ImageExporter.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @see https://github.com/NYTimes/svg-crowbar - A bit of used code from here, thanks to it's author.
3 | */
4 | var enableSVGDownload = function (classView) {
5 |
6 | var doctype = '';
7 |
8 | window.URL = (window.URL || window.webkitURL);
9 |
10 | var prefix = {
11 | xmlns: "http://www.w3.org/2000/xmlns/",
12 | xlink: "http://www.w3.org/1999/xlink",
13 | svg: "http://www.w3.org/2000/svg"
14 | };
15 |
16 | function getSources(doc, emptySvgDeclarationComputed) {
17 |
18 | var svgInfo = [],
19 | svgs = doc.querySelectorAll("#svgContainer > svg");
20 |
21 | [].forEach.call(svgs, function (svg) {
22 |
23 | var par = svg.parentNode;
24 | svg = svg.cloneNode(true);
25 | svg.style.position = "fixed";
26 | svg.style.left = 0;
27 | svg.style.top = 0;
28 | par.appendChild(svg);
29 | var gGroup = svg.childNodes[0];
30 |
31 | svg.setAttribute("version", "1.1");
32 |
33 | // removing attributes so they aren't doubled up
34 | svg.removeAttribute("xmlns");
35 | svg.removeAttribute("xlink");
36 |
37 | // These are needed for the svg
38 | if (!svg.hasAttributeNS(prefix.xmlns, "xmlns")) {
39 | svg.setAttributeNS(prefix.xmlns, "xmlns", prefix.svg);
40 | }
41 |
42 | if (!svg.hasAttributeNS(prefix.xmlns, "xmlns:xlink")) {
43 | svg.setAttributeNS(prefix.xmlns, "xmlns:xlink", prefix.xlink);
44 | }
45 |
46 | svg.style.zIndex = 0;
47 | gGroup.setAttribute("transform", "");
48 | var gRect = gGroup.getBoundingClientRect();
49 | gGroup.setAttribute("transform", "translate("+(-gRect.left)+","+(-gRect.top)+")");
50 | svg.setAttribute("width", gGroup.getBBox().width);
51 | svg.setAttribute("height", gGroup.getBBox().height);
52 |
53 | setInlineStyles(svg, emptySvgDeclarationComputed);
54 |
55 | var source = (new XMLSerializer()).serializeToString(svg);
56 | var rect = svg.getBoundingClientRect();
57 | svgInfo.push({
58 | top: rect.top,
59 | left: rect.left,
60 | width: rect.width,
61 | height: rect.height,
62 | class: svg.getAttribute("class"),
63 | id: svg.getAttribute("id"),
64 | childElementCount: svg.childElementCount,
65 | source: [doctype + source]
66 | });
67 |
68 | par.removeChild(svg);
69 |
70 | });
71 | return svgInfo;
72 | }
73 |
74 | document.getElementById("button.downloadSVG").addEventListener("click", function () {
75 |
76 | var emptySvg = document.createElementNS(prefix.svg, 'svg');
77 | document.body.appendChild(emptySvg);
78 | var emptySvgDeclarationComputed = getComputedStyle(emptySvg);
79 | var source = getSources(document, emptySvgDeclarationComputed)[0];
80 | var filename = (classView || {}).SELECTED_NAME || "classDiagram";
81 | var img = new Image();
82 | var url = window.URL.createObjectURL(new Blob(source.source, { "type" : 'image/svg+xml;charset=utf-8' }));
83 | var canvas = document.createElement("canvas");
84 | var ctx = canvas.getContext("2d");
85 | canvas.setAttribute("width", source.width);
86 | canvas.setAttribute("height", source.height);
87 | document.body.appendChild(canvas);
88 |
89 | img.onload = function () {
90 | ctx.drawImage(img, 0, 0);
91 | try {
92 | var a = document.createElement("a");
93 | a.setAttribute("download", filename + ".png");
94 | var dataURL = canvas.toDataURL("image/png");
95 | a.setAttribute("href", dataURL/*url*/);
96 | document.body.appendChild(a);
97 | a.click();
98 | } catch (e) {
99 | alert("This browser does not allow usage of canvas.toDataURL function. Please,"
100 | + " use different browser to download the image.");
101 | }
102 | setTimeout(function () {
103 | a.parentNode.removeChild(a);
104 | document.body.removeChild(emptySvg);
105 | canvas.parentNode.removeChild(canvas);
106 | window.URL.revokeObjectURL(url);
107 | }, 10);
108 | };
109 |
110 | img.src = url;
111 |
112 | });
113 |
114 | function setInlineStyles(svg, emptySvgDeclarationComputed) {
115 |
116 | function explicitlySetStyle (element) {
117 | var cSSStyleDeclarationComputed = getComputedStyle(element);
118 | var i, len, key, value;
119 | var computedStyleStr = "";
120 | for (i=0, len=cSSStyleDeclarationComputed.length; i| 119 | | 120 | | Show data type classes on diagram | 121 |
| 124 | | 125 | | Visualize class keywords (turn off for standard UML notation) | 126 |
| 129 | | 130 | | Visualize property keywords (turn off for standard UML notation) | 131 |
| 134 | | 135 | | Display block with class parameters | 136 |
| 139 | | 140 | | Display block with class properties | 141 |
| 144 | | 145 | | Display block with class methods | 146 |
| 149 | | 150 | | Display block with class queries | 151 |
| 154 | | 155 | | Display block with class xDatas | 156 |
| 159 | | 160 | | Dependency level of classes (leave blank for full structure) | 161 |
176 | This info graphics below shows all the basics of designations on the diagram. 177 |
178 |Class Types |
184 | ||||||
|---|---|---|---|---|---|---|
| 187 | Registered 188 | | 189 |190 | Persistent 191 | | 192 |193 | Serial 194 | | 195 |196 | DataType 197 | | 198 |199 | Index 200 | | 201 |202 | View 203 | | 204 |205 | Stream 206 | | 207 |
Connection Types |
214 | |
|---|---|
| Class Mention | 217 |
218 | |
220 |
| One - to - Many | 223 |
224 | |
226 |
| Parent - to - Child | 229 |
230 | |
232 |
| Inheritance | 235 |
236 | |
238 |
| crystalBall | Abstract |
| blueFlag | Final |
| moleculeCubeCross | Not a Procedure Block |
| ghost | Hidden |
| minus | Private |
| plus | Public |
| keyRed | Unique Key |
| keyGreen | Primary Key or ID Key |
| keyYellow | Just a Key |
| user | Client Method |
| redFlag | Not Inheritable |
| table | SQL Procedure |
| earth | WEB Method |
| zed | ZEN Method |
| eye | Read Only |
264 | Some of the class properties or parameters and all of the methods and SQL procedures 265 | are clickable. You can click them and get additional information such as code of 266 | the method or code of SQL procedure. 267 |
268 |269 | Elements which have italic font are hoverable. You can hover over them 270 | to get additional information. Non-hoverable elements are usually those which 271 | does not have any keywords or comments defined. 272 |
273 |274 | All links except inheritance are hoverable too. Hovering over links will 275 | highlight appropriate fields in linked classes. 276 |
277 |