Merge branch 'master' into fix-ExpandableToolMenu-props

This commit is contained in:
Danny Brown 2019-08-22 10:33:23 -04:00 committed by GitHub
commit ee68b7bcd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 114 additions and 1138 deletions

View File

@ -27,4 +27,4 @@ mv platform/viewer/dist/* .netlify/www/pwa -v
echo 'Nothing left to see here. Go home, folks.'
# Build using react-scripts
# npx cross-env PUBLIC_URL=/demo REACT_APP_CONFIG=config/netlify.js react-scripts --max_old_space_size=4096 build
# npx cross-env PUBLIC_URL=/demo APP_CONFIG=config/netlify.js react-scripts --max_old_space_size=4096 build

View File

@ -10,7 +10,7 @@
<!-- CORNERSTONE.js -->
<tr>
<td>
<a href="https://www.npmjs.com/package/ohif-cornerstone-extension">
<a href="https://www.npmjs.com/package/@ohif/extension-cornerstone">
Cornerstone
</a>
</td>
@ -22,7 +22,7 @@
<!-- VTK.js -->
<tr>
<td>
<a href="https://www.npmjs.com/package/ohif-vtk-extension">
<a href="https://www.npmjs.com/package/@ohif/extension-vtk">
VTK.js
</a>
</td>
@ -33,30 +33,30 @@
</tr>
<tr>
<td>
<a href="">HTML</a>
<a href="https://www.npmjs.com/package/@ohif/extension-dicom-html">DICOM HTML</a>
</td>
<td>
Renders text and HTML content for <a href="https://github.com/OHIF/Viewers/blob/react/extensions/ohif-dicom-html-extension/src/OHIFDicomHtmlSopClassHandler.js#L7-L15">specific SopClassUIDs</a>.
Renders text and HTML content for <a href="https://github.com/OHIF/Viewers/blob/master/extensions/dicom-html/src/OHIFDicomHtmlSopClassHandler.js#L4-L12">specific SopClassUIDs</a>.
</td>
<td>Viewport, SopClassHandler</td>
</tr>
<tr>
<td>
<a href="https://www.npmjs.com/package/ohif-dicom-pdf-extension">PDF</a>
<a href="https://www.npmjs.com/package/@ohif/extension-dicom-pdf">DICOM PDF</a>
</td>
<td>
Renders PDFs for a <a href="https://github.com/OHIF/Viewers/blob/react/extensions/ohif-dicom-pdf-extension/src/OHIFDicomPDFSopClassHandler.js#L8">specific SopClassUID</a>.
Renders PDFs for a <a href="https://github.com/OHIF/Viewers/blob/master/extensions/dicom-pdf/src/OHIFDicomPDFSopClassHandler.js#L4-L6">specific SopClassUID</a>.
</td>
<td>Viewport, SopClassHandler</td>
</tr>
<tr>
<td>
<a href="https://www.npmjs.com/package/ohif-dicom-microscopy-extension">Microscopy</a>
<a href="https://www.npmjs.com/package/@ohif/extension-dicom-microscopy">DICOM Microscopy</a>
</td>
<td>
Renders Microscopy images for a <a href="https://github.com/OHIF/Viewers/blob/react/extensions/ohif-dicom-microscopy-extension/src/DicomMicroscopySopClassHandler.js#L6">specific SopClassUID</a>.
Renders Microscopy images for a <a href="https://github.com/OHIF/Viewers/blob/master/extensions/dicom-microscopy/src/DicomMicroscopySopClassHandler.js#L5-L7">specific SopClassUID</a>.
</td>
<td>Viewport, SopClassHandler</td>
</tr>
</tbody>
</table>
</table>

View File

@ -152,7 +152,7 @@ is used depends on:
<center><i>An example of three Viewports</i></center>
For a complete example implementation,
[check out the OHIFCornerstoneViewport](https://github.com/OHIF/Viewers/blob/react/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneViewport.js).
[check out the OHIFCornerstoneViewport](https://github.com/OHIF/Viewers/blob/master/extensions/cornerstone/src/OHIFCornerstoneViewport.js).
#### Toolbar
@ -168,7 +168,7 @@ store.
Toolbar components are rendered in the `ToolbarRow` component.
For a complete example implementation,
[check out the OHIFCornerstoneViewport's Toolbar Module](https://github.com/OHIF/Viewers/blob/react/extensions/ohif-cornerstone-extension/src/ToolbarModule.js).
[check out the OHIFCornerstoneViewport's Toolbar Module](https://github.com/OHIF/Viewers/blob/master/extensions/cornerstone/src/toolbarModule.js).
#### SopClassHandler
@ -197,9 +197,9 @@ would like included at startup.
_app.js_
```js
import { createStore, combineReducers } from "redux";
import OHIF from "@ohif/core";
import OHIFCornerstoneExtension from "ohif-cornerstone-extension";
import { createStore, combineReducers } from 'redux';
import OHIF from '@ohif/core';
import OHIFCornerstoneExtension from 'ohif-cornerstone-extension';
const combined = combineReducers(OHIF.redux.reducers);
const store = createStore(combined);
@ -214,8 +214,8 @@ ExtensionManager.registerExtensions(store, extensions);
A small number of powerful extensions for popular use cases are maintained by
OHIF. They're co-located in the
[`OHIF/Viewers`](https://github.com/OHIF/Viewers/tree/react/) repository, in the
top level [`extensions/`](https://github.com/OHIF/Viewers/tree/react/extensions)
[`OHIF/Viewers`](https://github.com/OHIF/Viewers) repository, in the top level
[`extensions/`](https://github.com/OHIF/Viewers/tree/master/extensions)
directory.
{% include "./_maintained-extensions-table.md" %}
@ -225,6 +225,6 @@ directory.
-->
<!-- prettier-ignore-start -->
[example-ext-src]: https://github.com/OHIF/Viewers/blob/master/extensions/_ohif-example-extension/src/index.js)
[module-types]: https://github.com/OHIF/ohif-core/blob/43c08a29eff3fb646a0e83a03a236ddd84f4a6e8/src/plugins.js#L1-L6
[example-ext-src]: https://github.com/OHIF/Viewers/tree/master/extensions/_example/src
[module-types]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/extensions/MODULE_TYPES.js
<!-- prettier-ignore-end -->

View File

@ -53,7 +53,7 @@ Images can even be transcoded on the fly if this is desired.
```bash
cd OHIFViewer
yarn install
REACT_APP_CONFIG=config/google.js yarn run dev
APP_CONFIG=config/google.js yarn run dev
```
## Running via Docker

View File

@ -71,11 +71,11 @@ how to configure the project for your own imaging archive below.
#### How it Works
The configuration for our project is in the `/public/config` directory. Our
build process knows which configuration file to use based on the
`REACT_APP_CONFIG` environment variable. By default, its value is
[`default.js`](https://github.com/OHIF/Viewers/blob/react/public/config/default.js).
When we build, the `%REACT_APP_CONFIG%` value in
our[`/public/index.html`](https://github.com/OHIF/Viewers/blob/react/public/index.html#L12-L15)
build process knows which configuration file to use based on the `APP_CONFIG`
environment variable. By default, its value is
[`default.js`](https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/config/default.js).
When we build, the `%APP_CONFIG%` value in
our[`/public/index.html`](https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/index.html)
file is substituted for the correct configuration file's name. This sets
the`window.config` equal to our configuration file's value.
@ -104,17 +104,17 @@ window.config = {
},
],
},
}
};
```
You can also create a new config file and specify its path relative to the build
output's root by setting the `REACT_APP_CONFIG` environment variable. You can
set the value of this environment variable a few different ways:
output's root by setting the `APP_CONFIG` environment variable. You can set the
value of this environment variable a few different ways:
- [Add a temporary environment variable in your shell](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-temporary-environment-variables-in-your-shell)
- [Add environment specific variables in `.env` file(s)](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-development-environment-variables-in-env)
- Using the `cross-env` package in an npm script:
- `"build": "cross-env REACT_APP_CONFIG=config/my-config.js react-scripts build"`
- `"build": "cross-env APP_CONFIG=config/my-config.js react-scripts build"`
After updating the configuration, `yarn run build:web` to generate updated build
output.

View File

@ -11,7 +11,7 @@ control.
Do not use this recipe to host sensitive medical data on the open web. Depending
on your company's policies, this may be an appropriate setup on an internal
network when protected with a server's basic authentication. For a more robust
setup, check out our [user account control recpie](./user-account-control.md)
setup, check out our [user account control recipe](./user-account-control.md)
that builds on the lessons learned here.
## Overview
@ -51,7 +51,7 @@ We can solve this one of two ways:
This solution uses the first approach, but you can see an example of the second
in the `docker-compose` bundled with this project for local development:
[HERE](#)
[HERE](https://github.com/OHIF/Viewers/blob/master/platform/viewer/.recipes/Nginx-Orthanc/docker-compose.yml)
You can read more about CORS in this Medium article: [Understanding
CORS][understanding-cors]
@ -124,10 +124,10 @@ likely want to update:
The OHIF Viewer's configuration is imported from a static `.js` file and made
available globally at `window.config`. The configuration we use is set to a
specific file when we build the viewer, and determined by the env variable:
`REACT_APP_CONFIG`. You can see where we set its value in the `dockerfile` for
this solution:
`APP_CONFIG`. You can see where we set its value in the `dockerfile` for this
solution:
`ENV REACT_APP_CONFIG=config/docker_openresty-orthanc.js`
`ENV APP_CONFIG=config/docker_openresty-orthanc.js`
You can find the configuration we're using here:
`/public/config/docker_openresty-orthanc.js`

View File

@ -125,10 +125,10 @@ likely want to update:
The OHIF Viewer's configuration is imported from a static `.js` file and made
available globally at `window.config`. The configuration we use is set to a
specific file when we build the viewer, and determined by the env variable:
`REACT_APP_CONFIG`. You can see where we set its value in the `dockerfile` for
this solution:
`APP_CONFIG`. You can see where we set its value in the `dockerfile` for this
solution:
`ENV REACT_APP_CONFIG=config/docker_openresty-orthanc-keycloak.js`
`ENV APP_CONFIG=config/docker_openresty-orthanc-keycloak.js`
You can find the configuration we're using here:
`/public/config/docker_openresty-orthanc-keycloak.js`
@ -281,9 +281,9 @@ community members put together:
[orthanc-docs]: http://book.orthanc-server.com/users/configuration.html#configuration
[lua-resty-openidc-docs]: https://github.com/zmartzone/lua-resty-openidc
<!-- SRC -->
[config]: #
[dockerfile]: #
[config-nginx]: #
[config-orthanc]: #
[config-keycloak]: #
[config]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/src/config.js
[dockerfile]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/.recipes
[config-nginx]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/.recipes
[config-orthanc]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/.recipes
[config-keycloak]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/.recipes
<!-- prettier-ignore-end -->

View File

@ -7,11 +7,11 @@
## How it Works
The configuration for our project is in the `/public/config` directory. Our
build process knows which configuration file to use based on the
`REACT_APP_CONFIG` environment variable. By default, its value is
[`default.js`](https://github.com/OHIF/Viewers/blob/react/public/config/default.js).
When we build, the `%REACT_APP_CONFIG%` value in
our[`/public/index.html`](https://github.com/OHIF/Viewers/blob/react/public/index.html#L12-L15)
build process knows which configuration file to use based on the `APP_CONFIG`
environment variable. By default, its value is
[`default.js`](https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/config/default.js).
When we build, the `%APP_CONFIG%` value in
our[`/public/index.html`](https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/index.html)
file is substituted for the correct configuration file's name. This sets the
`window.config` equal to our configuration file's value.
@ -40,17 +40,17 @@ window.config = {
},
],
},
}
};
```
You can also create a new config file and specify its path relative to the build
output's root by setting the `REACT_APP_CONFIG` environment variable. You can
set the value of this environment variable a few different ways:
output's root by setting the `APP_CONFIG` environment variable. You can set the
value of this environment variable a few different ways:
- [Add a temporary environment variable in your shell](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-temporary-environment-variables-in-your-shell)
- [Add environment specific variables in `.env` file(s)](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-development-environment-variables-in-env)
- Using the `cross-env` package in an npm script:
- `"build": "cross-env REACT_APP_CONFIG=config/my-config.js react-scripts build"`
- `"build": "cross-env APP_CONFIG=config/my-config.js react-scripts build"`
After updating the configuration, `yarn run build:web` to generate updated build
output.

View File

@ -60,8 +60,8 @@ _Upload your first Study:_
#### Orthanc: Learn More
You can see the `docker-compose.yml` file this command runs at
[`<project-root>/docker/Nginx-Docker/`](#), and more on Orthanc for Docker in
[Orthanc's documentation][orthanc-docker].
[`<project-root>/platform/viewer/.recipes/Nginx-Orthanc/`](https://github.com/OHIF/Viewers/tree/master/platform/viewer/.recipes/Nginx-Orthanc),
and more on Orthanc for Docker in [Orthanc's documentation][orthanc-docker].
### Connecting to Orthanc
@ -87,19 +87,18 @@ is running the `dev:orthanc` script in our project's `package.json`. That script
is:
```js
cross-env PORT=5000 REACT_APP_CONFIG=config/docker_nginx-orthanc.js react-scripts start
cross-env PORT=5000 APP_CONFIG=config/docker_nginx-orthanc.js react-scripts start
```
- `cross-env` sets two environment variables
- PORT: 5000
- REACT_APP_CONFIG: `config/docker_nginx-orthanc.js`
- APP_CONFIG: `config/docker_nginx-orthanc.js`
- `react-scripts` runs it's `start` script. This is [the de-facto
way][cra-start] to run a "Create React App" in development mode.
The `REACT_APP_CONFIG` value tells our app which file to load on to
`window.config`. By default, our app uses the file at
`<project-root>/public/config/default.js`. Here is what that configuration looks
like:
The `APP_CONFIG` value tells our app which file to load on to `window.config`.
By default, our app uses the file at `<project-root>/public/config/default.js`.
Here is what that configuration looks like:
```js
window.config = {

View File

@ -37,8 +37,8 @@ Some tips for filing a new issue:
At the moment we are in the process of defining our roadmap and will do our best
to communicate this to the community. If your requested feature is on the
roadmap, then it will most likely be built at some point. If it is not, you are
welcome to build it yourself and [contribute it](../contributing.md). If you
have resources and would like to fund the development of a feature, please
welcome to build it yourself and [contribute it](contributing.md). If you have
resources and would like to fund the development of a feature, please
[contact us](http://www.ohif.org).
### Who should I contact about Academic Collaborations?

View File

@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.50.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.50.2...@ohif/extension-vtk@0.50.3) (2019-08-22)
**Note:** Version bump only for package @ohif/extension-vtk
## [0.50.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.50.1...@ohif/extension-vtk@0.50.2) (2019-08-15)

View File

@ -1,6 +1,6 @@
{
"name": "@ohif/extension-vtk",
"version": "0.50.2",
"version": "0.50.3",
"description": "OHIF extension for VTK.js",
"author": "OHIF",
"license": "MIT",
@ -52,7 +52,7 @@
"vtk.js": "^9.5.0"
},
"devDependencies": {
"@ohif/core": "^0.50.1",
"@ohif/core": "^0.50.2",
"@ohif/ui": "^0.50.1",
"cornerstone-tools": "^3.13.0",
"cornerstone-wado-image-loader": "^3.0.0",

View File

@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.50.2](https://github.com/OHIF/Viewers/compare/@ohif/core@0.50.1...@ohif/core@0.50.2) (2019-08-22)
**Note:** Version bump only for package @ohif/core
## [0.50.1](https://github.com/OHIF/Viewers/compare/@ohif/core@0.50.0-alpha.10...@ohif/core@0.50.1) (2019-08-14)
**Note:** Version bump only for package @ohif/core

View File

@ -1,6 +1,6 @@
{
"name": "@ohif/core",
"version": "0.50.1",
"version": "0.50.2",
"description": "Generic business logic for web-based medical imaging applications",
"author": "OHIF Core Team",
"license": "MIT",

View File

@ -18,8 +18,6 @@ import { StudyMetadataSource } from './StudyMetadataSource';
import { StudyPrefetcher } from './StudyPrefetcher';
import { TypeSafeCollection } from './TypeSafeCollection';
//import { StudySummary } from './metadata/StudySummary';
export {
OHIFStudyMetadataSource,
MetadataProvider,
@ -27,7 +25,7 @@ export {
HotkeysManager,
ImageSet,
StudyPrefetcher,
//StudyLoadingListener,
StudyLoadingListener,
StackLoadingListener,
DICOMFileLoadingListener,
StudyMetadata,

View File

@ -1,458 +0,0 @@
var dialogPolyfill = (function() {
var supportCustomEvent = window.CustomEvent;
if (!supportCustomEvent || typeof supportCustomEvent == 'object') {
supportCustomEvent = function CustomEvent(event, x) {
x = x || {};
var ev = document.createEvent('CustomEvent');
ev.initCustomEvent(event, !!x.bubbles, !!x.cancelable, x.detail || null);
return ev;
};
supportCustomEvent.prototype = window.Event.prototype;
}
/**
* Finds the nearest <dialog> from the passed element.
*
* @param {Element} el to search from
* @param {HTMLDialogElement} dialog found
*/
function findNearestDialog(el) {
while (el) {
if (el.nodeName == 'DIALOG') {
return el;
}
el = el.parentElement;
}
return null;
}
var dialogPolyfill = {};
dialogPolyfill.reposition = function(element) {
var scrollTop =
document.body.scrollTop || document.documentElement.scrollTop;
var topValue = scrollTop + (window.innerHeight - element.offsetHeight) / 2;
element.style.top = Math.max(0, topValue) + 'px';
element.dialogPolyfillInfo.isTopOverridden = true;
};
dialogPolyfill.inNodeList = function(nodeList, node) {
for (var i = 0; i < nodeList.length; ++i) {
if (nodeList[i] == node) return true;
}
return false;
};
dialogPolyfill.isInlinePositionSetByStylesheet = function(element) {
for (var i = 0; i < document.styleSheets.length; ++i) {
var styleSheet = document.styleSheets[i];
var cssRules = null;
// Some browsers throw on cssRules.
try {
cssRules = styleSheet.cssRules;
} catch (e) {}
if (!cssRules) continue;
for (var j = 0; j < cssRules.length; ++j) {
var rule = cssRules[j];
var selectedNodes = null;
// Ignore errors on invalid selector texts.
try {
selectedNodes = document.querySelectorAll(rule.selectorText);
} catch (e) {}
if (
!selectedNodes ||
!dialogPolyfill.inNodeList(selectedNodes, element)
)
continue;
var cssTop = rule.style.getPropertyValue('top');
var cssBottom = rule.style.getPropertyValue('bottom');
if ((cssTop && cssTop != 'auto') || (cssBottom && cssBottom != 'auto'))
return true;
}
}
return false;
};
dialogPolyfill.needsCentering = function(dialog) {
var computedStyle = window.getComputedStyle(dialog);
if (computedStyle.position != 'absolute') {
return false;
}
// We must determine whether the top/bottom specified value is non-auto. In
// WebKit/Blink, checking computedStyle.top == 'auto' is sufficient, but
// Firefox returns the used value. So we do this crazy thing instead: check
// the inline style and then go through CSS rules.
if (
(dialog.style.top != 'auto' && dialog.style.top != '') ||
(dialog.style.bottom != 'auto' && dialog.style.bottom != '')
)
return false;
return !dialogPolyfill.isInlinePositionSetByStylesheet(dialog);
};
dialogPolyfill.showDialog = function(isModal) {
if (this.open) {
throw 'InvalidStateError: showDialog called on open dialog';
}
this.open = true; // TODO: should be a getter mapped to attribute
this.setAttribute('open', 'open');
if (isModal) {
// Find element with `autofocus` attribute or first form control
var first_form_ctrl = null;
var autofocus = null;
var findElementToFocus = function(root) {
if (!root.children) {
return;
}
for (var i = 0; i < root.children.length; i++) {
var elem = root.children[i];
if (
first_form_ctrl === null &&
!elem.disabled &&
(elem.nodeName == 'BUTTON' ||
elem.nodeName == 'INPUT' ||
elem.nodeName == 'KEYGEN' ||
elem.nodeName == 'SELECT' ||
elem.nodeName == 'TEXTAREA')
) {
first_form_ctrl = elem;
}
if (elem.autofocus) {
autofocus = elem;
return;
}
findElementToFocus(elem);
if (autofocus !== null) return;
}
};
findElementToFocus(this);
if (autofocus !== null) {
autofocus.focus();
} else if (first_form_ctrl !== null) {
first_form_ctrl.focus();
}
}
if (dialogPolyfill.needsCentering(this)) dialogPolyfill.reposition(this);
if (isModal) {
this.dialogPolyfillInfo.modal = true;
dialogPolyfill.dm.pushDialog(this);
}
// IE sometimes complains when calling .focus() that it
// "Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus."
try {
if (autofocus !== null) {
autofocus.focus();
} else if (first_form_ctrl !== null) {
first_form_ctrl.focus();
}
} catch (e) {}
this.style.zoom = 1;
};
dialogPolyfill.close = function(retval) {
if (!this.open && !window.HTMLDialogElement) {
// Native implementations will set .open to false, so ignore this error.
throw 'InvalidStateError: close called on closed dialog';
}
this.open = false;
this.removeAttribute('open');
// Leave returnValue untouched in case it was set directly on the element
if (typeof retval != 'undefined') {
this.returnValue = retval;
}
// This won't match the native <dialog> exactly because if the user sets top
// on a centered polyfill dialog, that top gets thrown away when the dialog is
// closed. Not sure it's possible to polyfill this perfectly.
if (this.dialogPolyfillInfo.isTopOverridden) {
this.style.top = 'auto';
}
if (this.dialogPolyfillInfo.modal) {
dialogPolyfill.dm.removeDialog(this);
}
// Triggering "close" event for any attached listeners on the <dialog>
var event;
if (document.createEvent) {
event = document.createEvent('HTMLEvents');
event.initEvent('close', true, true);
} else {
event = new Event('close');
}
this.dispatchEvent(event);
return this.returnValue;
};
dialogPolyfill.registerDialog = function(element) {
if (element.show) {
// console.warn("This browser already supports <dialog>, the polyfill " +
// "may not work correctly.");
}
element.show = dialogPolyfill.showDialog.bind(element, false);
element.showModal = dialogPolyfill.showDialog.bind(element, true);
element.close = dialogPolyfill.close.bind(element);
element.dialogPolyfillInfo = {};
element.open = false;
};
// The overlay is used to simulate how a modal dialog blocks the document. The
// blocking dialog is positioned on top of the overlay, and the rest of the
// dialogs on the pending dialog stack are positioned below it. In the actual
// implementation, the modal dialog stacking is controlled by the top layer,
// where z-index has no effect.
var TOP_LAYER_ZINDEX = 100000;
var MAX_PENDING_DIALOGS = 100000;
dialogPolyfill.DialogManager = function() {
this.pendingDialogStack = [];
this.overlay = document.createElement('div');
this.overlay.style.width = '100%';
this.overlay.style.height = '100%';
this.overlay.style.position = 'fixed';
this.overlay.style.left = '0px';
this.overlay.style.top = '0px';
this.overlay.style.backgroundColor = 'rgba(0,0,0,0.0)';
this.focusPageLast = this.createFocusable();
this.overlay.appendChild(this.focusPageLast);
this.overlay.addEventListener('click', function(e) {
var redirectedEvent = document.createEvent('MouseEvents');
redirectedEvent.initMouseEvent(
e.type,
e.bubbles,
e.cancelable,
window,
e.detail,
e.screenX,
e.screenY,
e.clientX,
e.clientY,
e.ctrlKey,
e.altKey,
e.shiftKey,
e.metaKey,
e.button,
e.relatedTarget
);
document.body.dispatchEvent(redirectedEvent);
});
// TODO: Only install when any dialogs are open.
document.addEventListener(
'submit',
function(ev) {
var method = ev.target.getAttribute('method');
method = method ? method.toLowerCase() : '';
if (method != 'dialog') {
return;
}
ev.preventDefault();
var dialog = findNearestDialog(ev.target);
if (!dialog) {
return;
}
// FIXME: The original event doesn't contain the INPUT element used to
// submit the form (if any). Look in some possible places.
var returnValue;
var cands = [document.activeElement, ev.explicitOriginalTarget];
cands.some(function(cand) {
if (cand && cand.nodeName == 'INPUT' && cand.form == ev.target) {
returnValue = cand.value;
return true;
}
});
dialog.close(returnValue);
},
true
);
};
dialogPolyfill.DialogManager.prototype.createFocusable = function(tabIndex) {
var span = document.createElement('span');
span.tabIndex = tabIndex || 0;
span.style.opacity = 0;
span.style.position = 'static';
return span;
};
dialogPolyfill.DialogManager.prototype.blockDocument = function() {
if (!document.body.contains(this.overlay)) {
document.body.appendChild(this.overlay);
// On Safari/Mac (and possibly other browsers), the documentElement is
// not focusable. This is required for modal dialogs as it is the first
// element to be hit by a tab event, and further tabs are redirected to
// the most visible dialog.
if (this.needsDocumentElementFocus === undefined) {
document.documentElement.focus();
this.needsDocumentElementFocus =
document.activeElement != document.documentElement;
}
if (this.needsDocumentElementFocus) {
document.documentElement.tabIndex = 1;
}
}
};
dialogPolyfill.DialogManager.prototype.unblockDocument = function() {
document.body.removeChild(this.overlay);
if (this.needsDocumentElementFocus) {
// TODO: Restore the previous tabIndex, rather than clearing it.
document.documentElement.tabIndex = '';
}
};
dialogPolyfill.DialogManager.prototype.updateStacking = function() {
if (this.pendingDialogStack.length == 0) {
this.unblockDocument();
return;
}
this.blockDocument();
var zIndex = TOP_LAYER_ZINDEX;
for (var i = 0; i < this.pendingDialogStack.length; i++) {
if (i == this.pendingDialogStack.length - 1)
this.overlay.style.zIndex = zIndex++;
var dialog = this.pendingDialogStack[i];
dialog.dialogPolyfillInfo.backdrop.style.zIndex = zIndex++;
dialog.style.zIndex = zIndex++;
}
};
dialogPolyfill.DialogManager.prototype.handleKey = function(event) {
var dialogCount = this.pendingDialogStack.length;
if (dialogCount == 0) {
return;
}
var dialog = this.pendingDialogStack[dialogCount - 1];
var pfi = dialog.dialogPolyfillInfo;
switch (event.keyCode) {
case 9 /* tab */:
var activeElement = document.activeElement;
var forward = !event.shiftKey;
if (forward) {
// Tab forward, so look for document or fake last focus element.
if (
activeElement == document.documentElement ||
activeElement == document.body ||
activeElement == pfi.backdrop
) {
pfi.focusFirst.focus();
} else if (activeElement == pfi.focusLast) {
// TODO: Instead of wrapping to focusFirst, escape to browser chrome.
pfi.focusFirst.focus();
}
} else {
// Tab backwards, so look for fake first focus element.
if (activeElement == pfi.focusFirst) {
// TODO: Instead of wrapping to focusLast, escape to browser chrome.
pfi.focusLast.focus();
} else if (activeElement == this.focusPageLast) {
// The focus element is at the end of the page (e.g., shift-tab from
// the window chrome): move current focus to the last element in the
// dialog instead.
pfi.focusLast.focus();
}
}
break;
case 27 /* esc */:
event.preventDefault();
event.stopPropagation();
var cancelEvent = new supportCustomEvent('cancel', {
bubbles: false,
cancelable: true,
});
if (dialog.dispatchEvent(cancelEvent)) {
dialog.close();
}
break;
}
};
dialogPolyfill.DialogManager.prototype.pushDialog = function(dialog) {
if (this.pendingDialogStack.length >= MAX_PENDING_DIALOGS) {
throw 'Too many modal dialogs';
}
var backdrop = document.createElement('div');
backdrop.className = 'backdrop';
var clickEventListener = function(e) {
var redirectedEvent = document.createEvent('MouseEvents');
redirectedEvent.initMouseEvent(
e.type,
e.bubbles,
e.cancelable,
window,
e.detail,
e.screenX,
e.screenY,
e.clientX,
e.clientY,
e.ctrlKey,
e.altKey,
e.shiftKey,
e.metaKey,
e.button,
e.relatedTarget
);
dialog.dispatchEvent(redirectedEvent);
};
backdrop.addEventListener('click', clickEventListener);
dialog.parentNode.insertBefore(backdrop, dialog.nextSibling);
dialog.dialogPolyfillInfo.backdrop = backdrop;
dialog.dialogPolyfillInfo.clickEventListener = clickEventListener;
this.pendingDialogStack.push(dialog);
this.updateStacking();
dialog.dialogPolyfillInfo.focusFirst = this.createFocusable();
dialog.dialogPolyfillInfo.focusLast = this.createFocusable();
dialog.appendChild(dialog.dialogPolyfillInfo.focusLast);
dialog.insertBefore(
dialog.dialogPolyfillInfo.focusFirst,
dialog.firstChild
);
};
dialogPolyfill.DialogManager.prototype.removeDialog = function(dialog) {
var index = this.pendingDialogStack.indexOf(dialog);
if (index == -1) {
return;
}
this.pendingDialogStack.splice(index, 1);
var backdrop = dialog.dialogPolyfillInfo.backdrop;
var clickEventListener = dialog.dialogPolyfillInfo.clickEventListener;
backdrop.removeEventListener('click', clickEventListener);
backdrop.parentNode.removeChild(backdrop);
dialog.dialogPolyfillInfo.backdrop = null;
dialog.dialogPolyfillInfo.clickEventListener = null;
this.updateStacking();
dialog.removeChild(dialog.dialogPolyfillInfo.focusFirst);
dialog.removeChild(dialog.dialogPolyfillInfo.focusLast);
dialog.dialogPolyfillInfo.focusFirst = null;
dialog.dialogPolyfillInfo.focusLast = null;
};
dialogPolyfill.dm = new dialogPolyfill.DialogManager();
document.addEventListener(
'keydown',
dialogPolyfill.dm.handleKey.bind(dialogPolyfill.dm)
);
return dialogPolyfill;
})();

