QC Macro check
intermediateslide loadergallerymacroqc
Console
PMA.UI version: 2.43.3
Gallery & slide loader with macro image example
qc_macro_check.html
1<!doctype >
2<html lang="en">
3
4<head>
5 <meta charset="utf-8">
6 <meta http-equiv="X-UA-Compatible" content="IE=10">
7 <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
8
9 <!-- Include PMA.UI required libraries downloaded or from CDN -->
10 <script src="./pma.ui/jquery-3.1.0.js"></script>
11 <link href="./pma.ui/font-awesome.min.css" type="text/css" rel="stylesheet">
12
13 <!-- Include optional libraries downloaded or from CDN -->
14 <link rel="stylesheet" href="./pma.ui/bootstrap5.min.css">
15 <script src="./pma.ui/bootstrap5.bundle.min.js"></script>
16
17 <!-- Include PMA.UI script & css -->
18 <script src="./pma.ui/pma.ui.js"></script>
19 <link href="./pma.ui/pma.ui.css" type="text/css" rel="stylesheet">
20
21 <!-- Include custom script & css -->
22 <script src="./js/qc_macro_check.js"></script>
23 <link href="./css/qc_macro_check.css" type="text/css" rel="stylesheet">
24
25 <title>QC Macro check</title>
26</head>
27
28<body>
29 <div class="container-fluid">
30 <div class="row justify-content-center min-vh-100">
31 <div class="col">
32 <div class="d-flex flex-column h-100">
33 <div class="row p-0 g-2 align-items-center">
34 <div class="col-auto">
35 <div id="gallery"></div>
36 </div>
37 <div class="col-auto d-flex flex-grow-1 justify-content-center aprroval-buttons hide">
38 <div class="btn-group btn-group-lg" role="group" aria-label="Basic mixed styles example">
39 <button type="button" class="btn btn-success"
40 onclick="showMessage(true)">Approve</button>
41 <button type="button" class="btn btn-danger"
42 onclick="showMessage(false)">Reject</button>
43 </div>
44 </div>
45 </div>
46 <div class="row flex-grow-1">
47 <!-- The element that will host annotation actions -->
48 <div class="col-4 p-0">
49 <div id="qc" class="hide w-100 h-100">
50 <div id="macro_content_container" class="w-100 h-100">
51 <div id="mark_container_wrapper">
52 <div id="mark_container">
53 <div id="approve_mark" class="hide" aria-hidden="true"></div>
54 <div id="reject_mark" class="hide" aria-hidden="true"></div>
55 </div>
56 </div>
57 <div class="w-100 d-flex justify-content-center macro_link_wrapper">
58 <div class="macro_link_inner">
59 <a class="btn btn-secondary" id="macro_link" href="" target="_blank">
60 Open macro in new tab
61 </a>
62 </div>
63 </div>
64 <div id="macro-viewer"></div>
65 </div>
66 </div>
67 </div>
68 <div class="col p-0">
69 <!-- The element that will host the slide loader -->
70 <div id="viewer"></div>
71 </div>
72 </div>
73 </div>
74 </div>
75 </div>
76 </div>
77</body>
78
79</html>
qc_macro_check.css
1html,
2body {
3 height: 100%;
4 padding: 0px;
5 margin: 0px;
6 font-family: Arial, Helvetica, sans-serif;
7}
8
9body .pma-ui-viewport-container {
10 height: 100%;
11 width: 100%;
12}
13
14.mark-container {
15 position: relative;
16 height: 0;
17}
18
19.mark-container .mark-container-inner {
20 position: absolute;
21 bottom: 0;
22 right: 0;
23}
24
25#mark_container_wrapper {
26 position: relative;
27 height: 0;
28}
29
30#mark_container {
31 position: absolute;
32 top: 0;
33 right: 0;
34 z-index: 10;
35}
36
37#approve_mark {
38 border-top: 2vw solid rgba(65, 155, 69, 1);
39 border-left: 2vw solid rgba(255, 255, 255, 0);
40}
41
42#reject_mark {
43 border-top: 2vw solid rgba(247, 11, 0, 1);
44 border-left: 2vw solid rgba(255, 255, 255, 0);
45}
46
47#macro-viewer .ol-zoom.ol-control {
48 display: none;
49}
50
51.macro_link_wrapper {
52 position: relative;
53 height: 0;
54}
55
56.macro_link_inner {
57 position: absolute;
58 z-index: 10;
59}
qc_macro_check.js
1// Initial declarations
2var serverUrl = "https://host.pathomation.com/pma.core.3/";
3var serverUsername = "PMA_UI_demo";
4var serverPassword = "PMA_UI_demo";
5var galleryElementSelector = "#gallery";
6var slideLoaderElementSelector = "#viewer";
7var qcElementSelector = "#qc";
8var macroContainerElementSelector = "#macro_content_container";
9var macroElementSelector = "#macro_content";
10var figureMacroElementSelector = "#macro_figure";
11var macroLinkElementSelector = "#macro_link";
12var messageContentElementSelector = "#message_content";
13var approvalMessageContainerElementSelector = "#approval_message_container";
14var approveMarkElementSelector = "#approve_mark";
15var rejectMarkElementSelector = "#reject_mark";
16var caller = "DemoPortal";
17var galleryMode = "horizontal";
18var directoryPath = "Reference/Hamamatsu/Demo";
19var thumbnailWidth = 150;
20var thumbnailHeight = 100;
21var slideName = "Slide Name";
22var selectedSlideIndex = null;
23var statusSlideKey = null;
24var macroMagnifyImg = null;
25var macroViewport = null;
26
27// Message functionality →
28function showMessage(isApproved) {
29 let approval = isApproved ? "Approved" : "Denied";
30
31 if (statusSlideKey === null) {
32 $(approveMarkElementSelector).addClass("hide");
33 $(rejectMarkElementSelector).addClass("hide");
34
35 alert(`Please, select a slide in the gallery.`);
36 return;
37 } else {
38 let slideIndex = statusSlideKey.split("_").slice(-1)[0];
39 let galleryListItem = $(`#gallery ul li:eq(${slideIndex})`);
40 let statusUpIcon = `<div id=${statusSlideKey + "_up"} class="mark-container">
41 <div class="mark-container-inner">
42 <i class="fa fa-check-square mark text-success bg-white rounded" aria-hidden="true"></i>
43 </div>
44 </div>`;
45 let statusDownIcon = `<div id=${statusSlideKey + "_down"} class="mark-container">
46 <div class="mark-container-inner">
47 <i class="fa fa-window-close mark text-danger bg-white rounded" aria-hidden="true"></i>
48 </div>
49 </div>`;
50
51 if (isApproved) {
52 window.sessionStorage.setItem(statusSlideKey, "true");
53
54 $(approveMarkElementSelector).removeClass("hide");
55 $(rejectMarkElementSelector).addClass("hide");
56
57 $(`#${statusSlideKey}_down`).remove();
58 galleryListItem.append(statusUpIcon);
59 } else {
60 window.sessionStorage.setItem(statusSlideKey, "false");
61
62 $(approveMarkElementSelector).addClass("hide");
63 $(rejectMarkElementSelector).removeClass("hide");
64
65 $(`#${statusSlideKey}_up`).remove();
66 galleryListItem.append(statusDownIcon);
67 }
68 }
69
70 if (slideName !== "Slide Name") {
71 console.log(`The ${slideName} slide has been ${approval}.`);
72 } else {
73 alert(`Please, select a slide in the gallery.`);
74 }
75}
76// Message functionality ←
77
78jQuery(function () {
79 console.log(`PMA.UI version: ${PMA.UI.getVersion()}`);
80
81 // Create a context
82 var context = new PMA.UI.Components.Context({ caller: caller });
83
84 // Add an autologin authentication provider
85 new PMA.UI.Authentication.AutoLogin(context, [{ serverUrl: serverUrl, username: serverUsername, password: serverPassword }]);
86
87 // Create a gallery that will display the slides
88 var gallery = new PMA.UI.Components.Gallery(context, {
89 element: galleryElementSelector,
90 thumbnailWidth: thumbnailWidth,
91 thumbnailHeight: thumbnailHeight,
92 mode: galleryMode,
93 barcodeRotation: 90,
94 });
95
96 // Create an image loader that will allow us to load images easily
97 var slideLoader = new PMA.UI.Components.SlideLoader(context, {
98 element: slideLoaderElementSelector,
99 overview: false,
100 barcode: {
101 collapsed: false,
102 rotation: 90,
103 },
104 position: {
105 rotation: 1.570796325,
106 },
107 });
108
109 // Load the contents of a directory
110 gallery.loadDirectory(serverUrl, directoryPath, function () {
111 let sessStorage = window.sessionStorage;
112
113 for (let i = 0; i < sessStorage.length; i++) {
114 const key = sessStorage.key(i);
115
116 if (key.includes("status_")) {
117 let statusSlide = window.sessionStorage.getItem(key);
118 let slideIndex = key.split("_").slice(-1)[0];
119 let galleryListItem = $(`#gallery ul li:eq(${slideIndex})`);
120 let statusUpIcon = `<div id=${key + "_up"} class="mark-container">
121 <div class="mark-container-inner">
122 <i class="fa fa-check-square mark text-success bg-white rounded" aria-hidden="true"></i>
123 </div>
124 </div>`;
125 let statusDownIcon = `<div id=${key + "_down"} class="mark-container">
126 <div class="mark-container-inner">
127 <i class="fa fa-window-close mark text-danger bg-white rounded" aria-hidden="true"></i>
128 </div>
129 </div>`;
130
131 // Check the status of the slides and show status if possible
132 if (statusSlide === "true") {
133 $(`#${key}_down`).remove();
134 galleryListItem.append(statusUpIcon);
135 } else {
136 if (statusSlide === "false") {
137 $(`#${key}_up`).remove();
138 galleryListItem.append(statusDownIcon);
139 }
140 }
141 }
142 }
143
144 $(".aprroval-buttons").removeClass("hide");
145 });
146
147 // Listen for the slide selected event by the gallery
148 gallery.listen(PMA.UI.Components.Events.SlideSelected, function (args) {
149 console.log("Slide selected");
150 console.log(args);
151
152 // Status check →
153 // Set the index of the selected slide as value of the selectedSlideIndex variable
154 selectedSlideIndex = String(args.index);
155
156 // Get the approval status of the selected slide
157 statusSlideKey = "status_" + selectedSlideIndex;
158 let statusSelectedSlide = window.sessionStorage.getItem(statusSlideKey);
159
160 // Check the status of the selected slide and show status if needed
161 if (statusSelectedSlide === null) {
162 $(approveMarkElementSelector).addClass("hide");
163 $(rejectMarkElementSelector).addClass("hide");
164 } else {
165 if (statusSelectedSlide === "true") {
166 $(approveMarkElementSelector).removeClass("hide");
167 $(rejectMarkElementSelector).addClass("hide");
168 } else {
169 if (statusSelectedSlide === "false") {
170 $(approveMarkElementSelector).addClass("hide");
171 $(rejectMarkElementSelector).removeClass("hide");
172 }
173 }
174 }
175 // Status check ←
176
177 // Parse the slide name from the path
178 slideName = args.path.split("/").slice(-1)[0];
179
180 // Load the image selected from treeview
181 slideLoader.load(serverUrl, args.path);
182 });
183
184 // Listen for the slide deselected event by the gallery
185 gallery.listen(PMA.UI.Components.Events.SlideDeSelected, function (args) {
186 console.log("Slide deselected");
187 console.log(args);
188
189 // Clear approval state
190 statusSlideKey = null;
191
192 // Clear slide loader
193 slideLoader.load(serverUrl, null);
194
195 // Hide macro
196 $(qcElementSelector).addClass("hide");
197 });
198
199 // Listen for the slide loaded event by the slide loader
200 slideLoader.listen(PMA.UI.Components.Events.SlideLoaded, function (args) {
201 console.log("Slide loaded");
202 console.log(args);
203
204 if (!slideLoader.mainViewport) {
205 return;
206 }
207
208 const urlQuery = "?SessionID=" + slideLoader.mainViewport.getSessionID() + "&pathOrUid=" + args.path;
209 const macroImg = `${serverUrl}macro${urlQuery}`;
210
211 // Set the link to the Macro
212 $(macroLinkElementSelector).attr("href", macroImg);
213
214 // Show the Macro image
215 $(qcElementSelector).removeClass("hide");
216
217 macroViewport = new PMA.UI.View.Viewport(
218 {
219 element: "#macro-viewer",
220 referenceImage: {
221 src: macroImg,
222 width: 1000,
223 height: 333,
224 backgroundColor: "#ffffff",
225 },
226 digitalZoomLevels: 5,
227 overview: false,
228 dimensions: false,
229 barcode: false,
230 rotationControl: false,
231 filename: false,
232 scaleLine: false,
233 fullscreenControl: false,
234 loadingBar: false,
235 zoomSlider: false,
236 position: {
237 rotation: 1.570796325,
238 }
239 },
240 );
241 });
242
243 // Listen for the slide info error event by slide loader
244 slideLoader.listen(PMA.UI.Components.Events.SlideInfoError, function (args) {
245 console.log("Slide info error");
246 console.log(args);
247 });
248});