View File

@ -1,34 +0,0 @@
dialog
position: absolute
left: 0
right: 0
width: -moz-fit-content
width: -webkit-fit-content
width: fit-content
height: -moz-fit-content
height: -webkit-fit-content
height: fit-content
margin: auto
border: solid
padding: 1em
background: white
color: black
display: none
dialog[open]
display: block
dialog + .backdrop
position: fixed
top: 0
right: 0
bottom: 0
left: 0
background: rgba(0,0,0,0.1)
/* for small devices, modal dialogs go full-screen */
@media screen and (max-width: 540px)
dialog[_polyfill_modal]
top: 0
width: auto
margin: 1em

View File

@ -1 +0,0 @@
import './styleProperty.js';

View File

@ -1,66 +0,0 @@
/*
* https://github.com/swederik/dragula/blob/ccc15d75186f5168e7abadbe3077cf12dab09f8b/styleProperty.js
*/
(function() {
'use strict';
const browserProps = {};
function eachVendor(prop, fn) {
const prefixes = ['Webkit', 'Moz', 'ms', 'O'];
fn(prop);
for (let i = 0; i < prefixes.length; i++) {
fn(prefixes[i] + prop.charAt(0).toUpperCase() + prop.slice(1));
}
}
function check(property, testValue) {
const sandbox = document.createElement('iframe');
const element = document.createElement('p');
document.body.appendChild(sandbox);
sandbox.contentDocument.body.appendChild(element);
const support = set(element, property, testValue);
// We have to do this because remove() is not supported by IE11 and below
sandbox.parentElement.removeChild(sandbox);
return support;
}
function checkComputed(el, prop) {
const computed = window.getComputedStyle(el).getPropertyValue(prop);
return computed !== void 0 && computed.length > 0 && computed !== 'none';
}
function set(el, prop, value) {
let match = false;
if (browserProps[prop] === void 0) {
eachVendor(prop, function(vendorProp) {
if (el.style[vendorProp] !== void 0 && match === false) {
el.style[vendorProp] = value;
if (checkComputed(el, vendorProp)) {
match = true;
browserProps[prop] = vendorProp;
}
}
});
} else {
el.style[browserProps[prop]] = value;
return true;
}
return match;
}
const styleProperty = {
check,
set,
};
OHIF.ui.styleProperty = styleProperty;
})();
const { styleProperty } = OHIF.ui;
export { styleProperty };

View File

@ -1,150 +0,0 @@
/*!
* transition-to-from-auto 0.5.2
* https://github.com/75lb/transition-to-from-auto
* Copyright 2015 Lloyd Brookes <75pound@gmail.com>
*/
/**
@module
@alias transition
*/
(function(window, document) {
'use strict';
var getComputedStyle = window.getComputedStyle;
var isTransition = 'data-ttfaInTransition';
var elements = [];
var data = [];
// Transition detecting
var transitionProp = false;
var transitionEnd = false;
var testStyle = document.createElement('a').style;
var testProp;
if (testStyle[(testProp = 'webkitTransition')] !== undefined) {
transitionProp = testProp;
transitionEnd = testProp + 'End';
}
if (testStyle[(testProp = 'transition')] !== undefined) {
transitionProp = testProp;
transitionEnd = testProp + 'end';
}
function process(options, data) {
var el = options.element;
var val = options.val;
var prop = options.prop;
var style = el.style;
var startVal;
var autoVal;
if (!transitionProp) {
return (style[prop] = val);
}
if (el.hasAttribute(isTransition)) {
el.removeEventListener(transitionEnd, data.l);
} else {
style[transitionProp] = 'none';
startVal = getComputedStyle(el)[prop];
style[prop] = 'auto';
autoVal = getComputedStyle(el)[prop];
// Interrupt
if (startVal === val || (val === 'auto' && startVal === autoVal)) {
return;
}
data.auto = autoVal;
el.setAttribute(isTransition, 1);
// Transition
style[prop] = startVal;
el.offsetWidth;
style[transitionProp] = options.style;
}
style[prop] = val === 'auto' ? data.auto : val;
data.l = function(e) {
if (e.propertyName === prop) {
el.removeAttribute(isTransition);
el.removeEventListener(transitionEnd, data.l);
if (val === 'auto') {
/* avoid transition flashes in Safari */
style[transitionProp] = 'none';
style[prop] = val;
}
}
};
el.addEventListener(transitionEnd, data.l);
}
/**
@param options {Object}
@param options.element {string | element} - The DOM element or selector to transition
@param options.val {string} - The value you want to transition to
@param [options.prop] {string} - The CSS property to transition, defaults to `"height"`
@param [options.style] {string} - The desired value for the `transition` CSS property (e.g. `"height 1s"`). If specified, this value is added inline and will override your CSS. Leave this value blank if you already have it defined in your stylesheet.
@alias module:transition-to-from-auto
*/
function transition(options) {
var element = options.element;
var datum;
var index;
if (typeof element === 'string') {
element = document.querySelector(element);
}
element = options.element = element instanceof Node ? element : false;
options.prop = options.prop || 'height';
options.style = options.style || '';
if (element) {
index = elements.indexOf(element);
if (~index) {
datum = data[index];
} else {
datum = {};
elements.push(element);
data.push(datum);
}
process(options, datum);
}
}
/**
The name of the vendor-specific transition CSS property
@type {string}
@example
el.style[transition.prop + 'Duration'] = '1s';
*/
transition.prop = transitionProp;
/**
* The name of the [transition end event](https://developer.mozilla.org/en-US/docs/Web/Events/transitionend) in the current browser (typically `"transitionend"` or `"webkitTransitionEnd"`)
* @type {string}
* @example
* el.addEventListener(transition.end, function(){
* // the transition ended..
* });
*/
transition.end = transitionEnd;
if (typeof module === 'object' && module.exports) {
module.exports = transition;
} else if (typeof define === 'function' && define.amd) {
define(function() {
return transition;
});
} else {
window.transition = transition;
}
})(window, document);

View File

@ -13,7 +13,6 @@ import metadata from './classes/metadata/';
import object from './object.js';
import redux from './redux/';
import string from './string.js';
//import './schema.js';
import studies from './studies/';
import ui from './ui';
import user from './user.js';

View File

@ -1,34 +0,0 @@
//import SimpleSchema from 'simpl-schema'
/*
Extend the available options on schema definitions:
* valuesLabels: Used in conjunction with allowedValues to define the text
label for each value (used on forms)
* textOptional: Used to allow empty strings
*/
/*SimpleSchema.extendOptions({
valuesLabels: Match.Optional([String]),
textOptional: Match.Optional(Boolean)
});
// Add default required validation for empty strings which can be bypassed
// using textOptional=true definition
SimpleSchema.addValidator(function() {
if (
this.definition.optional !== true &&
this.definition.textOptional !== true &&
this.value === ''
) {
return 'required';
}
});*/
// Including [label] for some messages
/*SimpleSchema.messages({
maxCount: '[label] can not have more than [maxCount] values',
minCount: '[label] must have at least [minCount] values',
notAllowed: '[label] has an invalid value: "[value]"'
});*/

View File

@ -1,320 +0,0 @@
/*import SimpleSchema from 'simpl-schema';
const serverNameDefinitions = {
type: String,
label: 'Server Name',
max: 100
};
const serverTypeDefinitions = {
type: String,
label: 'Server Type',
allowedValues: ['dicomWeb', 'dimse'],
valuesLabels: ['DICOM Web', 'DIMSE'],
optional: true
};
const wadoUriRootDefinitions = {
type: String,
label: 'WADO URI root',
max: 1000
};
const availableMouseButtonTools = ['wwwc', 'zoom', 'pan', 'stackScroll'];
export const DICOMWebRequestOptions = new SimpleSchema({
auth: {
type: String,
label: 'Authentication',
defaultValue: 'orthanc:orthanc',
optional: true
},
requestFromBrowser: {
type: Boolean,
label: 'Make DICOMWeb requests from the Browser',
defaultValue: false,
optional: true
},
logRequests: {
type: Boolean,
defaultValue: true,
label: 'Requests'
},
logResponses: {
type: Boolean,
defaultValue: false,
label: 'Responses'
},
logTiming: {
type: Boolean,
defaultValue: true,
label: 'Timing'
}
});
export const DICOMWebServer = new SimpleSchema({
name: serverNameDefinitions,
type: serverTypeDefinitions,
wadoUriRoot: wadoUriRootDefinitions,
wadoRoot: {
type: String,
label: 'WADO root',
max: 1000
},
imageRendering: {
type: String,
label: 'Image rendering',
allowedValues: ['wadouri', 'wadors'],
valuesLabels: ['WADO URI', 'WADO RS'],
defaultValue: 'wadouri'
},
thumbnailRendering: {
type: String,
label: 'Thumbnail rendering',
allowedValues: ['wadouri', 'wadors'],
valuesLabels: ['WADO URI', 'WADO RS'],
defaultValue: 'wadouri'
},
qidoRoot: {
type: String,
label: 'QIDO root',
max: 1000
},
qidoSupportsIncludeField: {
type: Boolean,
label: 'QIDO supports "includefield" query key',
defaultValue: false
},
requestOptions: {
type: DICOMWebRequestOptions,
label: 'Request Options'
}
});
export const DIMSEPeer = new SimpleSchema({
aeTitle: {
type: String,
label: 'AE Title'
},
hostAE: {
type: String,
label: 'AE Host',
optional: true
},
host: {
type: String,
label: 'Host Domain/IP',
regEx: SimpleSchema.RegEx.WeakDomain
},
port: {
type: Number,
label: 'Port',
min: 1,
defaultValue: 11112,
max: 65535
},
default: {
type: Boolean,
label: 'Default',
defaultValue: false
},
server: {
type: Boolean,
label: 'Server',
defaultValue: false
},
supportsInstanceRetrievalByStudyUid: {
type: Boolean,
label: 'Supports instance retrieval by StudyUid',
defaultValue: true
}
});
export const DIMSEServer = new SimpleSchema({
name: serverNameDefinitions,
type: serverTypeDefinitions,
wadoUriRoot: wadoUriRootDefinitions,
requestOptions: {
type: DICOMWebRequestOptions,
label: 'Request Options'
},
peers: {
type: [DIMSEPeer],
label: 'Peer List',
minCount: 1
}
});
export const UISettings = new SimpleSchema({
studyListFunctionsEnabled: {
type: Boolean,
label: 'Study List Functions Enabled?',
defaultValue: true
},
leftSidebarOpen: {
type: Boolean,
label: 'Left sidebar open by default?',
defaultValue: false
},
leftSidebarDragAndDrop: {
type: Boolean,
label:
'Left sidebar allows thumbnail drag and drop. If false, images will be loaded on single click.',
defaultValue: true
},
displaySetNavigationLoopOverSeries: {
type: Boolean,
label:
'The UP/DOWN display set navigation buttons will start over when reach the last display set in viewport?',
defaultValue: true
},
displaySetNavigationMultipleViewports: {
type: Boolean,
label:
'The UP/DOWN display set navigation buttons will iterate over all the viewports at once?',
defaultValue: false
},
displayEchoUltrasoundWorkflow: {
type: Boolean,
label: 'Enable cine dialog enhancements for multiframe images.',
defaultValue: false
},
autoPositionMeasurementsTextCallOuts: {
type: String,
label: 'Auto position text call-outs for measurements when creating them.',
defaultValue: 'TRBL'
},
studyListDateFilterNumDays: {
type: Number,
label: 'Number of days to be used on Study List date filter',
min: 1
},
showStackLoadingProgressBar: {
type: Boolean,
label:
'Show a progress bar closest to the thumbnail showing how much the stack has loaded',
defaultValue: true
},
cornerstoneRenderer: {
type: String,
label: 'Cornerstone default image renderer',
defaultValue: 'webgl'
},
sortSeriesByIncomingOrder: {
type: Boolean,
label:
"Define if the series' images shall be sorted by incoming order. Sort by Instance Number by default.",
defaultValue: false
},
useMiddleSeriesInstanceAsThumbnail: {
type: Boolean,
label:
'Define if the middle instance of a series will be used as thumbnail. If not, the first instance will be used.',
defaultValue: true
}
});
export const PrefetchSchema = new SimpleSchema({
order: {
type: String,
label: 'Prefetch Order',
allowedValues: ['topdown', 'downward', 'closest'],
optional: false
},
displaySetCount: {
type: Number,
label: 'Display Set Count',
min: 1,
defaultValue: 1
}
});
export const MouseButtonToolSchema = new SimpleSchema({
left: {
type: String,
label: 'Left Mouse Button',
allowedValues: availableMouseButtonTools,
optional: true
},
right: {
type: String,
label: 'Right Mouse Button',
allowedValues: availableMouseButtonTools,
optional: true
},
middle: {
type: String,
label: 'Middle Mouse Button',
allowedValues: availableMouseButtonTools,
optional: true
}
});
export const PublicServerConfig = new SimpleSchema({
verifyEmail: {
type: Boolean,
label: 'Verify Email',
defaultValue: false
},
demoUserEnabled: {
type: Boolean,
label: 'Creates demo user on startup and show TestDrive button',
defaultValue: true
},
userAuthenticationRoutesEnabled: {
type: Boolean,
label: 'Enables routing to /login page.',
defaultValue: false
},
ui: {
type: UISettings,
label: 'UI Settings'
},
prefetch: {
type: PrefetchSchema,
label: 'Prefetch settings'
},
defaultMouseButtonTools: {
type: MouseButtonToolSchema,
label: 'Default Mouse Button Tools'
}
});
export const Servers = new SimpleSchema({
dicomWeb: {
type: [DICOMWebServer],
label: 'DICOMWeb Servers',
optional: true
},
dimse: {
type: [DIMSEServer],
label: 'DIMSE Servers',
optional: true
}
});
export const ServerConfiguration = new SimpleSchema({
servers: {
type: Servers,
label: 'Servers'
},
defaultServiceType: {
type: String,
label: 'Default Service Type',
defaultValue: 'dicomWeb'
},
dropCollections: {
type: Boolean,
label: 'Drop database collections',
defaultValue: false
},
public: {
type: PublicServerConfig,
label: 'Public Server Configuration'
},
origin: {
type: String,
label: 'Origin',
optional: true
}
});*/

View File

@ -69,7 +69,7 @@ services:
# - orthanc
environment:
- NODE_ENV=production
- REACT_APP_CONFIG=config/local_dcm4chee
- APP_CONFIG=config/local_dcm4chee
restart: always
networks:
- dcm4che_default

View File

@ -28,7 +28,7 @@ FROM node:11.2.0-slim as builder
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
ENV REACT_APP_CONFIG=config/docker_openresty-orthanc-keycloak.js
ENV APP_CONFIG=config/docker_openresty-orthanc-keycloak.js
ENV PATH /usr/src/app/node_modules/.bin:$PATH
COPY package.json /usr/src/app/package.json

View File

@ -28,7 +28,7 @@ FROM node:11.2.0-slim as builder
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
ENV REACT_APP_CONFIG=config/docker_openresty-orthanc.js
ENV APP_CONFIG=config/docker_openresty-orthanc.js
ENV PATH /usr/src/app/node_modules/.bin:$PATH
COPY package.json /usr/src/app/package.json

View File

@ -3,6 +3,33 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.50.6](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.5...@ohif/viewer@0.50.6) (2019-08-22)
**Note:** Version bump only for package @ohif/viewer
## [0.50.5](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.4...@ohif/viewer@0.50.5) (2019-08-21)
### Bug Fixes
* **StandaloneRouting:** Promise rejection - added `return` ([#791](https://github.com/OHIF/Viewers/issues/791)) ([d09fb4e](https://github.com/OHIF/Viewers/commit/d09fb4e))
## [0.50.4](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.3...@ohif/viewer@0.50.4) (2019-08-20)
**Note:** Version bump only for package @ohif/viewer
## [0.50.3](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.2...@ohif/viewer@0.50.3) (2019-08-15)
**Note:** Version bump only for package @ohif/viewer

View File

@ -1,6 +1,6 @@
{
"name": "@ohif/viewer",
"version": "0.50.3",
"version": "0.50.6",
"description": "OHIF Viewer",
"author": "OHIF Contributors",
"license": "MIT",
@ -44,12 +44,12 @@
},
"dependencies": {
"@babel/runtime": "^7.5.5",
"@ohif/core": "^0.50.1",
"@ohif/core": "^0.50.2",
"@ohif/extension-cornerstone": "^0.50.1",
"@ohif/extension-dicom-html": "^0.50.1",
"@ohif/extension-dicom-microscopy": "^0.50.1",
"@ohif/extension-dicom-pdf": "^0.50.1",
"@ohif/extension-vtk": "^0.50.2",
"@ohif/extension-vtk": "^0.50.3",
"@ohif/i18n": "^0.50.1",
"@ohif/ui": "^0.50.1",
"@tanem/react-nprogress": "^1.1.25",

View File

@ -26,7 +26,7 @@ class StandaloneRouting extends Component {
const url = query.url;
if (!url) {
reject(new Error("No URL was specified. Use ?url=$yourURL"));
return reject(new Error("No URL was specified. Use ?url=$yourURL"));
}
// Define a request to the server to retrieve the study data