From dab805ff9a9b04ca3ddcc3d3559712bab3bbe0f7 Mon Sep 17 00:00:00 2001 From: luckylionheart Date: Wed, 14 Oct 2026 10:37:03 -0400 Subject: [PATCH 01/25] Refactor into pure vanilla ES modules, remove jQuery - split the global-namespace codebase into ES modules with explicit imports (core/, components/, app/), keeping window.wmgui for embeddability - remove jQuery, selectize, jquery.tablesorter; replace with vanilla multiselect and tablesort components sharing the same CSS class contracts - replace the Closure Compiler build with the dependency-aware Python bundler deploy/build_js.py (no Node, no Java); CI updated accordingly - add deploy/dev_api_proxy.py for local development against the MPDS API - update README (module map, compilation, local development) --- .github/workflows/deploy-to-gh.yml | 12 +- README.md | 59 +- deploy/build_js.py | 194 + deploy/build_js.sh | 29 - deploy/dev_api_proxy.py | 141 + example_dev.html | 63 +- src_js/app/events.js | 2142 ++++++++++ src_js/{ => app}/markup.js | 17 +- src_js/app/ptable.js | 639 +++ src_js/app/router.js | 530 +++ src_js/app/run.js | 24 + src_js/app/search.js | 2477 +++++++++++ src_js/app/startup.js | 622 +++ src_js/components/autocomplete.js | 270 ++ src_js/components/multiselect.js | 365 ++ src_js/components/sliders.js | 140 + src_js/components/tablesort.js | 104 + src_js/core/ajax.js | 87 + src_js/core/dom.js | 221 + src_js/core/settings.js | 541 +++ src_js/core/utils.js | 1515 +++++++ src_js/events.js | 1571 ------- src_js/main_logic.js | 1634 -------- src_js/ptable.js | 520 --- src_js/router.js | 434 -- src_js/run.js | 14 - src_js/sliders.js | 102 - src_js/startup.js | 402 -- src_js/third_party/autocomplete.js | 205 - src_js/third_party/jquery.min.js | 2 - src_js/third_party/jquery.tablesorter.js | 904 ---- src_js/third_party/selectize.js | 3684 ----------------- .../third_party/selectize_preserve_on_blur.js | 41 - src_js/wmcore.js | 446 -- src_js/wmsettings.js | 366 -- 35 files changed, 10083 insertions(+), 10434 deletions(-) create mode 100644 deploy/build_js.py delete mode 100755 deploy/build_js.sh create mode 100644 deploy/dev_api_proxy.py create mode 100644 src_js/app/events.js rename src_js/{ => app}/markup.js (99%) mode change 100755 => 100644 create mode 100644 src_js/app/ptable.js create mode 100644 src_js/app/router.js create mode 100644 src_js/app/run.js create mode 100644 src_js/app/search.js create mode 100644 src_js/app/startup.js create mode 100644 src_js/components/autocomplete.js create mode 100644 src_js/components/multiselect.js create mode 100644 src_js/components/sliders.js create mode 100644 src_js/components/tablesort.js create mode 100644 src_js/core/ajax.js create mode 100644 src_js/core/dom.js create mode 100644 src_js/core/settings.js create mode 100644 src_js/core/utils.js delete mode 100755 src_js/events.js delete mode 100755 src_js/main_logic.js delete mode 100644 src_js/ptable.js delete mode 100755 src_js/router.js delete mode 100755 src_js/run.js delete mode 100755 src_js/sliders.js delete mode 100755 src_js/startup.js delete mode 100755 src_js/third_party/autocomplete.js delete mode 100644 src_js/third_party/jquery.min.js delete mode 100755 src_js/third_party/jquery.tablesorter.js delete mode 100644 src_js/third_party/selectize.js delete mode 100755 src_js/third_party/selectize_preserve_on_blur.js delete mode 100755 src_js/wmcore.js delete mode 100755 src_js/wmsettings.js diff --git a/.github/workflows/deploy-to-gh.yml b/.github/workflows/deploy-to-gh.yml index 7ce60a5..7bc2221 100644 --- a/.github/workflows/deploy-to-gh.yml +++ b/.github/workflows/deploy-to-gh.yml @@ -12,21 +12,19 @@ jobs: - name: Checkout repo uses: actions/checkout@v3 - - name: Setup JAVA - uses: actions/setup-java@v3 + - name: Setup Python + uses: actions/setup-python@v4 with: - distribution: 'zulu' - java-version: '17' - check-latest: true + python-version: '3.x' - name: Run per se - run: bash deploy/build_js.sh + run: python3 deploy/build_js.py shell: bash - name: Save files run: | mkdir dist - cp ermac.min.js src_js/third_party/jquery.min.js dist + cp ermac.min.js dist cp -r webassets oauth crystvis labs dist cp example_prod.html dist/index.html diff --git a/README.md b/README.md index 18a73c5..ca14f8a 100755 --- a/README.md +++ b/README.md @@ -20,26 +20,26 @@ cd ermac # then run your static web-server and open it in a web-browser ``` +**NB local development.** When served from a "localhost" origin, the GUI switches to development mode and expects the MPDS API at `http://localhost:7070` (see `src_js/core/settings.js`). There is no local backend in this repository — the data stays at the MPDS server — so run the bundled reverse proxy to the real API in a second terminal: -## Technical details +``` +python3 deploy/dev_api_proxy.py # 127.0.0.1:7070 -> https://api.mpds.io/v0 +``` -Ermac is just a thin browser client (with a little fat). From whatever physical location, it talks to the MPDS platform servers at the `api.mpds.io` domain. Beware, Ermac employs the old-style JQuery-fashioned ES5 JavaScript (see `src_js` folder). The `Node` and `npm` are intentionally **NOT** used. Several external dependencies are supplied simply along with the codebase in `third_party` and `src_js/third_party` folders. For future, we consider re-implementation of this codebase in the modular TypeScript framework. Please [contact us](mailto:hello@tilde.pro) if you'd like to know more or help. +Without it, the client data request fails and the GUI won't finish initializing (`Failed to load GUI`). Alternatively, serve the GUI from any non-"localhost" origin (e.g. `http://127.0.0.1:5555` or a LAN address): the GUI then talks to `https://api.mpds.io/v0` directly, no proxy needed. -## Compilation +## Technical details -Compilation into the production bundle `ermac.min.js` from `src_js` is done via the Google Closure Compiler supplied in `third_party/jscomp` folder, see `deploy/build_js.sh` script. For that you need a Java Runtime Environment (JRE), i.e. a command `java -version` should _not_ produce an error in your terminal. On a typical Unix, such as Debian, JRE is installed e.g. like this: +Ermac is just a thin browser client (with a little fat). From whatever physical location, it talks to the MPDS platform servers at the `api.mpds.io` domain. Ermac is written in modular **pure vanilla JavaScript (ES modules)**, without any framework. The `Node` and `npm` are intentionally **NOT** used. The few remaining external dependencies are supplied simply along with the codebase in `src_js/third_party` (noUiSlider, wNumb, the MPDS NLP parser, and darkmode.js — all framework-free), with the jQuery era of this codebase being over. Please [contact us](mailto:hello@tilde.pro) if you'd like to know more or help. -``` -apt-get -y update && apt-get -y upgrade -apt-get install default-jre -java -version -``` -Given your JRE works, compilation is done as follows: +## Compilation + +Compilation into the production bundle `ermac.min.js` from the ES modules in `src_js` is done via the dependency-aware script `deploy/build_js.py`, which requires only a Python 3 interpreter (still no Node). It concatenates the vendored libraries and the application modules in topological order, stripping the `import`/`export` statements: ``` -bash deploy/build_js.sh +python3 deploy/build_js.py ``` The resulted file `ermac.min.js` is to be included into your webpage (see `example_prod.html`). Alternatively, see [Ermac demo](https://mpds-io.github.io/ermac) which is just a repository branch `gh-pages` compiled by GitHub action. @@ -49,27 +49,34 @@ The resulted file `ermac.min.js` is to be included into your webpage (see `examp The entire app lives in a global namespace object `window.wmgui`. There is no module system, and the code is intentionally ES5 jQuery-style (some files use ES6+ features and are compiled with `ECMASCRIPT_NEXT`). -**Script load order** (defined in `example_dev.html` and mirrored in `deploy/build_js.sh`): +The entire app lives in the global state object `window.wmgui` (kept for embeddability) while being structured as ES modules with explicit dependencies. In the **development mode**, the code is served directly from the `src_js/app/run.js` ES module entry (see `example_dev.html`). In the **production mode**, the code is compiled into a single static bundle `ermac.min.js` (see `example_prod.html`). + +**Module map** (entry: `src_js/app/run.js`): -| File | Role | +| Module | Role | |---|---| -| `wmsettings.js` | All global state, constants, API endpoint URLs, edition configs, facet definitions | -| `wmcore.js` | Utility functions, DOM helpers, AJAX wrappers, selectize read/write helpers | -| `sliders.js` | Numeric range slider UI (noUiSlider-based) | -| `ptable.js` | Interactive periodic table widget | -| `router.js` | Hash-based routing — `url__()` functions handle `#search/`, `#inquiry/`, `#phase/`, `#polyhedra/`, etc. | -| `events.js` | DOM event listeners and `register_events()` | -| `markup.js` | HTML generation and `register_html()` (injects the full UI into ``) | -| `main_logic.js` | Core search logic: `request_search()`, display/render functions, `wmgui.notify()`, `wmgui.aug_search_cmd()` | -| `startup.js` | `satisfy_requirements()` — initializes selectize instances, loads `wmdata.json`, wires autocomplete, triggers initial route | -| `run.js` | Entry point — calls `assign_edition()`, `register_html()`, `satisfy_requirements()`, and `register_events()` | +| `core/dom.js` | Vanilla DOM helpers (`$`, `$$`, show/hide, delegated events, offsets) | +| `core/ajax.js` | Abortable promise-based XHR wrapper, URL serialization (`param`), `is_empty` | +| `core/settings.js` | All global state (`window.wmgui`), constants, API endpoint URLs, edition configs | +| `core/utils.js` | Base-type extensions, `wmgui.clean`, `loadCSS`, domain data, interpretation HTML, random query generators | +| `components/multiselect.js` | Vanilla multi-select input (replaces selectize.js, same CSS classes) | +| `components/tablesort.js` | Vanilla table sorting (replaces jquery.tablesorter, same CSS classes) | +| `components/autocomplete.js` | Simple autocompletion (converted from the vendored spin-off) | +| `components/sliders.js` | Numeric range slider UI (noUiSlider-based) | +| `app/ptable.js` | Interactive periodic table widget | +| `app/router.js` | Hash-based routing — an explicit registry of `url__()` handlers for `#search/`, `#inquiry/`, `#phase/`, `#polyhedra/`, etc. | +| `app/events.js` | DOM event listeners and `register_events()` | +| `app/markup.js` | HTML generation and `register_html()` (injects the full UI into ``) | +| `app/search.js` | Core search logic: `request_search()`, display/render functions, `wmgui.notify()`, `wmgui.aug_search_cmd()`, user session | +| `app/startup.js` | `satisfy_requirements()` — initializes multiselects, loads client data, wires autocomplete, triggers initial route | +| `app/run.js` | Entry point — calls `assign_edition()`, `register_html()`, `satisfy_requirements()`, and `register_events()` | **Key concepts:** - `wmgui.search` — the live search state object, synced with URL hash parameters - `wmgui.search_type` — `0` = entries, `1` = phases, `2` = articles - `wmgui.facets` — the 15 search categories (formulae, props, elements, classes, lattices, sgs, protos, authors, years, codens, doi, aeatoms, aetypes, geos, orgs) -- `wmdata.json` — client-side data (properties list, journal CODENs, property hierarchy) fetched at startup from `wmgui.client_data_addr` +- `wmdata` — client-side data (properties list, journal CODENs, property hierarchy) fetched at startup from `wmgui.wmdata_endpoint` - `wmgui.editions` — multi-tenant config keyed by edition ID (0 = MPDS, 1 = ASM, 10/15/16 = Ermac variants); the active edition is detected from the current hostname **Embedded sub-apps** (loaded in iframes): @@ -79,9 +86,9 @@ The entire app lives in a global namespace object `window.wmgui`. There is no mo - `labs/pd3d/` — 3D phase diagram viewer (Three.js-based) - `labs/view-phonons/` — phonon visualiser -**Third-party libraries** (vendored in `src_js/third_party/` and `third_party/`): +**Third-party libraries** (all framework-free, vendored in `src_js/third_party/`): -- jQuery, selectize.js, noUiSlider, wNumb, autocomplete.js, darkmode.js, jquery.tablesorter +- noUiSlider, wNumb, darkmode.js - `optimade_mpds_nlp.js` — NLP parser that converts free-text queries to structured facet objects ### No test suite diff --git a/deploy/build_js.py b/deploy/build_js.py new file mode 100644 index 0000000..0e523f3 --- /dev/null +++ b/deploy/build_js.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python3 +""" +Ermac ES-module bundler: builds ermac.min.js from src_js/ without Node.js. + +The application is authored as ES modules (native import/export). This script +concatenates them into a single classic script: + + 1. vendored vanilla libraries are prepended as-is (they define window globals); + 2. modules are appended in dependency order (topological sort, entry: src_js/app/run.js); + 3. `import ... from ...` statements are stripped (names resolve at script scope); + 4. `export function`/`export const` keep their declarations, `export default ` is dropped. + +Supported import syntax (single line each): + import { a, b } from './x.js'; + import name from './x.js'; (default export) +""" + +import os +import re +import sys + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +ENTRY = os.path.join(ROOT, "src_js", "app", "run.js") +TARGET = os.path.join(ROOT, "ermac.min.js") + +# NB order matters, these define window globals used by the app modules +VENDORED = [ + "src_js/third_party/wNumb.js", + "src_js/third_party/nouislider.js", + "src_js/third_party/optimade_mpds_nlp.js", + "src_js/third_party/darkmode.js", +] + +IMPORT_RE = re.compile( + r"""^\s*import\s+(?:([\w$]+)\s*,?\s*)?(?:\{([^}]*)\})?\s*from\s+['"]([^'"]+)['"];\s*$""" +) +EXPORT_DEFAULT_RE = re.compile(r"""^\s*export\s+default\s+([\w$]+)\s*;\s*$""") +EXPORT_DECL_RE = re.compile( + r"""^\s*export\s+(?=(?:async\s+)?function\b|const\b|let\b|var\b|class\b)""" +) + + +class Module(object): + def __init__(self, path): + self.path = path + with open(path, "r", encoding="utf-8") as f: + self.lines = f.read().splitlines() + self.imports = [] # (default_alias, [named], resolved_path) + self.default_export = None # local name of `export default` + self.exports = set() + self.emitted = None + + kept = [] + for line in self.lines: + import_match = IMPORT_RE.match(line) + if import_match: + default_alias, named, target = import_match.groups() + named = [n.strip() for n in (named or "").split(",") if n.strip()] + self.imports.append((default_alias, named, self.resolve(target))) + continue + + default_match = EXPORT_DEFAULT_RE.match(line) + if default_match: + self.default_export = default_match.group(1) + continue + + decl_match = EXPORT_DECL_RE.match(line) + if decl_match: + self.exports.add(declare_name(line)) + kept.append(EXPORT_DECL_RE.sub("", line, count=1)) + continue + + if re.match(r"^\s*export\s*\{", line): + raise SyntaxError( + "Named export blocks are not supported: %s in %s" % (line, path) + ) + + kept.append(line) + self.body = "\n".join(kept) + + def resolve(self, target): + if not target.startswith("."): + raise ImportError( + "Only relative imports are supported: %s in %s" % (target, self.path) + ) + resolved = os.path.normpath(os.path.join(os.path.dirname(self.path), target)) + if not os.path.exists(resolved): + raise ImportError("Unresolved import: %s in %s" % (target, self.path)) + return resolved + + +def declare_name(line): + m = ( + re.match(r"\s*(?:export\s+)?(?:async\s+)?function\s+([\w$]+)", line) + or re.match(r"\s*(?:export\s+)?(?:const|let|var)\s+([\w$]+)", line) + or re.match(r"\s*(?:export\s+)?class\s+([\w$]+)", line) + ) + if not m: + raise SyntaxError("Cannot determine the exported name: %s" % line) + return m.group(1) + + +def bundle(): + modules = {} + + def load(path): + path = os.path.abspath(path) + if path not in modules: + modules[path] = Module(path) + for default_alias, named, target in modules[path].imports: + load(target) + return modules[path] + + entry = load(ENTRY) + + # topological order, DFS post-order, cycle-tolerant + order = [] + visited = set() + + def visit(path): + if path in visited: + return + visited.add(path) + for default_alias, named, target in modules[path].imports: + visit(target) + order.append(path) + + visit(os.path.abspath(ENTRY)) + + # validate the import graph + for path, module in modules.items(): + for default_alias, named, target in module.imports: + target_module = modules[target] + if default_alias: + if not target_module.default_export: + raise ImportError( + "%s imports a default export, but %s has none" % (path, target) + ) + if default_alias != target_module.default_export: + raise ImportError( + "Default import %r in %s must be aliased as %r in the bundle" + % (default_alias, path, target_module.default_export) + ) + for name in named: + if name not in target_module.exports: + raise ImportError( + "%s imports %r, but %s does not export it" + % (path, name, target) + ) + + parts = [ + "/* Ermac, the embeddable MPDS GUI: https://github.com/mpds-io/ermac */", + "/* NB built by deploy/build_js.py, do not edit */", + '"use strict";', + "", + ] + + for vendor in VENDORED: + vendor_path = os.path.join(ROOT, vendor) + with open(vendor_path, "r", encoding="utf-8") as f: + parts.append("/* %s */" % vendor) + parts.append(f.read()) + parts.append("") + + for path in order: + module = modules[path] + parts.append("/* module: %s */" % os.path.relpath(path, ROOT)) + parts.append(module.body) + parts.append("") + + result = "\n".join(parts) + "\n" + with open(TARGET, "w", encoding="utf-8") as f: + f.write(result) + + print( + "Bundled %d app modules + %d vendored libs -> %s (%d KB)" + % ( + len(order), + len(VENDORED), + os.path.relpath(TARGET, ROOT), + len(result) // 1024, + ) + ) + print("Module order:") + for path in order: + print(" - %s" % os.path.relpath(path, ROOT)) + print("NB check absence of errors in the output above") + + +if __name__ == "__main__": + try: + bundle() + except (ImportError, SyntaxError) as e: + sys.exit("BUILD ERROR: %s" % e) diff --git a/deploy/build_js.sh b/deploy/build_js.sh deleted file mode 100755 index ec86f59..0000000 --- a/deploy/build_js.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -ROOT=$(dirname $0)/../ -JSCOMP=$ROOT/third_party/jscomp/compiler.jar -JSTARGET=$ROOT/ermac.min.js - -cat $ROOT/src_js/third_party/jquery.min.js > $JSTARGET - -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/third_party/jquery.tablesorter.js --compilation_level WHITESPACE_ONLY >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/third_party/wNumb.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/third_party/nouislider.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/third_party/selectize.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/third_party/selectize_preserve_on_blur.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT_NEXT --js $ROOT/src_js/third_party/optimade_mpds_nlp.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/third_party/darkmode.js >> $JSTARGET - -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/wmsettings.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT_NEXT --js $ROOT/src_js/wmcore.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/sliders.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT_NEXT --js $ROOT/src_js/ptable.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/third_party/autocomplete.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/router.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/events.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT_NEXT --js $ROOT/src_js/markup.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/main_logic.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/startup.js >> $JSTARGET -java -jar $JSCOMP --jscomp_off checkTypes --language_in ECMASCRIPT5_STRICT --js $ROOT/src_js/run.js >> $JSTARGET - -echo "NB check absense of errors in the compiler output" diff --git a/deploy/dev_api_proxy.py b/deploy/dev_api_proxy.py new file mode 100644 index 0000000..52c2644 --- /dev/null +++ b/deploy/dev_api_proxy.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 +""" +Ermac local development API proxy. + +The Ermac GUI talks to the MPDS platform API at https://api.mpds.io/v0. +When the GUI is served from a "localhost" origin, it switches to development +mode and expects the API at http://localhost:7070 (see src_js/core/settings.js). + +There is no local backend in this repository (the data stays at the MPDS server), +so for local development this script reverse-proxies localhost:7070 to the real +MPDS API, adding the CORS headers needed for the cross-origin XHR calls. +Pure Python standard library, no dependencies: + + python3 deploy/dev_api_proxy.py # 127.0.0.1:7070 -> https://api.mpds.io/v0 + +Then serve the GUI from any port, e.g.: + + python3 -m http.server 5555 + +and open http://localhost:5555/example_dev.html + +NB anonymous browsing (searches, wmdata, refinements) works without any key. +NB logging in through the proxy may not keep the session cookie, depending on +the MPDS cookie flags: for full account testing prefer a non-"localhost" origin +(e.g. http://127.0.0.1:5555), which makes the GUI talk to the MPDS API directly. +""" + +import http.server +import urllib.request +import urllib.error + +HOST = "127.0.0.1" +PORT = 7070 +REMOTE = "https://api.mpds.io/v0" +TIMEOUT = 20 + +HOP_BY_HOP = { + "connection", + "keep-alive", + "proxy-authenticate", + "proxy-authorization", + "te", + "trailers", + "transfer-encoding", + "upgrade", + "content-encoding", + "content-length", +} + + +class ProxyHandler(http.server.BaseHTTPRequestHandler): + protocol_version = "HTTP/1.1" + + def _cors(self): + origin = self.headers.get("Origin") + if origin: + self.send_header("Access-Control-Allow-Origin", origin) + self.send_header("Access-Control-Allow-Credentials", "true") + + def do_OPTIONS(self): + self.send_response(200) + self._cors() + self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") + self.send_header("Access-Control-Allow-Headers", "Content-Type") + self.send_header("Access-Control-Max-Age", "21600") + self.send_header("Content-Length", "0") + self.end_headers() + + def _forward(self, method): + url = REMOTE + self.path + body = None + + headers = {} + for header in ("Content-Type", "Origin", "Key", "Accept-Language"): + value = self.headers.get(header) + if value: + headers[header] = value + + if method == "POST": + length = int(self.headers.get("Content-Length") or 0) + body = self.rfile.read(length) if length else b"" + + request = urllib.request.Request(url, data=body, method=method, headers=headers) + + payload, status, response_headers = b"", 502, {} + + # NB the CDN may occasionally cut a response short, so retry once + last_error = None + for attempt in (1, 2): + try: + with urllib.request.urlopen(request, timeout=TIMEOUT) as response: + payload = response.read() + status = response.status + response_headers = response.headers + break + except urllib.error.HTTPError as error: + payload = error.read() + status = error.code + response_headers = error.headers + break + except Exception as error: + last_error = error + else: + payload = ('{"error": "dev proxy: %s"}' % last_error).encode() + + try: + self.send_response(status) + self._cors() + for name, value in (response_headers or {}).items(): + # NB the proxy handles CORS itself (the origin it sees is localhost, + # not the real browser origin), so drop the remote CORS headers + if name.lower() not in HOP_BY_HOP and not name.lower().startswith( + "access-control-" + ): + self.send_header(name, value) + self.send_header("Content-Length", str(len(payload))) + self.end_headers() + self.wfile.write(payload) + except (BrokenPipeError, ConnectionResetError): + pass # NB the browser aborted the request, e.g. on page reload + + def do_GET(self): + self._forward("GET") + + def do_POST(self): + self._forward("POST") + + def do_HEAD(self): + self._forward("GET") + + def log_message(self, fmt, *args): + print("proxy: %s - %s" % (self.address_string(), fmt % args)) + + +if __name__ == "__main__": + server = http.server.ThreadingHTTPServer((HOST, PORT), ProxyHandler) + print("dev API proxy: http://%s:%d -> %s" % (HOST, PORT, REMOTE)) + try: + server.serve_forever() + except KeyboardInterrupt: + server.shutdown() diff --git a/example_dev.html b/example_dev.html index 92d3bef..1e45fc5 100755 --- a/example_dev.html +++ b/example_dev.html @@ -1,42 +1,25 @@ - + - - - - - - - + + + + + + + + + + + + + diff --git a/src_js/app/events.js b/src_js/app/events.js new file mode 100644 index 0000000..f24ab0b --- /dev/null +++ b/src_js/app/events.js @@ -0,0 +1,2142 @@ +/** + * Ermac event wiring: register_events() binds all DOM listeners. + */ + +import wmgui from '../core/settings.js'; +import { wmutils } from '../core/utils.js'; +import { + $, + $$, + show, + hide, + toggle_display, + set_html, + append_html, + after_html, + empty, + remove, + isVisible, + on, + position, + offset, + scroll_top, + window_height, + data, + fade_out, + slide_up, + slide_down, +} from '../core/dom.js'; +import { ajax, param, is_empty } from '../core/ajax.js'; +import { + create_floating_slider, + destroy_numericbox, + serialize_numeric, +} from '../components/sliders.js'; +import { + select_ptable_el, + select_ptable_series, + ajax_download, + render_left, +} from './ptable.js'; +import { + request_search, + re_view_request, + show_advsbox, + show_aetmap, + show_tooltip, + show_hints, + open_context, + close_vibox, + launch_db_iframed, + build_cells, + build_thumbs, + update_databrowser_sort, + user_login, + user_logout, + force_relogin, + tab_user_login, + submit_factor_form_resp, + describe_perms, + get_visavis_url, +} from './search.js'; +import { url_redraw_react } from './router.js'; + +export function register_events() { + document + .querySelector('#ptable_area > ul') + .addEventListener('click', function (event) { + var that = event.target; + if (!that.hasAttribute || !that.hasAttribute('data-pos')) return; + + wmgui.ptable.update_selectize = true; + var selected_el = wmgui.ptable.elements[that.getAttribute('data-pos')]; + select_ptable_el(selected_el, that); + }); + + var radios = document.querySelectorAll('input[name="ptable_dtypes"]'); + for (var i = 0; i < radios.length; i++) { + radios[i].addEventListener('change', function () { + if (!this.checked) return; + wmgui.ptable.dtypes = this.value; + var check = wmgui.multiselects['main'].read(); + select_ptable_series(check.elements); + }); + } + + $('#search_trigger').addEventListener('click', function () { + var query = wmgui.multiselects['main'].read(), + val = $('#search_field-selectized') + ? $('#search_field-selectized').value + : ''; + + if (val) { + if (val.endsWith(' ') || val.endsWith(',')) + val = val.substr(0, val.length - 1); + var parsed = wmutils.guess(val); + + for (var key in parsed) { + if (key == 'ignored') continue; + else if (query[key] && key == 'elements') + query[key] += '-' + parsed[key]; + else if (query[key] && key == 'classes') + query[key] += ', ' + parsed[key]; + else query[key] = parsed[key]; + } + } + + if (wmgui.search.numeric && !query.numeric) { + query.numeric = ''; + wmgui.search.numeric.forEach(function (item) { + query.numeric += serialize_numeric.apply(this, item); // unpack + }); + delete query.props; // NB to make the numeric results "more clear" + } + + if (is_empty(query)) { + wmgui.notify('Sorry, unrecognized input'); + return false; + } + + wmgui.ctx_strict_phases = ''; + $('#ctx_strict_phases_trigger').checked = true; + + var urlstr = param(query); + if (window.location.hash == '#inquiry/' + urlstr) { + // hash-hack FIXME? + if (urlstr.slice(-1) == '=') urlstr = urlstr.substr(0, urlstr.length - 1); + else urlstr += '='; + } + window.location.hash = '#inquiry/' + urlstr; + return false; + }); + + $('#advsearch_do_trigger').addEventListener('click', function () { + var curval = '', + rest_input = '', + query = {}; + + wmgui.simple_facets.forEach(function (item) { + curval = $('#advs_fct_' + item).value; + if (curval) { + if (item == 'formulae') curval = wmutils.termify_formulae(curval); + else if (item == 'elements') + curval = curval.replaceAll(',', '').replaceAll(' ', '-'); + else if (item == 'doi') + curval = curval + .replace('http:\/\/dx\.doi\.org\/', '') + .replace('http:\/\/doi\.org\/', '') + .trim(); + else if (item == 'codens') curval = wmgui.journal_converter.j2c(curval); + query[item] = curval; + } + }); + + wmgui.multi_facets.forEach(function (item) { + curval = wmgui.multiselects[item].read(); + + if (curval[item]) { + curval = curval[item]; + if (item == 'authors') + curval = curval + .replace(/'/g, '') + .replaceAll('\\.', ' ') + .replaceAll('\\b\\w{1}\\b', '') + .trim(); + query[item] = curval; + } + rest_input = $('#advs_fct_' + item + '-selectized') + ? $('#advs_fct_' + item + '-selectized').value + : ''; + if (rest_input) { + if (query[item]) query[item] += ', ' + rest_input; + else query[item] = rest_input; + } + }); + + if (wmgui.search.numeric) { + query.numeric = ''; + wmgui.search.numeric.forEach(function (item) { + query.numeric += serialize_numeric.apply(this, item); // unpack + }); + delete query.props; // NB to make the numeric results "more clear" + } + + if (is_empty(query)) return wmgui.notify('Sorry, search is empty'); + + wmgui.ctx_strict_phases = ''; + $('#ctx_strict_phases_trigger').checked = true; + + var urlstr = param(query); + if (window.location.hash == '#inquiry/' + urlstr) { + // hash-hack FIXME? + if (urlstr.slice(-1) == '=') urlstr = urlstr.substr(0, urlstr.length - 1); + else urlstr += '='; + } + window.location.hash = '#inquiry/' + urlstr; + }); + + $('#advsearch_drop_trigger').addEventListener('click', function () { + $$('input.advs_input').forEach(function (input) { + input.value = ''; + }); + + wmgui.multi_facets.forEach(function (item) { + const rest_input = $('#advs_fct_' + item + '-selectized'); + if (rest_input) rest_input.value = ''; + wmgui.multiselects[item].clear(); + }); + + hide($('#aetmap')); + $('#aet_limit').checked = false; + + destroy_numericbox(); + delete wmgui.search.numeric; + // TODO? delete wmgui.search + }); + + $('#advsearch_init_trigger').addEventListener('click', function () { + $$('#advstab_options li').forEach(function (li) { + li.classList.remove('working'); + }); + $$('#advstab_options li[rev=advstab_cry]').forEach(function (li) { + li.classList.add('working'); + }); + show($('#advstab_cry')); + hide($$('#advstab_main, #advstab_bib')); + show_advsbox(); + return false; + }); + + on($('#search_box'), '#legend a', 'click', function (event) { + var legend = this.textContent; + window.location.hash = '#search/' + encodeURIComponent(legend); + event.preventDefault(); + return false; + }); + + $$('div.advs_legend > a').forEach(function (a) { + a.addEventListener('click', function (event) { + var legend = a.getAttribute('rel') || a.textContent, + multiselects = a.parentNode.dataset.multiselects; + + if (multiselects) { + const rest_input = $('#advs_fct_' + multiselects + '-selectized'); + if (rest_input) rest_input.value = ''; + wmgui.multiselects[multiselects].clear(); + var obj = {}; + obj[multiselects] = legend; + wmgui.multiselects[multiselects].write(obj); + //wmgui.multiselects[multiselects].write({[multiselects]: legend}); + } else { + const target_input = a.parentNode.parentNode.querySelector('input'); + if (target_input) { + target_input.value = legend; + target_input.focus(); + } + } + //if (legend.indexOf('-vertex') !== -1) show_aetmap(legend); + + event.preventDefault(); + return false; + }); + }); + + on($('#databrowser'), 'div.gallery_img', 'click', function (event) { + handle_gallery_img_click(this, event); + }); + on($('#ptable_results'), 'div.gallery_img', 'click', function (event) { + handle_gallery_img_click(this, event); + }); + + function handle_gallery_img_click(el, event) { + if (el.getAttribute('rel')) { + if (wmgui.view_mode === 1 && wmgui.ptable.dtypes > 1) { + var phid = el.getAttribute('rel'); + + if (wmgui.ptable.dtypes == 2) + document.querySelector( + '#ptable_vis > iframe', + ).contentWindow.location.hash = + '#' + wmgui.phase_endpoint + '?phid=' + phid + '&struct=1'; + else + document + .querySelector('#ptable_vis > iframe') + .contentWindow.location.replace( + get_visavis_url({ phid: phid }, 'graph', window.innerHeight - 50), + ); + + $$('div.gallery_item.active').forEach(function (item) { + item.classList.remove('active'); + }); + el.parentNode.classList.add('active'); + } else { + var path = el.getAttribute('data-path') || 'phase_id'; + window.location.hash = '#' + path + '/' + el.getAttribute('rel'); + } + } + } + + on($('#databrowser'), 'a.resolve_ref', 'mousedown', function (event) { + var bid = this.getAttribute('rel'); + $$('a.resolve_ref[rel="' + bid + '"]').forEach(function (a) { + a.classList.add('visited'); + }); // :visited + wmgui.bid_history.push(parseInt(bid)); + window.localStorage.setItem( + wmgui.store_bids_key, + JSON.stringify(wmgui.bid_history), + ); + return true; + }); + + on( + $('#databrowser'), + 'tr.tcell, div.gallery_item', + 'click', + function (event) { + open_context(this, false); + }, + ); + + on($('#databrowser'), 'span.launch_v', 'click', function (event) { + wmgui.cancel_event(event); + var parent_row = this.closest('tr'); + parent_row.classList.remove('busy_entry'); + open_context(parent_row, true); + }); + + on($('#databrowser'), 'a.launch_id', 'click', function (event) { + wmgui.cancel_event(event); + var phid_link = this.getAttribute('href'); + if (window.location.hash == phid_link) { + // hash-hack FIXME? + phid_link += '.'; + } + window.location.hash = phid_link; + return false; + }); + + on( + $('#all_polyhedra_content'), + 'div.gallery_item', + 'click', + function (event) { + $$('#advstab_options li').forEach(function (li) { + li.classList.remove('working'); + }); + $$('#advstab_options li[rev=advstab_cry]').forEach(function (li) { + li.classList.add('working'); + }); + hide($$('div.advstab')); + show($('#advstab_cry')); + hide($$('div.modal')); + show($$('#advsbox, #overlay')); + + var term = this.getAttribute('rel'), + selected_aetypes = ( + wmgui.multiselects['aetypes'].read()['aetypes'] || '' + ).split(', '); + if (selected_aetypes.indexOf(term) == -1) + wmgui.multiselects['aetypes'].write({ aetypes: term }); + show_aetmap(term); + }, + ); + + $('#aet_limit').addEventListener('click', function (event) { + var selected_classes = ( + wmgui.multiselects['classes'].read()['classes'] || '' + ).split(', '); + + if (this.checked) { + var selected_aetypes = ( + wmgui.multiselects['aetypes'].read()['aetypes'] || '' + ) + .split(', ') + .filter(function (x) { + return x; + }), + limit_kwd = wmgui.poly_limits[selected_aetypes.length]; + + if (!limit_kwd) { + wmgui.cancel_event(event); + wmgui.notify('Sorry, only up to 3 supported'); + return false; + } + if (selected_classes.indexOf(limit_kwd) == -1) { + wmgui.multiselects['classes'].write({ classes: limit_kwd }); + } + } else { + var poly_limits = Object.values(wmgui.poly_limits); + wmgui.multiselects['classes'].clear(); + wmgui.multiselects['classes'].write({ + classes: selected_classes + .filter(function (x) { + return poly_limits.indexOf(x) == -1; + }) + .join(', '), + }); + } + return true; + }); + + $$('#visualize, #xrpdize').forEach(function (el) { + el.addEventListener('click', function () { + close_vibox(); + launch_db_iframed(parseInt(this.getAttribute('data-rank'))); + }); + }); + + /*$('#absolidize').click(function(){ + ... commented out in the original ... + });*/ + + on($('#refine_col'), 'a.extd_refine', 'click', async function (event) { + var facet = this.getAttribute('rel'); + event.preventDefault(); + + if ($('#refine_col > ul > li.extd_rfns.fct_' + facet)) { + $$('#refine_col > ul > li:not(.fct_' + facet + ')').forEach( + function (li) { + li.classList.add('hidden_rfns'); + }, + ); + $$('#refine_col > ul > li:not(.fct_' + facet + ')').forEach( + function (li) { + if (li.classList.contains('hidden_rfns')) slide_up(li, 400); + }, + ); + $$('#refine_col > ul > li.extd_rfns.fct_' + facet).forEach(function (li) { + li.style.display = 'list-item'; + }); + $$('a.extd_refine[rel="' + facet + '"]').forEach(function (a) { + a.parentNode.style.display = 'none'; + }); + return false; + } + var given_search = { extd_refine: facet }; + Object.assign(given_search, wmgui.search); + try { + wmgui.active_ajax.abort(); + } catch (e) {} + + wmgui.active_ajax = ajax({ + type: 'GET', + url: wmgui.rfn_endpoint, + data: { q: JSON.stringify(given_search) }, + }); + + let found_data; + try { + found_data = await wmgui.active_ajax; + } catch (error) { + if (!(error && error.aborted)) + wmgui.notify( + 'Connection to server is lost, please try to reload', + ); + return false; + } + + if (found_data.error) return wmgui.notify(found_data.error); + var html = ''; + delete given_search['numeric']; + delete given_search['extd_refine']; + //if (given_search.classes) given_search.classes = given_search.classes.split(',').join(' '); + + var inquiry = false; + for (var n = 0; n < wmgui.inquiries.length; n++) { + if (given_search[wmgui.inquiries[n]]) { + inquiry = true; + break; + } + } + + found_data.payload.forEach(function (found, i) { + // FIXME: duplicating + var link_base = '', + orepr = {}; + //count_text = ' ('+found[1]+')'; + + for (var key in given_search) { + const val = given_search[key]; + if (key == 'search_type') continue; + else if ( + facet == 'elements' && + (key == 'elements' || key == 'formulae') + ) + continue; + else if (facet == 'props' && key == 'props') continue; + + link_base += val + ' '; + + if (orepr[key]) orepr[key] += ', ' + val; + else orepr[key] = val; + } + + //if (facet == 'elements') count_text = ''; + if (facet == 'props') { + found[0] = found[0].replace(/\(|\)/g, '').replace(/\/[\w\-]*/g, ''); // FIXME + } + + if (orepr[facet]) orepr[facet] += ', ' + found[0]; + else orepr[facet] = found[0]; + + if (orepr['elements']) + orepr['elements'] = orepr['elements'].replaceAll(', ', '-'); + + if (inquiry) + html += + '
  • ' + + found[0] + + '
  • '; + else + html += + '
  • ' + + found[0] + + '
  • '; + }); + + html += + '
  • Show less 
  • '; + $$('#refine_col > ul > li:not(.fct_' + facet + ')').forEach(function (li) { + li.classList.add('hidden_rfns'); + slide_up(li, 400); + }); + $$('a.extd_refine[rel="' + facet + '"]').forEach(function (a) { + a.parentNode.style.display = 'none'; + }); + const anchor = $$('a.extd_refine[rel="' + facet + '"]')[0]; + if (anchor) after_html(anchor.parentNode, wmgui.clean(html)); + + return false; + }); + + on($('#refine_col'), 'a.collapse_refine', 'click', function (event) { + var facet = this.getAttribute('rel'); + event.preventDefault(); + $$('a.extd_refine[rel="' + facet + '"]').forEach(function (a) { + a.parentNode.style.display = 'list-item'; + }); + $$('#refine_col > ul > li.hidden_rfns').forEach(function (li) { + li.classList.remove('hidden_rfns'); + slide_down(li, 250); + }); + $$('#refine_col > ul > li.extd_rfns').forEach(function (li) { + li.style.display = 'none'; + }); + return false; + }); + + /*$('#fdwidget').on('click', 'span', function(){ + ... commented out in the original ... + });*/ + + on($('#tagcloudbox'), 'a.collateral', 'click', function (event) { + data($('#userbox'), 'saved_hash', false); + var act = this.getAttribute('rel'); + event.preventDefault(); + + if (act == 'adv') { + $('#advsearch_init_trigger').click(); + hide($$('div.menu_collateral')); + } else if (act == 'idea') { + window.location.hash = + '#plot/' + + wmgui.get_random_term(['pie', 'lit', 'graph']) + + '/search/' + + wmgui.get_interesting()['text']; + } else if (act == 'sod') { + var now = new Date(), + pick = now.getDate() % wmgui.s_examples.length, + start = new Date(now.getFullYear(), 0, 0), + diff = + now - + start + + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000, + nday = Math.floor(diff / (1000 * 60 * 60 * 24)), + sod = wmgui.s_examples[pick] + nday; + window.location.hash = '#entry/S' + sod; + } else if (act == 'my') { + var locals = JSON.parse( + window.localStorage.getItem(wmgui.store_user_key) || '{}', + ); + if (locals.ipbased) { + window.location.hash = '#inquiry/orgs=' + locals.name; + } else if (locals.name) { + var names = locals.name.split(' '); + window.location.hash = + '#inquiry/authors=' + encodeURIComponent(names[names.length - 1]); + } + } + return false; + }); + + on($('#hintsbox_msg'), 'div.wmbutton', 'click', function () { + // copy to clipbox functionality + var range = document.createRange(); + range.selectNode($('#hintsbox_msg > pre')); + window.getSelection().removeAllRanges(); + window.getSelection().addRange(range); + document.execCommand('copy'); + wmgui.notify('Copied'); + }); + + on($('#tooltip'), 'span', 'click', function () { + var act = this.getAttribute('rel'), + forced = this.classList.contains('forced'); + document.getElementById('tooltip').style.display = 'none'; + if (act && wmgui.tooltips[act]) show_tooltip(wmgui.tooltips[act], forced); + }); + + on($('#sim_col'), 'li > a', 'click', function () { + $$('#sim_col > ul > li').forEach(function (li) { + li.classList.remove('selected'); + }); + this.parentNode.classList.add('selected'); + wmgui.passive_sim_col = false; + return true; + }); + + $$('div.close_user_dialogue').forEach(function (cross) { + cross.addEventListener('click', function () { + $('#userbox').click(); + }); + }); + + $$('div.close_advs_dialogue').forEach(function (cross) { + cross.addEventListener('click', function () { + hide($$('#advsbox, #overlay, #aetmap')); + }); + }); + + const close_inquiry = $('#close_inquiry_dialogue'); + if (close_inquiry) + close_inquiry.addEventListener('click', function () { + hide($('#inquirybox')); + }); + + $('#close_ss_dialogue').addEventListener('click', function () { + var x_sort = $('#ss_x > ul > li.ss_x').getAttribute('rel').split('_')[1], + y_sort = $('#ss_y > ul > li.ss_y').getAttribute('rel').split('_')[1], + x_op = $('#sops_x > ul > li.sops_x').textContent, + y_op = $('#sops_y > ul > li.sops_y').textContent, + x_op = x_op == 'none' ? false : x_op, + y_op = y_op == 'none' ? false : y_op; + + if (isVisible($('#ss_z'))) { + var z_sort = $('#ss_z > ul > li.ss_z').getAttribute('rel').split('_')[1], + z_op = $('#sops_z > ul > li.sops_z').textContent, + z_op = z_op == 'none' ? false : z_op; + + $$('#ctxpanel_cube > ul > li.embodied').forEach(function (li) { + li.classList.remove('embodied'); + }); + $('#viscube_' + x_sort).classList.add('embodied'); + $$('#ctxpanel_cube > ul > li.ss_y').forEach(function (li) { + li.classList.remove('ss_y'); + }); + $('#viscube_' + y_sort).classList.add('ss_y'); + $$('#ctxpanel_cube > ul > li.ss_z').forEach(function (li) { + li.classList.remove('ss_z'); + }); + $('#viscube_' + z_sort).classList.add('ss_z'); + + remove($$('span.sops')); + if (x_op) + append_html( + $('#viscube_' + x_sort), + '' + x_op + '', + ); + if (y_op) + append_html( + $('#viscube_' + y_sort), + '' + y_op + '', + ); + if (z_op) + append_html( + $('#viscube_' + z_sort), + '' + z_op + '', + ); + + if ( + document + .getElementById('visavis_iframe') + .contentWindow.location.hash.indexOf('fixel=1') !== -1 + ) + document + .getElementById('visavis_iframe') + .contentWindow.matrix_order(x_sort, y_sort, x_op, y_op); + else + document + .getElementById('visavis_iframe') + .contentWindow.cube_order(x_sort, y_sort, z_sort, x_op, y_op, z_op); + } else { + if ((x_op && x_sort == 'count') || (y_op && y_sort == 'count')) + return wmgui.notify('Sorry, data counts are not supported'); + + $$('#ctxpanel_matrix > ul > li.embodied').forEach(function (li) { + li.classList.remove('embodied'); + }); + $('#vismatrix_' + x_sort).classList.add('embodied'); + $$('#ctxpanel_matrix > ul > li.ss_y').forEach(function (li) { + li.classList.remove('ss_y'); + }); + $('#vismatrix_' + y_sort).classList.add('ss_y'); + + remove($$('span.sops')); + if (x_op) + append_html( + $('#vismatrix_' + x_sort), + '' + x_op + '', + ); + if (y_op) + append_html( + $('#vismatrix_' + y_sort), + '' + y_op + '', + ); + + document + .getElementById('visavis_iframe') + .contentWindow.matrix_order(x_sort, y_sort, x_op, y_op); + } + + hide($$('#ss_custom_box, #overlay')); + empty($$('div.ss_col > ul')); + }); + + $('#close_dc_dialogue').addEventListener('click', function () { + hide($$('#discovery_custom_box, #overlay')); + empty($$('#discovery_enabled, #discovery_disabled')); + document.getElementById('visavis_iframe').contentWindow.discovery_rerun(); + $('#select_cmp_trigger').value = 'X'; + }); + + // not handled by ermac? + const close_formal = $('#close_formal_dialogue'); + if (close_formal) + close_formal.addEventListener('click', function () { + window.location.hash = '#start'; + }); + + // not handled by ermac? + $$( + '#close_ph_dialogue, div.close_hy_dialogue, div.close_product_dialogue', + ).forEach(function (cross) { + cross.addEventListener('click', function () { + if (document.referrer.indexOf(window.location.host) == -1) + window.location.hash = '#start'; // FIXME: empty referrer + else { + var prev = window.location.href; + window.history.go(-1); + setTimeout(function () { + if (window.location.href == prev) window.location.hash = '#start'; + }, 500); + } + }); + }); + + /** $('#overlay').click(function(){ + $('div.modal:visible').each(function(){ + $(this).find('div.cross').trigger('click'); + }); + }); **/ + + $$('div._close_ctx').forEach(function (cross) { + cross.addEventListener('click', function () { + try { + wmgui.quick_ajax.abort(); + } catch (e) {} + $$('.busy_entry').forEach(function (el) { + el.classList.remove('busy_entry'); + }); + hide($$('#ctx_col, #sim_col')); + wmgui.passive_sim_col = true; + close_vibox(); + }); + }); + + on($('#hy_box'), 'span', 'click', function () { + var hyid = this.getAttribute('class'); + $$('span.' + hyid.split(' ')[0]).forEach(function (el) { + el.parentNode.querySelectorAll('ul').forEach(function (ul) { + toggle_display(ul, 'block'); + }); + el.textContent == 'expand' + ? (el.textContent = 'collapse') + : (el.textContent = 'expand'); + }); + }); + + on($('#hy_box'), 'a.dynprop', 'click', function (event) { + // FIXME cannot process with the optimade NLP parser + //if (wmgui.view_mode == 1) + // return true; + + var value = this.getAttribute('data-val'); + window.location.hash = wmgui.aug_search_cmd('props', value); + event.preventDefault(); + return false; + }); + + // numeric search + on($('#hy_box'), 'strong.numeric', 'click', function () { + var prop = this.getAttribute('rel'), + num_data = wmgui.numerics[prop], + prop_id = num_data[0], + units = num_data[1], + min = num_data[2], + max = num_data[3], + step = num_data[4]; + var nblocks = $$('div.slider_numerics').length; + if (nblocks >= 2) + wmgui.notify( + 'Too little phases have all these properties reported — expect no results', + ); + if (nblocks >= 8) return; + create_floating_slider(prop, prop_id, units, min, max, step); + }); + + $$('strong.numeric').forEach(function (el) { + el.addEventListener('click', function () { + var prop = this.getAttribute('rel'), + num_data = wmgui.numerics[prop], + prop_id = num_data[0], + units = num_data[1], + min = num_data[2], + max = num_data[3], + step = num_data[4]; + create_floating_slider(prop, prop_id, units, min, max, step); + }); + }); + + $$('#hy_options > li').forEach(function (li) { + li.addEventListener('click', function () { + var desttab = this.getAttribute('rev'); + if (desttab == 'hy_vis') { + window.open(wmgui.static_host + '/labs/ontology'); + return; + } + this.classList.add('working'); + $$('#hy_options > li').forEach(function (other) { + if (other !== this) other.classList.remove('working'); + }, this); + hide($$('div.hy_tabs')); + show($('#' + desttab)); + }); + }); + + $$('#dtypes > ul > li').forEach(function (li) { + li.addEventListener('click', function () { + var facet = this.getAttribute('data-facet'), + term = this.getAttribute('data-term'); + + if (facet == 'classes') { + if (wmgui.search.classes) + // FIXME? + wmgui.search.classes = wmgui.search.classes + .replace('peer-reviewed', '') + .replace('peer-review', '') + .replace('machine-learning', '') + .replace('machine learning', '') + .replace('ab initio calculations', '') + .split(',') + .map(function (x) { + return x.trim(); + }) + .filter(function (x) { + return x; + }) + .join(', '); + //wmgui.inquiries.forEach(function(item){ + // if (wmgui.search[item]) delete wmgui.search[item]; + //}); + } + window.location.hash = wmgui.aug_search_cmd(facet, term); + }); + }); + + $$('#dtypes_phid > ul > li').forEach(function (li) { + li.addEventListener('click', function () { + var rankfilter = this.getAttribute('data-rankfilter'), + active = this.classList.contains('active'), + legend = this.textContent; + request_search( + { phid: wmgui.search.phid, rankfilter: active ? null : rankfilter }, + legend + ' of phase ' + wmgui.search.phid, + true, + ); + $$('#dtypes_phid > ul > li').forEach(function (other) { + other.classList.remove('active'); + }); + active ? this.classList.remove('active') : this.classList.add('active'); + }); + }); + + window.addEventListener( + 'scroll', + wmgui.debounce(function () { + if (wmgui.view_mode == 2) { + if (wmgui.unfinished_page) { + if (offset($('#footer')).top - scroll_top() - window_height() < 50) { + // footer pos - scrolling - window height + + wmgui.unfinished_page = false; + var cur_search = { offset: wmgui.quick_page_size }; + Object.assign(cur_search, wmgui.search); + + // NB no abort of the other requests! + wmgui.show_preloader(); + const request = ajax({ + type: 'GET', + url: wmgui.search_endpoint, + data: { + q: JSON.stringify(cur_search), + strict: wmgui.ctx_strict_phases, + //subphases: wmgui.ctx_subphases, + sid: wmgui.sid, + }, + }); + wmgui.active_ajax = request; + + request + .then(function (fetch_data) { + wmgui.hide_preloader(); + if (fetch_data.error) return wmgui.notify(fetch_data.error); + hide($$('div.context_msg')); + show_hints(); + if (!fetch_data.out.length) return; + if (wmgui.thumbed_display) { + $$('#databrowser tr td').forEach(function (td) { + append_html(td, build_thumbs(fetch_data.out)); + }); + } else { + append_html( + $('#databrowser tbody'), + build_cells(fetch_data.out), + ); + update_databrowser_sort(); + } + }) + .catch(function (error) { + wmgui.hide_preloader(); + if (!(error && error.aborted)) + wmgui.notify( + 'Connection to server is lost, please try to reload', + ); + }); + } + } + var iframe = $('#iframe'); + if (iframe && !wmgui.is_inview(iframe)) close_vibox(); + } else if (wmgui.ptable.activated) { + var scroll_pos = window.scrollY; + //console.log(scroll_pos); + + if (scroll_pos > 40) { + document + .getElementById('ptable_dtypes_box') + .classList.remove('resulted'); + document.getElementById('legend').style.display = 'none'; + + wmgui.ptable.vis_fixed && scroll_pos > 550 + ? document.getElementById('ptable_vis').classList.add('fixed') + : document.getElementById('ptable_vis').classList.remove('fixed'); + } else { + document + .getElementById('ptable_dtypes_box') + .classList.add('resulted'); + document.getElementById('legend').style.display = 'block'; + document.getElementById('ptable_vis').classList.remove('fixed'); + } + } + }, 300), + ); + + $('#userbox').addEventListener('click', function () { + var that = this; + if (window.location.hash == data(that, 'saved_hash')) + data(that, 'saved_hash', false); + + if (data(that, 'saved_hash')) { + window.location.replace(data(that, 'saved_hash')); + data(that, 'saved_hash', false); + } else { + if (window.location.hash.indexOf('modal') !== -1) { + window.location.replace('#start'); + } else { + data(that, 'saved_hash', window.location.hash); + + if (wmgui.sid) window.location.replace('#modal/menu'); + else window.location.replace('#modal/login'); + } + } + }); + + $$('span.href[rel]').forEach(function (el) { + el.addEventListener('click', function () { + window.location.replace(this.getAttribute('rel')); + }); + }); + + $$('div.spinoff_pane').forEach(function (pane) { + on(pane, 'span.extd', 'click', function () { + const legend = this.parentNode.querySelector('span.legend'); + if (legend) toggle_display(legend, 'block'); + this.textContent == 'Show more info...' + ? (this.textContent = 'Hide more info...') + : (this.textContent = 'Show more info...'); + }); + }); + + on($('#interpret'), 'li', 'click', function () { + var link = this.getAttribute('rel'); + if (!!link) { + // search only ... arity + window.location.hash = link; + return; + } + + var csscls = this.getAttribute('class') || ''; + + if (csscls.indexOf('numeric') !== -1) { + window.location.hash = '#hierarchy'; + } else if ( + csscls.indexOf('authors') !== -1 || + csscls.indexOf('years') !== -1 || + csscls.indexOf('codens') !== -1 || + csscls.indexOf('doi') !== -1 || + csscls.indexOf('geos') !== -1 || + csscls.indexOf('orgs') !== -1 + ) { + $$('#advstab_options li').forEach(function (li) { + li.classList.remove('working'); + }); + $$('#advstab_options li[rev=advstab_bib]').forEach(function (li) { + li.classList.add('working'); + }); + hide($$('div.advstab')); + show($('#advstab_bib')); + show_advsbox(); + } else if ( + csscls.indexOf('formulae') !== -1 || + csscls.indexOf('props') !== -1 || + csscls.indexOf('elements') !== -1 || + csscls.indexOf('classes') !== -1 + ) { + $$('#advstab_options li').forEach(function (li) { + li.classList.remove('working'); + }); + $$('#advstab_options li[rev=advstab_main]').forEach(function (li) { + li.classList.add('working'); + }); + hide($$('div.advstab')); + show($('#advstab_main')); + show_advsbox(); + } else { + $$('#advstab_options li').forEach(function (li) { + li.classList.remove('working'); + }); + $$('#advstab_options li[rev=advstab_cry]').forEach(function (li) { + li.classList.add('working'); + }); + hide($$('div.advstab')); + show($('#advstab_cry')); + show_advsbox(); + if (wmgui.search.aetypes) show_aetmap(wmgui.search.aetypes); + } + }); + + $$('#tab_links > li').forEach(function (li) { + li.addEventListener('click', function () { + try { + wmgui.active_ajax.abort(); + } catch (e) {} + try { + wmgui.quick_ajax.abort(); + } catch (e) {} + + var desttab = this.getAttribute('rev'); + + this.classList.add('working'); + $$('#tab_links > li').forEach(function (other) { + if (other !== this) other.classList.remove('working'); + }, this); + hide($$('div.menu_tabs')); + show($('#' + desttab)); + + if (desttab == 'usr_tab_api_key') { + set_html($('#hintsbox_msg'), wmgui.api_msg); + + wmgui.show_preloader(); + const request = ajax({ + type: 'POST', + url: wmgui.api_key_endpoint, + data: { sid: wmgui.sid }, + }); + wmgui.active_ajax = request; + + request + .then(function (data) { + wmgui.hide_preloader(); + if (data.error) return wmgui.notify(data.error); + set_html($('#usr_api_key'), data.msg); + if (data.revokable) show($('#revoke_usr_api_key_holder')); + else if (data.creatable) show($('#create_usr_api_key_holder')); + else + return wmgui.notify( + 'Your session ended: please, log in again', + ); + }) + .catch(function (error) { + wmgui.hide_preloader(); + if (!(error && error.aborted)) + wmgui.notify( + 'Your session ended: please, log in again', + ); + set_html($('#usr_api_key'), 'authentication error'); + }); + } else if (desttab == 'usr_tab_perms') { + set_html($('#hintsbox_msg'), wmgui.get_random_term(wmgui.welcome_msgs)); + + var locals = JSON.parse( + window.localStorage.getItem(wmgui.store_user_key) || '{}', + ); + + wmgui.show_preloader(); + const request = ajax({ + type: 'POST', + url: locals.ipbased ? wmgui.ip_perms_endpoint : wmgui.perms_endpoint, + data: { sid: wmgui.sid }, + }); + wmgui.active_ajax = request; + + request + .then(function (data) { + wmgui.hide_preloader(); + if (data.error) return wmgui.notify(data.error); + if (!data.hasOwnProperty('gui') || !data.hasOwnProperty('api')) + return wmgui.notify( + 'Your session ended: please, log in again', + ); + set_html($('#perms_view'), describe_perms(data)); + }) + .catch(function (error) { + wmgui.hide_preloader(); + if (!(error && error.aborted)) + wmgui.notify( + 'Your session ended: please, log in again', + ); + set_html($('#perms_view'), 'authentication error'); + }); + } else if (desttab == 'usr_tab_ctrl') { + // redirect to an external app + window.location.href = '/ctrl/?' + Math.floor(Math.random() * 1000); + } else if (desttab == 'usr_tab_absolidix') { + // redirect to an external app + window.location.href = wmgui.mydata_addr; + } else if (desttab == 'usr_tab_account') { + set_html($('#hintsbox_msg'), wmgui.get_random_term(wmgui.welcome_msgs)); + } + }); + }); + + $$('#advstab_options > li').forEach(function (li) { + li.addEventListener('click', function () { + var desttab = this.getAttribute('rev'); + + this.classList.add('working'); + $$('#advstab_options > li').forEach(function (other) { + if (other !== this) other.classList.remove('working'); + }, this); + + hide($$('div.advstab')); + show($('#' + desttab)); + }); + }); + + $$('a.link_adjuster').forEach(function (a) { + a.addEventListener('click', function (event) { + // hash-hack FIXME? + if (window.location.hash == '#polyhedra') { + window.location.hash = '#polyhedra/'; + event.preventDefault(); + return false; + } else if (window.location.hash == '#polyhedra/') { + window.location.hash = '#polyhedra'; + event.preventDefault(); + return false; + } else return true; + }); + }); + + $('#create_usr_api_key').addEventListener('click', function () { + hide(this.parentNode); + try { + wmgui.active_ajax.abort(); + } catch (e) {} + + wmgui.show_preloader(); + const request = ajax({ + type: 'POST', + url: wmgui.api_key_endpoint, + data: { sid: wmgui.sid, create: true }, + }); + wmgui.active_ajax = request; + + request + .then(function (data) { + wmgui.hide_preloader(); + if (data.error) return wmgui.notify(data.error); + set_html($('#usr_api_key'), data.msg); + show($('#revoke_usr_api_key_holder')); + }) + .catch(function (error) { + wmgui.hide_preloader(); + if (!(error && error.aborted)) + wmgui.notify( + 'Your session ended: please, log in again', + ); + }); + }); + + $('#revoke_usr_api_key').addEventListener('click', function () { + hide(this.parentNode); + try { + wmgui.active_ajax.abort(); + } catch (e) {} + + wmgui.show_preloader(); + const request = ajax({ + type: 'POST', + url: wmgui.api_key_endpoint, + data: { sid: wmgui.sid, revoke: true }, + }); + wmgui.active_ajax = request; + + request + .then(function (data) { + wmgui.hide_preloader(); + if (data.error) return wmgui.notify(data.error); + set_html($('#usr_api_key'), 'Successfully revoked'); + show($('#create_usr_api_key_holder')); + }) + .catch(function (error) { + wmgui.hide_preloader(); + if (!(error && error.aborted)) + wmgui.notify( + 'Your session ended: please, log in again', + ); + }); + }); + + $('#login_trigger').addEventListener('click', function () { + if (data(this, 'busy')) return; + data(this, 'busy', true); + this.textContent = 'In process...'; + + try { + wmgui.active_ajax.abort(); + } catch (e) {} + + wmgui.show_preloader(); + const request = ajax({ + type: 'POST', + url: wmgui.login_endpoint, + data: { + login: $('#login_email').value.trim(), + pass: $('#login_password').value, + ed: wmgui.edition, + }, + }); + wmgui.active_ajax = request; + + request + .then(function (answer) { + data($('#login_trigger'), 'busy', false); + $('#login_trigger').textContent = 'Login'; + wmgui.hide_preloader(); + + if (answer.error) return wmgui.notify(answer.error); + if (!answer.sid || !answer.name || !answer.acclogin) + return wmgui.notify( + 'Connection to server is lost, please try to reload', + ); + user_login( + answer.sid, + answer.name, + answer.acclogin, + answer.admin, + answer.oauths, + ); + $('#userbox').click(); + }) + .catch(function (error) { + data($('#login_trigger'), 'busy', false); + $('#login_trigger').textContent = 'Login'; + wmgui.hide_preloader(); + wmgui.notify('Login unsuccessful'); + }); + }); + + $('#factor_trigger').addEventListener('click', function () { + if (data(this, 'busy')) return; + data(this, 'busy', true); + this.textContent = 'Sending...'; + + try { + wmgui.active_ajax.abort(); + } catch (e) {} + + wmgui.show_preloader(); + const request = ajax({ + type: 'POST', + url: wmgui.factor_endpoint, + data: { login: $('#factor_by_email').value.trim() }, + }); + wmgui.active_ajax = request; + + request + .then(function (answer) { + data($('#factor_trigger'), 'busy', false); + $('#factor_trigger').textContent = 'Send code'; + wmgui.hide_preloader(); + + if (answer.error) return wmgui.notify(answer.error); + wmgui.notify('Please, check your inbox (and spam)'); + + // handle factor log in step two... + document.getElementById('factor_trigger').style.display = 'none'; + document.getElementById('factor_form_step_one').style.display = 'none'; + document.getElementById('factor_form_step_two').style.display = 'block'; + document.getElementById('factor_form_resp_0').focus(); + }) + .catch(function (error) { + data($('#factor_trigger'), 'busy', false); + $('#factor_trigger').textContent = 'Send code'; + wmgui.hide_preloader(); + if (!(error && error.aborted)) + wmgui.notify('Sorry, a network error occured. Please, try again'); + }); + }); + + $('#restore_trigger').addEventListener('click', function () { + if (data(this, 'busy')) return; + data(this, 'busy', true); + this.textContent = 'Sending...'; + + try { + wmgui.active_ajax.abort(); + } catch (e) {} + + wmgui.show_preloader(); + const request = ajax({ + type: 'POST', + url: wmgui.restore_endpoint, + data: { login: $('#restore_by_email').value.trim(), ed: wmgui.edition }, + }); + wmgui.active_ajax = request; + + request + .then(function (answer) { + data($('#restore_trigger'), 'busy', false); + $('#restore_trigger').textContent = 'Send link'; + wmgui.hide_preloader(); + + if (answer.error) return wmgui.notify(answer.error); + wmgui.notify('Please, check your inbox (and spam)'); + $('#userbox').click(); + }) + .catch(function (error) { + data($('#restore_trigger'), 'busy', false); + $('#restore_trigger').textContent = 'Send link'; + wmgui.hide_preloader(); + if (!(error && error.aborted)) + wmgui.notify('Sorry, a network error occured. Please, try again'); + }); + }); + + $('#accpass_trigger').addEventListener('click', function () { + if (this.classList.contains('disabled')) return false; + + toggle_display($('#account_pass_change')); + }); + + $('#password_trigger').addEventListener('click', function () { + var p1 = $('#new_password_1').value, + p2 = $('#new_password_2').value; + if (!p1 || !p2) + return wmgui.notify('Please, type your new password in both fields'); + if (p1 !== p2) return wmgui.notify('Passwords do not match (typo?)'); + + if (data(this, 'busy')) return; + data(this, 'busy', true); + this.textContent = 'Changing...'; + + try { + wmgui.active_ajax.abort(); + } catch (e) {} + + wmgui.show_preloader(); + const request = ajax({ + type: 'POST', + url: wmgui.password_endpoint, + data: { new_password: p2, sid: wmgui.sid, ed: wmgui.edition }, + }); + wmgui.active_ajax = request; + + request + .then(function (answer) { + data($('#password_trigger'), 'busy', false); + $('#password_trigger').textContent = 'Change'; + wmgui.hide_preloader(); + + if (answer.error) return wmgui.notify(answer.error); + user_login( + answer.sid, + answer.name, + answer.acclogin, + answer.admin, + answer.oauths, + ); + window.location.replace('#start'); + hide($('#account_pass_change')); + }) + .catch(function (error) { + data($('#password_trigger'), 'busy', false); + $('#password_trigger').textContent = 'Change'; + wmgui.hide_preloader(); + if (!(error && error.aborted)) + wmgui.notify( + 'Your session ended: please, log in again', + ); + }); + }); + + $('#logout_trigger').addEventListener('click', function () { + if (this.classList.contains('disabled')) return false; + + ajax({ + type: 'POST', + url: wmgui.logout_endpoint, + data: { sid: wmgui.sid }, + }) + .then(function () {}) + .catch(function () {}); + user_logout(); + $('#userbox').click(); + }); + + on($('#notifybox'), 'span.relogin', 'click', function () { + force_relogin(); + }); + + var resps = document.getElementsByClassName('factor_form_resp'); + for (var i = 0; i < resps.length; i++) { + resps[i].addEventListener('keyup', function (evt) { + // back, left arrow + if (evt.keyCode == 8 || evt.keyCode == 37) { + var prev = this.previousElementSibling; + if (prev) { + prev.focus(); + prev.select(); + } + } else if (evt.keyCode > 47 && evt.keyCode < 58) { + submit_factor_form_resp(); + + var next = this.nextElementSibling; + if (next) { + next.focus(); + next.select(); + } + } + }); + + resps[i].addEventListener('paste', function (evt) { + var pasted = (evt.clipboardData || window.clipboardData).getData('text'); + if (!pasted || !pasted.length) return false; + + for (var i = 0; i < 6; i++) { + document.getElementById('factor_form_resp_' + i).value = + pasted.charAt(i); + } + submit_factor_form_resp(); + }); + } + + $('#search_holder').addEventListener('keydown', function (e) { + var key = window.event ? e.keyCode : e.which; + if (key == 13) $('#search_trigger').click(); + }); + + // switch sliders: first row abf + $('#control_a').addEventListener('click', function () { + // entries + ///re_view_request(0); + var orepr = {}; + for (var key in wmgui.search) { + if (['search_type', 'phid'].indexOf(key) !== -1) continue; + orepr[key] = wmgui.search[key]; + } + + wmgui.search_type = 0; + wmgui.search.search_type = wmgui.search_type; + + var urlstr = param(orepr); + if (urlstr.slice(-1) == '=') urlstr = urlstr.substr(0, urlstr.length - 1); + else urlstr += '='; + + window.location.hash = '#inquiry_entries/' + urlstr; + }); + $('#control_b').addEventListener('click', function () { + // phases + ///re_view_request(1); + var orepr = {}; + for (var key in wmgui.search) { + if (['search_type', 'phid'].indexOf(key) !== -1) continue; + orepr[key] = wmgui.search[key]; + } + + wmgui.search_type = 1; + wmgui.search.search_type = wmgui.search_type; + + var urlstr = param(orepr); + if (urlstr.slice(-1) == '=') urlstr = urlstr.substr(0, urlstr.length - 1); + else urlstr += '='; + + window.location.hash = '#inquiry_phases/' + urlstr; + }); + $('#control_f').addEventListener('click', function () { + // articles + ///re_view_request(2); + var orepr = {}; + for (var key in wmgui.search) { + if (['search_type', 'phid'].indexOf(key) !== -1) continue; + orepr[key] = wmgui.search[key]; + } + + wmgui.search_type = 2; + wmgui.search.search_type = wmgui.search_type; + + var urlstr = param(orepr); + if (urlstr.slice(-1) == '=') urlstr = urlstr.substr(0, urlstr.length - 1); + else urlstr += '='; + + window.location.hash = '#inquiry_articles/' + urlstr; + }); + + // switch sliders: second row cde + $('#control_c').addEventListener('click', function () { + // table + wmgui.visavis_terminating = true; + wmgui.thumbed_display = false; + if (wmgui.visavis_working) { + var orepr = {}; + for (var key in wmgui.search) { + if (['search_type', 'phid', 'numeric'].indexOf(key) !== -1) continue; + orepr[key] = wmgui.search[key]; + } + var urlstr = param(orepr); + if (window.location.hash == '#inquiry/' + urlstr) { + // hash-hack FIXME? + if (urlstr.slice(-1) == '=') + urlstr = urlstr.substr(0, urlstr.length - 1); + else urlstr += '='; + } + window.location.hash = '#inquiry/' + urlstr; + } else re_view_request(wmgui.search_type); + wmgui.chosen_table_browser = true; + }); + $('#control_d').addEventListener('click', function () { + // previews + wmgui.visavis_terminating = true; + wmgui.thumbed_display = true; + if (wmgui.visavis_working) { + var orepr = {}; + for (var key in wmgui.search) { + if (['search_type', 'phid', 'numeric'].indexOf(key) !== -1) continue; + orepr[key] = wmgui.search[key]; + } + var urlstr = param(orepr); + if (window.location.hash == '#inquiry/' + urlstr) { + // hash-hack FIXME? + if (urlstr.slice(-1) == '=') + urlstr = urlstr.substr(0, urlstr.length - 1); + else urlstr += '='; + } + window.location.hash = '#inquiry/' + urlstr; + } else re_view_request(wmgui.search_type); + wmgui.chosen_table_browser = true; + }); + $('#control_e').addEventListener('click', function () { + // plotting + var orepr = {}; + for (var key in wmgui.search) { + if (['search_type', 'phid', 'numeric'].indexOf(key) !== -1) continue; + orepr[key] = wmgui.search[key]; + } + while (true) { + var plot_type = wmgui.get_random_term(['matrix', 'cube']); // the most interesting visualization types + if (plot_type != wmgui.visavis_curtype) break; + } + window.location.hash = '#plot/' + plot_type + '/inquiry/' + param(orepr); + }); + + $('#ctx_strict_phases_trigger').addEventListener('change', function (e) { + //$('#ctx_subphases_trigger').prop('checked', false); + + if (!wmgui.search.elements) { + wmgui.cancel_event(e); + return false; + } + + var arity_kwd = wmutils.arity_keys[wmgui.search.elements.split('-').length], + kwd_exists = false; + + if (wmgui.search.classes) { + var arity_keys = wmutils.arity_keys.slice(1); + for (var num = 0; num < arity_keys.length; num++) { + if (num == 6) break; + + var value = arity_keys[num]; + if (wmgui.search.classes.indexOf(value) !== -1) { + kwd_exists = true; + break; + } + } + + if (!kwd_exists) { + wmgui.search.classes += ', ' + arity_kwd; + wmgui.multiselects['main'].write({ classes: arity_kwd }); + } + } else { + wmgui.search.classes = arity_kwd; + wmgui.multiselects['main'].write({ classes: arity_kwd }); + } + + wmgui.ctx_strict_phases = $('#ctx_strict_phases_trigger').checked + ? '' + : '1'; + re_view_request(wmgui.search_type); + }); + /*$('#ctx_subphases_trigger').change(function(){ + //$('#ctx_strict_phases_trigger').prop('checked', false); + wmgui.ctx_subphases = wmgui.search.elements && $('#ctx_subphases_trigger').is(':checked') ? '1' : ''; + re_view_request(wmgui.search_type); + });*/ + + // visavis ctx + $$('#ctxpanel_matrix > ul > li').forEach(function (li) { + li.addEventListener('click', function () { + if ( + this.classList.contains('embodied') || + this.classList.contains('ss_y') + ) + return; + var type = this.id.split('_')[1]; + $$('#ctxpanel_matrix > ul > li.embodied').forEach(function (el) { + el.classList.remove('embodied'); + }); + $$('#ctxpanel_matrix > ul > li.ss_y').forEach(function (el) { + el.classList.remove('ss_y'); + }); + this.classList.add('embodied'); + remove($$('span.sops')); + + document + .getElementById('visavis_iframe') + .contentWindow.matrix_order(type); + }); + }); + $$('#ctxpanel_cube > ul > li').forEach(function (li) { + li.addEventListener('click', function () { + if ( + this.classList.contains('embodied') || + this.classList.contains('ss_y') || + this.classList.contains('ss_z') + ) + return; + var type = this.id.split('_')[1]; + $$('#ctxpanel_cube > ul > li.embodied').forEach(function (el) { + el.classList.remove('embodied'); + }); + $$('#ctxpanel_cube > ul > li.ss_y').forEach(function (el) { + el.classList.remove('ss_y'); + }); + $$('#ctxpanel_cube > ul > li.ss_z').forEach(function (el) { + el.classList.remove('ss_z'); + }); + this.classList.add('embodied'); + remove($$('span.sops')); + + if ( + document + .getElementById('visavis_iframe') + .contentWindow.location.hash.indexOf('fixel=1') !== -1 + ) + document + .getElementById('visavis_iframe') + .contentWindow.matrix_order(type); + else + document + .getElementById('visavis_iframe') + .contentWindow.cube_order(type, type, type); + }); + }); + $$('#ctxpanel_graph > ul > li').forEach(function (li) { + li.addEventListener('click', function () { + if (this.classList.contains('embodied')) return; + var type = this.id.split('_')[1]; + $$('#ctxpanel_graph > ul > li.embodied').forEach(function (el) { + el.classList.remove('embodied'); + }); + this.classList.add('embodied'); + + document + .getElementById('visavis_iframe') + .contentWindow.graph_rebuild(type); + }); + }); + $('#select_cmp_trigger').addEventListener('change', function () { + var value = this.value, + title = this.options[this.selectedIndex].text; + + wmgui.dc_ctrl_flag = true; + + if (value == 'X') return; + else if (value == 'Y') { + document + .getElementById('visavis_iframe') + .contentWindow.cmp_discard(wmgui.visavis_curtype); + return; + } + + if (['matrix', 'cube', 'discovery'].indexOf(wmgui.visavis_curtype) == -1) + return; + + var url = wmgui.vis_endpoint + '/' + wmgui.visavis_curtype + '?q=' + value; + document + .getElementById('visavis_iframe') + .contentWindow.cmp_download(url, wmgui.visavis_curtype); + }); + $$('li.discovery_custom').forEach(function (li) { + li.addEventListener('click', function () { + if ( + !document.getElementById('visavis_iframe') || + !document.getElementById('visavis_iframe').contentWindow + ) + return false; + + var list = + document.getElementById('visavis_iframe').contentWindow.visavis + .elementals_on, + html_list_on = '', + html_list_off = ''; + + for (var prop in wmgui.elemental_names) { + if (list.indexOf(prop) !== -1) + html_list_on += + '
    ' + + wmgui.elemental_names[prop] + + ' (−)
    '; + else + html_list_off += + '
    ' + + wmgui.elemental_names[prop] + + ' (+)
    '; + } + if (html_list_off) set_html($('#discovery_disabled'), html_list_off); + + set_html($('#discovery_enabled'), html_list_on); + show($$('#discovery_custom_box, #overlay')); + }); + }); + on($('#discovery_custom_box'), 'div.rearrange', 'click', function () { + var prop = this.getAttribute('rel'), + idx = document + .getElementById('visavis_iframe') + .contentWindow.visavis.elementals_on.indexOf(prop); + if (this.parentNode.id == 'discovery_enabled') { + if ($$('#discovery_enabled div.rearrange').length == 1) return false; + if (idx !== -1) + document + .getElementById('visavis_iframe') + .contentWindow.visavis.elementals_on.splice(idx, 1); + append_html( + $('#discovery_disabled'), + '
    ' + + wmgui.elemental_names[prop] + + ' (+)
    ', + ); + hide($('#dc_' + prop)); + } else { + if (idx == -1) + document + .getElementById('visavis_iframe') + .contentWindow.visavis.elementals_on.push(prop); + append_html( + $('#discovery_enabled'), + '
    ' + + wmgui.elemental_names[prop] + + ' (−)
    ', + ); + show($('#dc_' + prop)); + } + this.remove(); + }); + $$('#ss_gear_matrix, #ss_gear_cube').forEach(function (gear) { + gear.addEventListener('click', function () { + var domain = this.id.substr(8); // ss_gear_ + if (domain == 'matrix') { + hide($$('#ss_z, #sops_z')); + $$('#ss_x, #ss_y, #sops_x, #sops_y').forEach(function (el) { + el.style.width = '50%'; + }); + } else { + $$('#ss_x, #ss_y, #ss_z, #sops_x, #sops_y, #sops_z').forEach( + function (el) { + el.style.width = '33%'; + }, + ); + show($$('#ss_z, #sops_z')); + } + + // ss_ logic + var common_type = $( + '#ctxpanel_' + domain + ' > ul > li.embodied', + ).id.split('_')[1], // NB embodied, not ss_x + y_id = $('#ctxpanel_' + domain + ' > ul > li.ss_y'), + z_id = $('#ctxpanel_' + domain + ' > ul > li.ss_z'), + x_type = common_type, + y_type = y_id ? y_id.id.split('_')[1] : common_type, + z_type = z_id ? z_id.id.split('_')[1] : common_type, + x_orders_html = '', + y_orders_html = '', + z_orders_html = ''; + + $$('#ctxpanel_' + domain + ' > ul > li').forEach(function (li) { + var type = li.id.split('_')[1], + text_nodes = Array.prototype.slice + .call(li.childNodes) + .filter(function (node) { + return node.nodeType !== 1; + }), + label = ( + text_nodes.length ? text_nodes[0].data : li.textContent + ).substr(3), // filter text only, then cut "by " + cls_html = type == x_type ? ' class="ss_x"' : ''; + x_orders_html += + '
  • ' + + label + + '
  • '; + cls_html = type == y_type ? ' class="ss_y"' : ''; + y_orders_html += + '
  • ' + + label + + '
  • '; + if (domain == 'matrix') return; + cls_html = type == z_type ? ' class="ss_z"' : ''; + z_orders_html += + '
  • ' + + label + + '
  • '; + }); + + set_html($('#ss_x > ul'), x_orders_html); + set_html($('#ss_y > ul'), y_orders_html); + if (domain == 'cube') set_html($('#ss_z > ul'), z_orders_html); + + // sops_ logic + $$('li.sops_x').forEach(function (el) { + el.classList.remove('sops_x'); + }); + $$('li.sops_y').forEach(function (el) { + el.classList.remove('sops_y'); + }); + $$('li.sops_z').forEach(function (el) { + el.classList.remove('sops_z'); + }); + + var sops_types = ['x', 'y', 'z']; + $$('span.sops').forEach(function (span) { + var op = span.textContent, + type = span.getAttribute('rel'); + $$('#sops_' + type + ' > ul > li').forEach(function (li) { + if (li.textContent.indexOf(op) !== -1) + li.classList.add('sops_' + type); + }); + sops_types = sops_types.filter(function (x) { + return x !== type; + }); + }); + sops_types.forEach(function (item) { + $$('#sops_' + item + ' > ul > li').forEach(function (li) { + if (li.textContent.indexOf('none') !== -1) + li.classList.add('sops_' + item); + }); + }); + + show($$('#ss_custom_box, #overlay')); + }); + }); + $$('div.ss_col').forEach(function (col) { + on(col, 'li', 'click', function () { + var rowid = this.getAttribute('rev'), + rel_dat = this.getAttribute('rel').split('_'), + axis = rel_dat[0], + clsname = axis == 'x' ? 'ss_x' : axis == 'y' ? 'ss_y' : 'ss_z'; + $$('#' + rowid + ' > ul > li.' + clsname).forEach(function (li) { + li.classList.remove(clsname); + }); + this.classList.add(clsname); + }); + }); + $$('div.sops_col').forEach(function (col) { + on(col, 'li', 'click', function () { + var rowid = this.closest('.sops_col').id, + axis = rowid.split('_')[1], + clsname = axis == 'x' ? 'sops_x' : axis == 'y' ? 'sops_y' : 'sops_z'; + $$('#' + rowid + ' > ul > li.' + clsname).forEach(function (li) { + li.classList.remove(clsname); + }); + this.classList.add(clsname); + }); + }); + + const tips_trigger = $('#tips_trigger'); + if (tips_trigger) + tips_trigger.addEventListener('click', function () { + wmgui.tooltip_counter = 0; + show_tooltip(wmgui.tooltips[wmgui.tooltip_landing]); + return false; + }); + + // numeric search + on($('#numericbox'), 'div.slider_close', 'click', function () { + if ($$('div.slider_numerics').length == 1) { + destroy_numericbox(); + delete wmgui.search.numeric; + const main_input = $('#search_field-selectized'); + if (main_input) main_input.value = ''; + wmgui.multiselects['main'].clear(); + wmgui.multiselects['main'].write(wmgui.search); + return false; + } + const slider = this.parentNode.querySelector('div.slider_numerics'); + if (slider && slider.noUiSlider) slider.noUiSlider.destroy(); + const li = this.closest('li'); + if (li) + fade_out(li, 250, function () { + li.remove(); + }); + }); + + $('#numericbox_do_trigger').addEventListener('click', function () { + var sliders_numerics = document.getElementsByClassName('slider_numerics'), + numeric = []; + + for (var i = 0; i < sliders_numerics.length; i++) { + var sdata = sliders_numerics[i].noUiSlider.get(), + srange = sliders_numerics[i].noUiSlider.options.range, + srange = [srange.min, srange.max]; + //if (sdata[0] == srange[0] && sdata[1] == srange[1]) continue; + //console.log(sdata); + + var prop = sliders_numerics[i].getAttribute('rel'); + numeric.push([prop, '>', sdata[0]]); + numeric.push([prop, '<', sdata[1]]); + } + + if (numeric.length) wmgui.search.numeric = numeric; + + if (isVisible($('#advsbox'))) $('#advsearch_do_trigger').click(); + else $('#search_trigger').click(); + }); + + $('#numericbox_drop_trigger').addEventListener('click', function () { + var sliders_numerics = document.getElementsByClassName('slider_numerics'); + + //console.log(sliders_numerics); + + for (var i = 0; i < sliders_numerics.length; i++) { + var srange = sliders_numerics[i].noUiSlider.options.range; + sliders_numerics[i].noUiSlider.set([srange.min, srange.max]); + } + }); + + $('#close_numericbox').addEventListener('click', function () { + destroy_numericbox(); + delete wmgui.search.numeric; + const main_input = $('#search_field-selectized'); + if (main_input) main_input.value = ''; + wmgui.multiselects['main'].clear(); + wmgui.multiselects['main'].write(wmgui.search); + }); + + // mobile version switching + /*$('#mobilebox span').click(function(){ + window.location.href = '/m/' + window.location.hash; + }); + $('#mobilebox a').click(function(){ + $('#mobilebox').remove(); + return false; + });*/ + + // keys press + document.addEventListener('keydown', function (e) { + var key = window.event ? e.keyCode : e.which; + if (key == 13) { + // ENTER: input must trigger submit button via two parent divs! + var focused = document.activeElement; + //console.log(focused); + + if ( + focused && + focused.classList && + focused.classList.contains('submitter') + ) { + const target = focused.parentElement.parentElement.querySelector( + 'div.def_submittable', + ); + if (target) target.click(); + } else if ( + focused && + focused.classList && + (focused.classList.contains('advs_input') || + (focused.id || '').startswith('advs_fct_')) + ) { + $('#advsearch_do_trigger').click(); + } + } else if (key == 27) { + // ESC + const target = $$('div.cross').find(isVisible); + if (target) target.click(); + } + }); + + window.addEventListener('hashchange', url_redraw_react); + + // execute a command in all the active GUI windows (except the current) e.g. setting a new state + const storage_runnables = { + tab_user_login: tab_user_login, + user_logout: user_logout, + }; + window.addEventListener('storage', function (ev) { + if (ev.key != wmgui.store_comm_exec_key) return; + + var runnable_name = ev.newValue; + if (runnable_name && storage_runnables[runnable_name]) + storage_runnables[runnable_name](); + }); + + /*$(window).resize(function(){ + //document.title = document.body.clientWidth + ' px'; + if (document.body.clientWidth < 1000) $('#mobilebox').show(); + else $('#mobilebox').hide(); + });*/ + + document + .querySelector('#ptable_previews') + .addEventListener('click', function (event) { + if (event.target.classList.contains('subphases_trigger')) { + var state = parseInt(event.target.getAttribute('data-state')), + req = Object.assign({}, wmgui.ptable.query), + param_str; + + if (state === 1) { + param_str = 'strict=1'; + } else { + param_str = 'subphases=1'; + delete req.classes; + } + ajax_download( + wmgui.search_endpoint + '?q=' + JSON.stringify(req) + '&' + param_str, + render_left, + true, + ); + wmgui.ptable.subphases_set(state); + } + }); + + // theme switcher + document.getElementById('darkmode_trigger').onclick = function () { + wmgui.darkmode.toggle(); + document.getElementById('darkmode_trigger').innerHTML = + wmgui.darkmode.isActivated() ? 'enabled' : 'disabled'; + document + .getElementById('comms') + .contentWindow.postMessage( + JSON.stringify({ darkmode: wmgui.darkmode.isActivated() ? 1 : 2 }), + '*', + ); + }; + + // cross-site comms + window.addEventListener('message', function (message) { + //if (message.origin === 'https://trusted.com') { + var received = {}; + try { + received = JSON.parse(message.data); + } catch (ignore) {} + var darkmode = received.darkmode; + if (darkmode !== undefined) { + darkmode = darkmode === 1; + if (darkmode !== wmgui.darkmode.isActivated()) wmgui.darkmode.toggle(); + document.getElementById('darkmode_trigger').innerHTML = + wmgui.darkmode.isActivated() ? 'enabled' : 'disabled'; + } + //} + }); + // EOF register_events +} diff --git a/src_js/markup.js b/src_js/app/markup.js old mode 100755 new mode 100644 similarity index 99% rename from src_js/markup.js rename to src_js/app/markup.js index b553ec0..1095f0c --- a/src_js/markup.js +++ b/src_js/app/markup.js @@ -1,9 +1,11 @@ -"use strict"; - -var wmgui = window.wmgui || {}; - -function register_html(){ - $('body').append(` +/** + * Ermac UI markup: injects the full application HTML into . + */ + +export function register_html() { + document.body.insertAdjacentHTML( + 'beforeend', + `
    Web-browser is either busy or not supported: try to restart
    @@ -877,5 +879,6 @@ function register_html(){ -`); + `, + ); } diff --git a/src_js/app/ptable.js b/src_js/app/ptable.js new file mode 100644 index 0000000..5b4b09d --- /dev/null +++ b/src_js/app/ptable.js @@ -0,0 +1,639 @@ +/** + * Ermac interactive periodic table. + */ + +import wmgui from '../core/settings.js'; +import { wmutils } from '../core/utils.js'; +import { ajax } from '../core/ajax.js'; +import { $, $$, hide, show } from '../core/dom.js'; +import { get_visavis_url } from './search.js'; + +const ptable = {}; +wmgui.ptable = ptable; + +ptable.update_selectize = false; +ptable.active_ajax = null; +ptable.query = null; +ptable.els_data = []; +ptable.pdsvg_path = wmgui.static_host + '/pds_svgs'; +ptable.crsvg_path = wmgui.static_host + '/crs_svgs'; +ptable.ppsvg_path = wmgui.static_host + '/pps_svgs'; +ptable.first_el = null; +ptable.second_el = null; +ptable.visible = false; // needed to debounce +ptable.activated = false; // should it "jump" on top by input +ptable.dtypes = 1; // 0, 1, 2, or 3, see #ptable_dtypes +ptable.subphases_button = ''; +ptable.vis_fixed = false; +ptable.elements = ['X'].concat(wmutils.periodic_elements_cased); + +// patch display keyword unary to elementary +ptable.arity_keys = wmutils.arity_keys.slice(); +ptable.arity_keys[1] = 'elementary'; + +ptable.show = function () { + if (ptable.visible) return; + document.getElementById('ptable_holder').style.display = 'block'; + ptable.visible = true; +}; + +ptable.hide = function () { + if (!ptable.visible) return; + document.getElementById('ptable_holder').style.display = 'none'; + ptable.visible = false; +}; + +ptable.activate = function () { + ptable.activated = true; + document.getElementById('ermac_logo').classList.add('resulted'); + document.getElementById('ptable_holder').classList.add('resulted'); + if (window.scrollY <= 40) + document.getElementById('ptable_dtypes_box').classList.add('resulted'); + wmgui.mpdsgui.ptable_activate(); +}; + +ptable.deactivate = function () { + ptable.activated = false; + document.getElementById('ermac_logo').classList.remove('resulted'); + document.getElementById('ptable_holder').classList.remove('resulted'); + document.getElementById('ptable_dtypes_box').classList.remove('resulted'); + wmgui.mpdsgui.ptable_deactivate(); +}; + +ptable.decide = function () { + const scroll_pos = window.scrollY; + //console.log(scroll_pos); + + if (scroll_pos > 60) + // forward to intro_stats screen + ptable.hide(); // back to ptable screen + else ptable.show(); +}; + +ptable.subphases_set = function (state) { + if (!state) { + ptable.subphases_button = ''; + } else if (state === 1) { + ptable.subphases_button = + '
    Load binary and ternary phases ↑
    '; + } else { + ptable.subphases_button = + '
    Load ternary phases only ↑
    '; + } +}; + +export function read_ptable_html() { + let unaries_data = [{}]; // NB zero-th element (X) + + ptable.elements.forEach(function (_, idx) { + if (idx == 0 || idx > 103) + // X - Lr + return; + + const item = document.querySelector( + '#ptable_area > ul > li[data-pos="' + idx + '"]', + ); + let elem_data = { pos: idx, classes: [] }; // NB prop html: + + item.classList.forEach(function (cls) { + elem_data.classes.push(cls); + }); + + unaries_data.push(elem_data); + }); + return unaries_data; +} + +function removeAllCls(cls) { + const collection = document.getElementsByClassName(cls); + while (collection.length) collection[0].classList.remove(cls); +} + +function clear_results_area() { + try { + ptable.active_ajax.abort(); + } catch (e) {} + document.getElementById('ptable_previews').innerHTML = ''; + document.getElementById('ptable_vis').innerHTML = ''; + ptable.deactivate(); +} + +function refresh_ptable_results(elA, elB, elC) { + if (wmgui.view_mode !== 1) return; + + //console.log('Refreshing table with ' + [elA, elB, elC]); + + const els = [elA, elB, elC].filter(function (item) { + return !!item; + }), + query_ph = els.length + ? { + search_type: 1, + classes: wmutils.arity_keys[els.length], + elements: els.join('-'), + } + : false; + + if (ptable.update_selectize) { + ptable.update_selectize = false; + + wmgui.multiselects['main'].clear(); + wmgui.multiselects['main'].write({ elements: els.join('-') }); + } + + ptable.subphases_set(); + + if (query_ph) { + ptable.query = query_ph; + ptable.vis_fixed = false; + + let iframe_addr, + iframe_height = 900; + + if (els.length == 1) { + if (ptable.dtypes == 2) { + iframe_addr = wmgui.engines_addrs['cifplayer']; + ptable.vis_fixed = true; + } else if (ptable.dtypes == 3) { + iframe_addr = wmgui.engines_addrs['visavis']; + ptable.vis_fixed = true; + } else document.getElementById('ptable_vis').innerHTML = ''; + } else if (els.length == 2) { + iframe_height = 800; + + if (ptable.dtypes == 1) { + const query_pds = { + search_type: 0, + classes: wmutils.arity_keys[els.length], + elements: els.join('-'), + props: 'phase diagram', + }; + ajax_download( + wmgui.search_endpoint + '?q=' + JSON.stringify(query_pds), + render_right, + false, + ); + } else if (ptable.dtypes == 2) { + iframe_addr = wmgui.engines_addrs['cifplayer']; + ptable.vis_fixed = true; + } else if (ptable.dtypes == 3) { + iframe_addr = wmgui.engines_addrs['visavis']; + ptable.vis_fixed = true; + } else document.getElementById('ptable_vis').innerHTML = ''; + } else { + ptable.subphases_set(1); + iframe_height = window.innerHeight - 200; + ptable.vis_fixed = true; + + if (ptable.dtypes == 1) { + iframe_addr = wmgui.v_pd_3d_addr + els.join('-'); + } else if (ptable.dtypes == 2) { + iframe_addr = wmgui.engines_addrs['cifplayer']; + } else if (ptable.dtypes == 3) { + iframe_addr = wmgui.engines_addrs['visavis']; + } else document.getElementById('ptable_vis').innerHTML = ''; + } + ajax_download( + wmgui.search_endpoint + '?q=' + JSON.stringify(query_ph) + '&strict=1', + render_left, + true, + ); + + if (iframe_addr) + document.getElementById('ptable_vis').innerHTML = + ''; + + ptable.activate(); + } else clear_results_area(); +} + +export function ajax_download(url, callback, reuse) { + wmgui.show_preloader(); + if (reuse && ptable.active_ajax && ptable.active_ajax.abort) { + try { + ptable.active_ajax.abort(); + } catch (e) {} + } + const request = ajax({ url: url, dataType: 'text' }); + if (reuse) ptable.active_ajax = request; + request + .then(function (response_text) { + wmgui.hide_preloader(); + callback(response_text); + }) + .catch(function (error) { + wmgui.hide_preloader(); + if (error && !error.aborted) + console.error( + 'Error: HTTP ' + + error.status + + ' status received during data retrieval from the server', + ); + }); +} + +export function render_left(data) { + data = JSON.parse(data); + if (data.error) return wmgui.notify(data.error); + + const header = + '

    Reported phases of ' + + ptable.arity_keys[wmutils.arity_keys.indexOf(ptable.query.classes)] + + ' ' + + ptable.query.elements + + (ptable.query.elements.indexOf('-') == -1 ? '' : ' system') + + '

    '; + + const parent = document.getElementById('ptable_previews'); + parent.className = ''; + parent.classList.add('ptable_dtype_' + ptable.dtypes); + parent.innerHTML = + header + + (data.out.length ? build_thumbs_ph(data.out) : '

    No results

    ') + + ptable.subphases_button; + + if (data.out.length < 10) ptable.vis_fixed = false; // prevent screen jumping + + if (ptable.dtypes == 2) { + const els = document.querySelectorAll( + '#ptable_results div.gallery_img.renderable', + ); + if (els.length) { + const rnd_i = Math.floor(Math.random() * els.length); + els[rnd_i].parentNode.classList.add('active'); + const phid = els[rnd_i].getAttribute('rel'), + target = document.querySelector('#ptable_vis > iframe'), + target_addr = + '#' + wmgui.phase_endpoint + '?phid=' + phid + '&struct=1'; + + if (target) target.contentWindow.location.hash = target_addr; + else + document.getElementById('ptable_vis').innerHTML = + ''; + } else document.getElementById('ptable_vis').innerHTML = ''; + } else if (ptable.dtypes == 3) { + const els = document.querySelectorAll( + '#ptable_results div.gallery_img.renderable', + ); + if (els.length) { + const rnd_i = Math.floor(Math.random() * els.length); + els[rnd_i].parentNode.classList.add('active'); + const phid = els[rnd_i].getAttribute('rel'), + target = document.querySelector('#ptable_vis > iframe'), + target_addr = get_visavis_url( + { phid: phid }, + 'graph', + window.innerHeight - 50, + ); + + if (target) target.contentWindow.location.replace(target_addr); + else + document.getElementById('ptable_vis').innerHTML = + ''; + } else document.getElementById('ptable_vis').innerHTML = ''; + } +} + +function render_right(data) { + data = JSON.parse(data); + if (data.error) return wmgui.notify(data.error); + + if (data.fuzzy_notice || !data.out.length) + document.getElementById('ptable_vis').innerHTML = ''; + else + document.getElementById('ptable_vis').innerHTML = + '

    Reported phase diagrams of ' + + ptable.query.elements + + ' system

    ' + + build_thumbs_pd(data.out); +} + +function render_unaries() { + if (!ptable.first_el) return; + + ptable.els_data.forEach(function (elem_data) { + if (!elem_data.pos) return; + + const that = document.querySelector( + '#ptable_area > ul > li[data-pos="' + elem_data.pos + '"]', + ); + that.style.backgroundImage = 'none'; + //that.innerHTML = elem_data.html; + that.className = ''; + that.classList.add(...elem_data.classes); + }); + + ptable.first_el = null; +} + +function render_binaries(elA, elB) { + //console.log('RENDERING BINARIES FOR: ' + [elA, elB]); + + document.querySelectorAll('#ptable_area > ul > li').forEach(function (item) { + if (!item.hasAttribute('data-pos')) return; + + const current_el = ptable.elements[parseInt(item.getAttribute('data-pos'))]; + + if (ptable.dtypes == 1) { + if (current_el != elA && current_el != elB) { + item.style.backgroundImage = + "url('" + + ptable.pdsvg_path + + '/bin/' + + elA + + '-' + + current_el + + ".svg')"; + item.className = 'active_a'; + } + } else if (ptable.dtypes == 2) { + if (current_el != elA && current_el != elB) { + let pair = [elA, current_el]; + pair.sort(); + item.style.backgroundImage = + "url('" + ptable.crsvg_path + '/bin/' + pair.join('-') + ".svg')"; + item.className = 'active_a'; + } + } else if (ptable.dtypes == 3) { + if (current_el != elA && current_el != elB) { + let pair = [elA, current_el]; + pair.sort(); + item.style.backgroundImage = + "url('" + ptable.ppsvg_path + '/bin/' + pair.join('-') + ".svg')"; + item.className = 'active_a'; + } + } else { + if (current_el != elA && current_el != elB) { + item.style.backgroundImage = 'none'; + item.className = 'active_a'; + } else if (current_el == elA) { + item.className = 'selected_a'; + item.classList.add( + ...ptable.els_data[parseInt(item.getAttribute('data-pos'))].classes, + ); + } + } + }); +} + +function render_ternaries(elA, elB) { + //console.log('RENDERING TERNARIES FOR: ' + [elA, elB]); + + document.querySelectorAll('#ptable_area > ul > li').forEach(function (item) { + if (!item.hasAttribute('data-pos')) return; + + const current_el = ptable.elements[parseInt(item.getAttribute('data-pos'))]; + + if (ptable.dtypes == 1) { + if (current_el != elA && current_el != elB) { + let triple = [elA, elB, current_el]; + triple.sort(); + item.style.backgroundImage = + "url('" + ptable.pdsvg_path + '/ter/' + triple.join('-') + ".svg')"; + item.classList.add('active_b'); + } + } else if (ptable.dtypes == 2) { + if (current_el != elA && current_el != elB) { + let triple = [elA, elB, current_el]; + triple.sort(); + item.style.backgroundImage = + "url('" + ptable.crsvg_path + '/ter/' + triple.join('-') + ".svg')"; + item.classList.add('active_b'); + } + } else if (ptable.dtypes == 3) { + if (current_el != elA && current_el != elB) { + let triple = [elA, elB, current_el]; + triple.sort(); + item.style.backgroundImage = + "url('" + ptable.ppsvg_path + '/ter/' + triple.join('-') + ".svg')"; + item.classList.add('active_b'); + } + } else { + if (current_el != elA && current_el != elB) { + item.style.backgroundImage = 'none'; + item.classList.add('active_b'); + } else if (current_el == elA) { + item.className = 'selected_a'; + item.classList.add( + ...ptable.els_data[parseInt(item.getAttribute('data-pos'))].classes, + ); + } else if (current_el == elB) { + item.className = 'selected_b'; + } + } + }); +} + +function build_thumbs_ph(json) { + // FIXME duplicates another function *build_thumbs* + let result_html = ''; + + json.sort(function (a, b) { + return a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0; + }); + + json.forEach(function (row) { + result_html += ''; + }); + return result_html; +} + +function build_thumbs_pd(json) { + // FIXME duplicates another function *build_thumbs* + let result_html = ''; + + json.sort(function (a, b) { + return a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0; + }); + + json.forEach(function (row) { + if (row[3] == 0) + // filter unprocs + return; + row[2] = row[2].split(';')[0]; + row[2] = row[2].split(' ')[row[2].split(' ').length - 1]; + const content = + '' +
+      row[0] +
+      '

    ' + + row[2] + + '

    '; + + result_html += + ''; + }); + return result_html; +} + +export function select_ptable_el(selected_el, dom_el) { + //console.log('Selected element is ' + selected_el); + + if (!dom_el) { + const found = document.querySelector( + '#ptable_area > ul > li[data-pos="' + + ptable.elements.indexOf(selected_el) + + '"]', + ); + if (!found) return wmgui.notify('Sorry, wrong element: ' + selected_el); + dom_el = found; + } + + if (dom_el.classList.contains('selected_a')) { + // first element removal + dom_el.classList.remove('selected_a'); + render_unaries(); + refresh_ptable_results(); + } else if (dom_el.classList.contains('selected_b')) { + // second element removal + dom_el.classList.remove('selected_b'); + render_binaries(ptable.first_el, selected_el); + ptable.second_el = null; + refresh_ptable_results(ptable.first_el); + } else if (dom_el.classList.contains('selected_c')) { + // third element removal + dom_el.classList.remove('selected_c'); + refresh_ptable_results(ptable.first_el, ptable.second_el); + } else if (dom_el.classList.contains('active_b')) { + // third element selection + removeAllCls('selected_c'); + dom_el.classList.add('selected_c'); + refresh_ptable_results(ptable.first_el, ptable.second_el, selected_el); + } else if (dom_el.classList.contains('active_a')) { + // second element selection + removeAllCls('selected_b'); + dom_el.classList.add('selected_b'); + render_ternaries(ptable.first_el, selected_el); + ptable.second_el = selected_el; + refresh_ptable_results(ptable.first_el, selected_el); + } else { + // first element selection + dom_el.classList.add('selected_a'); + ptable.first_el = selected_el; + render_binaries(ptable.first_el, selected_el); + refresh_ptable_results(selected_el); + } +} + +export function select_ptable_series(els) { + //console.log('Received for TABLE DRAW: ' + els); + if (!els) { + render_unaries(); + clear_results_area(); + return; + } + + els = els.split('-'); + if (els.length > 3) els = els.slice(0, 3); + + ptable.first_el = els[0]; + ptable.second_el = els[1] || null; + + const domelA = document.querySelector( + '#ptable_area > ul > li[data-pos="' + + ptable.elements.indexOf(els[0]) + + '"]', + ); + + if (domelA) { + removeAllCls('selected_a'); + domelA.classList.add('selected_a'); + } + + if (els.length == 1) { + render_binaries(els[0], els[0]); + } else if (els.length == 2) { + const domelB = document.querySelector( + '#ptable_area > ul > li[data-pos="' + + ptable.elements.indexOf(els[1]) + + '"]', + ); + + if (domelB) { + removeAllCls('selected_b'); + domelB.classList.add('selected_b'); + domelB.classList.add( + ...ptable.els_data[parseInt(domelB.getAttribute('data-pos'))].classes, + ); + domelB.style.backgroundImage = 'none'; + } + render_ternaries(els[0], els[1]); + } else { + const domelB = document.querySelector( + '#ptable_area > ul > li[data-pos="' + + ptable.elements.indexOf(els[1]) + + '"]', + ), + domelC = document.querySelector( + '#ptable_area > ul > li[data-pos="' + + ptable.elements.indexOf(els[2]) + + '"]', + ); + + if (domelB) { + removeAllCls('selected_b'); + domelB.classList.add('selected_b'); + domelB.classList.add( + ...ptable.els_data[parseInt(domelB.getAttribute('data-pos'))].classes, + ); + domelB.style.backgroundImage = 'none'; + } + if (domelC) { + removeAllCls('selected_c'); + domelC.classList.add('selected_c'); + } + render_ternaries(els[0], els[1]); + } + refresh_ptable_results(...els); +} diff --git a/src_js/app/router.js b/src_js/app/router.js new file mode 100644 index 0000000..a6e0445 --- /dev/null +++ b/src_js/app/router.js @@ -0,0 +1,530 @@ +/** + * Ermac hash-based router: the url__() functions. + * Dispatch happens via an explicit route registry instead of the old window globals. + */ + +import wmgui from '../core/settings.js'; +import { wmutils } from '../core/utils.js'; +import { $, $$, show, hide, set_html, set_val } from '../core/dom.js'; +import { ajax } from '../core/ajax.js'; +import { + switch_view_mode, + show_interpretation, + request_search, + show_tooltip, + show_modal, + arrange_menu_collateral, + user_login, + force_relogin, + describe_perms, + start_visavis, + render_all_polyhedra, +} from './search.js'; + +export function url_redraw_react() { + var anchors = window.location.hash.substr(1).split('/'); + + if (!anchors.length) return; + hide($$('#overlay, #aetmap, #dtypes_phid, div.modal, div.menu_collateral')); + $$('#dtypes_phid > ul > li').forEach(function (li) { + li.classList.remove('active'); + }); + + try { + wmgui.active_ajax.abort(); + } catch (e) {} + try { + wmgui.quick_ajax.abort(); + } catch (e) {} + + const route = routes[anchors[0]]; + if (route) route(anchors.slice(1).join('/')); + else wmgui.notify('Sorry, unknown route requested'); +} + +/** + * The main landing route /#start + */ +function url__start(arg) { + switch_view_mode(1); + if (wmgui.tooltip_counter < 2) + setTimeout(function () { + show_tooltip(wmgui.tooltips[wmgui.tooltip_landing]); + }, 4000); +} + +/** + * A free-form fuzzy search /#search/arg + * given by the OptimadeNLP wmutils + */ +function url__search(arg, no_sync) { + var query = decodeURIComponent(arg), + parsed = wmutils.guess(query); + //console.log(parsed); + + if (parsed.numeric) wmgui.search_type = 1; + + show_interpretation(parsed); + delete parsed.ignored; + + const main_input = $('#search_field-selectized'); + if (main_input) main_input.value = ''; + wmgui.multiselects['main'].clear(); + wmgui.multiselects['main'].write(parsed); + + wmgui.search = parsed; + parsed.search_type = wmgui.search_type; + + if (!no_sync) request_search(parsed, query, wmgui.search_type); +} + +/** + * The parameters-based exact search /#inquiry/arg + */ +function url__inquiry(arg, no_sync) { + var inquiry = arg.split('&').map( + function (n) { + return ((n = n.split('=')), (this[n[0]] = n[1]), this); + }.bind({}), + )[0]; + + wmgui.facets.forEach(function (item) { + if (inquiry[item]) + inquiry[item] = decodeURIComponent(inquiry[item].replaceAll('+', ' ')); + }); + + // re-inventing serialization for numeric nested arrays + if (inquiry.numeric) { + inquiry.numeric = decodeURIComponent(inquiry.numeric) + .split(';') + .map(function (item) { + return item.split(','); + }); + inquiry.numeric = inquiry.numeric.filter(function (item) { + return item.length == 3; + }); + wmgui.search_type = 1; // force phases search type + } + //console.log(inquiry); + + show_interpretation(inquiry); + delete inquiry.ignored; + + var caption_items = []; + for (var k in inquiry) { + caption_items.push(inquiry[k]); + } + + const main_input = $('#search_field-selectized'); + if (main_input) main_input.value = ''; + wmgui.multiselects['main'].clear(); + wmgui.multiselects['main'].write(inquiry); + + wmgui.search = inquiry; + inquiry.search_type = wmgui.search_type; + + if (!no_sync) + request_search( + inquiry, + caption_items.join(' ').replaceAll(',', ' '), + wmgui.search_type, + ); +} + +/** + * The 3 brothers routing exact search into the search_type (TODO?) + */ +function url__inquiry_entries(arg) { + wmgui.search_type = 0; + return url__inquiry(arg); +} +function url__inquiry_phases(arg) { + wmgui.search_type = 1; + return url__inquiry(arg); +} +function url__inquiry_articles(arg) { + wmgui.search_type = 2; + return url__inquiry(arg); +} + +/** + * The plotting subsystem (Vis-a-vis) /#plot/arg + */ +function url__plot(arg) { + var q = arg.split('/'), + plot_type = q[0], + search_verb = q[1], + query = q[2]; + + if (!plot_type || !search_verb || !query) + return wmgui.notify('Sorry, unknown route: ' + arg); + + if (search_verb == 'search') url__search(query, true); + else if (search_verb == 'inquiry') url__inquiry(query, true); + else return wmgui.notify('Sorry, unknown route: ' + arg); + + wmgui.visavis_curtype = plot_type; + + //if (wmgui.view_mode == 1) + switch_view_mode(2); + + setTimeout(function () { + start_visavis(plot_type); + }, 0); + + if ( + wmgui.tooltip_counter < 2 && + (plot_type == 'matrix' || plot_type == 'cube') + ) { + setTimeout(function () { + show_tooltip(wmgui.tooltips['ss_axes'], true); + }, 3000); + } +} + +/** + * The individual entry display /#entry/ID + */ +function url__entry(arg) { + wmgui.search_type = 0; + wmgui.visavis_terminating = true; + request_search({ entry: arg }, 'entry ' + arg, true); + wmgui.search = {}; // mockup to reset previous properties + wmgui.passive_sim_col = true; + const main_input = $('#search_field-selectized'); + if (main_input) main_input.value = ''; + wmgui.multiselects['main'].clear(); + show_interpretation(); +} + +/** + * The individual phase display /#phase_id/integer + */ +function url__phase_id(arg) { + wmgui.search_type = 0; + if (!wmgui.ptable.visible) { + const main_input = $('#search_field-selectized'); + if (main_input) main_input.value = ''; + wmgui.multiselects['main'].clear(); + } + show_interpretation(); + var phid = parseInt(arg); + wmgui.search = { phid: phid }; + wmgui.search.search_type = wmgui.search_type; + request_search({ phid: phid }, 'phase ' + phid, true); +} + +/** + * The individual phase display /#phase/ID + */ +function url__phase(arg) { + var phase_data = arg.split('/'), + formula = phase_data[0], + spg = phase_data[1], + pearson = phase_data[2]; + + if (formula && spg && pearson) { + wmgui.show_preloader(); + const request = ajax({ + type: 'GET', + url: wmgui.phph_endpoint, + data: { phase: [formula, spg, pearson].join('/') }, + }); + wmgui.active_ajax = request; + + request + .then(function (data) { + wmgui.hide_preloader(); + if (data.error) return wmgui.notify(data.error); + window.location.replace('#phase_id/' + data.phid); + }) + .catch(function (error) { + wmgui.hide_preloader(); + if (!(error && error.aborted)) + wmgui.notify('Sorry, a network error occured. Please, try again'); + }); + } else return wmgui.notify('Sorry, wrong phase given'); +} + +/** + * The individual B-entry display /#article/integer + */ +function url__article(arg) { + wmgui.search_type = 0; + const main_input = $('#search_field-selectized'); + if (main_input) main_input.value = ''; + wmgui.multiselects['main'].clear(); + show_interpretation(); + var bentry = parseInt(arg); + wmgui.search = { bid: bentry }; + wmgui.search.search_type = wmgui.search_type; + request_search({ bid: bentry }, 'B' + bentry, true); +} + +/** + * The display of menu with all the physical props + */ +function url__hierarchy() { + document.body.classList.remove('noscroll'); + show($('#overlay')); + window.scrollTo(0, 0); + show($('#hy_box')); +} + +/** + * The different types of modal windows + */ +function url__modal(arg) { + //var url_params = new URLSearchParams(window.location.search), + // redir = url_params.get('redir'); + + if (arg == 'login') { + if (wmgui.sid) return window.location.replace('#modal/menu'); + + // edition-based OAuth login (mpdsgui only) + if (wmgui.edition == 1) { + return window.location.replace('oauth/asm.html'); // NB history replacement + } + show_modal(arg); + } else if (arg == 'restore' || arg == 'factor') { + if (wmgui.sid) return window.location.replace('#modal/menu'); + show_modal(arg); + } else if (arg == 'menu') { + if (!wmgui.sid) return window.location.replace('#modal/login'); + set_val($('#new_password_1'), ''); + set_val($('#new_password_2'), ''); + arrange_menu_collateral(); + show($$('#menubox, div.menu_collateral')); + } else return wmgui.notify('Sorry, unknown modal window'); + + show($('#overlay')); +} + +/** + * Retrieving the access via email by the secret link + */ +function url__access(arg) { + ajax({ + type: 'POST', + url: wmgui.access_endpoint, + data: { a: arg, ed: wmgui.edition }, + }) + .then(function (data) { + if (data.error) { + window.location.replace('#start'); + return wmgui.notify(data.error); + } + if (!data.sid || !data.name || !data.acclogin) { + window.location.replace('#start'); + return wmgui.notify( + 'Connection to server is lost, please try to reload', + ); + } + user_login(data.sid, data.name, data.acclogin, data.admin, data.oauths); + window.location.replace('#start'); + }) + .catch(function () { + window.location.replace('#start'); + return wmgui.notify('Sorry, a network error occured. Please, try again'); + }); +} + +/** + * Confirming the access via email by the secret link + */ +function url__ratify(arg) { + ajax({ + type: 'POST', + url: wmgui.ratify_endpoint, + data: { a: arg, ed: wmgui.edition }, + }) + .then(function (data) { + if (data.error) { + window.location.replace('#start'); + return wmgui.notify(data.error); + } + if (!data.sid || !data.name || !data.acclogin) { + window.location.replace('#start'); + return wmgui.notify( + 'Connection to server is lost, please try to reload', + ); + } + user_login(data.sid, data.name, data.acclogin, data.admin, data.oauths); + window.location.replace('#modal/menu'); + }) + .catch(function () { + window.location.replace('#start'); + return wmgui.notify('Sorry, a network error occured. Please, try again'); + }); +} + +/** + * A special display of the related entries + */ +function url__interlinkage(arg) { + wmgui.search_type = 1; + request_search({ interlinkage: arg }, 'linked phases for ' + arg, true); + wmgui.search = { numeric: true }; // mockup FIXME? + //$('#search_field-selectized').val(''); + //wmgui.multiselects['main'].clear(); + show_interpretation(); +} + +/** + * All polyhedra menu + */ +function url__polyhedra(arg) { + document.body.classList.remove('noscroll'); + show($('#overlay')); + window.scrollTo(0, 0); + render_all_polyhedra(); + show($('#all_polyhedra_box')); +} + +/** + * Access denied route: trying to identify the reason + */ +function url__junction(arg) { + if (!wmgui.sid) return window.location.replace('#products'); + + var locals = JSON.parse( + window.localStorage.getItem(wmgui.store_user_key) || '{}', + ); + + wmgui.show_preloader(); + const request = ajax({ + type: 'POST', + url: locals.ipbased ? wmgui.ip_perms_endpoint : wmgui.perms_endpoint, + data: { sid: wmgui.sid }, + }); + wmgui.active_ajax = request; + + request + .then(function (data) { + wmgui.hide_preloader(); + + if (data.error) return wmgui.notify(data.error); + + if (!data.hasOwnProperty('gui') || !data.hasOwnProperty('api')) + return force_relogin('Please, re-login'); + + window.location.replace('#modal/menu'); + $$('#tab_links > li').forEach(function (li) { + li.classList.remove('working'); + }); + $$('#tab_links > li[rev=usr_tab_perms]').forEach(function (li) { + li.classList.add('working'); + }); + hide($$('div.menu_tabs')); + show($('#usr_tab_perms')); + set_html($('#perms_view'), describe_perms(data)); + setTimeout(function () { + wmgui.notify('Please, check your data access.'); + }, 1500); + }) + .catch(function (error) { + wmgui.hide_preloader(); + if (!(error && error.aborted)) return force_relogin('Please, re-login'); + }); +} + +/** + * Moved from mpdsgui + */ +function url__products(arg) { + if (!wmgui.mpds_native) + window.location.href = wmgui.static_host + '/#products'; + + if (wmgui.edition === 1) { + // NB no history replacement and no new windows + window.location.href = + 'https://www.asminternational.org/asm-materials-platform-for-data-science-api'; + } else { + show($('#overlay')); + window.scrollTo(0, 0); + show($('#productbox')); + } +} + +/** + * Moved from mpdsgui + */ +function url__formal(arg) { + if (!wmgui.mpds_native) + window.location.href = wmgui.static_host + '/#formal/' + arg; + + var header = '', + addr = ''; + + if (arg == 'terms') + ((header = 'Website Terms & Conditions'), (addr = '/terms.json')); + else if (arg == 'api') + ((header = 'MPDS API Terms & Conditions'), (addr = '/api.json')); + else if (arg == 'usfed') + ((header = 'Procurement Details'), (addr = '/usfed.json')); + else if (arg == 'refunds') + ((header = 'Refund Policy'), (addr = '/refunds.json')); + else if (arg == 'privacy') + ((header = 'Privacy Policy'), (addr = '/privacy.json')); + else return wmgui.notify('Sorry, unknown document requested'); + + wmgui.show_preloader(); + + $$('#formalbox_navi > ul > li').forEach(function (li) { + li.classList.remove('working'); + }); + $$('a[href="#formal/' + arg + '"]').forEach(function (a) { + a.parentNode.classList.add('working'); + }); + + const request = ajax({ + url: addr, + type: 'GET', + data: { nocache: Math.floor(Math.random() * 1000) }, + }); + request + .then(function (answer) { + wmgui.hide_preloader(); + var html = '

    ' + header + '

    '; + answer.forEach(function (value, n) { + html += + '§' + + (n + 1) + + '. ' + + value.header + + '

    ' + + value.content + + '

    '; + }); + set_html($('#formalbox_content'), html); + show($$('#formalbox, #overlay')); + window.scrollTo(0, 0); + wmgui.hide_preloader(); + }) + .catch(function () { + wmgui.hide_preloader(); + }); +} + +const routes = { + start: url__start, + search: url__search, + inquiry: url__inquiry, + inquiry_entries: url__inquiry_entries, + inquiry_phases: url__inquiry_phases, + inquiry_articles: url__inquiry_articles, + plot: url__plot, + entry: url__entry, + phase_id: url__phase_id, + phase: url__phase, + article: url__article, + hierarchy: url__hierarchy, + modal: url__modal, + access: url__access, + ratify: url__ratify, + interlinkage: url__interlinkage, + polyhedra: url__polyhedra, + junction: url__junction, + products: url__products, + formal: url__formal, +}; diff --git a/src_js/app/run.js b/src_js/app/run.js new file mode 100644 index 0000000..c862211 --- /dev/null +++ b/src_js/app/run.js @@ -0,0 +1,24 @@ +/** + * Ermac entry point. + */ + +import { assign_edition } from './search.js'; +import { register_html } from './markup.js'; +import { satisfy_requirements } from './startup.js'; +import { register_events } from './events.js'; + +// now, run everything + +assign_edition(); + +register_html(); + +satisfy_requirements(); + +register_events(); + +// use MPDS API, please +console.log( + '%cWeb-scraping or automated usage apart of the public MPDS API is in violation of our ToS (https://mpds.io/formal/terms) and results in banned account.', + 'color:red;font-size:16px;', +); diff --git a/src_js/app/search.js b/src_js/app/search.js new file mode 100644 index 0000000..43fba88 --- /dev/null +++ b/src_js/app/search.js @@ -0,0 +1,2477 @@ +/** + * Ermac search logic: request_search, display/render functions, + * user session handling, and the selectize read/write helpers. + */ + +import wmgui from '../core/settings.js'; +import { wmutils } from '../core/utils.js'; +import { + $, + $$, + show, + hide, + set_html, + append_html, + prepend_html, + empty, + remove, + isVisible, + position, + slide_down, + slide_up, + data, + get_val, + set_val, +} from '../core/dom.js'; +import { ajax, param, is_empty } from '../core/ajax.js'; +import { + create_floating_slider, + destroy_numericbox, + get_sliders_ranges, + serialize_numeric, +} from '../components/sliders.js'; +import { make_sortable } from '../components/tablesort.js'; + +let db_sorter = null; + +wmgui.notify = function (msg) { + var delay = 0; + if (wmgui.notify_counter) { + clearTimeout(wmgui.notify_counter); + wmgui.notify_counter = null; + delay = 1500; + } + setTimeout(function () { + set_html($('#notifybox'), wmgui.clean(msg)); + show($('#notifybox')); + wmgui.notify_counter = setTimeout(function () { + hide($('#notifybox')); + }, 4000); + }, delay); +}; + +// external API function +wmgui.aug_search_cmd = function (new_fct, new_val) { + // Take care of mutually exclusive facets + var checks = [ + ['elements', 'formulae'], + ['formulae', 'elements'], + ['lattices', 'sgs'], + ['sgs', 'lattices'], + ['protos', 'sgs'], + ['sgs', 'protos'], + ['lattices', 'protos'], + ['protos', 'lattices'], + ]; + for (var i = 0; i < checks.length; i++) { + if (wmgui.search[checks[i][0]] && new_fct == checks[i][1]) { + delete wmgui.search[checks[i][0]]; + break; + } + } + + var orepr = {}; + + wmgui.facets.forEach(function (fct) { + if (wmgui.search[fct] && fct == new_fct) { + if (wmgui.multi_facets.indexOf(fct) !== -1) + orepr[fct] = wmgui.search[fct] + ',' + new_val; + else orepr[fct] = new_val; + } else if (wmgui.search[fct]) { + orepr[fct] = wmgui.search[fct]; + } else if (fct == new_fct) { + orepr[fct] = new_val; + } + }); + return '#inquiry/' + param(orepr); +}; + +// reading the multiselect at the main search input (landing) +wmgui._selectize_read_main = function () { + var result = {}, + instance = wmgui.multiselects['main']; + + (instance ? instance.items : []).forEach(function (item) { + var facet = item.facet; + + if (wmgui.other_facets.indexOf(facet) !== -1 && wmgui.search[facet]) + result[facet] = wmgui.search[facet]; + else if (facet == 'numeric') { + if (wmgui.search[facet]) { + result[facet] = ''; + wmgui.search[facet].forEach(function (num_item) { + result[facet] += serialize_numeric.apply(this, num_item); // unpack + }); + if (result[facet].length) + result[facet] = result[facet].substr(0, result[facet].length - 1); + } // NB else just skip! + } else if (result[facet] && facet == 'elements') + result[facet] += '-' + item.label; + else if (result[facet] && wmgui.multi_facets.indexOf(facet) !== -1) + result[facet] += ', ' + item.label; + else if (facet == 'formulae') + result[facet] = item.label + .replaceAll('', '') + .replaceAll('', ''); + else result[facet] = item.label; + }); + + return result; +}; + +// reading the multiselect at the *wmgui.multi_facets* categories +wmgui._selectize_read_facet = function (fct) { + var result = {}, + instance = wmgui.multiselects[fct]; + + (instance ? instance.items : []).forEach(function (item) { + var facet = item.facet; + + if (result[facet]) result[facet] += ', ' + item.label; + else result[facet] = item.label; + return; + }); + + return result; +}; + +wmgui._selectize_write = function (multiselect, name, search_obj) { + wmgui.selectize_emit = false; + + var given_search = {}; + Object.assign(given_search, search_obj); + + if (name == 'main') { + name = ['formulae', 'props', 'elements', 'classes', 'lattices', 'aetypes']; + + for (var i = 0; i < wmgui.other_facets.length; i++) { + if (given_search[wmgui.other_facets[i]]) { + wmgui._selectize_display( + multiselect, + wmgui.other_facets[i], + wmgui.facet_names[wmgui.other_facets[i]].toLowerCase(), + ); // stub display + } + } + + if (given_search.numeric) + wmgui._selectize_display(multiselect, 'numeric', 'range search'); + } else name = [name]; + + name.forEach(function (facet) { + // facets supported for multiselect autocomplete + if (!given_search[facet]) return; + else if (facet == 'elements' && given_search[facet].indexOf('-') > 0) { + given_search[facet].split('-').forEach(function (part) { + wmgui._selectize_display(multiselect, facet, part); + }); + } else if ( + wmgui.multi_facets.indexOf(facet) !== -1 && + given_search[facet].indexOf(',') > 0 + ) { + given_search[facet].split(',').forEach(function (part) { + wmgui._selectize_display(multiselect, facet, part); + }); + } else if (facet == 'formulae') { + given_search[facet] = wmgui.to_formula(given_search[facet]); + wmgui._selectize_display(multiselect, facet, given_search[facet]); + } else wmgui._selectize_display(multiselect, facet, given_search[facet]); + }); + + multiselect.clearOptions(); + wmgui.selectize_emit = true; +}; + +wmgui._selectize_display = function (multiselect, facet, term) { + const option_data = { facet: facet, label: term }; + multiselect.addOption(option_data); + multiselect.addItem(option_data.id); +}; + +export function show_interpretation(search) { + // FIXME only allow pre-defined props + set_html( + $('#interpret'), + wmgui.clean( + wmgui.get_interpretation(search, wmgui.facet_names, wmgui.numerics), + ), + ); +} + +// re-loading without history affection +export function re_view_request(search_type) { + var caption_items = []; + for (var k in wmgui.search) { + if (k == 'search_type') continue; + caption_items.push(wmgui.search[k]); + } + if (!caption_items.length) return; + + wmgui.search_type = search_type; + wmgui.search.search_type = search_type; + request_search( + wmgui.search, + caption_items.join(' ').replaceAll(',', ' '), + true, + ); + $$('#dtypes_phid > ul > li').forEach(function (li) { + li.classList.remove('active'); + }); +} + +export function update_databrowser_sort() { + if (db_sorter) db_sorter.update(); +} + +export async function request_search(search, caption, without_history) { + if (manage_visavis(rebuild_history_box, search, caption)) return; + + try { + wmgui.active_ajax.abort(); + } catch (e) {} + try { + wmgui.quick_ajax.abort(); + } catch (e) {} + + wmgui.show_preloader(); + const request = ajax({ + type: 'GET', + url: wmgui.search_endpoint, + data: { + q: JSON.stringify(search), + strict: wmgui.ctx_strict_phases, + //subphases: wmgui.ctx_subphases, + sid: wmgui.sid, + }, + }); + wmgui.active_ajax = request; + + let data; + try { + data = await request; + } catch (error) { + wmgui.hide_preloader(); + if (!(error && error.aborted)) + wmgui.notify( + 'Connection to server is lost, please try to reload', + ); + return; + } + wmgui.hide_preloader(); + + if (data.error) return wmgui.notify(data.error); + + caption = caption.replaceAll('%2F', '/'); + + if (!data.out.length) return wmgui.notify('No hits for ' + caption); + + wmgui.fuzzyout = false; + if (data.fuzzy_notice) { + wmgui.fuzzyout = true; + wmgui.notify(data.fuzzy_notice); + } + + var res_str = data.estimated_count == 1 ? ' result' : ' results', + notice = data.estimated_count > 150 ? 'At least ' : ''; + document.title = notice + data.estimated_count + res_str; // + ' (' + wmgui.estimate + ')'; + //console.log('Obtained: '+data.estimated_count+', expected: '+wmgui.estimate); + switch_view_mode(2); + + if (!wmgui.chosen_table_browser) + // TODO add smarter check? + wmgui.thumbed_display = data.out.length > wmgui.ntab_tolerance; + + if (wmgui.thumbed_display) { + var db = $('#databrowser'); + db.className = 'thumbed'; + db.innerHTML = '' + build_thumbs(data.out) + ''; + slide_down($('#results'), 250); + } else { + var db = $('#databrowser'); + db.className = 'tabled'; + db.innerHTML = build_cells(data.out, '', ''); + slide_down($('#results'), 250); + + if (wmgui.search_type == 2) { + db.classList.add('tablesorter'); + db_sorter = make_sortable(db, { + sortMultiSortKey: 'ctrlKey', + headers: { + 0: { sorter: 'doi' }, + 5: { sorter: false }, + }, + selectorHeaders: '#dataheader_articles > thead > tr > th', + }); + show($('#header_articles')); + } else if (wmgui.search_type == 1) { + db.classList.add('tablesorter'); + db_sorter = make_sortable(db, { + sortMultiSortKey: 'ctrlKey', + headers: { + 0: { sorter: 'chemical' }, + 1: { sorter: 'digit' }, + 2: { sorter: 'digit' }, + 3: { sorter: 'digit' }, + 4: { sorter: false }, + }, + selectorHeaders: '#dataheader_phases > thead > tr > th', + }); + show($('#header_phases')); + } else { + db.classList.add('tablesorter'); + db_sorter = make_sortable(db, { + sortMultiSortKey: 'ctrlKey', + headers: { + 0: { sorter: 'chemical' }, + 1: { sorter: false }, + 5: { sorter: 'doi' }, + }, + selectorHeaders: '#dataheader_entries > thead > tr > th', + }); + show($('#header_entries')); + } + } + + // count & show ctx + wmgui.unfinished_page = false; + if (wmgui.search_type || search.phid) { + if (data.estimated_count >= wmgui.quick_page_size * 3) { + set_html($('#toomuch span'), 'other'); + show($('#toomuch')); + } + show_hints(search.entry || search.interlinkage); + } else { + if (data.estimated_count > wmgui.quick_page_size + wmgui.fetch_page_size) { + set_html( + $('#toomuch span'), + 'nearly ' + (data.estimated_count - wmgui.quick_page_size), + ); + show($('#toomuch')); + show_hints(search.entry, data.estimated_count); + } else if (data.estimated_count > wmgui.quick_page_size) { + show($('#loadscroll')); + wmgui.unfinished_page = true; + } else show_hints(search.entry, data.estimated_count); + } + + // switchers + if (wmgui.visavis_terminating) stop_visavis(); + + if ( + wmgui.search_type || + search.phid || + search.bid || + search.entry || + search.interlinkage || + search.doi || + search.numeric + ) { + if (search.phid || search.bid || search.entry) { + switch_control_mode(9, 11, 'a', 'c'); + show_dunit_info(search.phid, search.bid, search.entry); + } else if (search.interlinkage) { + switch_control_mode(9, 11, 'a', 'c'); + show_examples('#examples', true, true); + hide($('#dtypes')); + } else if (search.numeric) { + switch_control_mode(1, 12, 'b', false); + //console.log(search.numeric); + destroy_numericbox(); + get_sliders_ranges(search.numeric, wmgui.numerics).forEach( + function (item) { + create_floating_slider.apply(this, item); // unpack + }, + ); + show_examples('#examples', true, true); + } else { + switch_control_mode(1, 10, false, false); + show_examples('#examples', true, true); + } + + if (search.entry) { + var that = document.getElementById('e__' + search.entry); + if (search.entry.indexOf('-') == -1 && !that) + that = document.getElementById('e__' + search.entry + '-1'); + if (that && that.getAttribute('data-rank') != 0) { + // NB "!=", not "!==" + that.classList.remove('busy_entry'); + open_context(that, true); + } + } + } else { + wmgui.fuzzyout + ? switch_control_mode(1, 11, 'a', false) + : switch_control_mode(0, 10, false, false); + request_refinement(search, data.estimated_count > wmgui.quick_page_size); + } + + //console.log(search); + if (!search.numeric) { + destroy_numericbox(); + delete wmgui.search.numeric; + } + if (search.props && wmgui.numerics[search.props]) { + // making a hint + var num_data = wmgui.numerics[search.props], + prop_id = num_data[0], + units = num_data[1], + min = num_data[2], + max = num_data[3], + step = num_data[4]; + create_floating_slider(search.props, prop_id, units, min, max, step); + } + if (!without_history) rebuild_history_box(search, caption); + wmgui.search.elements && wmgui.search_type == 1 + ? show($('#phases_ctx')) + : hide($('#phases_ctx')); +} + +function rebuild_history_box(search, caption) { + var orepr = {}; + wmgui.facets.forEach(function (item) { + if (search[item]) orepr[item] = search[item]; + }); + + var inquiry = false; + for (var m = 0; m < wmgui.inquiries.length; m++) { + if (orepr[wmgui.inquiries[m]]) { + inquiry = true; + break; + } + } + + var title = []; + for (var prop in orepr) { + title.push(orepr[prop].toLowerCase()); + } + title.sort(); + var fingerprint = title.join(' '), + search_log = JSON.parse( + window.localStorage.getItem(wmgui.store_history_key) || '[]', + ), + chk_searches = []; + if (search_log.length > 8) search_log = search_log.slice(0, 7); + search_log.forEach(function (item) { + var past_title = []; + for (var p in item) { + past_title.push(item[p].toLowerCase()); + } + past_title.sort(); + chk_searches.push(past_title.join(' ')); + }); + if (chk_searches.indexOf(fingerprint) == -1) { + var item; + if (inquiry) + item = '' + caption + ''; + else + item = + '' + + caption + + ''; + + prepend_html($('#history ul'), '
  • ' + wmgui.clean(item) + '
  • '); + search_log.unshift(orepr); + window.localStorage.setItem( + wmgui.store_history_key, + JSON.stringify(search_log), + ); + const history_lis = $$('#history ul li'); + if (history_lis.length > 8) history_lis[history_lis.length - 1].remove(); + } + wmgui.tooltip_counter++; + if (wmgui.tooltip_counter == 1) { + setTimeout(function () { + show_tooltip(wmgui.tooltips['interpretation']); + }, 3000); + } +} + +export function rotate_interesting() { + set_html( + $('#legend'), + 'e.g. ' + + wmgui.get_interesting()['text'].replace(/\d/g, 'Ȉ$&;') + + '', + ); +} + +export function show_examples(box, more_examples, fix_rfn_header) { + if (wmgui.cliff_counter === null) + wmgui.cliff_counter = Math.floor(Math.random() * wmgui.cliffhangers.length); + var html = ''; + for (var i = 0; i < (more_examples ? 7 : 3); i++) { + wmgui.cliff_counter += 1; + if (wmgui.cliff_counter > wmgui.cliffhangers.length - 1) + wmgui.cliff_counter = 0; + html += + '
  • ' + + wmgui.cliffhangers[wmgui.cliff_counter].charAt(0).toUpperCase() + + wmgui.cliffhangers[wmgui.cliff_counter].slice(1) + + '
  • '; + + var legend = wmgui.get_interesting()['text']; + html += + '
  • ' + + legend.charAt(0).toUpperCase() + + legend.slice(1).replace(/\d/g, 'Ȉ$&;') + + '
  • '; + } + empty($(box + ' > ul')); + append_html($(box + ' > ul'), html); + show($(box)); + + if (fix_rfn_header) { + hide($$('#refine_col > div.col_title, #refine_col > ul')); + show($('#refine_col')); + } +} + +export function arrange_menu_collateral() { + empty($$('#hintsbox_msg, #tagcloudbox')); + + var links_html = ''; + for (var i = 0; i < wmgui.collateral_links.length; i++) { + var rel = wmgui.collateral_links[i][1], + cls = wmgui.collateral_links[i][1] ? 'collateral' : false, + target = '', + lbr = ''; + if (i % 2) { + cls = cls ? cls + ' violet' : 'violet'; + lbr = '
    '; + } + if (wmgui.collateral_links[i][3]) target = ' target="_blank"'; + links_html += + '' + + wmgui.collateral_links[i][2] + + '' + + lbr; + } + append_html($('#tagcloudbox'), links_html); + + append_html($('#hintsbox_msg'), wmgui.get_random_term(wmgui.welcome_msgs)); +} + +export function switch_view_mode(mode) { + wmgui.view_mode = mode; + hide($$('div.autocomplete-suggestions')); + hide($$('#results, #header_entries, #header_phases, #header_articles')); + hide($$('div.context_msg')); + close_vibox(); + + if (mode == 1) { + stop_visavis(); + document.title = 'Materials Platform for Data Science'; + document.body.classList.add('noscroll'); + $('#search_box').classList.remove('fluid'); + + hide($$('div.side_cols')); + show($('#legend')); + + $('#search_holder').classList.remove('prolonged'); + $('#search_area').classList.remove('prolonged'); + $('#ermac_logo').classList.remove('cornered'); + + wmgui.ptable.decide(); + if (wmgui.ptable.activated) + document.getElementById('ptable_dtypes_box').classList.add('resulted'); + } else if (mode == 2) { + hide($('#legend')); + hide($('#ctx_col')); + if (wmgui.passive_sim_col) hide($('#sim_col')); + + document.body.classList.remove('noscroll'); + $('#search_box').classList.add('fluid'); + + show($('#right_col')); + show($('#dtypes')); + $('#search_holder').classList.add('prolonged'); + $('#search_area').classList.add('prolonged'); + $('#ermac_logo').classList.add('cornered'); + + wmgui.ptable.hide(); + document.getElementById('ptable_dtypes_box').classList.remove('resulted'); + } + // hook back into a parent integration + wmgui.mpdsgui.view(mode); +} + +function switch_control_mode(mode, next_mode, active_abf, active_cde) { + // NB (0, 10) is the most common 6-button layout + if (mode == 0) { + // cde, second + $$('#control_c, #control_d, #control_e').forEach(function (el) { + el.style.width = '33.3%'; + }); + show($$('#control_c, #control_d, #control_e')); + } else if (mode == 1) { + // cde, second + hide($('#control_e')); + $$('#control_c, #control_d').forEach(function (el) { + el.style.width = '50%'; + }); + show($$('#control_c, #control_d')); + } else if (mode == 9) { + // cde, second + hide($$('#control_e, #control_d')); + $('#control_c').style.width = '100%'; + show($('#control_c')); + } else if (mode == 10) { + // abf, first + $$('#control_a, #control_b, #control_f').forEach(function (el) { + el.style.width = '33.3%'; + }); + show($$('#control_a, #control_b, #control_f')); + } else if (mode == 11) { + // abf, first + hide($$('#control_b, #control_f')); + $('#control_a').style.width = '100%'; + show($('#control_a')); + } else if (mode == 12) { + // abf, first + hide($$('#control_a, #control_f')); + $('#control_b').style.width = '100%'; + show($('#control_b')); + } + if (!next_mode) return; + + if (!active_abf) active_abf = { 0: 'a', 1: 'b', 2: 'f' }[wmgui.search_type]; + if (!active_cde) active_cde = wmgui.thumbed_display ? 'd' : 'c'; + + $$('#control_' + active_abf + ', #control_' + active_cde).forEach( + function (el) { + el.classList.remove('active'); + }, + ); + $('#control_' + active_abf).classList.add('active'); + $('#control_' + active_cde).classList.add('active'); + + switch_control_mode(next_mode); +} + +export function build_cells(json, header, footer) { + var cls_map = { + 7: 'ml_data', + 8: 'ab_data', + 9: 'ab_data', + 10: 'ab_data', + 11: 'ab_data', + 13: 'deactivated', + }, + result_html = ''; + + if (header) result_html += header; + + if (wmgui.search_type == 2) { + if (json[0].length != 6) { + wmgui.notify( + 'Rendering error, please try to reload', + ); + return ''; + } + + var act_link = ''; + + json.forEach(function (row, k) { + act_link = 'Show'; + + row[0] = parseInt(row[0]); + if (row[0] == 999999) { + row[4] = wmgui.mockyear; // special *ref_id*, only handled in GUI + act_link = ' '; + } + result_html += + '[' + + row[0] + + ']' + + row[1] + + '' + + row[2] + + '' + + row[5] + + '' + + row[4] + + '' + + act_link + + ''; + }); + } else if (wmgui.search_type == 1) { + if (json[0].length != 5) { + wmgui.notify( + 'Rendering error, please try to reload', + ); + return ''; + } + + json.forEach(function (row, k) { + result_html += + '' + + row[1] + + '' + + row[2] + + '' + + row[3] + + '' + + row[4] + + 'Show entries'; + }); + } else { + if (json[0].length != 8) { + wmgui.notify( + 'Rendering error, please try to reload', + ); + return ''; + } + + json.forEach(function (row, k) { + row[7] = parseInt(row[7]); + var dtype = row[0].substr(0, 1), + preview = + row[3] == 4 || + row[3] == 5 || + row[3] == 6 || + row[3] == 9 || + row[3] == 10 || + row[3] == 12 + ? 'Show' + : ' ', // FIXME? w.r.t. open_context + biblio_html = + row[7] == 999999 + ? '—' + + wmgui.mockyear + + '—' + : '' + + row[5] + + '' + + row[6] + + '[' + + row[7] + + ']'; // special *ref_id*, only handled in GUI + + result_html += + '' + + row[1] + + '' + + preview + + '' + + row[2] + + '' + + biblio_html + + ''; + }); + } + if (footer) result_html += footer; + return result_html; +} + +export function build_thumbs(json) { + var cls_map = { + 6: 'pd_full', + 7: 'ml_data', + 8: 'ab_data', + 9: 'ab_data', + 10: 'ab_data', + 11: 'ab_data', + 13: 'deactivated', + }, + result_html = ''; + + if (wmgui.search_type == 2) { + if (json[0].length != 6) { + wmgui.notify( + 'Rendering error, please try to reload', + ); + return ''; + } + + json.sort(function (a, b) { + return a[4] > b[4] ? 1 : a[4] < b[4] ? -1 : 0; // pubyear + }); + + var title_html = '', + full_display = !!wmgui.sid, + act_link = ''; + + json.forEach(function (row, k) { + act_link = + 'Show entries'; + + row[0] = parseInt(row[0]); + if (row[0] == 999999) { + row[4] = wmgui.mockyear; // special *ref_id*, only handled in GUI + act_link = 'Too many to show...'; + } + if (full_display) + title_html = + (row[1].length > 60 ? row[1].substr(0, 60) + '…' : row[1]) + + ', ' + + (row[2].length > 80 ? row[2].substr(0, 80) + '…' : row[2]) + + ''; + else title_html = '📖'; // book icon + + result_html += + ''; + }); + } else if (wmgui.search_type == 1) { + if (json[0].length != 5) { + wmgui.notify( + 'Rendering error, please try to reload', + ); + return ''; + } + + json.sort(function (a, b) { + return a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0; + }); + json.forEach(function (row, k) { + result_html += + ''; + }); + } else { + if (json[0].length != 8) { + wmgui.notify( + 'Rendering error, please try to reload', + ); + return ''; + } + + json.sort(function (a, b) { + var dtype_a = a[0].substr(0, 1), + dtype_b = b[0].substr(0, 1); + + if (dtype_a == 'S') { + if (dtype_b == 'S') return a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0; + return -1; + } + if (dtype_a == 'C') { + if (dtype_b == 'C') return a[7] > b[7] ? 1 : a[7] < b[7] ? -1 : 0; + if (dtype_b == 'S') return 1; + if (dtype_b == 'P') return -1; + } + if (dtype_a == 'P') { + if (dtype_b == 'P') + return a[2].toUpperCase() > b[2].toUpperCase() + ? 1 + : a[2].toUpperCase() < b[2].toUpperCase() + ? -1 + : 0; + return 1; + } + }); + json.forEach(function (row, k) { + row[7] = parseInt(row[7]); + var dtype = row[0].substr(0, 1), + content, + biblio_html = + row[7] == 999999 + ? '
    —' + : '
    [' + + row[5] + + '’' + + row[6].toString().substr(2, 2) + + ']'; // special *ref_id*, only handled in GUI + + if (dtype == 'P') content = '
    ' + row[2] + '
    '; + else if (dtype == 'S') + content = + '' +
+          row[0] +
+          ''; + else { + // FIXME + row[2] = row[2].split(';')[0]; + row[2] = row[2].split(' ')[row[2].split(' ').length - 1]; + var url_dest = + row[3] == 12 + ? row[2].split('-').length == 3 + ? '/prism' + : '/tetrahedron' + : '/pd_thumbs/' + row[0].split('-')[0]; + content = + '' +
+          row[0] +
+          '

    ' + + row[2] + + '

    '; + } + result_html += + ''; + }); + } + return result_html; +} + +export async function request_refinement(query_obj, is_heavy) { + hide($$('#examples, #ind_col')); + empty($('#ind_col > span')); + empty($('#refine_col > ul')); + show($('#refine_col')); + show($('#refine_col > div.col_title')); + + var given_search = { is_heavy: is_heavy }; + Object.assign(given_search, query_obj); + try { + wmgui.active_ajax.abort(); + } catch (e) {} + + //console.log(given_search); + show($('#rfn_preloader')); + const request = ajax({ + type: 'GET', + url: wmgui.rfn_endpoint, + data: { q: JSON.stringify(given_search) }, + }); + wmgui.active_ajax = request; + + let data; + try { + data = await request; + } catch (error) { + hide($('#rfn_preloader')); + if (!(error && error.aborted)) + wmgui.notify( + 'Connection to server is lost, please try to reload', + ); + return; + } + hide($('#rfn_preloader')); + + if (data.error) return wmgui.notify(data.error); + + var was_facet = null, + refine_html = '', + classes_chk = [], + num_terms = 0; + delete given_search['is_heavy']; + + if (given_search.classes) { + // no whitespace in multiple classes + classes_chk = given_search.classes.split(',').map(function (x) { + return x.trim(); + }); + given_search.classes = classes_chk.join(','); + } + + var inquiry = false; + for (var m = 0; m < wmgui.inquiries.length; m++) { + if (given_search[wmgui.inquiries[m]]) { + inquiry = true; + break; + } + } + + for (var i = 0; i < data.payload.length; i++) { + const found_obj = data.payload[i]; + if (query_obj.formulae && found_obj.facet == 'elements') continue; // NB no sense to show elements in this context + + var link_base = '', + //count_text = ' ('+found_obj.count+')', + nested_skip = false, + orepr = {}; + + for (var key in given_search) { + const val = given_search[key]; + if (['search_type', 'phid', 'numeric'].indexOf(key) !== -1) continue; + else if ( + found_obj.facet == 'elements' && + (key == 'elements' || key == 'formulae') + ) + continue; + else if (found_obj.facet == 'props' && key == 'props') continue; + + link_base += val + ' '; + + if (orepr[key]) orepr[key] += ', ' + val; + else orepr[key] = val; + } + //if (found_obj.facet == 'elements') count_text = ''; + if (query_obj.classes && found_obj.facet == 'classes') { + for (var n = 0; n < classes_chk.length; n++) { + if (classes_chk[n] == found_obj.value) { + nested_skip = true; + break; + } + } + } + if (nested_skip) continue; + + if (found_obj.facet != was_facet) { + if (was_facet && is_heavy) + refine_html += + '
  • Show more 
  • '; + refine_html += + '
  • ' + + wmgui.facet_names[found_obj.facet] + + '
  • '; + was_facet = found_obj.facet; + } + if (found_obj.facet == 'props') { + found_obj.value = found_obj.value + .replace(/\(|\)/g, '') + .replace(/\/[\w\-]*/g, ''); // FIXME + } + + if (orepr[found_obj.facet]) + orepr[found_obj.facet] += ', ' + found_obj.value; + else orepr[found_obj.facet] = found_obj.value; + + if (orepr['elements']) + orepr['elements'] = orepr['elements'].replaceAll(', ', '-'); + + if (inquiry) + refine_html += + '
  • ' + + found_obj.value + + '
  • '; + else + refine_html += + '
  • ' + + found_obj.value + + '
  • '; + num_terms++; + } + + if (is_heavy) + refine_html += + '
  • Show more 
  • '; + + if (num_terms == 0) show_examples('#examples', true, true); + else { + show($('#refine_col > ul')); + append_html($('#refine_col > ul'), wmgui.clean(refine_html)); + if (num_terms <= 10) show_examples('#examples', false, false); + } +} + +/** + * NB: Ranks legend + * 0 - bib-ref (unproc) + P-entries data on + * 1 - textual (diagrammatic) P-entry + * 2 - scalar (numeric) P-entry + * 3 - C-phase + * 4 - SD-entry (P-array) + * 5 - S-entry + * 6 - C-diagram + * 7 - ML P-entry + * 8 - ab initio entry (scalar) + * 9 - ab initio entry (P-array) electron spectra + * 10 - ab initio entry (P-array) phonon spectra + * 11 - ab initio data in progress (unproc) + * 12 - 3d combination of C-diagrams + * 13 - deactivated entries + */ +export function open_context(el, launch_ext) { + close_vibox(); + if (el.classList.contains('busy_entry')) { + el.classList.remove('busy_entry'); + hide($$('#ctx_col, #sim_col')); + try { + wmgui.quick_ajax.abort(); + } catch (e) {} + } else { + var entry = el.id.substr(3), + rank = parseInt(el.getAttribute('data-rank')), + entype = entry.substr(0, 1), + orig_id = entry.split('-')[0]; + + $$('.busy_entry').forEach(function (busy) { + busy.classList.remove('busy_entry'); + }); + el.classList.add('busy_entry'); + + if (entype == 'Z' || entype == 'B') return; + + set_html( + $('#entryno'), + '' + orig_id + '', + ); + + show($('#ctx_col')); + const visualize = $('#visualize'); + if (visualize) visualize.setAttribute('data-rank', rank); + const xrpdize = $('#xrpdize'); + if (xrpdize) xrpdize.setAttribute('data-rank', 99); // FIXME hack + //$('#visualize, #xrpdize, #absolidize, div.spinoff_pane, li.d_icon').hide(); + hide($$('#visualize, #xrpdize, div.spinoff_pane, li.d_icon')); + + open_sim_col(entry, entype, rank); + + if (rank == 0) { + show($('#download_bib')); + } else if (rank == 1) { + show($$('#download_bib, #download_pdf')); + ajax({ type: 'GET', url: wmgui.path_pp_ping + entry }) + .then(function () { + show($$('#visualize, #download_png, #download_json')); + }) + .catch(function () {}); + } else if (rank == 2) { + show($$('#download_bib, #download_pdf, #download_json')); + } else if (rank == 3) { + show($$('#download_bib, #download_png, #download_cdr')); + } else if (rank == 4) { + show($$('#download_bib, #download_json, #visualize')); + } else if (rank == 5) { + //$('#absolidize, #download_bib, #download_pdf, #visualize, #xrpdize, #absolidize, #download_cif, #download_inp, #download_json').show(); + show( + $$( + '#download_bib, #download_pdf, #visualize, #xrpdize, #download_cif, #download_inp, #download_json', + ), + ); + } else if (rank == 6) { + show( + $$( + '#download_bib, #download_pdf, #visualize, #download_png, #download_cdr, #download_json', + ), + ); + } else if (rank == 7) { + show($$('#ml_data, #download_pdf, #download_json')); + } else if (rank == 8) { + show($$('#ab_data, #download_pdf, #download_json, #download_raw')); + } else if (rank == 9) { + show( + $$( + '#ab_data, #download_pdf, #download_json, #visualize, #download_png, #download_raw', + ), + ); + } else if (rank == 10) { + show( + $$( + '#ab_data, #download_pdf, #download_json, #visualize, #download_raw', + ), + ); + } else if (rank == 11) { + show($$('#ab_promise, #download_json')); + } else if (rank == 12) { + show($$('#pd3d_data, #visualize')); + } else if (rank == 13) { + show($$('#deactivated_data, #download_bib')); + } + $$('#ctx_col > ul > li.d_icon > a').forEach(function (a) { + var fmt = a.getAttribute('rel'), + link_add = entype == 'S' ? '&export=1' : '', + link_sid = fmt == 'raw' ? 'null' : wmgui.sid, + link_url = + wmgui.dd_addr_tpl + + '/' + + entype.toLowerCase() + + '?q=' + + entry + + '&fmt=' + + fmt + + '&sid=' + + link_sid + + link_add + + '&ed=' + + wmgui.edition; + + a.setAttribute('href', link_url); + }); + + //(wmgui.mydata_history.indexOf(entry) == -1) ? $('#absolidize').addClass('wmbutton') : $('#absolidize').removeClass('wmbutton'); + + if (launch_ext) launch_db_iframed(rank); + } +} + +async function open_sim_col(entry, entype, rank) { + empty($$('#sim_col > ul, #sim_legend')); + hide($$('.sim_col_ctx')); + show($('#sim_col')); + + var cur_obj = { q: entry }, + allpurpose = [0, 1, 4, 9].indexOf(rank) !== -1; + if (allpurpose) cur_obj.allpurpose = true; + + try { + wmgui.quick_ajax.abort(); + } catch (e) {} + + show($('#sim_preloader')); + const request = ajax({ + type: 'GET', + url: wmgui.sim_endpoint, + data: cur_obj, + }); + wmgui.quick_ajax = request; + + let data; + try { + data = await request; + } catch (error) { + hide($('#sim_preloader')); + if (!(error && error.aborted)) + wmgui.notify( + 'Connection to server is lost, please try to reload', + ); + return; + } + hide($('#sim_preloader')); + + if (data.error) return wmgui.notify(data.error); + var counter = 0, + sim_html = ''; + + if (allpurpose) { + data.out.sim.forEach(function (row, k) { + if (counter == 7) return; + if (row[4]) + sim_html += + '
  • ' + + row[0] + + '
  • '; + else + sim_html += + '
  • ' + + row[0] + + '
  • '; + counter++; + }); + } else if (entype == 'C' || entype == 'S') { + if (rank > 3) { + data.out.sim.forEach(function (row, k) { + if (counter == 8) return; + sim_html += + '
  • ' + row[0] + '
  • '; + counter++; + }); + if (entype == 'C') show($('#pd_legend')); + else if (counter == 1) counter = 0; + } + } else { + // FIXME this is fragile + var prop = wmgui.thumbed_display + ? $('#sim_col div.busy_entry > div.gallery_img > div').textContent.split( + ';', + )[0] + : $('#sim_col tr.busy_entry > td.c2').textContent.split(';')[0]; + + data.out.sim.forEach(function (row, k) { + if (counter == 8) return; + sim_html += + '
  • ' + + row[0] + + '
  • '; + counter++; + }); + } + + if (counter) { + $('#sim_legend').classList.remove('apparent'); + + if (allpurpose) + $('#sim_legend').textContent = 'Also studied by these authors:'; + else if (entype == 'C') + $('#sim_legend').textContent = 'Phases at the diagram:'; + else if (entype == 'S') + $('#sim_legend').textContent = 'The same prototype structures:'; + else $('#sim_legend').textContent = 'Similar ' + prop + ':'; + + if (counter > 7) { + //var link = (entype == 'C') ? '#entry/' + $('#entryno').text() : '#interlinkage/' + entry; + $('#sim_trigger').setAttribute('href', '#interlinkage/' + entry); + show($('#sim_trigger')); + } + set_html($('#sim_col > ul'), sim_html); + } else { + if (allpurpose) { + $('#sim_legend').classList.add('apparent'); + $('#sim_legend').textContent = 'No cross-links found'; + } else if (entype == 'C' && rank == 3) { + // FIXME this is fragile + var els, + html_3d = ''; + + if (wmgui.thumbed_display) { + els = $('div.busy_entry > div.gallery_img > p').textContent.split('-'); + } else { + els = $('tr.busy_entry > td.c2') + .textContent.replace('; ', '') + .split(' '); + els = els[els.length - 1].split('-'); + } + if (els.length == 3 || els.length == 4) + html_3d = + '

    3d
    3d phase diagram
    '; + + $('#sim_legend').classList.add('apparent'); + set_html( + $('#sim_legend'), + '
    C-entry
    Full phase diagram
    ' + + html_3d, + ); + } else if (entype == 'C' && rank == 5) { + $('#sim_legend').classList.add('apparent'); + $('#sim_legend').textContent = 'No links to other phases found.'; + } else if (entype == 'C' && rank == 12) { + $('#sim_legend').classList.add('apparent'); + $('#sim_legend').textContent = + 'Hover the binary or ternary diagrams for more data.'; + } else if (entype == 'S') { + $('#sim_legend').classList.add('apparent'); + $('#sim_legend').textContent = + 'No other structures for this prototype found.'; + } else { + $('#sim_legend').classList.add('apparent'); + $('#sim_legend').textContent = 'No similar values found.'; + } + } + + if (data.out.own.length && !wmgui.search.phid) { + set_html( + $('#own_phase'), + 'Phase
    Linked ' + + (entype == 'S' ? 'distinct phase' : 'crystalline structure') + + '
    ', + ); + show($('#own_phase')); + } +} + +export function close_vibox() { + const iframe = $('#iframe'); + if (iframe) { + if (wmgui.thumbed_display) + slide_up(iframe, 400, function () { + iframe.remove(); + }); + else iframe.remove(); + hide($('#vibox')); + return true; + } + return false; +} + +export function launch_db_iframed(rank) { + const that = $$('.busy_entry')[0]; + if (!that) return; + + var entry = that.id.substr(3), + entype = entry.substr(0, 1), + iframe_src, + iframe_height; + + if (entype == 'S') { + if (rank == 99) { + ((iframe_src = + wmgui.engines_addrs['visavis'] + wmgui.path_s_xrpd + entry), + (iframe_height = 550)); + } else + ((iframe_src = + wmgui.engines_addrs['cifplayer'] + wmgui.path_s_entry + entry), + (iframe_height = 650)); + } else if (entype == 'P') { + if (rank == 1) { + ((iframe_src = + wmgui.engines_addrs['visavis'] + wmgui.path_pp_plot + entry), + (iframe_height = 550)); + wmgui.notify('P-curves are in beta-testing'); + } else if (rank == 4) + ((iframe_src = + wmgui.engines_addrs['visavis'] + wmgui.path_sd_plot + entry), + (iframe_height = 550)); + else if (rank == 9) + ((iframe_src = + wmgui.v_pd_user_addr + + wmgui.api_host + + '/download/p?fmt=png&q=' + + entry), + (iframe_height = 600)); + else if (rank == 10) + ((iframe_src = wmgui.v_ab_vis_addr + entry), (iframe_height = 600)); + else return; + } else { + if (rank == 12) { + var triple = wmgui.thumbed_display + ? $('div.busy_entry > div.gallery_img > p').textContent + : $('tr.busy_entry > td.c1').textContent.split(' ')[0]; + ((iframe_src = wmgui.v_pd_3d_addr + triple), (iframe_height = 550)); + } else if (rank == 6) + ((iframe_src = + (wmgui.sid + ? wmgui.v_pd_user_addr + wmgui.api_host + '/download/c?fmt=png&q=' + : wmgui.engines_addrs['visavis'] + wmgui.path_c_entry) + entry), + (iframe_height = 600)); + else return; + + if (wmgui.entries_messages[entry]) + wmgui.notify(wmgui.entries_messages[entry]); + } + + if (wmgui.sid) iframe_src += '&sid=' + wmgui.sid; + + var iframe_html = + ''; + if (wmgui.thumbed_display) + iframe_html = + '
    ' + + iframe_html + + '
    '; + else + iframe_html = + '' + + iframe_html + + ''; + + that.insertAdjacentHTML('afterend', iframe_html); + window.scrollTo(0, position(that).top - 95); +} + +export function start_visavis(plot_type) { + destroy_numericbox(); + delete wmgui.search.numeric; + if (plot_type) wmgui.visavis_curtype = plot_type; + + hide($$('div.ctxpanel')); + const toshow = $('#ctxpanel_' + wmgui.visavis_curtype); + if (toshow) show(toshow); + if (['matrix', 'cube', 'discovery'].indexOf(wmgui.visavis_curtype) !== -1) + show($('#cmppanel_plots')); + + if (wmgui.visavis_working) return manage_visavis(); + + rebuild_visavis(); + + // visavis_col preparation + show($('#visavis_col')); + show($('#visavis')); + + switch_control_mode(0, 11, 'a', 'e'); + document.body.classList.add('noscroll'); + + wmgui.search_type = 0; + wmgui.visavis_working = true; + + var cur_obj = { total_count: 1 }; + Object.assign(cur_obj, wmgui.search); + + try { + document + .getElementById('visavis_iframe') + .contentWindow.location.replace(get_visavis_url(cur_obj)); + } catch (e) { + console.error('No iframe access'); + } +} + +function manage_visavis(callback_fn, param_a, param_b) { + if (wmgui.visavis_terminating || !wmgui.visavis_working) { + return false; + } + + if (wmgui.search.numeric) { + // not supported for plotting yet! + wmgui.visavis_terminating = true; + return false; + } + + try { + wmgui.active_ajax.abort(); + } catch (e) {} + try { + wmgui.quick_ajax.abort(); + } catch (e) {} + + rebuild_visavis(); + + var cur_obj = { total_count: 1 }; + Object.assign(cur_obj, wmgui.search); + + try { + document + .getElementById('visavis_iframe') + .contentWindow.location.replace(get_visavis_url(cur_obj)); + } catch (e) { + console.error('No iframe access'); + } + + if (callback_fn) callback_fn(param_a, param_b); + return true; +} + +function rebuild_visavis() { + var extr = window.location.hash.indexOf('search/'); + if (extr == -1) { + var extr = window.location.hash.indexOf('inquiry/'); + if (extr == -1) return; + } + + var query = window.location.hash.substr(extr); + + $$('a.pltcol_links').forEach(function (a) { + var plot_type = a.getAttribute('rev'); + a.setAttribute( + 'href', + wmgui.gui_host + + window.location.pathname + + '#plot/' + + plot_type + + '/' + + query, + ); + }); + + $$('#visavis_col > ul > li').forEach(function (li) { + li.classList.remove('embodied'); + }); + const pltchoice = $('#pltchoice_' + wmgui.visavis_curtype); + if (pltchoice) pltchoice.classList.add('embodied'); + + // ctx reset + if (['matrix', 'cube', 'discovery'].indexOf(wmgui.visavis_curtype) !== -1) + update_dc(); + + if (wmgui.visavis_curtype == 'matrix') { + $$('#ctxpanel_matrix > ul > li.embodied').forEach(function (li) { + li.classList.remove('embodied'); + }); + $$('#ctxpanel_matrix > ul > li.ss_y').forEach(function (li) { + li.classList.remove('ss_y'); + }); + $('#vismatrix_nump').classList.add('embodied'); // set the default sort order, also in Visavis: TODO + remove($$('span.sops')); + } else if (wmgui.visavis_curtype == 'cube') { + $$('#ctxpanel_cube > ul > li.embodied').forEach(function (li) { + li.classList.remove('embodied'); + }); + $$('#ctxpanel_cube > ul > li.ss_y').forEach(function (li) { + li.classList.remove('ss_y'); + }); + $$('#ctxpanel_cube > ul > li.ss_z').forEach(function (li) { + li.classList.remove('ss_z'); + }); + $('#viscube_nump').classList.add('embodied'); + remove($$('span.sops')); + } else if (wmgui.visavis_curtype == 'graph') { + $$('#ctxpanel_graph > ul > li.embodied').forEach(function (li) { + li.classList.remove('embodied'); + }); + $('#visgraph_props').classList.add('embodied'); + } + + try { + document + .getElementById('visavis_iframe') + .contentWindow.fixel_manage( + wmgui.visavis_curtype == 'cube' && wmgui.search.elements, + ); + } catch (e) { + console.error('No iframe access'); + } +} + +function stop_visavis() { + hide($$('#visavis, #visavis_col')); + wmgui.visavis_working = false; + wmgui.visavis_terminating = false; +} + +export function get_visavis_url(request, type, height) { + if (wmgui.visavis_curtype == 'pie' && !type) + return ( + wmgui.engines_addrs['visavis'] + + '#' + + wmgui.rfn_endpoint + + '?q=' + + encodeURIComponent(JSON.stringify(request)) + ); + + var height_str = height ? '&visavis_height=' + height : ''; + + return ( + wmgui.engines_addrs['visavis'] + + '#' + + wmgui.vis_endpoint + + '/' + + (type || wmgui.visavis_curtype) + + '?q=' + + encodeURIComponent(JSON.stringify(request)) + + height_str + ); +} + +export function describe_perms(perms) { + var out_gui = '

    Web-browser access = GUI

      ', + out_api = '

      Programmatic access = API

        '; + + if (perms.gui) { + if (perms.gui.root) out_gui += '
      • complete access
      • '; + else { + if (!Array.isArray(perms.gui)) perms.gui = [perms.gui]; + for (var m = 0; m < perms.gui.length; m++) { + const ruleset = perms.gui[m]; + if (m > 3) { + out_gui += '
      • and ' + (perms.gui.length - 4) + ' more...
      • '; + break; + } + wmgui.facets.forEach(function (item) { + if (ruleset[item]) { + try { + out_gui += + '
      • ' + + wmgui.facet_names[item] + + ': ' + + ruleset[item] + .map(function (x) { + return x.replace(', ', ' & '); + }) + .join(', ') + + '
      • '; + } catch (e) {} + } + }); + if (ruleset.refs == 'ALL') + out_gui += '
      • full access to reference details
      • '; + else if (ruleset.refs == 'MENTIONED') + out_gui += '
      • access to corresponding references
      • '; + else out_gui += '
      • no access to reference details
      • '; + out_gui += '

      • '; + } + } + } else out_gui += '
      • only open data
      • '; + + if (perms.api) { + if (perms.api.root) out_api += '
      • complete access
      • '; + else if (perms.api.disabled) + out_api += '
      • disabled — please check on the other device
      • '; + else { + if (!Array.isArray(perms.api)) perms.api = [perms.api]; + for (var m = 0; m < perms.api.length; m++) { + const ruleset = perms.api[m]; + if (m > 3) { + out_api += '
      • and ' + (perms.api.length - 4) + ' more...
      • '; + break; + } + wmgui.facets.forEach(function (item) { + if (ruleset[item]) { + try { + out_api += + '
      • ' + + wmgui.facet_names[item] + + ': ' + + ruleset[item] + .map(function (x) { + return x.replace(', ', ' & '); + }) + .join(', ') + + '
      • '; + } catch (e) {} + } + }); + out_api += '

      • '; + } + } + } else out_api += '
      • only open data
      • '; + + return out_gui + '
      ' + out_api + '
    '; +} + +export function show_advsbox() { + hide($$('div.modal')); + show($$('#advsbox, #overlay')); + + // show typed terms + if (!is_empty(wmgui.search)) { + wmgui.simple_facets.forEach(function (item) { + if (wmgui.search[item]) { + var value = wmgui.search[item]; + + if (item == 'codens') value = wmgui.journal_converter.c2j(value); + else if (item == 'doi') value = value.replaceAll('%2F', '/'); + + $('#advs_fct_' + item).value = decodeURIComponent( + value.replace(/\+/g, '%20'), + ); + } else $('#advs_fct_' + item).value = ''; + }); + + wmgui.multi_facets.forEach(function (item) { + const rest_input = $('#advs_fct_' + item + '-selectized'); + if (rest_input) rest_input.value = ''; + wmgui.multiselects[item].clear(); + + if (wmgui.search[item]) { + var obj = {}; + obj[item] = wmgui.search[item]; + wmgui.multiselects[item].write(obj); + //wmgui.multiselects[item].write({[item]: wmgui.search[item]}); + if (item == 'aetypes') + show_aetmap(wmgui.search[item].split(',').pop().trim()); + } + }); + } + if (!show_aetmap.cached_aetmap) { + show_aetmap.cached_aetmap = new Image(); + show_aetmap.cached_aetmap.src = wmgui.aetmap_addr; + } +} + +export function show_hints(disabled, res_count) { + //$('#fdwidget').html('Were you satisfied with the data quality? Did everything work as expected? YesNo').show(); + + if ( + disabled || + wmgui.search.numeric || + wmgui.search.doi || + wmgui.search.phid || + wmgui.search.bid || + wmgui.fuzzyout || + wmgui.search_type == 2 + ) + return; + + var cur_obj = {}; + Object.assign(cur_obj, wmgui.search); + delete cur_obj.ignored; + delete cur_obj.search_type; + + var hint = JSON.stringify(cur_obj) + .replaceAll(' ', '+') + .replace('\{', '\\{') + .replace('\}', '\\}'); + set_html($('#apihint kbd'), hint); + show($('#apihint')); + + if (wmgui.search_type === 0 && (res_count > 3 || res_count === undefined)) { + $$('a.plthint_links').forEach(function (a) { + var plot_type = a.getAttribute('rev'); + a.setAttribute( + 'href', + wmgui.gui_host + + window.location.pathname + + '#plot/' + + plot_type + + '/' + + window.location.hash.substr(1), + ); + }); + show($('#plthint')); + } +} + +export function show_tooltip(info, forced) { + if ( + info.view_mode != wmgui.view_mode || + (wmgui.visavis_working && !forced) || + $$('.modal').some(isVisible) + ) + return; + + var ref = position($('#' + info.el)), + tooltip_el = document.getElementById('tooltip'); + + tooltip_el.style.left = ref.left + info.oleft + 'px'; + tooltip_el.style.top = ref.top + info.otop + 'px'; + tooltip_el.firstChild.innerHTML = info.text; + document.getElementById('tooltip').style.display = 'block'; +} + +export function show_modal(which) { + if (which == 'login') { + if ($('#factor_by_email').value) + $('#login_email').value = $('#factor_by_email').value; + else $('#login_email').value = ''; + + $('#login_password').value = ''; + show($('#loginbox')); + $('#login_email').focus(); + + // for OAuth linking redirect only + // see email_chain.html + var u_email = + window.localStorage.getItem(wmgui.store_oauth_email_key) || false; + if (u_email) { + $('#login_email').value = u_email; + window.localStorage.removeItem(wmgui.store_oauth_email_key); + } + } else if (which == 'factor') { + if ($('#login_email').value) + $('#factor_by_email').value = $('#login_email').value; + else $('#factor_by_email').value = ''; + + show($('#factorbox')); + $('#factor_by_email').focus(); + } else if (which == 'restore') { + if ($('#login_email').value) + $('#restore_by_email').value = $('#login_email').value; + else $('#restore_by_email').value = ''; + + show($('#restorebox')); + $('#restore_by_email').focus(); + } +} + +export function init_user_login() { + // to prevent re-execution + var locals = JSON.parse( + window.localStorage.getItem(wmgui.store_user_key) || '{}', + ); + if (locals.sid === wmgui.sid) return; + + if (!locals.ipbased && locals.sid && locals.name && locals.acclogin) { + user_login( + locals.sid, + locals.name, + locals.acclogin, + locals.admin, + locals.oauths, + false, + ); + } else { + // attempt IP-based login + ajax({ + type: 'POST', + url: wmgui.ip_endpoint, + }) + .then(function (data) { + if (data.sid && data.name && data.acclogin) + user_login( + data.sid, + data.name, + data.acclogin, + data.admin, + data.oauths, + true, + ); + }) + .catch(function () {}); + } +} + +export function user_login(sid, name, acclogin, admin, oauths, ipbased) { + var corner_name = name.length > 40 ? name.substr(0, 37) + '…' : name; + set_html($('#auth_user'), corner_name); + set_html($('#account_holder_name'), 'Hello ' + name + ' 👍'); + set_html( + $('#account_holder_acclogin > span'), + ipbased + ? 'location-based' + : '' + acclogin + '', + ); + + wmgui.sid = sid; + wmgui.oauths = oauths; + + hide($$('div.logged_out')); + show($$('div.logged_in')); + hide($('#account_pass_change')); + + window.localStorage.setItem( + wmgui.store_user_key, + JSON.stringify({ + sid: sid, + name: name, + acclogin: acclogin, + admin: admin, + ipbased: ipbased, + }), + ); // TODO? oauths: oauths + + if (admin && (wmgui.edition == 0 || wmgui.edition == 1)) show($$('li.admin')); + else hide($$('li.admin')); + + if (ipbased) { + hide($$('.only_regular')); + $('#logout_trigger').classList.add('disabled'); + $('#accpass_trigger').textContent = 'disabled'; + $('#accpass_trigger').classList.add('disabled'); + } else { + show($$('.only_regular')); + $('#logout_trigger').classList.remove('disabled'); + $('#accpass_trigger').textContent = 'change'; + $('#accpass_trigger').classList.remove('disabled'); + } + + try { + document.getElementById('visavis_iframe').contentWindow.location.reload(); + } catch (e) { + console.error('No iframe access'); + } + communicate_windows('tab_user_login'); + + wmgui.notify('Logged in as ' + name); + + // One-off redirection + var redir = window.localStorage.getItem(wmgui.store_redir_key); + if (redir) { + window.localStorage.removeItem(wmgui.store_redir_key); + return window.location.replace(redir); // FIXME? replace vs. href + } +} + +export function tab_user_login() { + // to prevent re-execution + var locals = JSON.parse( + window.localStorage.getItem(wmgui.store_user_key) || '{}', + ); + if (locals.sid === wmgui.sid) return; + + window.location.reload(); +} + +export function user_logout(silent) { + if (!wmgui.sid) return; + + wmgui.sid = null; + wmgui.oauths = null; + hide($$('li.admin')); + hide($$('div.logged_in')); + show($$('div.logged_out')); + + window.localStorage.removeItem(wmgui.store_user_key); + + try { + document.getElementById('visavis_iframe').contentWindow.location.reload(); + } catch (e) { + console.error('No iframe access'); + } + communicate_windows('user_logout'); + + if (!silent) wmgui.notify('You are logged out'); +} + +export function force_relogin(show_msg) { + ajax({ + type: 'POST', + url: wmgui.logout_endpoint, + data: { sid: wmgui.sid }, + }) + .then(function () {}) + .catch(function () {}); + user_logout(true); + window.location.replace('#modal/login'); + if (show_msg) wmgui.notify(show_msg); +} + +function communicate_windows(runnable_name) { + // NB the active window doesn't receive a storage event + window.localStorage.setItem(wmgui.store_comm_exec_key, runnable_name); + setTimeout(function () { + window.localStorage.removeItem(wmgui.store_comm_exec_key); + }, 0); +} + +function reset_factor_form() { + document.getElementById('factor_trigger').style.display = 'block'; + document.getElementById('factor_form_step_one').style.display = 'block'; + document.getElementById('factor_form_step_two').style.display = 'none'; + var resps = document.getElementsByClassName('factor_form_resp'); + for (var i = 0; i < resps.length; i++) { + resps[i].value = ''; + } +} + +export function submit_factor_form_resp() { + var result = ''; + var resps = document.getElementsByClassName('factor_form_resp'); + for (var i = 0; i < resps.length; i++) { + result += resps[i].value; + } + if (result.length !== 6 || !Number.isInteger(parseInt(result))) return false; + + ajax({ + type: 'POST', + url: wmgui.factor_v_endpoint, + data: { a: result, ed: wmgui.edition }, + }) + .then(function (data) { + if (data.error) return wmgui.notify(data.error); + if (!data.sid || !data.name || !data.acclogin) { + window.location.replace('#start'); + return wmgui.notify( + 'Connection to server is lost, please try to reload', + ); + } + user_login(data.sid, data.name, data.acclogin, data.admin, data.oauths); + + reset_factor_form(); + + $('#userbox').click(); + }) + .catch(function () {}); +} + +function update_dc() { + var title = [], + orepr = {}; + for (var key in wmgui.search) { + if (['search_type', 'phid', 'numeric'].indexOf(key) !== -1) continue; + orepr[key] = wmgui.search[key]; + title.push(wmgui.search[key]); + } + title = title.join(' '); + + var count = 0, + cur_str = JSON.stringify(orepr), + cmp_html = ''; + + JSON.parse( + window.localStorage.getItem(wmgui.store_history_key) || '[]', + ).forEach(function (past) { + if (count > 6) return; + + var past_title = [], + past_str = JSON.stringify(past); + if (cur_str == past_str) return; + + for (var prop in past) { + past_title.push(past[prop]); + } + past_title = past_title.join(' '); + cmp_html += + ''; + count++; + }); + cmp_html += ''; + const select_cmp = $('#select_cmp_trigger'); + select_cmp.innerHTML = ''; + select_cmp.insertAdjacentHTML('beforeend', cmp_html); +} + +export function show_aetmap(term) { + var coords = wmgui.aets[term]; + if (coords) { + const aetmap = $('#aetmap'); + aetmap.style.height = coords[1] + 'px'; + aetmap.style.background = + 'url(' + wmgui.aetmap_addr + ') 0 -' + coords[0] + 'px no-repeat'; + show(aetmap); + } else hide($('#aetmap')); +} + +export function render_all_polyhedra() { + const content = $('#all_polyhedra_content'); + if (content.firstChild) return; + var aetypes_html = '', + defined_aetypes = Object.keys(wmgui.aets); + defined_aetypes.sort(function (a, b) { + var partsa = a.split('-vertex')[0].split(' '), + va = parseInt(partsa[partsa.length - 1]), + partsb = b.split('-vertex')[0].split(' '), + vb = parseInt(partsb[partsb.length - 1]); + return va > vb + ? 1 + : va < vb + ? -1 + : a.length > b.length + ? 1 + : a.length < b.length + ? -1 + : 0; + }); + defined_aetypes.forEach(function (value) { + var coords = wmgui.aets[value]; + aetypes_html += + ''; + }); + set_html(content, aetypes_html); +} + +function show_dunit_info(phid, bid, entry) { + if (phid) { + set_html($('#ind_title'), 'Phase ' + phid); + const ind_link = $('#ind_link'); + ind_link.setAttribute('href', 'https://mpds.io/phase_id/' + phid); + set_html(ind_link, 'www.mpds.io/phase_id/' + phid); + } else if (bid) { + set_html($('#ind_title'), 'Publication B' + bid); + const ind_link = $('#ind_link'); + ind_link.setAttribute('href', 'https://mpds.io/article/' + bid); + set_html(ind_link, 'www.mpds.io/article/' + bid); + } else if (entry) { + set_html($('#ind_title'), 'Entry ' + entry); + const ind_link = $('#ind_link'); + ind_link.setAttribute('href', 'https://mpds.io/entry/' + entry); + set_html(ind_link, 'www.mpds.io/entry/' + entry); + } + + hide($$('#refine_col, #ctx_col')); + empty($$('#phase_info, #ind_col > span')); + + if (phid) { + set_html( + $('#ind_col > span'), + '', + ); + + wmgui.show_preloader(); + const request = ajax({ + type: 'GET', + url: wmgui.phase_endpoint, + data: { phid: phid }, + }); + wmgui.active_ajax = request; + + request + .then(function (data) { + wmgui.hide_preloader(); + if (data.error) return wmgui.notify(data.error); + + var html = + '

    ' + + data.out.formula_html.split(' ')[0] + + ' ' + + (data.out.spg || '?') + + ' ' + + (data.out.pearson || '—') + + '

    '; + + if (data.out.mpid) + html += + '

    Materials Project mp-' + + data.out.mpid + + '

    '; + + html += '

    '; + if (data.out.articles_count) + html += + 'This phase was reported in ' + + data.out.articles_count + + ' article' + + (data.out.articles_count > 1 ? 's' : '') + + '.'; + if (data.out.sim_count > 1) + html += + ' There are ' + + data.out.sim_count + + ' structurally similar phases from other articles.'; + html += '

    '; + + set_html($('#phase_info'), html); + show($('#dtypes_phid')); + }) + .catch(function (error) { + wmgui.hide_preloader(); + if (!(error && error.aborted)) + wmgui.notify('Sorry, a network error occured. Please, try again'); + }); + } else if (bid) { + set_html($('#ind_col > span'), '📖'); // book icon + set_html( + $('#phase_info'), + '

    Ref. ' + + bid + + '

    Please make sure you are
    logged in to see all the details.

    ', + ); + + wmgui.show_preloader(); + const request = ajax({ + type: 'GET', + url: + wmgui.refs_endpoint + + '?noredir=1&fmt=bib&ref_id=' + + bid + + '&sid=' + + wmgui.sid, + dataType: 'text', + }); + wmgui.active_ajax = request; + + request + .then(function (data) { + wmgui.hide_preloader(); + var citation = wmgui.parse_bib(data), + citation_html = '', + main_author = '', + links_html = ''; + + if (citation[0].length) { + citation[0].split(',').forEach(function (item, index) { + var author_name = item.trim().split('.')[0]; + author_name = author_name + .substr(0, author_name.length - 2) + .replace("'", ''); + if (index === 0) main_author = author_name; + links_html += + '' + + author_name + + ' or '; + }); + links_html = links_html.substr(0, links_html.length - 4); // " or " + if (citation[0].indexOf(',') !== -1) main_author += ' et al.'; + citation_html += + ' ' + + main_author + + ', ' + + citation[1] + + '. ' + + citation[2] + + ' (' + + citation[3] + + ')'; + } + + if (bid == 999999) { + set_html( + $('#phase_info'), + '

    In-house data

    These data were generated automatically on the MPDS platform based on the original peer-reviewed Pauling File data. Please cite as ' + + citation_html + + '.

    ', + ); + } else { + var n_entries = wmgui.thumbed_display + ? $$('div.gallery_item').length + : $$('tr.tcell').length; + if (n_entries == 1000) n_entries = 'more than ' + n_entries; + set_html( + $('#phase_info'), + '

    Ref. ' + + bid + + '

    We have ' + + (n_entries == 1 ? 'one entry' : n_entries + ' entries') + + ' from this reference' + + citation_html + + '.

    ' + + (links_html.length + ? '

    Retrieve all data co-authored by ' + links_html + '.

    ' + : ''), + ); + } + }) + .catch(function () { + wmgui.hide_preloader(); + }); + } else { + set_html($('#ind_col > span'), '🔬'); // microscope icon + } + + show($('#ind_col')); + hide($('#dtypes')); +} + +export function assign_edition() { + function run_edition(edition_key) { + edition_key = parseInt(edition_key); + if (!wmgui.editions[edition_key]) edition_key = 0; + wmgui.edition = edition_key; + if (wmgui.editions[edition_key].css) + wmgui.loadCSS(wmgui.editions[edition_key].css); + if (wmgui.editions[edition_key].actions) + wmgui.editions[edition_key].actions(); + } + + for (var key in wmgui.editions) { + if ( + wmgui.gui_host == wmgui.editions[key]['prod_url'] || + wmgui.gui_host == wmgui.editions[key]['dev_url'] + ) { + run_edition(key); + break; + } + } + + // for any unknown domain, ICDD MPDS is assumed + if (!wmgui.edition) run_edition(0); + + // for any third-party integrations, id="mpds_native" should not be used + wmgui.mpds_native = !!document.getElementById('mpds_native'); +} diff --git a/src_js/app/startup.js b/src_js/app/startup.js new file mode 100644 index 0000000..835ecbb --- /dev/null +++ b/src_js/app/startup.js @@ -0,0 +1,622 @@ +/** + * Ermac startup: satisfy_requirements() initializes autocompletes, multiselects, + * client-side data features, and triggers the initial route. + */ + +/* global Darkmode */ + +import wmgui from '../core/settings.js'; +import { wmutils } from '../core/utils.js'; +import { $, $$, hide, set_attr, append_html, isVisible } from '../core/dom.js'; +import { ajax, param } from '../core/ajax.js'; +import { create_autocomplete } from '../components/autocomplete.js'; +import { create_multiselect } from '../components/multiselect.js'; +import { + create_floating_slider, + destroy_numericbox, +} from '../components/sliders.js'; +import { show_aetmap, init_user_login, rotate_interesting } from './search.js'; +import { url_redraw_react } from './router.js'; +import { read_ptable_html, select_ptable_series } from './ptable.js'; + +export function satisfy_requirements() { + hide($$('#notifybox, #preloader')); + //document.title = document.body.clientWidth + ' px'; + const absolidize_href = $('#absolidize > span.disabled > span.href'); + if (absolidize_href) set_attr(absolidize_href, 'rel', wmgui.mydata_addr); + + wmgui.ptable.els_data = read_ptable_html(); + + init_user_login(); + + // building history box + var history_html = ''; + JSON.parse( + window.localStorage.getItem(wmgui.store_history_key) || '[]', + ).forEach(function (past, n) { + wmgui.tooltip_counter++; + + if (n > 5) return; + + var title = [], + inquiry = false; + + for (var prop in past) { + title.push(past[prop]); + } + title = title.join(' '); + wmgui.inquiries.forEach(function (item) { + if (past[item]) { + inquiry = true; + } + }); + + if (inquiry) + history_html += + '
  • ' + title + '
  • '; + else + history_html += + '
  • ' + + title + + '
  • '; + }); + append_html($('#history ul'), history_html); + + JSON.parse(window.localStorage.getItem(wmgui.store_bids_key) || '[]').forEach( + function (item) { + wmgui.bid_history.push(parseInt(item)); + }, + ); + + JSON.parse( + window.localStorage.getItem(wmgui.store_mydata_key) || '[]', + ).forEach(function (item) { + wmgui.mydata_history.push(item); + }); + + // set client-side data features + ajax({ + url: wmgui.wmdata_endpoint, + type: 'GET', + //data: {nocache: Math.floor(Math.random() * 1000)} + }) + .then(function (answer) { + var i = 0, + len = answer.props_ref.length; + for (i; i < len; i++) { + if (!answer.props_ref[i]) answer.props_ref[i] = answer.props[i]; + } + + // local search algo + // #1 + ['props', 'lattices', 'sgs', 'protos', 'codens', 'geos', 'orgs'].forEach( + function (fct) { + create_autocomplete({ + custom_type: fct, + selector: 'advs_fct_' + fct, + minChars: 1, + cache: 1, + source: function (term, fct_type, suggest) { + // other names are used, define them first here + var fct_src = fct_type, + fct_chk = fct_type, + anypos = false; + + if (fct_type !== 'lattices') { + anypos = true; + if (fct_type == 'props') fct_src = 'props_ref'; + else if (fct_type == 'codens') { + fct_src = 'jfull'; + fct_chk = 'jfull'; + } + } + + var suggestions = [], + cnt = 0, + checks = [], + i = 0, + len = answer[fct_chk].length; + + term = term.toLowerCase(); + for (i; i < len; i++) { + if (answer[fct_chk][i].toLowerCase().startswith(term)) { + suggestions.push(answer[fct_src][i]); + if (anypos) checks.push(answer[fct_src][i]); + cnt++; + if (cnt > 12) break; + } + } + if (anypos && suggestions.length < 6) { + for (i = 0; i < len; i++) { + if ( + answer[fct_chk][i].toLowerCase().indexOf(term) != -1 && + checks.indexOf(answer[fct_src][i]) == -1 + ) { + suggestions.push(answer[fct_src][i]); + cnt++; + if (cnt > 12) break; + } + } + } + suggest(suggestions); + }, + renderItem: function (item, search) { + return ( + '
    ' + + item + + '
    ' + ); + }, + }); + }, + ); + + // local search algo + // #2 + wmgui.multi_facets.forEach(function (fct) { + wmgui.multiselects[fct] = create_multiselect($('#advs_fct_' + fct), { + plugins: ['remove_button', 'preserve_on_blur'], + valueField: 'id', + labelField: 'label', + searchField: 'label', + create: false, + highlight: false, + maxItems: 5, + closeAfterSelect: true, + diacritics: false, + options: [], + onChange: function (value) { + if (fct == 'aetypes') { + var term = (wmgui.multiselects['aetypes'].read()['aetypes'] || '') + .split(', ') + .pop(); + show_aetmap(term); + if ($('#aet_limit').checked) $('#aet_limit').click(); + } else if (fct == 'wyckoff') { + var terms = ( + wmgui.multiselects['wyckoff'].read()['wyckoff'] || '' + ) + .split(',') + .map(function (x) { + return x.trim(); + }); + if (terms && terms[0] && terms.length > 1) { + var cmp = wmgui.is_wyckoff_position(terms[0]); + if ( + !terms.every(function (x) { + return cmp === wmgui.is_wyckoff_position(x); + }) + ) + wmgui.notify( + 'Wyckoff sequence and positions are mutually exclusive', + ); + } + } + }, + onItemRemove: function (value) { + var input = this; + setTimeout(function () { + input.close(); + }, 750); + }, + load: function (term, callback) { + this.clearOptions(); + if (!term.length) return callback(); + + var suggestions = [], + cnt = 0, + checks = [], + i = 0, + len = answer[fct].length; + + term = term.toLowerCase(); + for (i; i < len; i++) { + if (answer[fct][i].toLowerCase().startswith(term)) { + suggestions.push({ + facet: fct, + label: answer[fct][i], + id: fct + i, + }); + checks.push(answer[fct][i]); + cnt++; + if (cnt > 12) break; + } + } + if (suggestions.length < 6) { + for (i = 0; i < len; i++) { + if ( + answer[fct][i].toLowerCase().indexOf(term) != -1 && + checks.indexOf(answer[fct][i]) == -1 + ) { + suggestions.push({ + facet: fct, + label: answer[fct][i], + id: fct + i, + }); + cnt++; + if (cnt > 12) break; + } + } + } + callback(suggestions); + }, + score: function () { + return function () { + return 1; + }; + }, // no client scoring + render: { + option: function (item, escape) { + return ( + '
    ' + item.label + '
    ' + ); + }, + item: function (item, escape) { + return ( + '
    ' + + item.label + + '
    ' + ); + }, + }, + }); + + wmgui.multiselects[fct].read = function () { + return wmgui._selectize_read_facet(fct); + }; + wmgui.multiselects[fct].write = function (search_obj) { + wmgui._selectize_write(wmgui.multiselects[fct], fct, search_obj); + }; + wmgui.multiselects[fct].display = function (facet, term) { + wmgui._selectize_display(wmgui.multiselects[fct], facet, term); + }; + }); + + wmgui.journal_converter.j2c = function (x) { + var fi = answer.jfull.indexOf(x); + if (fi == -1) { + wmgui.notify('Sorry, unknown journal: ' + x); + return x; + } + return answer.codens[fi]; + }; + wmgui.journal_converter.c2j = function (x) { + var fi = answer.codens.indexOf(x); + if (fi == -1) { + wmgui.notify('Sorry, unknown CODEN: ' + x); + return x; + } + return answer.jfull[fi]; + }; + + var html_scalars = '', + html_complex = '', + html_arrays = '', + counter = 0; + + (function () { + for (var term in answer.hy_scalars) { + const content = answer.hy_scalars[term]; + term = parseInt(term); + //console.log(term); + term = answer.props_ref[term] + ? answer.props_ref[term] + : answer.props[term]; + //console.log(term); + counter += 1; + html_scalars += + '
  • ' + + term + + ' (expand)
      '; + (function () { + for (var sub_term in content) { + const sub_content = content[sub_term]; + sub_term = parseInt(sub_term); + //console.log(sub_term); + sub_term = answer.props_ref[sub_term] + ? answer.props_ref[sub_term] + : answer.props[sub_term]; + //console.log('----' + sub_term); + html_scalars += + '
    • ' + + sub_term + + '
        '; + sub_content.forEach(function (item, n) { + item = parseInt(item); + var prop = answer.props_ref[item] + ? answer.props_ref[item] + : answer.props[item], + specs = answer.numerics[item]; // NB object vs. array + //console.log('---------' + item + ' ' + prop); + html_scalars += + '
      • ' + + prop + + ''; + if (specs) { + html_scalars += + '' + + (specs[0] || '') + + '  [' + + specs[1] + + ' ↔ ' + + specs[2] + + '] 🔍'; + wmgui.numerics[prop] = [ + item, + specs[0], + specs[1], + specs[2], + specs[3], + ]; // prop_name: [client_prop_id, units, min, max, ?step, ?origname] + } + html_scalars += '
      • '; + }); + html_scalars += '
    • '; + } + })(); + html_scalars += '
  • '; + } + })(); + append_html($('#hy_scalars > ul'), html_scalars); + + wmgui.hy_complex.forEach(function (item) { + // FIXME cannot process with optimade NLP parser + html_complex += + '
  • ' + + item + + '
  • '; + }); + append_html($('#hy_complex > ul'), html_complex); + + (function () { + for (var term in answer.hy_textual) { + const content = answer.hy_textual[term]; + term = parseInt(term); + term = answer.props_ref[term] + ? answer.props_ref[term] + : answer.props[term]; + counter += 1; + html_arrays += + '
  • ' + + term + + ' (expand)
      '; + (function () { + for (var sub_term in content) { + const sub_content = content[sub_term]; + sub_term = parseInt(sub_term); + sub_term = answer.props_ref[sub_term] + ? answer.props_ref[sub_term] + : answer.props[sub_term]; + html_arrays += + '
    • ' + + sub_term + + '
        '; + sub_content.forEach(function (item) { + item = parseInt(item); + item = answer.props_ref[item] + ? answer.props_ref[item] + : answer.props[item]; + html_arrays += + '
      • ' + + item + + '
      • '; + }); + html_arrays += '
    • '; + } + })(); + html_arrays += '
  • '; + } + })(); + append_html($('#hy_arrays > ul'), html_arrays); + + create_autocomplete({ + selector: 'hy_suggest', + minChars: 1, + cache: 1, + source: function (term, fct_type, suggest) { + var fct_src = 'props_ref', + term = term.toLowerCase(), + suggestions = [], + cnt = 0, + checks = [], + i = 0, + len = answer[fct_type].length; + for (i; i < len; i++) { + if (answer[fct_type][i].startswith(term)) { + suggestions.push(answer[fct_src][i]); + checks.push(answer[fct_src][i]); + cnt++; + if (cnt > 18) break; + } + } + if (suggestions.length < 12) { + for (i = 0; i < len; i++) { + if ( + answer[fct_type][i].indexOf(term) != -1 && + checks.indexOf(answer[fct_src][i]) == -1 + ) { + suggestions.push(answer[fct_src][i]); + cnt++; + if (cnt > 18) break; + } + } + } + suggest(suggestions); + }, + renderItem: function (item, search) { + return ( + '
    ' + + item + + '
    ' + ); + }, + onSelect: function (e, term, item) { + var numerics = wmgui.numerics[term]; + + if (isVisible($('#numericbox')) && numerics) + create_floating_slider( + term, + numerics[0], + numerics[1], + numerics[2], + numerics[3], + numerics[4], + ); + else window.location.hash = wmgui.aug_search_cmd('props', term); + + $('#hy_suggest').value = ''; + }, + }); + + rotate_interesting(); + setInterval(rotate_interesting, 2000); + + window.location.hash + ? url_redraw_react() + : window.location.replace('#start'); + }) + .catch(function (errorThrown) { + console.error(errorThrown); + throw new Error('Failed to load GUI'); + }); + + // set server-side data features + wmgui.multiselects['main'] = create_multiselect($('#search_field'), { + plugins: ['remove_button', 'preserve_on_blur'], + valueField: 'id', + labelField: 'label', + searchField: 'label', + create: false, + highlight: false, + maxItems: 10, + closeAfterSelect: true, + diacritics: false, + options: [], + onInitialize: function () { + $('#search_field-selectized').focus(); + }, + onItemAdd: function () { + if (wmgui.selectize_emit) { + var check = wmgui.multiselects['main'].read(); + select_ptable_series(check.elements); + } + }, + onItemRemove: function () { + var check = wmgui.multiselects['main'].read(), + input = this; + if (!check.numeric) { + destroy_numericbox(); + delete wmgui.search.numeric; + if (wmgui.selectize_emit) select_ptable_series(check.elements); + } + setTimeout(function () { + input.close(); + }, 750); + }, + load: function (query, callback) { + this.clearOptions(); + if (!query.length) return callback(); + ajax({ + url: wmgui.auto_endpoint + '?q=' + encodeURIComponent(query), + type: 'GET', + }) + .then(function (res) { + if (!res.length) { + return; + } + callback(res); + }) + .catch(function () { + callback(); + }); + }, + score: function () { + return function () { + return 1; + }; + }, // no client scoring + render: { + option: function (item, escape) { + return '
    ' + item.label + '
    '; + }, + item: function (item, escape) { + return ( + '
    ' + + item.label + + '
    ' + ); + }, + }, + }); + + wmgui.multiselects['main'].read = function () { + return wmgui._selectize_read_main(); + }; + wmgui.multiselects['main'].write = function (search_obj) { + wmgui._selectize_write(wmgui.multiselects['main'], 'main', search_obj); + }; + wmgui.multiselects['main'].display = function (facet, term) { + wmgui._selectize_display(wmgui.multiselects['main'], facet, term); + }; + + wmgui.darkmode = new Darkmode({ saveInCookies: false }); + document.getElementById('darkmode_trigger').innerHTML = + wmgui.darkmode.isActivated() ? 'enabled' : 'disabled'; + + //create_floating_slider('density', 42, 'Mg/m3', 10, 900, 10); + // EOF satisfy_requirements +} diff --git a/src_js/components/autocomplete.js b/src_js/components/autocomplete.js new file mode 100644 index 0000000..04f6dfd --- /dev/null +++ b/src_js/components/autocomplete.js @@ -0,0 +1,270 @@ +// spin-off from https://github.com/Pixabay/JavaScript-autoComplete +// converted to an ES module + +import { show_aetmap } from '../app/search.js'; + +export const create_autocomplete = (function () { + function autoComplete(options) { + if (!document.querySelector) return; + + // helpers + function hasClass(el, className) { + return el.classList + ? el.classList.contains(className) + : new RegExp('\\b' + className + '\\b').test(el.className); + } + + function addEvent(el, type, handler) { + el.addEventListener(type, handler); + } + function removeEvent(el, type, handler) { + el.removeEventListener(type, handler); + } + function live(elClass, event, cb, context) { + addEvent(context || document, event, function (e) { + var found, + el = e.target || e.srcElement; + while (el && !(found = hasClass(el, elClass))) el = el.parentElement; + if (found) cb.call(el, e); + }); + } + + var o = { + selector: 0, + source: 0, + minChars: 3, + delay: 150, + offsetLeft: 0, + offsetTop: 1, + cache: 1, + menuClass: '', + renderItem: function (item, search) {}, + onSelect: function (e, term, item) {}, + arrow_pressed: false, + custom_type: false, + }; + for (var k in options) { + if (options.hasOwnProperty(k)) o[k] = options[k]; + } + + // init + var that = document.getElementById(o.selector), + fct_type = that.getAttribute('rel'); + + // create suggestions container "sc" + that.sc = document.createElement('div'); + that.sc.className = 'autocomplete-suggestions ' + o.menuClass; + + that.autocompleteAttr = that.getAttribute('autocomplete'); + that.setAttribute('autocomplete', 'off'); + that.cache = {}; + that.last_val = ''; + + that.updateSC = function (resize, next) { + var rect = that.getBoundingClientRect(); + that.sc.style.left = + Math.round( + rect.left + + (window.pageXOffset || document.documentElement.scrollLeft) + + o.offsetLeft, + ) + 'px'; + that.sc.style.top = + Math.round( + rect.bottom + + (window.pageYOffset || document.documentElement.scrollTop) + + o.offsetTop, + ) + 'px'; + that.sc.style.width = Math.round(rect.right - rect.left) + 'px'; // outerWidth + if (!resize) { + that.sc.style.display = 'block'; + if (!that.sc.maxHeight) { + that.sc.maxHeight = parseInt( + (window.getComputedStyle + ? getComputedStyle(that.sc, null) + : that.sc.currentStyle + ).maxHeight, + ); + } + if (!that.sc.suggestionHeight) + that.sc.suggestionHeight = that.sc.querySelector( + '.autocomplete-suggestion', + ).offsetHeight; + if (that.sc.suggestionHeight) + if (!next) that.sc.scrollTop = 0; + else { + var scrTop = that.sc.scrollTop, + selTop = + next.getBoundingClientRect().top - + that.sc.getBoundingClientRect().top; + if (selTop + that.sc.suggestionHeight - that.sc.maxHeight > 0) + that.sc.scrollTop = + selTop + that.sc.suggestionHeight + scrTop - that.sc.maxHeight; + else if (selTop < 0) that.sc.scrollTop = selTop + scrTop; + } + } + }; + addEvent(window, 'resize', that.updateSC); + document.body.appendChild(that.sc); + + live( + 'autocomplete-suggestion', + 'mouseleave', + function (e) { + var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); + if (sel) + setTimeout(function () { + sel.className = sel.className.replace('selected', ''); + }, 20); + }, + that.sc, + ); + + live( + 'autocomplete-suggestion', + 'mouseover', + function (e) { + var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); + if (sel) sel.className = sel.className.replace('selected', ''); + this.className += ' selected'; + + // account aetypes aetmap + if (o.custom_type == 'aetypes' && show_aetmap) + show_aetmap(this.innerText); + }, + that.sc, + ); + + live( + 'autocomplete-suggestion', + 'mousedown', + function (e) { + if (hasClass(this, 'autocomplete-suggestion')) { + // else outside click + var v = this.getAttribute('data-val'); + that.value = v; + o.onSelect(e, v, this); + that.sc.style.display = 'none'; + } + }, + that.sc, + ); + + that.blurHandler = function () { + try { + var over_sb = document.querySelector('.autocomplete-suggestions:hover'); + } catch (e) { + var over_sb = 0; + } + if (!over_sb) { + that.last_val = that.value; + that.sc.style.display = 'none'; + setTimeout(function () { + that.sc.style.display = 'none'; + }, 350); // hide suggestions on fast input + } else if (that !== document.activeElement) + setTimeout(function () { + that.focus(); + }, 20); + }; + addEvent(that, 'blur', that.blurHandler); + + var suggest = function (data) { + o.arrow_pressed = false; + var val = that.value; + that.cache[val] = data; + if (data.length && val.length >= o.minChars) { + var s = ''; + for (var i = 0; i < data.length; i++) s += o.renderItem(data[i], val); + that.sc.innerHTML = s; + that.updateSC(0); + } else that.sc.style.display = 'none'; + }; + + that.keydownHandler = function (e) { + var key = window.event ? e.keyCode : e.which; + // down (40), up (38) + if ((key == 40 || key == 38) && that.sc.innerHTML) { + o.arrow_pressed = true; + var next, + sel = that.sc.querySelector('.autocomplete-suggestion.selected'); + if (!sel) { + next = + key == 40 + ? that.sc.querySelector('.autocomplete-suggestion') + : that.sc.childNodes[that.sc.childNodes.length - 1]; // first : last + next.className += ' selected'; + that.value = next.getAttribute('data-val'); + } else { + next = key == 40 ? sel.nextSibling : sel.previousSibling; + if (next) { + sel.className = sel.className.replace('selected', ''); + next.className += ' selected'; + that.value = next.getAttribute('data-val'); + } else { + sel.className = sel.className.replace('selected', ''); + that.value = that.last_val; + next = 0; + } + } + that.updateSC(0, next); + return false; + } + // esc + else if (key == 27) { + that.value = that.last_val; + that.sc.style.display = 'none'; + } + // enter + else if (key == 13 || key == 9) { + var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); + if (sel && that.sc.style.display != 'none' && o.arrow_pressed) { + o.onSelect(e, sel.getAttribute('data-val'), sel); + that.sc.style.display = 'none'; + //setTimeout(function(){ that.sc.style.display = 'none'; }, 20); + } + } + }; + addEvent(that, 'keydown', that.keydownHandler); + + that.keyupHandler = function (e) { + var key = window.event ? e.keyCode : e.which; + if (!key || ((key < 35 || key > 40) && key != 13 && key != 27)) { + var val = that.value; + if (val.length >= o.minChars) { + if (val != that.last_val) { + that.last_val = val; + clearTimeout(that.timer); + if (o.cache) { + if (val in that.cache) { + suggest(that.cache[val]); + return; + } + // no requests if previous suggestions were empty + for (var i = 1; i < val.length - o.minChars; i++) { + var part = val.slice(0, val.length - i); + if (part in that.cache && !that.cache[part].length) { + suggest([]); + return; + } + } + } + that.timer = setTimeout(function () { + o.source(val, fct_type, suggest); + }, o.delay); + } + } else { + that.last_val = val; + that.sc.style.display = 'none'; + } + } + }; + addEvent(that, 'keyup', that.keyupHandler); + + that.focusHandler = function (e) { + that.last_val = '\n'; + that.keyupHandler(e); + }; + if (!o.minChars) addEvent(that, 'focus', that.focusHandler); + } + return autoComplete; +})(); diff --git a/src_js/components/multiselect.js b/src_js/components/multiselect.js new file mode 100644 index 0000000..3fb7d1b --- /dev/null +++ b/src_js/components/multiselect.js @@ -0,0 +1,365 @@ +/** + * Ermac multiselect: a vanilla replacement for the selectize jQuery plugin, + * reusing the same CSS class contract (.selectize-control / .selectize-input / + * .selectize-dropdown, see webassets/ermac.css) and the same item DOM contract + * (data-facet / data-term attributes), so that the app reading paths stay identical. + * + * API mirrors the subset of selectize actually used by Ermac: + * addOption(data), addItem(id), clearOptions(), clear(), close(), items, + * and the callbacks: onInitialize, onChange, onItemAdd, onItemRemove, load. + * The text input keeps the selectize id convention: -selectized. + */ + +export function create_multiselect(select_el, settings) { + const self = { + settings: settings || {}, + options: {}, // id -> {facet, label, id} + items: [], // array of {facet, label, id} + opened: false, + active_option: null, + counter: 0, + load_timer: null, + }; + + const render_item = + (settings.render && settings.render.item) || + function (item) { + return ( + '
    ' + + item.label + + '
    ' + ); + }; + + const render_option = + (settings.render && settings.render.option) || + function (item) { + return '
    ' + item.label + '
    '; + }; + + const max_items = settings.maxItems || Infinity; + + // DOM structure mirroring selectize: + + const control = document.createElement('div'); + control.className = 'selectize-control plugin-remove_button multi'; + + const input_holder = document.createElement('div'); + input_holder.className = 'selectize-input items not-full'; + control.appendChild(input_holder); + + const text_input = document.createElement('input'); + text_input.type = 'text'; + text_input.autocomplete = 'off'; + text_input.id = (select_el.id ? select_el.id : '') + '-selectized'; + text_input.setAttribute('role', 'combobox'); + input_holder.appendChild(text_input); + + const dropdown = document.createElement('div'); + dropdown.className = 'selectize-dropdown multi plugin-remove_button'; + dropdown.style.display = 'none'; + const dropdown_content = document.createElement('div'); + dropdown_content.className = 'selectize-dropdown-content'; + dropdown.appendChild(dropdown_content); + control.appendChild(dropdown); + + select_el.style.display = 'none'; + select_el.insertAdjacentElement('afterend', control); + + /** + * Options dropdown management + */ + + function render_dropdown() { + dropdown_content.innerHTML = ''; + for (const id in self.options) { + const option_data = self.options[id]; + const tpl = document.createElement('template'); + tpl.innerHTML = render_option(option_data).trim(); + const option_el = tpl.content.firstElementChild; + if (option_el) { + option_el.setAttribute('data-selectable', ''); + option_el.setAttribute('data-value', id); + if (self.active_option === id) option_el.classList.add('active'); + dropdown_content.appendChild(option_el); + } + } + } + + function open() { + if (self.opened || !dropdown_content.children.length) return; + self.opened = true; + input_holder.classList.add('dropdown-active'); + dropdown.style.display = 'block'; + } + + self.open = open; + + self.close = function () { + if (!self.opened) return; + self.opened = false; + self.active_option = null; + input_holder.classList.remove('dropdown-active'); + dropdown.style.display = 'none'; + }; + + function set_active_option(id) { + self.active_option = id; + dropdown_content + .querySelectorAll('.option, [data-selectable]') + .forEach(function (el) { + el.classList.toggle('active', el.getAttribute('data-value') === id); + }); + } + + /** + * Items management + */ + + function get_value(data) { + // valueField is 'id' by contract with the app + return data.id; + } + + self.addOption = function (data) { + if (Array.isArray(data)) { + data.forEach(function (d) { + self.addOption(d); + }); + return; + } + self.counter += 1; + if (data.id === undefined) data.id = self.counter; + self.options[data.id] = data; + }; + + self.clearOptions = function () { + self.options = {}; + self.active_option = null; + self.close(); + }; + + function refresh_state() { + input_holder.classList.toggle('has-items', self.items.length > 0); + input_holder.classList.toggle('full', self.items.length >= max_items); + text_input.readOnly = self.items.length >= max_items; + } + + function trigger(event_name, a, b) { + const callback = self.settings[event_name]; + if (typeof callback === 'function') callback.apply(self, [a, b]); + if ( + event_name === 'onItemAdd' || + event_name === 'onItemRemove' || + event_name === 'clear' + ) { + if (typeof self.settings.onChange === 'function') + self.settings.onChange.call( + self, + self.items + .map(function (item) { + return item.label; + }) + .join(','), + ); + } + } + + self.addItem = function (id) { + if ( + self.items.some(function (item) { + return get_value(item) === id; + }) + ) + return; + if (!self.options.hasOwnProperty(id)) return; + if (self.items.length >= max_items) return; + + const option_data = self.options[id]; + + const tpl = document.createElement('template'); + tpl.innerHTML = render_item(option_data).trim(); + const item_el = tpl.content.firstElementChild; + if (!item_el) return; + + // remove_button plugin behavior + const remove_anchor = document.createElement('a'); + remove_anchor.href = 'javascript:void(0)'; + remove_anchor.className = 'remove'; + remove_anchor.tabIndex = -1; + remove_anchor.title = 'Remove'; + remove_anchor.innerHTML = '×'; + item_el.appendChild(remove_anchor); + + input_holder.insertBefore(item_el, text_input); + self.items.push(option_data); + refresh_state(); + + if (self.settings.closeAfterSelect !== false) self.close(); + text_input.value = ''; + set_active_option(null); + + trigger('onItemAdd', id, item_el); + }; + + self.removeItem = function (id, item_el) { + const index = self.items.findIndex(function (item) { + return get_value(item) === id; + }); + if (index === -1) return; + if (!item_el) + item_el = input_holder.querySelector( + '[data-value="' + + id + + '"], [data-term="' + + (self.items[index] && self.items[index].label) + + '"]', + ); + if (item_el && item_el.parentNode === input_holder) + input_holder.removeChild(item_el); + self.items.splice(index, 1); + refresh_state(); + trigger('onItemRemove', id, item_el); + }; + + self.clear = function () { + const previous = self.items; + self.items = []; + input_holder.querySelectorAll('div').forEach(function (el) { + input_holder.removeChild(el); + }); + refresh_state(); + if (previous.length) trigger('clear'); + }; + + /** + * Event wiring + */ + + input_holder.addEventListener('mousedown', function (event) { + // item click: focus the text input (mimicking selectize caret behavior) + if (event.target === text_input) return; + event.preventDefault(); + text_input.focus(); + }); + + control.addEventListener('click', function (event) { + const remove_button = event.target.closest('a.remove'); + if (remove_button) { + event.preventDefault(); + event.stopPropagation(); + const item_el = remove_button.parentNode; + const data_term = item_el.getAttribute('data-term'); + const found = self.items.find(function (item) { + return item.label === data_term; + }); + if (found) self.removeItem(get_value(found), item_el); + text_input.focus(); + return; + } + + const option_el = event.target.closest('[data-selectable]'); + if (option_el && dropdown_content.contains(option_el)) { + event.preventDefault(); + event.stopPropagation(); + self.addItem(option_el.getAttribute('data-value')); + } + }); + + dropdown_content.addEventListener('mouseover', function (event) { + const option_el = event.target.closest('[data-selectable]'); + if (option_el) set_active_option(option_el.getAttribute('data-value')); + }); + + text_input.addEventListener('input', function () { + clearTimeout(self.load_timer); + const query = text_input.value; + if (typeof self.settings.load !== 'function') return; + self.load_timer = setTimeout(function () { + self.settings.load.call(self, query, function (suggestions) { + if (!suggestions || !suggestions.length) { + self.close(); + return; + } + self.addOption(suggestions); + render_dropdown(); + open(); + }); + }, 300); // mimicking selectize default loadThrottle + }); + + text_input.addEventListener('keydown', function (event) { + const selectable = dropdown_content.querySelectorAll('[data-selectable]'); + const active_el = dropdown_content.querySelector( + '[data-selectable].active', + ); + + if (event.key === 'ArrowDown' || event.key === 'ArrowUp') { + if (!selectable.length) return; + event.preventDefault(); + if (!self.opened) { + open(); + set_active_option(selectable[0].getAttribute('data-value')); + return; + } + let next; + if (!active_el) { + next = + event.key === 'ArrowDown' + ? selectable[0] + : selectable[selectable.length - 1]; + } else { + next = + event.key === 'ArrowDown' + ? active_el.nextElementSibling + : active_el.previousElementSibling; + } + if (next) set_active_option(next.getAttribute('data-value')); + } else if (event.key === 'Enter') { + if (self.opened && active_el) { + event.preventDefault(); + event.stopPropagation(); + self.addItem(active_el.getAttribute('data-value')); + } + } else if (event.key === 'Escape') { + if (self.opened) event.stopPropagation(); + self.close(); + } else if ( + event.key === 'Backspace' && + !text_input.value && + self.items.length + ) { + const last = self.items[self.items.length - 1]; + const item_el = input_holder.querySelector('div:last-of-type'); + self.removeItem(get_value(last), item_el); + } + }); + + text_input.addEventListener('focus', function () { + input_holder.classList.add('focus'); + input_holder.classList.add('input-active'); + if (dropdown_content.children.length) open(); + }); + + text_input.addEventListener('blur', function () { + input_holder.classList.remove('focus'); + input_holder.classList.remove('input-active'); + // preserve_on_blur plugin behavior: keep the typed text + self.close(); + }); + + // the "rest input" is read by the app via the id convention + self.input_el = text_input; + + refresh_state(); + if (typeof self.settings.onInitialize === 'function') + self.settings.onInitialize(); + + return self; +} diff --git a/src_js/components/sliders.js b/src_js/components/sliders.js new file mode 100644 index 0000000..e324038 --- /dev/null +++ b/src_js/components/sliders.js @@ -0,0 +1,140 @@ +/** + * Ermac numeric range sliders, based on the vendored vanilla noUiSlider. + */ + +/* global noUiSlider, wNumb */ + +import wmgui from '../core/settings.js'; +import { $, $$, show, hide, isVisible } from '../core/dom.js'; + +export function create_floating_slider( + prop_name, + prop_id, + units, + p_min, + p_max, + p_step, + p_start, + p_end, +) { + // FIXME compatibilize with *wmgui.numerics* + + if (document.getElementById('slider_' + prop_id)) { + console.log('Attempted to create an existing slider id' + prop_id); + return; + } + + var html = '
  • '; + html += '
    '; + html += + (wmgui.numerics[prop_name][5] || prop_name) + + (units ? ', ' + units + '' : ''); + html += '
    '; + html += '
    '; + html += '
    '; // #numericbox > ul > li > div.slider + html += + ''; + html += + '
    '; + html += '
  • '; + + show($('#numericbox')); + $('#numericbox > ul').insertAdjacentHTML('afterbegin', html); + + var decimals = p_step + ? Math.abs(Math.log10(p_step)) + : Math.max(p_min.count_decimals(), p_max.count_decimals()); + //console.log('decimals = ', decimals); + + noUiSlider.create(document.getElementById('slider_' + prop_id), { + start: [p_start || p_min, p_end || p_max], + step: p_step || (p_max - p_min) / 250, + tooltips: [wNumb({ decimals: decimals }), wNumb({ decimals: decimals })], + connect: true, + behaviour: 'drag', + range: { min: p_min, max: p_max }, + format: { + to: function (value) { + return value; + }, + from: function (value) { + return Number(value); + }, + }, + }); +} + +export function destroy_numericbox() { + const numericbox = $('#numericbox'); + if (isVisible(numericbox)) { + $$('#numericbox > ul > li').forEach(function (li) { + const slider = li.querySelector('div.slider_numerics'); + if (slider && slider.noUiSlider) slider.noUiSlider.destroy(); + li.remove(); + }); + hide(numericbox); + } +} + +export function get_sliders_ranges(url_num_obj, num_database) { + // given by: + // (1.) wmutils.guess, or + // (2.) from re-inventing serialization for numeric nested arrays, or + // (3.) by the user + var props = {}, + output = []; + + for (var i = 0; i < url_num_obj.length; i++) { + if (url_num_obj[i][1] !== '>' && url_num_obj[i][1] !== '<') continue; + + var prop = url_num_obj[i][1] == '>' ? 'start' : 'end'; + + if (!props[url_num_obj[i][0]]) props[url_num_obj[i][0]] = {}; + + props[url_num_obj[i][0]][prop] = parseFloat(url_num_obj[i][2]); // TODO? consequent series like > 100, > 200, etc. + } + //console.log(props); + for (var key in props) { + if (!num_database[key]) { + console.log('Unsupported key: ' + key); + continue; + } + + if (!props[key]['start']) + props[key]['start'] = num_database[key][2]; // min + else if (!props[key]['end']) props[key]['end'] = num_database[key][3]; // max + + if (props[key]['end'] < props[key]['start']) + throw new Error('The end of range is lower than the start of range!'); + output.push([ + key, + num_database[key][0], + num_database[key][1], + num_database[key][2], + num_database[key][3], + num_database[key][4], + props[key]['start'], + props[key]['end'], + ]); + } + output.sort(function (a, b) { + return a[1] > b[1] ? 1 : -1; // prop_id + }); + return output; +} + +export function serialize_numeric(prop, sign, value) { + // re-inventing serialization for numeric nested arrays + return prop + ',' + sign + ',' + value + ';'; +} diff --git a/src_js/components/tablesort.js b/src_js/components/tablesort.js new file mode 100644 index 0000000..3270af8 --- /dev/null +++ b/src_js/components/tablesort.js @@ -0,0 +1,104 @@ +/** + * Ermac table sorter: a vanilla replacement for the jquery.tablesorter plugin, + * reusing the same CSS class contract (th.header, th.headerSortUp, + * th.headerSortDown, see webassets/ermac.css). + * + * The data table body and the header cells live in two separate tables + * (the old tablesorter 'selectorHeaders' / 'selectorHeaderParent' use case). + * Ctrl-click appends a column to the current multi-sort. + */ + +function cell_text(row, col) { + const cell = row.cells[col]; + return cell ? cell.textContent.trim() : ''; +} + +function format_float(str) { + const num = parseFloat(str.replace(/[^0-9.\-]/g, '')); + return isNaN(num) ? 0 : num; +} + +function compare_cells(a, b, col, sorter) { + const va = cell_text(a, col), + vb = cell_text(b, col); + if (sorter === 'digit') { + const na = format_float(va), + nb = format_float(vb); + return na < nb ? -1 : na > nb ? 1 : 0; + } + // NB 'doi' and 'chemical' behave as plain text, exactly like the old plugin + return va < vb ? -1 : va > vb ? 1 : 0; +} + +export function make_sortable(data_table, options) { + options = options || {}; + const header_cells = document.querySelectorAll(options.selectorHeaders); + const headers_conf = options.headers || {}; + const tbody = data_table.tBodies[0]; + + let sortlist = []; // [{col, dir}] where dir 0 = asc, 1 = desc + + function header_sorter(index) { + const conf = headers_conf[index]; + return conf && conf.sorter !== undefined ? conf.sorter : 'text'; + } + + function apply() { + if (!sortlist.length || !tbody) return; + const rows = Array.prototype.slice.call(tbody.rows); + rows.sort(function (a, b) { + for (let i = 0; i < sortlist.length; i++) { + const { col, dir } = sortlist[i]; + const result = compare_cells(a, b, col, header_sorter(col)); + if (result !== 0) return dir === 1 ? -result : result; + } + return 0; + }); + rows.forEach(function (row) { + tbody.appendChild(row); + }); + } + + function refresh_header_classes() { + header_cells.forEach(function (th, index) { + th.classList.remove('headerSortUp', 'headerSortDown'); + const found = sortlist.find(function (entry) { + return entry.col === index; + }); + if (found) + th.classList.add(found.dir === 1 ? 'headerSortDown' : 'headerSortUp'); + }); + } + + header_cells.forEach(function (th, index) { + if (header_sorter(index) === false) return; // unsortable column + th.classList.add('header'); + th.style.cursor = 'pointer'; + th.addEventListener('click', function (event) { + const existing = sortlist.find(function (entry) { + return entry.col === index; + }); + + if (event.ctrlKey && options.sortMultiSortKey === 'ctrlKey') { + if (existing) existing.dir = existing.dir === 0 ? 1 : 0; + else sortlist.push({ col: index, dir: 0 }); + } else { + if (existing && sortlist.length === 1) + existing.dir = existing.dir === 0 ? 1 : 0; + else sortlist = [{ col: index, dir: 0 }]; + } + refresh_header_classes(); + apply(); + }); + }); + + return { + update: apply, + destroy: function () { + sortlist = []; + header_cells.forEach(function (th) { + th.classList.remove('header', 'headerSortUp', 'headerSortDown'); + }); + }, + }; +} diff --git a/src_js/core/ajax.js b/src_js/core/ajax.js new file mode 100644 index 0000000..044932a --- /dev/null +++ b/src_js/core/ajax.js @@ -0,0 +1,87 @@ +/** + * Ermac AJAX: a minimal promise-based XMLHttpRequest wrapper, + * keeping cross-domain credentials and abortability of the old jQuery $.ajax calls. + * + * Returns a promise, additionally fitted with an .abort() method. + * The promise resolves with the parsed response, or rejects with + * {aborted: true} for aborted requests, or {status: N} otherwise. + */ + +export function ajax(settings) { + const xhr = new XMLHttpRequest(); + let url = settings.url; + const type = (settings.type || 'GET').toUpperCase(); + let query = null; + + if (settings.data) { + if (type === 'GET') { + url += (url.indexOf('?') === -1 ? '?' : '&') + param(settings.data); + } else { + query = param(settings.data); + } + } + + const promise = new Promise(function (resolve, reject) { + xhr.onreadystatechange = function () { + if (xhr.readyState !== 4) return; + if (xhr.status === 0) return reject({ aborted: true, xhr: xhr }); + if (xhr.status >= 200 && xhr.status < 300) { + let answer = xhr.responseText; + if ( + settings.dataType === 'json' || + (settings.dataType !== 'text' && + (xhr.getResponseHeader('Content-Type') || '').indexOf('json') !== + -1) + ) { + try { + answer = JSON.parse(answer); + } catch (e) { + /* keep raw text */ + } + } + resolve(answer); + } else { + reject({ status: xhr.status, xhr: xhr }); + } + }; + xhr.open(type, url); + xhr.withCredentials = true; + if (type === 'POST' && query) { + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + } + xhr.send(query); + }); + + promise.abort = function () { + try { + xhr.abort(); + } catch (e) {} + }; + return promise; +} + +/** + * URL query serialization, mimicking jQuery $.param(): + * encodeURIComponent with spaces encoded as '+'. + */ + +export function param(obj) { + const parts = []; + for (const key in obj) { + if (obj[key] === undefined || obj[key] === null) continue; + parts.push( + encodeURIComponent(key) + + '=' + + encodeURIComponent(String(obj[key])).replace(/%20/g, '+'), + ); + } + return parts.join('&'); +} + +export function is_empty(obj) { + if (!obj) return true; + for (const key in obj) { + if (obj.hasOwnProperty(key)) return false; + } + return true; +} diff --git a/src_js/core/dom.js b/src_js/core/dom.js new file mode 100644 index 0000000..f4ce35c --- /dev/null +++ b/src_js/core/dom.js @@ -0,0 +1,221 @@ +/** + * Ermac DOM helpers: a minimal vanilla replacement for the jQuery idioms used in this codebase. + */ + +export function $(selector, root) { + return (root || document).querySelector(selector); +} + +export function $$(selector, root) { + return Array.prototype.slice.call( + (root || document).querySelectorAll(selector), + ); +} + +/** + * Element data store, mimicking jQuery .data(key, value) + */ + +const data_store = new WeakMap(); + +export function data(el, key, value) { + if (value !== undefined) { + if (!data_store.has(el)) data_store.set(el, {}); + data_store.get(el)[key] = value; + return value; + } + const stored = data_store.get(el); + return stored && stored[key] !== undefined ? stored[key] : undefined; +} + +/** + * Display control + */ + +export function show(els, display) { + if (!els) return; + if (!Array.isArray(els)) els = [els]; + els.forEach(function (el) { + if (el) el.style.display = display || 'block'; + }); +} + +export function hide(els) { + if (!els) return; + if (!Array.isArray(els)) els = [els]; + els.forEach(function (el) { + if (el) el.style.display = 'none'; + }); +} + +export function toggle_display(els, display) { + if (!els) return; + if (!Array.isArray(els)) els = [els]; + els.forEach(function (el) { + if (el) el.style.display = isVisible(el) ? 'none' : display || 'block'; + }); +} + +export function isVisible(el) { + return !!( + el && + (el.offsetParent || + el.offsetWidth || + el.offsetHeight || + el.getClientRects().length) + ); +} + +/** + * Content manipulation + */ + +export function set_html(el, markup) { + if (el) el.innerHTML = markup; +} + +export function append_html(el, markup) { + if (el) el.insertAdjacentHTML('beforeend', markup); +} + +export function prepend_html(el, markup) { + if (el) el.insertAdjacentHTML('afterbegin', markup); +} + +export function after_html(el, markup) { + if (el) el.insertAdjacentHTML('afterend', markup); +} + +export function empty(els) { + if (!Array.isArray(els)) els = [els]; + els.forEach(function (el) { + if (el) while (el.firstChild) el.removeChild(el.firstChild); + }); +} + +export function remove(els) { + if (!Array.isArray(els)) els = [els]; + els.forEach(function (el) { + if (el && el.parentNode) el.parentNode.removeChild(el); + }); +} + +/** + * Attributes, values, classes + */ + +export function get_attr(el, name) { + return el ? el.getAttribute(name) : null; +} + +export function set_attr(el, name, value) { + if (el) el.setAttribute(name, value); +} + +export function get_val(el) { + return el ? el.value : ''; +} + +export function set_val(el, value) { + if (el) el.value = value; +} + +export function get_text(el) { + return el ? el.textContent : ''; +} + +/** + * Geometry, mimicking jQuery .offset() and .position() + */ + +export function offset(el) { + if (!el) return { left: 0, top: 0 }; + const rect = el.getBoundingClientRect(); + return { + left: rect.left + window.scrollX, + top: rect.top + window.scrollY, + }; +} + +export function position(el) { + if (!el) return { left: 0, top: 0 }; + const rect = el.getBoundingClientRect(); + if (!el.offsetParent) return { left: rect.left, top: rect.top }; + const parent = el.offsetParent.getBoundingClientRect(); + return { + left: rect.left - parent.left - el.offsetParent.clientLeft, + top: rect.top - parent.top - el.offsetParent.clientTop, + }; +} + +export function scroll_top() { + return window.scrollY || document.documentElement.scrollTop; +} + +export function window_height() { + return window.innerHeight || document.documentElement.clientHeight; +} + +/** + * Simple animations, mimicking jQuery slideUp/slideDown/fadeOut + */ + +function animate(el, from, to, duration, on_finish) { + const start = performance.now(); + el.style.overflow = 'hidden'; + function step(now) { + const progress = Math.min((now - start) / duration, 1); + el.style.height = from + (to - from) * progress + 'px'; + if (progress < 1) requestAnimationFrame(step); + else { + el.style.overflow = ''; + el.style.height = ''; + if (on_finish) on_finish(); + } + } + requestAnimationFrame(step); +} + +export function slide_up(el, duration, on_finish) { + if (!el || !isVisible(el)) { + if (on_finish) on_finish(); + return; + } + const h = el.offsetHeight; + animate(el, h, 0, duration || 250, function () { + el.style.display = 'none'; + if (on_finish) on_finish(); + }); +} + +export function slide_down(el, duration) { + if (!el) return; + el.style.display = ''; // NB let the natural display apply, mimicking jQuery + if (!isVisible(el)) el.style.display = 'block'; + const h = el.offsetHeight; + animate(el, 0, h, duration || 250); +} + +export function fade_out(el, duration, on_finish) { + if (!el) { + if (on_finish) on_finish(); + return; + } + el.style.transition = 'opacity ' + (duration || 250) / 1000 + 's'; + el.style.opacity = '0'; + setTimeout(on_finish || function () {}, duration || 250); +} + +/** + * Delegated events, mimicking jQuery .on(event, selector, handler) + */ + +export function on(root, selector, type, handler) { + (root || document).addEventListener(type, function (event) { + const matched = event.target.closest + ? event.target.closest(selector) + : null; + if (matched && (root || document).contains(matched)) + handler.call(matched, event, matched); + }); +} diff --git a/src_js/core/settings.js b/src_js/core/settings.js new file mode 100644 index 0000000..b3c83a5 --- /dev/null +++ b/src_js/core/settings.js @@ -0,0 +1,541 @@ +/** + * Ermac global state, constants, API endpoint URLs, edition configs. + * The state object is exposed as window.wmgui for embeddability (external host apps + * may override wmgui.mpdsgui hooks or call wmgui.notify), while remaining + * a regular ES module export internally. + */ + +import { $, $$, hide, show, set_html } from './dom.js'; + +const wmgui = {}; +window.wmgui = wmgui; +export default wmgui; + +wmgui.search = {}; // the main object containing the app state synced to the server +wmgui.search_type = 0; // 0 = entries, 1 = phases, or 2 = articles (NB copied into the main state object, defines *without_history*) +wmgui.view_mode = 1; // 1 = intro screen, 2 = results screen +wmgui.thumbed_display = false; +wmgui.ctx_strict_phases = ''; // empty string or anything (bool) +//wmgui.ctx_subphases = ''; // empty string or anything (bool) +wmgui.ntab_tolerance = 100; +wmgui.chosen_table_browser = false; +wmgui.fuzzyout = false; +wmgui.passive_sim_col = true; + +wmgui.active_ajax = null; +wmgui.quick_ajax = null; + +// these are all usual search categories +wmgui.facets = [ + 'formulae', + 'props', + 'elements', + 'classes', + 'lattices', + 'sgs', + 'protos', + 'authors', + 'years', + 'codens', + 'doi', + 'aeatoms', + 'aetypes', + 'geos', + 'orgs', + 'wyckoff', +]; + +// these are those categories only accessible from the advanced search menu +wmgui.inquiries = [ + 'sgs', + 'protos', + 'authors', + 'years', + 'codens', + 'doi', + 'aeatoms', + 'aetypes', + 'geos', + 'orgs', + 'wyckoff', +]; +wmgui.other_facets = wmgui.inquiries.filter(function (item) { + return item !== 'aetypes'; +}); // NOT main search field or NLP-handled +wmgui.simple_facets = [ + 'formulae', + 'props', + 'elements', + 'lattices', + 'sgs', + 'protos', + 'years', + 'codens', + 'doi', + 'aeatoms', + 'geos', + 'orgs', +]; +wmgui.multi_facets = ['classes', 'authors', 'aetypes', 'wyckoff']; +wmgui.facet_names = { + props: 'Physical properties', + elements: 'Chemical elements', + classes: 'Materials classes', + lattices: 'Crystal systems', + formulae: 'Chemical formulae', + protos: 'Prototypes', + sgs: 'Space groups', + numeric: 'Numerical search', // NB not a real facet + authors: 'Authors', + years: 'Years', + codens: 'Journal codes', + doi: 'DOI', + aeatoms: 'Polyhedron atoms', + aetypes: 'Polyhedral types', + geos: 'Geography', + orgs: 'Organization', + wyckoff: 'Wyckoff search', // also positions and sequence +}; +wmgui.multiselects = {}; // multiselect component instances, for *wmgui.multi_facets* and *main* +wmgui.selectize_emit = true; +wmgui.unfinished_page = false; +wmgui.quick_page_size = 150; +wmgui.fetch_page_size = 850; +wmgui.notify_counter = null; +wmgui.cliff_counter = null; +wmgui.sid = null; +wmgui.oauths = null; +wmgui.prod = window.location.host.indexOf('localhost') === -1; +wmgui.darkmode = null; + +wmgui.cliffhangers = [ + 'binary compounds with negative thermal expansion', + 'band gap of hexagonal ZnO', + 'ternary oxides of indium', + //"microhardness < 0.05", + //"temperature for metal-nonmetal transition < 10", + //"thermoelectric figure of merit > 0.5", + 'electronic properties for semiconductor carbides', + //"c/a > 3, a/b > 3, density < 4", + 'noble gases superconductivity', + 'W-Mo ternary phase diagram', + //"density < 3 and temperature for congruent melting > 2000", + 'tetragonal SrTiO₃ phonons', + 'radioactive elements conductivity', + 'O₃Al₂ elastic properties', + //"refractive index > 5", // FIXME + 'sidorenkite crystal cell', + //"birefringence < 0.005 and static permittivity > 7.5", + 'phase diagrams from ab initio literature', + //"adiabatic bulk modulus > 250 and isothermal bulk modulus > 250", + 'magnetic properties of binary compounds', + 'radioactive binary compounds', + 'binary frank-kasper type', + 'liquidus projection phase diagrams', +]; +wmgui.welcome_msgs = [ + "The distinct phases is the central concept at the MPDS. Thanks to it, the crystal structures are linked to the phase diagrams and physical properties. Any distinct phase is uniquely determined by its chemical formula, space group, and Pearson symbol e.g. CuAl2 140 tI12.", + "Our data back up such products as Springer Materials, ICDD PDF-5+, ASM Alloy Phase Diagrams, Pearson's Crystal Data, MedeA Materials Design, and AtomWork Advanced.", + 'Each peer-reviewed crystal structure, phase diagram, or physical property at the MPDS originates from a particular publication.', + 'There are two search modes, simple and advanced. The simple one presents one "smart" input field, the advanced one offers many various search fields.', + 'The MPDS includes the data extracted from the rare USSR and Japanese journals from 60-es, 70-es, and 80-es. These journals were never online.', + "A unique feature of the MPDS is the support of the polyhedral type searches, taking into account the atomic environments.", +]; +// NB this is used also in legacy Ermac detection (FIXME) +wmgui.api_msg = + 'Try to run e.g. the command given below in a terminal. As finished, do not forget to revoke your API key. See the manual for more details and the license for open data listing.
    curl -H Key:YOUR_API_KEY \'https://api.mpds.io/v0/download/facet?q=\{"elements":"Ag-K"\}\'
    Copy to clipboard
    '; + +wmgui.bid_history = []; +wmgui.mydata_history = []; +wmgui.journal_converter = { j2c: function () {}, c2j: function () {} }; +wmgui.hy_complex = [ + 'crystalline structure', + 'phase diagram', + 'electron energy band structure', + 'electron density of states', + 'vibrational spectra', +]; // NB check exact match in "props" p2i FIXME 'electron density of states - ab initio calculations' + +wmgui.visavis_curtype = 'pie'; // pie, graph, discovery, matrix, cube, qproj, lit, TODO heuristic plot type detection +wmgui.visavis_ready = false; +wmgui.visavis_working = false; +wmgui.visavis_terminating = false; +wmgui.visavis_starting = false; // only used by an old engine, to delete TODO + +wmgui.numerics = { + // these first 8 below are *pseudo_numerics*, client_prop_id > 5000 + volume: [5001, 'Å3', 3, 10000, 1], + density: [5002, 'Mg/m3', 0.1, 30, 0.1], + 'a--b': [5003, false, 0.1, 10, false, 'a/b'], + 'b--c': [5004, false, 0.1, 10, false, 'b/c'], + 'c--a': [5005, false, 0.1, 10, false, 'c/a'], + alat: [5006, 'Å', 1.5, 20, 0.1, 'alat'], + blat: [5007, 'Å', 1.5, 20, 0.1, 'blat'], + clat: [5008, 'Å', 1.5, 20, 0.1, 'clat'], +}; // client data *numerics*: prop_name: [client_prop_id, units, min, max, ?step, ?origname] + +// NB all URLs follow below +wmgui.gui_host = window.location.protocol + '//' + window.location.host; +wmgui.api_host = wmgui.prod + ? 'https://api.mpds.io/v0' + : 'http://localhost:7070'; +wmgui.static_host = 'https://mpds.io'; +wmgui.app_folder = window.location.pathname.slice( + 0, + window.location.pathname.lastIndexOf('/'), +); + +// below are the main MPDS API endpoints +wmgui.login_endpoint = wmgui.api_host + '/users/login'; +wmgui.logout_endpoint = wmgui.api_host + '/users/logout'; +wmgui.factor_endpoint = wmgui.api_host + '/users/factor'; +wmgui.factor_v_endpoint = wmgui.api_host + '/users/factor_v'; +wmgui.restore_endpoint = wmgui.api_host + '/users/lost_password'; +wmgui.password_endpoint = wmgui.api_host + '/users/new_password'; +wmgui.access_endpoint = wmgui.api_host + '/users/access'; +wmgui.ip_endpoint = wmgui.api_host + '/users/ip'; +wmgui.ratify_endpoint = wmgui.api_host + '/users/ratify'; +wmgui.api_key_endpoint = wmgui.api_host + '/users/api_key'; +wmgui.perms_endpoint = wmgui.api_host + '/users/perms'; +wmgui.ip_perms_endpoint = wmgui.api_host + '/users/ip_perms'; +wmgui.funnel_endpoint = wmgui.api_host + '/users/funnel'; +//wmgui.fd_endpoint = wmgui.api_host + '/users/feedback'; +wmgui.search_endpoint = wmgui.api_host + '/search/facet'; +wmgui.rfn_endpoint = wmgui.api_host + '/search/refinement'; +wmgui.sim_endpoint = wmgui.api_host + '/search/interlinkage'; +wmgui.phase_endpoint = wmgui.api_host + '/search/phase'; +wmgui.phph_endpoint = wmgui.api_host + '/search/phase_phid'; +wmgui.auto_endpoint = wmgui.api_host + '/search/selectize'; +wmgui.refs_endpoint = wmgui.api_host + '/download/bib'; +wmgui.wmdata_endpoint = wmgui.api_host + '/download/wmdata'; +wmgui.vis_endpoint = wmgui.api_host + '/visavis'; +wmgui.pdist_endpoint = wmgui.api_host + '/visavis/pdistribs'; +wmgui.mydata_endpoint = wmgui.api_host + '/extension/mydata'; + +wmgui.dd_addr_tpl = wmgui.api_host + '/download'; +wmgui.mydata_addr = wmgui.prod + ? 'https://app.absolidix.com' + : 'http://localhost:5000'; + +wmgui.path_c_entry = '#' + wmgui.api_host + '/download/c?fmt=json&q='; +wmgui.path_s_entry = '#' + wmgui.api_host + '/download/s?fmt=cif&q='; +wmgui.path_s_xrpd = '#' + wmgui.api_host + '/download/s?fmt=xrpd&q='; +wmgui.path_sd_plot = '#' + wmgui.api_host + '/download/p?fmt=json&q='; +wmgui.path_pp_plot = '#https://data.mpds.io/export?fmt=json&q='; // TODO +wmgui.path_pp_ping = wmgui.prod + ? 'https://data.mpds.io/ping?q=' + : 'http://localhost:8080/ping?q='; + +wmgui.engines_addrs = { + cifplayer: wmgui.app_folder + '/webassets/iframe_cifplayer.html', + visavis: wmgui.app_folder + '/webassets/iframe_visavis.html', +}; + +wmgui.v_pd_user_addr = wmgui.app_folder + '/webassets/pd_stub.html#'; +wmgui.v_ab_vis_addr = + wmgui.app_folder + + '/labs/view-phonons/#' + + wmgui.api_host + + '/download/p?fmt=json&q='; +wmgui.v_pd_3d_addr = wmgui.app_folder + '/labs/pd3d/?'; +wmgui.aetmap_addr = wmgui.static_host + '/aets.jpg'; + +wmgui.mpds_native = false; // TODO relate to wmgui.edition +wmgui.edition = null; // NB edition ID (e.g. 0, 1) is determined by a domain + +wmgui.editions = { + 0: { + name: 'Materials Platform for Data Science', + prod_url: 'https://mpds.io', + dev_url: 'http://localhost:8070', + css: wmgui.static_host + '/editions/wm/style.css?220923', + actions: function () { + const logo = $('#logo_l'); + if (logo) logo.textContent = 'MPDS'; + $$('.only_asm').forEach(hide); + $$('.only_mpds').forEach(function (el) { + el.style.display = 'inline-block'; + }); + }, + }, + 1: { + name: 'ASM International Materials Platform', + prod_url: 'https://asm.mpds.io', + dev_url: 'http://localhost:8075', + css: wmgui.static_host + '/editions/asm/style.css?150125', + actions: function () { + $$('.only_mpds').forEach(hide); + $$('.only_asm').forEach(function (el) { + el.style.display = 'inline-block'; + }); + // custom favicon + var link = + document.querySelector("link[rel*='icon']") || + document.createElement('link'); + link.type = 'image/x-icon'; + link.rel = 'shortcut icon'; + link.href = wmgui.static_host + '/editions/asm/asm.ico'; + document.getElementsByTagName('head')[0].appendChild(link); + }, + }, +}; +// NB all URLs are above + +wmgui.elemental_names = { + num: 'atomic number', + nump: 'periodic number', + size: 'atomic size', + rea: 'atomic reactivity', + rpp: 'pseudopotential radii', + rion: 'ionic radii', + rcov: 'covalent radii', + rmet: 'metallic radii', + tmelt: 'melting temperature', + eneg: 'electronegativity', +}; + +wmgui.collateral_links = [ + // [link_href, link_rel_attr, link_value, _blank] + ['#', 'my', 'search my publications'], + ['#', 'adv', 'try advanced search'], + ['#polyhedra', false, 'explore polyhedra'], + ['#hierarchy', false, 'browse physical properties'], + [ + wmgui.static_host + '/labs/mpds-ml-labs/design.html', + false, + 'design new material', + true, + ], + [ + wmgui.static_host + '/labs/mpds-ml-labs/props.html', + false, + 'predict properties for crystal', + true, + ], + ['#', 'idea', 'get inspired'], + ['#', 'sod', 'show structure of the day'], + ['oauth/asm.html', false, 'connect ASM profile', true], + ['oauth/github.html', false, 'connect GitHub profile', true], + ['oauth/orcid.html', false, 'connect ORCID profile', true], + ['oauth/linkedin.html', false, 'connect LinkedIn profile', true], +]; + +wmgui.aets = { + 'single atom 1-vertex': [0, 83], + '4-capped trigonal prism 10-vertex': [85, 102], + 'bicapped square prism 10-vertex': [189, 123], + 'bicapped square antiprism 10-vertex': [314, 125], + 'triangle-pentagon faced polyhedron 10-vertex': [441, 125], + 'distorted equatorial 4-capped trigonal prism 10-vertex': [568, 113], + 'truncated hexagonal bipyramid 10-vertex': [683, 111], + 'polar bicapped square prism 10-vertex': [796, 125], + 'pentagonal prism 10-vertex': [923, 121], + 'octagonal bipyramid 10-vertex': [1046, 122], + '5-capped trigonal prism 11-vertex': [1170, 119], + 'pseudo Frank-Kasper 11-vertex': [1291, 125], + 'monotruncated icosahedron 11-vertex': [1418, 102], + 'tricapped cube same plane 11-vertex': [1522, 87], + 'tricapped cube different plane 11-vertex': [1611, 123], + 'icosahedron 12-vertex': [1736, 125], + 'cuboctahedron 12-vertex': [1863, 117], + 'bicapped pentagonal prism 12-vertex': [1982, 125], + 'anticuboctahedron 12-vertex': [2109, 109], + 'hexagonal prism 12-vertex': [2220, 90], + 'triangle-hexagon faced polyhedron 12-vertex': [2312, 112], + 'double-bicapped cube 12-vertex': [2426, 114], + 'pseudo Frank-Kasper 13-vertex': [2542, 125], + 'tricapped pentagonal prism 13-vertex': [2669, 114], + 'monocapped cuboctahedron-a 13-vertex': [2785, 111], + 'monocapped cuboctahedron-b 13-vertex': [2898, 120], + '14-vertex Frank-Kasper': [3020, 116], + 'rhombic dodecahedron 14-vertex': [3138, 121], + 'distorted rhombic dodecahedron 14-vertex': [3261, 123], + 'bicapped hexagonal prism 14-vertex': [3386, 122], + '6-capped hexagonal bipyramid 14-vertex': [3510, 125], + 'double-bicapped hexagonal prism 14-vertex': [3637, 111], + '15-vertex Frank-Kasper': [3750, 125], + 'equatorial 5-capped pentagonal-prism 15-vertex': [3877, 97], + 'polar equatorial tricapped pentagonal-prism 15-vertex': [3976, 125], + 'monotruncated 16-vertex Frank-Kasper': [4103, 107], + '16-vertex Frank-Kasper': [4212, 125], + 'defective 8-equatorial capped pentagonal prism 16-vertex': [4339, 92], + 'octagonal prism 16-vertex': [4433, 119], + '7-capped pentagonal prism 17-vertex': [4554, 125], + '8-equatorial capped pentagonal prism 18-vertex': [4681, 125], + 'pseudo Frank-Kasper 18-vertex': [4808, 125], + '6-capped hexagonal prism 18-vertex': [4935, 108], + 'double-bicapped heptagonal prism 18-vertex': [5045, 110], + 'distorted pseudo Frank-Kasper 19-vertex': [5157, 125], + 'pseudo Frank-Kasper 19-vertex': [5284, 122], + 'non-collinear atoms 2-vertex': [5408, 41], + 'collinear atoms 2-vertex': [5451, 111], + 'pseudo Frank-Kasper 20-vertex': [5564, 125], + '20-pentagonal faced polyhedron 20-vertex': [5691, 114], + 'pseudo Frank-Kasper 21-vertex': [5807, 125], + 'polar 8-equatorial capped hexagonal prism 22-vertex': [5934, 125], + 'pseudo Frank-Kasper 23-vertex': [6061, 118], + '6-square 8-hexagonal faced polyhedron 24-vertex': [6181, 118], + 'pseudo Frank-Kasper 24-vertex': [6301, 125], + 'truncated cube dice 24-vertex': [6428, 118], + 'triangle-square-hexagon faced polyhedron 24-vertex': [6548, 97], + 'triangle-square faced polyhedron 24-vertex': [6647, 125], + 'pseudo Frank-Kasper 26-vertex': [6774, 125], + 'pseudo Frank-Kasper 28-vertex': [6901, 123], + 'non-coplanar triangle 3-vertex': [7026, 75], + 'coplanar triangle 3-vertex': [7103, 64], + '32-vertex': [7169, 122], + 'tetrahedron central atom outside 4-vertex': [7293, 99], + 'coplanar square 4-vertex': [7394, 68], + 'non-coplanar square 4-vertex': [7464, 69], + 'tetrahedron 4-vertex': [7535, 120], + 'square pyramid central atom outside of base plane 5-vertex': [7657, 81], + 'coplanar pentagon 5-vertex': [7740, 67], + 'square pyramid 5-vertex': [7809, 125], + 'trigonal bipyramid 5-vertex': [7936, 107], + 'coplanar hexagon 6-vertex': [8045, 49], + 'non-coplanar hexagon 6-vertex': [8096, 80], + 'octahedron 6-vertex': [8178, 125], + 'trigonal prism 6-vertex': [8305, 120], + 'pentagonal pyramid 6-vertex': [8427, 116], + 'distorted prism 6-vertex': [8545, 110], + 'monocapped octahedron 7-vertex': [8657, 125], + 'top-monocapped trigonal prism 7-vertex': [8784, 125], + 'bicapped hexagon 7-vertex': [8911, 108], + 'hexagonal pyramid 7-vertex': [9021, 96], + 'monocapped trigonal prism 7-vertex': [9119, 125], + 'pentagonal bipyramid 7-vertex': [9246, 122], + 'square prism cube 8-vertex': [9370, 115], + 'square antiprism 8-vertex': [9487, 103], + 'hexagonal bipyramid 8-vertex': [9592, 125], + 'distorted square anti-prism-a 8-vertex': [9719, 123], + 'double anti-trigonal prism 8-vertex': [9844, 99], + 'side-bicapped trigonal prism 8-vertex': [9945, 107], + 'distorted square anti-prism-b 8-vertex': [10054, 125], + 'tricapped trigonal prism 9-vertex': [10181, 119], + 'monocapped square prism 9-vertex': [10302, 125], + 'monocapped double anti-trigonal prism 9-vertex': [10429, 113], + 'truncated hexagonal pyramid 9-vertex': [10544, 75], + 'bicapped hexagonal pyramid 9-vertex': [10621, 116], +}; + +//wmgui.contact_html = '
    Send
    '; + +wmgui.s_examples = [ + 251737, 261485, 301194, 458778, 525194, 533193, 1005414, 1030546, 1122968, + 1215422, 1232477, 1321212, 1406036, 1613664, 1638591, 1640622, 1707997, + 1711681, 1722027, 1819191, 1928624, 1933647, 1940797, +]; +wmgui.mockyear = '2022'; // used for the in-house generated data, TODO switch to 2024 + +wmgui.store_history_key = 'wm_search_log_v5'; +wmgui.store_user_key = 'wm'; +wmgui.store_bids_key = 'bid_history'; // TODO rename to wm_bid_history +wmgui.store_mydata_key = 'absolidix_v1'; +wmgui.store_oauth_email_key = 'wm_u_email'; +wmgui.store_comm_exec_key = 'wm_reload_v1'; +wmgui.store_redir_key = 'wm_redir_v1'; + +wmgui.tooltips = { + //'advsearch': {el: 'advsearch_init_trigger', oleft: -90, otop: 60, view_mode: 1, text: 'Use the ☰ button for the detailed search by 15+ categories.
    Next'}, + //'hierarchy': {el: 'advsearch_init_trigger', oleft: -50, otop: 60, view_mode: 1, text: 'Use the μ button to select physical properties from the curated hierarchy.
    Next'}, + userbox: { + el: 'userbox', + oleft: -105, + otop: 60, + view_mode: 1, + text: 'Check your full access
    with your account here.
    OK', + }, + interpretation: { + el: 'right_col', + oleft: -70, + otop: 99, + view_mode: 2, + text: 'The entries are grouped in the phases.
    Next', + }, + databrowser: { + el: 'databrowser', + oleft: 0, + otop: 200, + view_mode: 2, + text: 'Click the particular entry to get more info. Opened lock means open access.
    OK', + }, + //'plots': {el: 'databrowser', oleft: 0, otop: 500, view_mode: 2, text: 'Use the graph chart buttons in the footer (at the very bottom of the page).
    OK'}, + ss_axes: { + el: 'ctxpanel_plots', + oleft: 60, + otop: 114, + view_mode: 2, + text: 'Click gear icon to sort axes differently.
    Next', + }, + visavis: { + el: 'right_col', + oleft: -150, + otop: 500, + view_mode: 2, + text: 'Fine-tune visualizations with the commands here.
    OK', + }, +}; +wmgui.tooltip_counter = 0; +wmgui.tooltip_landing = 'userbox'; + +wmgui.poly_limits = { + 1: 'isopolyhedral', + 2: 'dipolyhedral', + 3: 'tripolyhedral', +}; + +// external integrations +// TODO account contentWindow iframe calls here + +wmgui.mpdsgui = {}; +wmgui.mpdsgui.view = function () {}; +wmgui.mpdsgui.ptable_activate = function () {}; +wmgui.mpdsgui.ptable_deactivate = function () {}; + +wmgui.entries_messages = { + C900500: 'This system is stable (dashed metastable)', + C904090: 'This system is metastable (dashed stable)', + C904091: 'This system is metastable', + C904092: 'This system is metastable (dashed stable)', + C904124: 'This system is metastable (dashed stable)', + C904221: 'This system is stable; allotropic transition of Fe is not shown', + C904222: 'This system is stable', + C904223: 'This system is stable', + C904313: 'This system is stable', + C904322: 'This system is stable', + C904329: 'This system is stable', + C904330: 'This system is metastable (dashed stable)', + C904331: 'This system is metastable (dashed stable)', + C904332: 'This system is stable', + C904343: 'This system is stable', + C904344: 'This system is stable', + C904345: 'This system is stable (dashed metastable)', + C904354: 'This system is metastable (dashed stable)', + C904366: 'This system is metastable', + C904376: 'This system is metastable (dashed stable)', + C904437: 'This system is stable', + C904478: 'This system is stable', + C905006: 'This system is metastable', + C905621: 'This system is metastable', + C905635: 'This system is stable (dashed metastable)', + C905636: 'This system is stable', + C905637: 'This system is stable (dashed metastable)', + C905638: 'This system is stable (dashed metastable)', + C905985: 'This system is metastable (dashed stable)', + C906635: 'This system is stable', + C906931: 'This system is stable', + C908341: 'This system is stable; p = 8.0 GPa', + C908342: 'This system is metastable', + C908343: 'This system is metastable', + C979860: 'This system is stable', + C979861: 'This system is stable', + C979862: 'This system is stable', + C979863: 'This system is metastable', + C979864: 'This system is stable', + C979865: 'This system is stable', + C102059: 'This system is metastable', + C103150: 'This system is stable', + C104069: 'This system is metastable', + C105034: 'This system is metastable', + C105035: 'This system is metastable', +}; diff --git a/src_js/core/utils.js b/src_js/core/utils.js new file mode 100644 index 0000000..c4e77c9 --- /dev/null +++ b/src_js/core/utils.js @@ -0,0 +1,1515 @@ +/** + * Ermac core utilities: base-type extensions, DOM-adjacent helpers, + * domain data and methods ported from the old wmcore.js. + */ + +import wmgui from './settings.js'; +import { $, show, hide } from './dom.js'; +import { is_empty } from './ajax.js'; + +/** + * Vendored NLP parser (src_js/third_party/optimade_mpds_nlp.js) defines the window global. + */ +/* global OptimadeNLP */ + +if (typeof OptimadeNLP === 'undefined') { + throw new Error('Failed to load OptimadeNLP'); +} + +export const wmutils = OptimadeNLP(); + +/** + * Extending base types with the utilities + */ + +Array.prototype.extend = function (other_array) { + other_array.forEach(function (v) { + this.push(v); + }, this); +}; + +String.prototype.startswith = function (prefix) { + return this.indexOf(prefix) === 0; +}; + +Number.prototype.count_decimals = function () { + if (isFinite(this) && Math.floor(this) === this) return 0; // is integer + var repr = this.toString(); + if (repr.indexOf('.') == -1) return 0; + return repr.split('.')[1].length || 0; +}; + +/** + * Auxiliary methods relevant for DOM + */ + +wmgui.clean = function (str) { + const tpl = document.createElement('template'); + tpl.innerHTML = (str || '').bold(); + tpl.content.querySelectorAll('script').forEach(function (script) { + script.remove(); + }); + const first = tpl.content.firstElementChild; + return first ? first.innerHTML : tpl.innerHTML; +}; + +wmgui.cancel_event = function (evt) { + evt = evt || window.event; + if (evt.cancelBubble) evt.cancelBubble = true; + else { + if (evt.stopPropagation) evt.stopPropagation(); + if (evt.preventDefault) evt.preventDefault(); + } +}; + +wmgui.debounce = function (func, wait, immediate) { + var timeout; + + return function () { + var context = this, + args = arguments; + var later = function () { + timeout = null; + if (!immediate) func.apply(context, args); + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); + }; +}; + +wmgui.is_inview = function (element) { + if (!element) return false; + + var pageTop = window.scrollY, + pageBottom = pageTop + window.innerHeight, + elementTop = element.getBoundingClientRect().top + pageTop, + elementBottom = elementTop + element.offsetHeight; + + return elementTop <= pageBottom && elementBottom >= pageTop; +}; + +wmgui.show_preloader = function () { + show($('#preloader')); +}; + +wmgui.hide_preloader = function () { + hide($('#preloader')); +}; + +wmgui.loadCSS = function (href, before, media, attributes) { + // Arguments: + // `href` [REQUIRED] is the URL for your CSS file. + // `before` [OPTIONAL] is the element the script should use as a reference for injecting our stylesheet before + // By default, loadCSS attempts to inject the link after the last stylesheet or script in the DOM. However, you might desire a more specific location in your document. + // `media` [OPTIONAL] is the media type or query of the stylesheet. By default it will be 'all' + // `attributes` [OPTIONAL] is the Object of attribute name/attribute value pairs to set on the stylesheet's DOM Element. + var ss = document.createElement('link'); + var ref; + + if (before) { + ref = before; + } else { + var refs = (document.body || document.getElementsByTagName('head')[0]) + .childNodes; + ref = refs[refs.length - 1]; + } + + var sheets = document.styleSheets; + // Set any of the provided attributes to the stylesheet DOM Element. + if (attributes) { + for (var attributeName in attributes) { + if (attributes.hasOwnProperty(attributeName)) { + ss.setAttribute(attributeName, attributes[attributeName]); + } + } + } + ss.rel = 'stylesheet'; + ss.href = href; + // temporarily set media to something inapplicable to ensure it'll fetch without blocking render + ss.media = 'only x'; + + // wait until body is defined before injecting link. This ensures a non-blocking load in IE11. + function ready(cb) { + if (document.body) { + return cb(); + } + setTimeout(function () { + ready(cb); + }); + } + // Inject link + // Note: the ternary preserves the existing behavior of "before" argument, but we could choose to change the argument to "after" in a later release and standardize on ref.nextSibling for all refs + // Note: `insertBefore` is used instead of `appendChild`, for safety re: http://www.paulirish.com/2011/surefire-dom-element-insertion/ + ready(function () { + ref.parentNode.insertBefore(ss, before ? ref : ref.nextSibling); + }); + + // A method (exposed on return object for external use) that mimics onload by polling document.styleSheets until it includes the new sheet. + var onloadcssdefined = function (cb) { + var resolvedHref = ss.href; + var i = sheets.length; + while (i--) { + if (sheets[i].href === resolvedHref) { + return cb(); + } + } + setTimeout(function () { + onloadcssdefined(cb); + }); + }; + + function loadCB() { + if (ss.addEventListener) { + ss.removeEventListener('load', loadCB); + } + ss.media = media || 'all'; + } + + // once loaded, set link's media back to `all` so that the stylesheet applies once it loads + if (ss.addEventListener) { + ss.addEventListener('load', loadCB); + } + ss.onloadcssdefined = onloadcssdefined; + onloadcssdefined(loadCB); + return ss; +}; + +/** + * Domain subject definitions + */ + +wmgui.most_frequent_els = [ + 'O', + 'Si', + 'Al', + 'Fe', + 'Ca', + 'Na', + 'Mg', + 'K', + 'Ti', + 'H', + 'Cl', + 'S', + 'Br', + 'C', +]; + +// just less probable than the *most_frequent_els* +wmgui.probable_els = wmutils.periodic_elements_cased.slice(0, 55); +wmgui.probable_els.splice(53, 1); // Xe +wmgui.probable_els.splice(42, 1); // Tc +wmgui.probable_els.splice(35, 1); // Kr +wmgui.probable_els.splice(17, 1); // Ar +wmgui.probable_els.splice(9, 1); // Ne +wmgui.probable_els.splice(1, 1); // He + +wmgui.classes_groups = [ + 'transitional', + 'chalcogen', + 'rare earth', + 'lanthanoid', + 'metalloid', + 'alkaline', + 'halogen', + 'pnictogen', + 'alkali', + 'actinoid', +]; // NB noble gas + +wmgui.classes_families = [ + 'metal', + 'intermetallic', + 'oxide', + 'conductor', + 'nonmetal', + 'antiferromagnet', + 'ferromagnet', + 'semiconductor', + 'intermediate valence', + 'superconductor', + 'close-packed', + 'perovskite', + 'scheelite', + 'high-tc superconductor', + 'silicide', + 'diamagnetic', + 'cuprate', + 'ferrimagnet', + 'sulfide', + 'spin glass', + 'rocksalt', + 'ferroelectric', + 'frank-kasper', + 'selenide', + 'adamantane', + 'paramagnet', + 'friauf-laves', + 'boride', + 'semimetal', + 'pauli paramagnet', + 'fluoride', + 'telluride', + 'hydrate', + 'carbide', + 'ionic conductor', + 'chloride', + 'spinel', + 'intercalation', + 'fluorite', + 'hard magnet', + 'arsenide', + 'ferroelastic', + 'orthophosphate', + 'phosphide', + 'nitride', + 'piezoelectric', + 'antiferroelectric', + 'hydroxide', + 'silicate', + 'organic', + 'hydride', + 'iodide', + 'bromide', + 'charge-density wave state', + 'spin-density wave state', + 'ruddlesden-popper', + 'sulfate', + 'superionic conductor', + 'pyrochlore', + 'orthosilicate', + 'borocarbide', + 'molybdate', + 'borate', + 'garnet', + 'cyanide', + 'thermoelectric', + 'helimagnet', + 'vanadate', + 'zeolite', + 'birefringent', + 'deuteride', + 'orthoborate', + 'van vleck paramagnet', + 'mictomagnet', + 'carbonate', + 'phosphate', + 'chevrel', + 'gamma-brass', + 'polaron conductor', + 'nasicon', + 'luminescent', + 'tungstate', + 'arsenate', + 'nitrate', + 'radioactive', +]; + +wmgui.most_frequent_classes = [ + 'metal', + 'oxide', + 'conductor', + 'nonmetal', + 'antiferromagnet', + 'semiconductor', + 'perovskite', + 'scheelite', + 'sulfide', + 'paramagnet', + 'ab initio literature', + 'hydrate', + 'chloride', + 'spinel', + 'fluorite', + 'orthophosphate', + 'silicate', + 'machine learning', + 'ab initio calculations', +]; + +wmgui.most_frequent_props = [ + 'magnetism', + 'crystal structure', + 'electronic properties', + 'mechanical properties', + 'thermodynamics', + 'phase transitions', + 'optical properties', + 'superconductivity', + 'enthalpy of formation', + 'heat capacity', + 'thermal expansion', + 'Seebeck coefficient', +]; // TODO cell parameters + +wmgui.most_frequent_lats = [ + 'cubic', + 'tetragonal', + 'orthorhombic', + 'monoclinic', +]; + +wmgui.most_frequent_formulae = [ + 'Ag2S', + 'Ag2Se', + 'Ag2Te', + 'Ag3Sn', + 'AgBr', + 'AgCe', + 'AgCl', + 'AgCu4Yb', + 'AgGaS2', + 'AgGaSe2', + 'AgI', + 'AgYbGe', + 'Al2O3', + 'Al4C3', + 'AlAs', + 'AlF3', + 'AlN', + 'AlP', + 'AlSb', + 'Al[PO4]', + 'As2S3', + 'As2Se3', + 'As2Te3', + 'AsS', + 'AuSn', + 'AuTe2', + 'B13C2', + 'Ba2Cu2YFeO7', + 'Ba2Cu3DyO7', + 'Ba2Cu3ErO7', + 'Ba2Cu3EuO7', + 'Ba2Cu3GdO7', + 'Ba2Cu3HoO7', + 'Ba2Cu3LaO7', + 'Ba2Cu3NdO7', + 'Ba2Cu3PrO7', + 'Ba2Cu3SmO7', + 'Ba2Cu3TmO7', + 'Ba2Cu3YO6', + 'Ba2Cu3YO7', + 'Ba2Cu3YbO7', + 'Ba2Cu4YO8', + 'Ba2CuTl2O6', + 'Ba2MoFeO6', + 'Ba4Ga8Ge15', + 'Ba4Ga8Sn15', + 'BaBiO3', + 'BaCl2', + 'BaF2', + 'BaFe12O19', + 'BaFe2As2', + 'BaIrO3', + 'BaLaMn2O6', + 'BaMnF4', + 'BaO', + 'BaPbO3', + 'BaRuO3', + 'BaTiO3', + 'BaVS3', + 'BaYCo4O7', + 'BaZrO3', + 'Be13U', + 'BeO', + 'Bi2O3', + 'Bi2S3', + 'Bi2Se3', + 'Bi2Te3', + 'C60', + 'Ca2ReFeO6', + 'Ca2RuO4', + 'Ca3Co2O6', + 'Ca3Co4O9', + 'CaAl2', + 'CaAlSi', + 'CaCu3Ti4O12', + 'CaF2', + 'CaFe2As2', + 'CaIrO3', + 'CaMnO3', + 'CaO', + 'CaRuO3', + 'CaS', + 'CaSi2', + 'CaTiO3', + 'Ca[CO3]', + 'Ca[WO4]', + 'Cd2Nb2O7', + 'Cd3As2', + 'CdAs2', + 'CdCr2S4', + 'CdCr2Se4', + 'CdF2', + 'CdI2', + 'CdO', + 'CdS', + 'CdSb', + 'CdSe', + 'CdTe', + 'Ce2Fe17', + 'Ce3Al11', + 'Ce3Sn', + 'CeAl2', + 'CeAl3', + 'CeB6', + 'CeBi', + 'CeCo2', + 'CeCo5', + 'CeCoGe3', + 'CeCoIn5', + 'CeFe2', + 'CeFe4Sb12', + 'CeIn3', + 'CeIrSi3', + 'CeMn2Si2', + 'CeNi', + 'CeNi2Ge2', + 'CeNi2Si2', + 'CeNi2Sn2', + 'CeNiGe2', + 'CeNiSn', + 'CeO2', + 'CeP', + 'CePd2Al3', + 'CePd2Si2', + 'CePd3', + 'CePdSn', + 'CePt2Si2', + 'CePt3Si', + 'CePtSn', + 'CeRh2Si2', + 'CeRh3B2', + 'CeRhAs', + 'CeRhGe', + 'CeRhIn5', + 'CeRhSb', + 'CeRhSn', + 'CeRu2', + 'CeRu2Ge2', + 'CeRu2Si2', + 'CeRuRhSi2', + 'CeSb', + 'CeSi2', + 'Co2Al9', + 'Co2B', + 'Co2Si', + 'Co3O4', + 'Co3[VO4]2', + 'CoAl', + 'CoGa', + 'CoO', + 'CoPt', + 'CoS2', + 'CoSb3', + 'CoSi', + 'CoSi2', + 'Cr23C6', + 'Cr2FeS4', + 'Cr2O3', + 'Cr2S3', + 'Cr3C2', + 'Cr3Si', + 'Cr7Al45', + 'Cr7C3', + 'CrAs', + 'CrB2', + 'CrN', + 'CrO2', + 'CrSi2', + 'CrTe', + 'Cs2ZnI4', + 'CsBr', + 'CsC8', + 'CsCl', + 'CsI', + 'Cu2Ce', + 'Cu2CeSi2', + 'Cu2GdSi2', + 'Cu2Nd', + 'Cu2O', + 'Cu2S', + 'Cu2Se', + 'Cu2Te', + 'Cu2UGe2', + 'Cu2USi2', + 'Cu2Y', + 'Cu2Y2O5', + 'Cu2YbSi2', + 'Cu2ZnSnS4', + 'Cu33Al17', + 'Cu3As', + 'Cu3Au', + 'Cu3Sb', + 'Cu3Sn', + 'Cu41Sn11', + 'Cu4CeAl', + 'Cu4YbIn', + 'Cu5U', + 'Cu5Zn8', + 'Cu6Ce', + 'Cu9Al4', + 'CuAl', + 'CuAl2', + 'CuAu', + 'CuBr', + 'CuCl', + 'CuCr2Se4', + 'CuCrO2', + 'CuFe2O4', + 'CuFeO2', + 'CuGaS2', + 'CuGaSe2', + 'CuGd2O4', + 'CuGeO3', + 'CuI', + 'CuInS2', + 'CuInSe2', + 'CuInTe2', + 'CuIr2S4', + 'CuLa2O4', + 'CuNd2O4', + 'CuO', + 'CuPr2O4', + 'CuS', + 'CuTi2', + 'CuV2S4', + 'CuZn', + 'Dy2Fe14B', + 'Dy2Fe17', + 'DyAl2', + 'DyCo2', + 'DyFe2', + 'DyFe4Al8', + 'DyMn2', + 'DyMn2O5', + 'DyMo2Fe10', + 'DyTiFe11', + 'Dy[VO4]', + 'Er2Fe14B', + 'Er2Fe17', + 'Er2Fe17C3', + 'Er5Si4', + 'ErAl2', + 'ErCo2', + 'ErFe2', + 'ErFeO3', + 'ErMn2O5', + 'ErNi2B2C', + 'ErRh4B4', + 'ErTiFe11', + 'Eu2O3', + 'Eu4Ga8Ge15', + 'EuB6', + 'EuFe2As2', + 'EuFe4Sb12', + 'EuMo6S8', + 'EuO', + 'EuS', + 'EuSe', + 'EuTe', + 'Fe2As', + 'Fe2B', + 'Fe2CoO4', + 'Fe2NiO4', + 'Fe2O3', + 'Fe2P', + 'Fe3Al', + 'Fe3C', + 'Fe3Ga', + 'Fe3O4', + 'Fe3P', + 'Fe3Si', + 'Fe4Al13', + 'Fe4N', + 'Fe5Si3', + 'FeAl', + 'FeAs', + 'FeB', + 'FeBiO3', + 'FeCl2', + 'FeCo', + 'FeCo2Si', + 'FeGaO3', + 'FeGe', + 'FeGe2', + 'FeNi3', + 'FeO', + 'FeP', + 'FePt3', + 'FeRh', + 'FeS', + 'FeS2', + 'FeSb2', + 'FeSe', + 'FeSi', + 'FeSi2', + 'Ga2O3', + 'GaAs', + 'GaN', + 'GaP', + 'GaS', + 'GaSb', + 'GaSe', + 'GaTe', + 'Ga[PO4]', + 'Gd2Fe14B', + 'Gd2Fe17', + 'Gd2O3', + 'Gd2[MoO4]3', + 'Gd3Co', + 'Gd5Ge4', + 'GdAl2', + 'GdB6', + 'GdCo2', + 'GdCo5', + 'GdFe2', + 'GdFe3[BO3]4', + 'GdMn2', + 'GdMn2Ge2', + 'GdMnO3', + 'GdN', + 'GdNi2', + 'GdSi2', + 'GdTiFe11', + 'GeO2', + 'GeS', + 'GeSe', + 'GeSe2', + 'GeTe', + 'H2', + 'H2Cs[PO4]', + 'H2K[PO4]', + 'H2O', + 'H2Rb[PO4]', + 'H3Na[SeO3]2', + 'HK[CO3]', + 'HfB2', + 'HfC', + 'HfO2', + 'HgCr2S4', + 'HgCr2Se4', + 'HgI2', + 'HgS', + 'HgSe', + 'HgTe', + 'Ho2Fe14B', + 'HoAl2', + 'HoCo2', + 'HoFe2', + 'HoMn2O5', + 'HoMnO3', + 'HoNi2', + 'HoNi2B2C', + 'In2O3', + 'In2S3', + 'In2Se3', + 'InAs', + 'InBi', + 'InN', + 'InP', + 'InSb', + 'InSe', + 'InTe', + 'K2[SeO4]', + 'K3Mo10O30', + 'K3Na[SeO4]2', + 'K3[C60]', + 'KBr', + 'KC24', + 'KC8', + 'KCl', + 'KLi[SO4]', + 'KMnF3', + 'KNbO3', + 'KOs2O6', + 'KTaO3', + 'KTi[PO4]O', + 'K[CN]', + 'La2NiO4', + 'La2O3', + 'La3Ga5SiO14', + 'La3S4', + 'LaAl2', + 'LaAlO3', + 'LaB6', + 'LaCoO3', + 'LaCrO3', + 'LaF3', + 'LaFe11Si2', + 'LaFe4Sb12', + 'LaFeAsO', + 'LaFeO3', + 'LaGaO3', + 'LaH3', + 'LaMn2Ge2', + 'LaMnO3', + 'LaNi5', + 'LaNiO3', + 'LaTiO3', + 'LaVO3', + 'Li2Pd3B', + 'Li2S', + 'Li3N', + 'LiAl', + 'LiBr', + 'LiCl', + 'LiCoO2', + 'LiF', + 'LiFe[PO4]', + 'LiH', + 'LiMn2O4', + 'LiNbO3', + 'LiNiO2', + 'LiTaO3', + 'LiTi2O4', + 'LiV2O5', + 'LiVO2', + 'LiYF4', + 'Lu2Fe17', + 'Lu5Ir4Si10', + 'LuNi2B2C', + 'Mg17Al12', + 'Mg24Y5', + 'Mg28Al45', + 'Mg2Si', + 'Mg2Sn', + 'Mg2TiO4', + 'Mg2[SiO4]', + 'MgAl2O4', + 'MgB2', + 'MgCu2', + 'MgF2', + 'MgFe2O4', + 'MgFeAlO4', + 'MgFe[SiO4]', + 'MgO', + 'MgSiO3', + 'MgZn2', + 'Mn11Al15', + 'Mn3C', + 'Mn3O4', + 'Mn5Si3', + 'MnAl6', + 'MnAs', + 'MnBi', + 'MnF2', + 'MnFe2O4', + 'MnNi2Ga', + 'MnNi2In', + 'MnNi2Sb', + 'MnNi2Sn', + 'MnNiSb', + 'MnO', + 'MnO2', + 'MnP', + 'MnS', + 'MnSi', + 'MnTe', + 'Mo2S3', + 'Mo3Al8', + 'Mo4O11', + 'Mo6PbS8', + 'Mo7Ni7', + 'MoB2', + 'MoO3', + 'MoS2', + 'MoSi2', + 'NaBr', + 'NaCl', + 'NaF', + 'NaI', + 'NaNbO3', + 'Na[NO2]', + 'Na[NO3]', + 'Nb2Al', + 'Nb3FeSe6', + 'Nb3Ge', + 'Nb3Si', + 'Nb3Sn', + 'Nb5Si3', + 'Nb7Ni6', + 'NbAl3', + 'NbB2', + 'NbC', + 'NbCr2', + 'NbFe2', + 'NbH', + 'NbN', + 'NbNi3', + 'NbO2', + 'NbSe2', + 'NbSe3', + 'NbSi2', + 'Nd2Co14B', + 'Nd2Fe13CoB', + 'Nd2Fe14B', + 'Nd2Fe17', + 'Nd2O3', + 'Nd6Fe11Al3', + 'NdAl2', + 'NdB6', + 'NdCo2', + 'NdCo5', + 'NdFeAsO', + 'NdFeO3', + 'NdMn2Ge2', + 'NdMnFeGe2', + 'NdMnO3', + 'NdMo2Fe10', + 'NdNiO3', + 'NdTiFe11', + 'NdTiO3', + 'NdV2Fe10', + 'Ni2Al3', + 'Ni2B', + 'Ni2Si', + 'Ni31Si12', + 'Ni3Al', + 'Ni3B', + 'Ni3Si', + 'Ni3[VO4]2', + 'Ni4B3', + 'NiAl', + 'NiAl3', + 'NiO', + 'NiS', + 'NiS2', + 'NiSb', + 'NiSi', + 'NiSi2', + 'NpPd5Al2', + 'O2', + 'PbF2', + 'PbI2', + 'PbO', + 'PbO2', + 'PbS', + 'PbSe', + 'PbTe', + 'Pb[WO4]', + 'Pd2Si', + 'PdAl', + 'PdH', + 'Pr2Fe14B', + 'Pr2O3', + 'PrAl2', + 'PrB6', + 'PrCo5', + 'PrFe2Ge2', + 'PrFe4P12', + 'PrFeAsO', + 'PrMn2Ge2', + 'PrMnO3', + 'PrNi2Si2', + 'PrNi5', + 'PrOs4Sb12', + 'Rb2ZnBr4', + 'Rb2ZnCl4', + 'Rb3[C60]', + 'RbBr', + 'RbCl', + 'RbF', + 'RbI', + 'RbLi[SO4]', + 'Rb[C60]', + 'ReO3', + 'RuAl2', + 'Sb2S3', + 'Sb2Se3', + 'Sb2Te3', + 'SbSI', + 'Sc2[WO4]3', + 'ScAl3', + 'Si3N4', + 'SiC', + 'SiO2', + 'Sm2Co17', + 'Sm2Fe17', + 'Sm2Fe17N3', + 'Sm2O3', + 'SmB6', + 'SmCo5', + 'SmFeAsO', + 'SmMn2Ge2', + 'SmS', + 'SmTiFe11', + 'SnO2', + 'SnS', + 'SnS2', + 'SnSe', + 'SnSe2', + 'SnTe', + 'Sr14Cu24O41', + 'Sr2CuBi2O6', + 'Sr2LaMn2O7', + 'Sr2MoFeO6', + 'Sr2RuO4', + 'SrAl4', + 'SrCoO3', + 'SrCuLaO4', + 'SrF2', + 'SrFe12O19', + 'SrFe2As2', + 'SrFeO3', + 'SrLaMnO4', + 'SrLaNiO4', + 'SrMnO3', + 'SrNb2Bi2O9', + 'SrO', + 'SrRuO3', + 'SrTa2Bi2O9', + 'SrTiO3', + 'SrZrO3', + 'TaC', + 'TaS2', + 'TaS3', + 'TaSe2', + 'Tb3Fe5O12', + 'TbFe2', + 'TbMn2', + 'TbMn2O5', + 'TbMnO3', + 'TbNi2Si2', + 'TbRh2Si2', + 'TbTiFe11', + 'TeO2', + 'ThO2', + 'Ti2Ni', + 'Ti2O3', + 'Ti3Al', + 'Ti3Bi4O12', + 'Ti5Si3', + 'TiAl', + 'TiAl2', + 'TiAl3', + 'TiB2', + 'TiC', + 'TiCo', + 'TiCo2Al', + 'TiCo2Sn', + 'TiCoSb', + 'TiCr2', + 'TiFe', + 'TiFe2', + 'TiFeO3', + 'TiH2', + 'TiN', + 'TiNi', + 'TiNi3', + 'TiO', + 'TiO2', + 'TiPbO3', + 'TiS2', + 'TiSe2', + 'TiSi2', + 'TiVO3', + 'Tl2S', + 'Tl5Se3', + 'Tl5Te3', + 'TlBr', + 'TlCl', + 'TlGaSe2', + 'TlI', + 'TlInS2', + 'TlS', + 'TlSe', + 'TlTe', + 'Tm2Fe14B', + 'TmSe', + 'TmTe', + 'U2C3', + 'U2Ni2Sn', + 'U2Pt2In', + 'U6Fe', + 'UAl2', + 'UAs', + 'UC2', + 'UCo2Ge2', + 'UCoAl', + 'UFe10Si2', + 'UFe2', + 'UFe4Al8', + 'UGe2', + 'UMn2', + 'UNi2Al3', + 'UNiAl', + 'UNiGa', + 'UNiSn', + 'UO2', + 'UPd2Al3', + 'UPd3', + 'UPdSn', + 'UPt3', + 'UPtGe', + 'URu2Si2', + 'USb', + 'UTe', + 'V2MnO4', + 'V2O3', + 'V2O5', + 'V3Ga', + 'V3Ge', + 'V3O5', + 'V3Si', + 'V4O7', + 'V5Al8', + 'V5O9', + 'V6O11', + 'V6O13', + 'V7O13', + 'VAl3', + 'VFe2Al', + 'VO2', + 'VSe2', + 'W2C', + 'WBi2O6', + 'WMnO4', + 'WO3', + 'WSi2', + 'Y2Co17', + 'Y2Fe14B', + 'Y2Fe17', + 'Y2O3', + 'Y3Al5O12', + 'Y3Fe5O12', + 'YAl2', + 'YAl3', + 'YB6', + 'YCo2', + 'YCo3', + 'YCo4B', + 'YCo5', + 'YFe2', + 'YFe4Al8', + 'YH3', + 'YMn2', + 'YMnO3', + 'YMo2Fe10', + 'YNi2B2C', + 'YTiFe11', + 'YTiO3', + 'YV2Fe10', + 'YVO3', + 'Yb2O3', + 'Yb4As3', + 'YbAl3', + 'YbFe4Sb12', + 'YbMnO3', + 'YbRh2Si2', + 'Zn10Fe3', + 'Zn2Zr', + 'Zn3As2', + 'Zn3P2', + 'ZnCr2O4', + 'ZnCr2Se4', + 'ZnF2', + 'ZnFe2O4', + 'ZnGeP2', + 'ZnO', + 'ZnS', + 'ZnSe', + 'ZnSiP2', + 'ZnTe', + 'Zr2Ni', + 'ZrAl2', + 'ZrAl3', + 'ZrB2', + 'ZrC', + 'ZrCo2', + 'ZrCr2', + 'ZrFe2', + 'ZrMn2', + 'ZrMo2', + 'ZrN', + 'ZrNiSn', + 'ZrO2', + 'ZrPbO3', + 'ZrV2', + 'Zr[WO4]2', + '[NH4]2ZnCl4', +]; + +wmgui.most_frequent_anonymous = [ + 'AB', + 'AB2', + 'ABC3', + 'ABC', + 'ABC2', + 'ABCD3', + 'AB3', + 'AB2C4', + 'AB2C2', + 'ABC4', + 'ABC2D6', + 'ABCD4', + 'A2B3', + 'ABC2D4', + 'ABCD', + 'ABCD2', + 'AB2C3', + 'AB2C6', + 'AB2C5', + 'AB2C3D7', + 'A3B4', + 'A3B5', + 'ABC2D2', + 'A2B2C7', + 'AB3C5', + 'ABC2D5', + 'ABC2D7', + 'AB5', + 'AB3C6', + 'AB3C4', + 'ABC5', + 'ABC2D8', + 'AB3C3', + 'AB4', + 'AB6', + 'AB2C2D7', + 'AB4C12', + 'A2B17', + 'AB3C4D12', + 'ABCD5', + 'ABCD6', + 'A2B3C4', + 'ABC3D7', + 'A2B3C5', + 'AB2C10', + 'A2B2C5', + 'AB2C2D6', + 'AB2C3D8', + 'AB2C8', + 'ABC2D3', + 'A2B5', + 'AB2C3D6', + 'AB4C8', + 'ABC6', + 'AB2C2D8', + 'AB6C6', + 'AB3C7', + 'A4B5', +]; + +// FIXME? this concerns MPDS S-numerics: +//if (props_fgrs) props_fgrs.extend(['c--a', 'a--b', 'b--c', 'volume', 'density', 'alat', 'blat', 'clat']); +//if (props_ref) props_ref.extend( ['c--a', 'a--b', 'b--c', 'volume', 'density', 'alat', 'blat', 'clat']); + +/** + * Methods + */ + +wmgui.get_random_term = function (sequence) { + return sequence[Math.floor(Math.random() * sequence.length)]; +}; + +wmgui.is_wyckoff_position = function (input) { + return /^[1-9]/.test(input.trim()); +}; + +/** + * Generate random sequences + */ + +wmgui.get_realistic = function (facet, cur_nlen) { + var term; + + if (facet == 'elements') { + var i = 0, + els = [], + prob_arity = [2, 3], // 4 is improbable + cur_nlen = cur_nlen || wmgui.get_random_term(prob_arity); + + while (i < cur_nlen) { + var el; + if (i < 2) el = wmgui.get_random_term(wmgui.probable_els); + else el = wmgui.get_random_term(wmgui.most_frequent_els); + if (els.indexOf(el) > -1) continue; + els.push(el); + i++; + } + term = els.join('-'); + } else if (facet == 'formulae') { + term = wmgui.get_random_term(wmgui.most_frequent_formulae); + } else if (facet == 'anonymous') { + term = wmgui.get_random_term(wmgui.most_frequent_anonymous); + } else if (facet == 'props') { + term = wmgui.get_random_term(wmgui.most_frequent_props); + } else if (facet == 'classes') { + term = wmgui.get_random_term(wmgui.classes_families); + } else if (facet == 'lattices') { + term = wmgui.get_random_term(wmgui.most_frequent_lats); + } else + return wmgui.get_realistic( + ['elements', 'formulae', 'props', 'classes', 'lattices'][ + Math.floor(Math.random() * 5) + ], + ); + + return term; +}; + +/** + * Generate random sequences + */ + +wmgui.get_interesting = function (scene) { + var scenarios = [1, 2, 3, 4, 5, 6, 7, 8], + scene = scene || wmgui.get_random_term(scenarios), + result = { text: '', terms: [], facets: [] }; + + if (scene == 1) { + // classes-elements, 4% fails + result['facets'].extend(['classes', 'elements']); + result['terms'].extend([ + wmgui.get_random_term(wmgui.most_frequent_classes), + wmgui.get_realistic('elements', 2), + ]); + result['text'] += result['terms'][0] + ' ' + result['terms'][1]; + } else if (scene == 2) { + // classes-classes, 4.5% fails + result['facets'].extend(['classes', 'classes']); + result['terms'].extend([ + wmgui.get_random_term(wmgui.classes_groups), + wmgui.get_realistic('classes'), + ]); + result['text'] += result['terms'][0] + ' group, ' + result['terms'][1]; + } else if (scene == 3) { + // formulae-lattices, 1% fails + result['facets'].extend(['formulae', 'lattices']); + result['terms'].extend([ + wmgui.get_realistic('formulae'), + wmgui.get_realistic('lattices'), + ]); + result['text'] += + result['terms'][0] + ' ' + result['terms'][1] + ' crystal'; + } else if (scene == 4) { + // props-classes, always correct + result['facets'].extend(['props', 'classes']); + result['terms'].extend([ + wmgui.get_realistic('props'), + wmgui.get_realistic('classes'), + ]); + result['text'] += result['terms'][0] + ' for ' + result['terms'][1]; + if (!result['text'].endsWith('d') && !result['text'].endsWith('s')) + result['text'] += 's'; + } else if (scene == 5) { + // classes-lattices, 3% fails + result['facets'].extend(['classes', 'lattices']); + result['terms'].extend([ + wmgui.get_realistic('classes'), + wmgui.get_realistic('lattices'), + ]); + result['text'] += + result['terms'][0] + ', ' + result['terms'][1] + ' crystal'; + } else if (scene == 6) { + // elements-lattices, 3% fails + result['facets'].extend(['elements', 'lattices']); + result['terms'].extend([ + wmgui.get_realistic('elements'), + wmgui.get_realistic('lattices'), + ]); + result['text'] += + result['terms'][0] + ', ' + result['terms'][1] + ' crystal'; + } else if (scene == 7) { + // props and anonymous formulae + result['facets'].extend(['props', 'formulae']); + result['terms'].extend([ + wmgui.get_realistic('props'), + wmgui.get_realistic('anonymous'), + ]); + result['text'] += result['terms'][0] + ' ' + result['terms'][1]; + } else { + // props-formulae, 4% fails + result['facets'].extend(['props', 'formulae']); + result['terms'].extend([ + wmgui.get_realistic('props'), + wmgui.get_realistic('formulae'), + ]); + result['text'] += result['terms'][0] + ' of ' + result['terms'][1]; + } + return result; +}; + +/** + * Convert formula to HTML + */ + +wmgui.to_formula = function (input) { + return input.replace(/\d/g, '$&'); +}; + +/** + * Display processing results in HTML + */ + +wmgui.get_interpretation = function (search, facet_names, num_database) { + if (!search) search = {}; + + var interpret_html = '', + cur_nlen = 0; + + for (var k in search) { + var val = search[k]; + if (!facet_names[k] || !val) continue; + else if (k == 'formulae') val = wmgui.to_formula(val); + else if (k == 'doi' || k == 'sgs') val = decodeURIComponent(val); + else if (k == 'elements') { + var els = val.split('-'); + cur_nlen = els.length; + val = els + .map(function (x) { + return x.charAt(0).toUpperCase() + x.slice(1).toLowerCase(); + }) + .join(', '); + } else if (k == 'classes') { + val = val + .split(',') + .map(function (x) { + return x.trim(); + }) + .join(', '); + } else if (k == 'authors') { + val = val + .split(',') + .map(function (surname) { + return surname + .trim() + .split(' ') + .map(function (part) { + return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase(); + }) + .join(' '); + }) + .join(', '); + } else if (k == 'aeatoms') { + val = wmutils.parse_aeatoms(val); + val = val[0] + ' center and ' + val[1] + ' as ligands'; + } else if (k == 'aetypes') { + val = val + .split(',') + .map(function (x) { + var parts = x.trim().split('-vertex')[0].split(' '), + va = parseInt(parts[parts.length - 1]); + return x.replace(/\d{1,2}\-vertex/, 'CN = ' + va); + }) + .join(', '); + } else if (k == 'wyckoff') { + if (wmgui.is_wyckoff_position(val)) { + facet_names[k] = 'Wyckoff positions'; + } else { + facet_names[k] = 'Wyckoff sequence'; + val = val.replace(/\d/g, function (x) { + return [ + '⁰', + '¹', + '²', + '³', + '⁴', + '⁵', + '⁶', + '⁷', + '⁸', + '⁹', + ][x]; + }); + } + } else if (k == 'numeric') { + var out = ''; + val.forEach(function (member) { + var repr = member[0], + units = ''; + + if (num_database[repr]) { + var decimals = num_database[repr][4] + ? Math.abs(Math.log10(num_database[repr][4])) + : Math.max( + num_database[repr][2].count_decimals(), + num_database[repr][3].count_decimals(), + ); + member[2] = Number(member[2]).toFixed(decimals); + + if (num_database[repr][1]) units = ' ' + num_database[repr][1]; // units + + if (num_database[repr][5]) repr = num_database[repr][5]; // origname + } + out += repr + ' ' + member[1] + ' ' + member[2] + units + '
    '; + }); + val = out; + } + + interpret_html += + '
  • ' + + facet_names[k] + + '
    ' + + val + + '
  • '; + } + + if (!search.formulae && !is_empty(search)) { + var add_arity_helper = true, + arity_helper_html = '', + arity_keys = wmutils.arity_keys.slice(1); + + for (var num = 0; num < arity_keys.length; num++) { + var value = arity_keys[num]; + + if (search.classes && search.classes.indexOf(value) !== -1) { + add_arity_helper = false; + break; + } + + if (cur_nlen - 1 > num) continue; + + if ((cur_nlen < 4 && num > 3) || num > 4) break; + + if (window.location.hash.indexOf('inquiry') > -1) { + if (window.location.hash.indexOf('classes=') > -1) + var addr = window.location.hash.replace( + 'classes=', + 'classes=' + value + ',', + ); + else + var addr = window.location.hash.replace( + 'inquiry/', + 'inquiry/classes=' + value + '&', + ); + } else var addr = window.location.hash + ' ' + value; + + arity_helper_html += + '
  • Show only ' + + value.substr(0, value.length - 1) + + 'ies
  • '; + } + if (add_arity_helper) interpret_html += arity_helper_html; + } + + return interpret_html; +}; + +/** + * Parse MPDS BIBTEX + */ + +wmgui.parse_bib = function (string) { + try { + var title = string.split('title={')[1].split('},')[0].trim(), + authors = string.split('author={')[1].split('},')[0].trim(), + journal = string.split('journal={')[1].split('},')[0].trim(), + pubyear = string.split('year={')[1].split('},')[0].trim(); + } catch (error) { + console.error('Misformatted BIB, terminating...'); + var title = '', + authors = '', + journal = '', + pubyear = ''; + } + return [authors, title, journal, pubyear]; +}; diff --git a/src_js/events.js b/src_js/events.js deleted file mode 100755 index 3fe6e57..0000000 --- a/src_js/events.js +++ /dev/null @@ -1,1571 +0,0 @@ -"use strict"; - -var wmgui = window.wmgui || {}; - -function register_events(){ - - document.querySelector('#ptable_area > ul').addEventListener('click', function(event){ - var that = event.target; - if (!that.hasAttribute('data-pos')) - return; - - wmgui.ptable.update_selectize = true; - var selected_el = wmgui.ptable.elements[that.getAttribute('data-pos')]; - select_ptable_el(selected_el, that); - }); - - var radios = document.querySelectorAll('input[name="ptable_dtypes"]'); - for (var i = 0; i < radios.length; i++){ - radios[i].addEventListener('change', function(){ - if (!this.checked) return; - wmgui.ptable.dtypes = this.value; - var check = wmgui.multiselects['main'].read(); - select_ptable_series(check.elements); - }); - } - - $('#search_trigger').click(function(){ - - var query = wmgui.multiselects['main'].read(), - val = $('#search_field-selectized').val(); - - if (val){ - if (val.endsWith(" ") || val.endsWith(",")) val = val.substr(0, val.length - 1); - var parsed = wmutils.guess(val); - - for (var key in parsed){ - if (key == 'ignored') - continue; - else if (query[key] && key == 'elements') - query[key] += '-' + parsed[key]; - else if (query[key] && key == 'classes') - query[key] += ', ' + parsed[key]; - else - query[key] = parsed[key]; - } - } - - if (wmgui.search.numeric && !query.numeric){ - query.numeric = ''; - wmgui.search.numeric.forEach(function(item){ - query.numeric += serialize_numeric.apply(this, item); // unpack - }); - delete query.props; // NB to make the numeric results "more clear" - } - - if ($.isEmptyObject(query)){ - wmgui.notify('Sorry, unrecognized input'); - return false; - } - - wmgui.ctx_strict_phases = ''; - $('#ctx_strict_phases_trigger').prop('checked', true); - - var urlstr = $.param(query); - if (window.location.hash == '#inquiry/' + urlstr){ - // hash-hack FIXME? - if (urlstr.slice(-1) == '=') urlstr = urlstr.substr(0, urlstr.length - 1); - else urlstr += '='; - } - window.location.hash = '#inquiry/' + urlstr; - return false; - }); - - $('#advsearch_do_trigger').click(function(){ - var curval = '', - rest_input = '', - query = {}; - - $.each(wmgui.simple_facets, function(n, item){ - curval = $('#advs_fct_' + item).val(); - if (curval){ - if (item == "formulae") curval = wmutils.termify_formulae(curval); - else if (item == "elements") curval = curval.replaceAll(',', '').replaceAll(' ', '-'); - else if (item == "doi") curval = curval.replace('http:\/\/dx\.doi\.org\/', '').replace('http:\/\/doi\.org\/', '').trim(); - else if (item == "codens") curval = wmgui.journal_converter.j2c(curval); - query[item] = curval; - } - }); - - $.each(wmgui.multi_facets, function(n, item){ - curval = wmgui.multiselects[item].read(); - - if (curval[item]){ - curval = curval[item]; - if (item == "authors") curval = curval.replace(/'/g, '').replaceAll('\\.', ' ').replaceAll('\\b\\w{1}\\b', '').trim(); - query[item] = curval; - } - rest_input = $('#advs_fct_' + item + '-selectized').val(); - if (rest_input){ - if (query[item]) - query[item] += ', ' + rest_input; - else - query[item] = rest_input; - } - }); - - if (wmgui.search.numeric){ - query.numeric = ''; - wmgui.search.numeric.forEach(function(item){ - query.numeric += serialize_numeric.apply(this, item); // unpack - }); - delete query.props; // NB to make the numeric results "more clear" - } - - if ($.isEmptyObject(query)) return wmgui.notify('Sorry, search is empty'); - - wmgui.ctx_strict_phases = ''; - $('#ctx_strict_phases_trigger').prop('checked', true); - - var urlstr = $.param(query); - if (window.location.hash == '#inquiry/' + urlstr){ - // hash-hack FIXME? - if (urlstr.slice(-1) == '=') urlstr = urlstr.substr(0, urlstr.length - 1); - else urlstr += '='; - } - window.location.hash = '#inquiry/' + urlstr; - }); - - $('#advsearch_drop_trigger').click(function(){ - - $('input.advs_input').val(''); - - $.each(wmgui.multi_facets, function(n, item){ - $('#advs_fct_' + item + '-selectized').val(''); - wmgui.multiselects[item].clear(); - }); - - $('#aetmap').hide(); - $('#aet_limit').prop('checked', false); - - destroy_numericbox(); - delete wmgui.search.numeric; - // TODO? delete wmgui.search - }); - - $('#advsearch_init_trigger').click(function(){ - $('#advstab_options li').removeClass('working'); - $('#advstab_options li[rev=advstab_cry]').addClass('working'); - $('#advstab_cry').show(); - $('#advstab_main, #advstab_bib').hide(); - show_advsbox(); - return false; - }); - - $('#search_box').on('click', '#legend a', function(){ - var legend = $(this).text(); - window.location.hash = '#search/' + encodeURIComponent(legend); - return false; - }); - - $('div.advs_legend > a').click(function(){ - var that = $(this), - legend = that.attr('rel') || that.text(), - multiselects = that.parent().data('multiselects'); - - if (multiselects){ - $('#advs_fct_' + multiselects + '-selectized').val(''); - wmgui.multiselects[multiselects].clear(); - var obj = {}; - obj[multiselects] = legend; - wmgui.multiselects[multiselects].write(obj); - //wmgui.multiselects[multiselects].write({[multiselects]: legend}); - } else { - that.parent().parent().children('input').val(legend).focus(); - } - //if (legend.indexOf('-vertex') !== -1) show_aetmap(legend); - - return false; - }); - - $('#databrowser, #ptable_results').on('click', 'div.gallery_img', function(){ - var that = $(this); - if (that.attr('rel')){ - if (wmgui.view_mode === 1 && wmgui.ptable.dtypes > 1){ - var phid = that.attr('rel'); - - wmgui.ptable.dtypes == 2 ? - document.querySelector('#ptable_vis > iframe').contentWindow.location.hash = '#' + wmgui.phase_endpoint + '?phid=' + phid + '&struct=1' : - document.querySelector('#ptable_vis > iframe').contentWindow.location.replace(get_visavis_url({phid: phid}, 'graph', window.innerHeight - 50)); - - $('div.gallery_item.active').removeClass('active'); - that.parent().addClass('active'); - - } else { - var path = that.attr('data-path') || "phase_id"; - window.location.hash = '#' + path + '/' + that.attr('rel'); - } - } - }); - - $('#databrowser').on('mousedown', 'a.resolve_ref', function(e){ - var that = $(this), - bid = that.attr('rel'); - $('a.resolve_ref[rel=' + bid + ']').addClass('visited'); // :visited - wmgui.bid_history.push(parseInt(bid)); - window.localStorage.setItem(wmgui.store_bids_key, JSON.stringify(wmgui.bid_history)); - return true; - }); - - $('#databrowser').on('click', 'tr.tcell, div.gallery_item', function(){ - open_context($(this), false); - }); - - $('#databrowser').on('click', 'span.launch_v', function(e){ - wmgui.cancel_event(e); - var parent_row = $(this).parent().parent(); - parent_row.removeClass('busy_entry'); - open_context(parent_row, true); - }); - - $('#databrowser').on('click', 'a.launch_id', function(e){ - wmgui.cancel_event(e); - var phid_link = $(this).attr('href'); - if (window.location.hash == phid_link){ - // hash-hack FIXME? - phid_link += '.'; - } - window.location.hash = phid_link; - return false; - }); - - $('#all_polyhedra_content').on('click', 'div.gallery_item', function(){ - $('#advstab_options li').removeClass('working'); - $('#advstab_options li[rev=advstab_cry]').addClass('working'); - $('div.advstab').hide(); - $('#advstab_cry').show(); - $('div.modal').hide(); - $('#advsbox, #overlay').show(); - - var term = $(this).attr('rel'), - selected_aetypes = (wmgui.multiselects['aetypes'].read()['aetypes'] || "").split(', '); - if (selected_aetypes.indexOf(term) == -1) - wmgui.multiselects['aetypes'].write({'aetypes': term}); - show_aetmap(term); - }); - - $('#aet_limit').click(function(e){ - var selected_classes = (wmgui.multiselects['classes'].read()['classes'] || "").split(', '); - - if (this.checked){ - var selected_aetypes = (wmgui.multiselects['aetypes'].read()['aetypes'] || "").split(', ').filter(function(x){ return x }), - limit_kwd = wmgui.poly_limits[selected_aetypes.length]; - - if (!limit_kwd){ - wmgui.cancel_event(e); - wmgui.notify('Sorry, only up to 3 supported'); - return false; - } - if (selected_classes.indexOf(limit_kwd) == -1){ - wmgui.multiselects['classes'].write({'classes': limit_kwd}); - } - - } else { - var poly_limits = Object.values(wmgui.poly_limits); - wmgui.multiselects['classes'].clear(); - wmgui.multiselects['classes'].write({'classes': selected_classes.filter(function(x){ return poly_limits.indexOf(x) == -1 }).join(', ')}); - } - return true; - }); - - $('#visualize, #xrpdize').click(function(){ - close_vibox(); - launch_db_iframed(this.getAttribute('data-rank')); - }); - - /*$('#absolidize').click(function(){ - - if (!$(this).hasClass('wmbutton')) return false; - - if (!wmgui.sid){ - window.localStorage.setItem(window.store_redir_key, '/' + window.location.hash); - return window.location.replace('#modal/login'); - } - - var entry = $('#entryno > a').text(); - - try { wmgui.active_ajax.abort() } catch(e){} - - $.ajax({ - type: 'GET', - url: wmgui.mydata_endpoint, - data: {q: entry, sid: wmgui.sid}, - beforeSend: wmgui.show_preloader - - }).always(wmgui.hide_preloader).done(function(data){ - - if (data.error) return wmgui.notify(data.error); - - wmgui.mydata_history.push(entry); - window.localStorage.setItem(wmgui.store_mydata_key, JSON.stringify(wmgui.mydata_history)); - $('#absolidize').removeClass('wmbutton'); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Please, make sure your access works
    and try again'); - }); - });*/ - - $('#refine_col').on('click', 'a.extd_refine', function(){ - var facet = $(this).attr('rel'); - if ($('#refine_col > ul > li.extd_rfns.fct_' + facet).length){ - $('#refine_col > ul > li:not(.fct_' + facet + ')').addClass('hidden_rfns').slideUp(); - $('#refine_col > ul > li.extd_rfns.fct_' + facet).show(); - $('a.extd_refine[rel=' + facet + ']').parent().hide(); - return false; - } - var given_search = {extd_refine: facet}; - $.extend(given_search, wmgui.search); - try { wmgui.active_ajax.abort() } catch(e){} - - wmgui.active_ajax = $.ajax({ - type: 'GET', - url: wmgui.rfn_endpoint, - data: {q: JSON.stringify(given_search)} - - }).done(function(data){ - if (data.error) return wmgui.notify(data.error); - var html = ''; - delete given_search['numeric']; - delete given_search['extd_refine']; - //if (given_search.classes) given_search.classes = given_search.classes.split(',').join(' '); - - var inquiry = false; - $.each(wmgui.inquiries, function(n, i){ if (given_search[i]){ inquiry = true; return false; } }); - - $.each(data.payload, function(i, found){ - // FIXME: duplicating - var link_base = '', - orepr = {}; - //count_text = ' ('+found[1]+')'; - - $.each(given_search, function(key, val){ - if (key == 'search_type') - return true; - else if (facet == 'elements' && (key == 'elements' || key == 'formulae')) - return true; - else if (facet == 'props' && key == 'props') - return true; - - link_base += val + ' '; - - if (orepr[key]) orepr[key] += ', ' + val; - else orepr[key] = val; - }); - - //if (facet == 'elements') count_text = ''; - if (facet == 'props'){ - found[0] = found[0].replace(/\(|\)/g, "").replace(/\/[\w\-]*/g, ""); // FIXME - } - - if (orepr[facet]) orepr[facet] += ', ' + found[0]; - else orepr[facet] = found[0]; - - if (orepr['elements']) orepr['elements'] = orepr['elements'].replaceAll(', ', '-'); - - if (inquiry) html += '
  • ' + found[0] + '
  • '; - else html += '
  • ' + found[0] + '
  • '; - }); - - html += '
  • Show less 
  • '; - $('#refine_col > ul > li:not(.fct_' + facet + ')').addClass('hidden_rfns').slideUp(); - $('a.extd_refine[rel=' + facet + ']').parent().hide().after(wmgui.clean(html)); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Connection to server is lost, please try to reload'); - }); - return false; - }); - - $('#refine_col').on('click', 'a.collapse_refine', function(){ - var facet = $(this).attr('rel'); - $('a.extd_refine[rel=' + facet + ']').parent().show(); - $('#refine_col > ul > li.hidden_rfns').removeClass('hidden_rfns').slideDown(250); - $('#refine_col > ul > li.extd_rfns').hide(); - return false; - }); - - /*$('#fdwidget').on('click', 'span', function(){ - var what = $(this).attr('id'); - if (what == 'fdwidget_yes'){ - $('#fdwidget').html('We appreciate your feedback!'); - } else { - $('#fdwidget').html(wmgui.contact_html); - $('#fdwidget_msg').focus(); - } - });*/ - - /*$('#fdwidget').on('click', 'div.wmbutton', function(){ - if ($(this).data('busy')) return; - $(this).data('busy', true); - $.ajax({ - type: 'POST', - url: wmgui.fd_endpoint, - data: {fdwidget_msg: $('#fdwidget_msg').val(), fdwidget_msgtype: $('#fdwidget_msgtype').val(), fdwidget_url: window.location.href}, - beforeSend: wmgui.show_preloader - - }).always(wmgui.hide_preloader).done(function(data){ - $('#fdwidget_trigger').data('busy', false); - if (data.error) return wmgui.notify(data.error); - $('#fdwidget').html('We appreciate your feedback!'); - - }).fail(function(xhr, textStatus, errorThrown){ - wmgui.notify("Sorry, cannot process your input"); - }); - });*/ - - $('#tagcloudbox').on('click', 'a.collateral', function(){ - $('#userbox').data('saved_hash', false) - var act = $(this).attr('rel'); - if (act == 'adv'){ - $('#advsearch_init_trigger').trigger('click'); - $('div.menu_collateral').hide(); - - } else if (act == 'idea'){ - window.location.hash = '#plot/' + wmgui.get_random_term(['pie', 'lit', 'graph']) + '/search/' + wmgui.get_interesting()['text']; - - } else if (act == 'sod'){ - var now = new Date(), - pick = now.getDate() % wmgui.s_examples.length, - start = new Date(now.getFullYear(), 0, 0), - diff = (now - start) + ((start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000), - nday = Math.floor(diff / (1000 * 60 * 60 * 24)), - sod = wmgui.s_examples[pick] + nday; - window.location.hash = '#entry/S' + sod; - - } else if (act == 'my'){ - var locals = JSON.parse(window.localStorage.getItem(wmgui.store_user_key) || '{}'); - if (locals.ipbased){ - window.location.hash = '#inquiry/orgs=' + locals.name; - - } else if (locals.name){ - var names = locals.name.split(' '); - window.location.hash = '#inquiry/authors=' + encodeURIComponent(names[names.length - 1]); - } - } - return false; - }); - - $('#hintsbox_msg').on('click', 'div.wmbutton', function(){ - // copy to clipbox functionality - var range = document.createRange(); - range.selectNode($('#hintsbox_msg > pre').get(0)); - window.getSelection().removeAllRanges(); - window.getSelection().addRange(range); - document.execCommand('copy'); - wmgui.notify('Copied'); - }); - - $('#tooltip').on('click', 'span', function(){ - var that = $(this), - act = that.attr('rel'), - forced = that.hasClass('forced'); - document.getElementById('tooltip').style.display = 'none'; - if (act && wmgui.tooltips[act]) show_tooltip(wmgui.tooltips[act], forced); - }); - - $('#sim_col').on('click', 'li > a', function(){ - $('#sim_col > ul > li').removeClass('selected'); - $(this).parent().addClass('selected'); - wmgui.passive_sim_col = false; - return true; - }); - - $('div.close_user_dialogue').click(function(){ - $('#userbox').trigger('click'); - }); - - $('div.close_advs_dialogue').click(function(){ - $('#advsbox, #overlay, #aetmap').hide(); - }); - - $('#close_inquiry_dialogue').click(function(){ - $('#inquirybox').hide(); - }); - - $('#close_ss_dialogue').click(function(){ - - var x_sort = $('#ss_x > ul > li.ss_x').attr('rel').split('_')[1], - y_sort = $('#ss_y > ul > li.ss_y').attr('rel').split('_')[1], - x_op = $('#sops_x > ul > li.sops_x').text(), - y_op = $('#sops_y > ul > li.sops_y').text(), - x_op = (x_op == 'none') ? false : x_op, - y_op = (y_op == 'none') ? false : y_op; - - if ($('#ss_z').is(':visible')){ - var z_sort = $('#ss_z > ul > li.ss_z').attr('rel').split('_')[1], - z_op = $('#sops_z > ul > li.sops_z').text(), - z_op = (z_op == 'none') ? false : z_op; - - $('#ctxpanel_cube > ul > li.embodied').removeClass('embodied'); - $('#viscube_' + x_sort).addClass('embodied'); - $('#ctxpanel_cube > ul > li.ss_y').removeClass('ss_y'); - $('#viscube_' + y_sort).addClass('ss_y'); - $('#ctxpanel_cube > ul > li.ss_z').removeClass('ss_z'); - $('#viscube_' + z_sort).addClass('ss_z'); - - $('span.sops').remove(); - if (x_op) $('' + x_op + '').appendTo('#viscube_' + x_sort); - if (y_op) $('' + y_op + '').appendTo('#viscube_' + y_sort); - if (z_op) $('' + z_op + '').appendTo('#viscube_' + z_sort); - - if (document.getElementById('visavis_iframe').contentWindow.location.hash.indexOf('fixel=1') !== -1) - document.getElementById('visavis_iframe').contentWindow.matrix_order(x_sort, y_sort, x_op, y_op); - else - document.getElementById('visavis_iframe').contentWindow.cube_order(x_sort, y_sort, z_sort, x_op, y_op, z_op); - - } else { - if ((x_op && x_sort == 'count') || (y_op && y_sort == 'count')) return wmgui.notify('Sorry, data counts are not supported'); - - $('#ctxpanel_matrix > ul > li.embodied').removeClass('embodied'); - $('#vismatrix_' + x_sort).addClass('embodied'); - $('#ctxpanel_matrix > ul > li.ss_y').removeClass('ss_y'); - $('#vismatrix_' + y_sort).addClass('ss_y'); - - $('span.sops').remove(); - if (x_op) $('' + x_op + '').appendTo('#vismatrix_' + x_sort); - if (y_op) $('' + y_op + '').appendTo('#vismatrix_' + y_sort); - - document.getElementById('visavis_iframe').contentWindow.matrix_order(x_sort, y_sort, x_op, y_op); - } - - $('#ss_custom_box, #overlay').hide(); - $('div.ss_col > ul').empty(); - }); - - $('#close_dc_dialogue').click(function(){ - $('#discovery_custom_box, #overlay').hide(); - $('#discovery_enabled, #discovery_disabled').empty(); - document.getElementById('visavis_iframe').contentWindow.discovery_rerun(); - $('#select_cmp_trigger').val('X'); - }); - - // not handled by ermac? - $('#close_formal_dialogue').click(function(){ - window.location.hash = '#start'; - }); - - // not handled by ermac? - $('#close_ph_dialogue, div.close_hy_dialogue, div.close_product_dialogue').click(function(){ - if (document.referrer.indexOf(window.location.host) == -1) window.location.hash = '#start'; // FIXME: empty referrer - else { - var prev = window.location.href; - window.history.go(-1); - setTimeout(function(){ if (window.location.href == prev) window.location.hash = '#start' }, 500); - } - }); - - /** $('#overlay').click(function(){ - $('div.modal:visible').each(function(){ - $(this).find('div.cross').trigger('click'); - }); - }); **/ - - $('div._close_ctx').click(function(){ - try { wmgui.quick_ajax.abort() } catch(e){} - $('.busy_entry').removeClass('busy_entry'); - $('#ctx_col, #sim_col').hide(); - wmgui.passive_sim_col = true; - close_vibox(); - }); - - $('#hy_box').on('click', 'span', function(){ - var hyid = $(this).attr('class'); - $('span.' + hyid).each(function(){ - var that = $(this); - that.parent().find('ul').toggle(); - that.text() == 'expand' ? that.text('collapse') : that.text('expand'); - }); - }); - - $('#hy_box').on('click', 'a.dynprop', function(){ - // FIXME cannot process with the optimade NLP parser - //if (wmgui.view_mode == 1) - // return true; - - var value = $(this).attr('data-val'); - window.location.hash = wmgui.aug_search_cmd("props", value); - return false; - }); - - // numeric search - $('#hy_box').on('click', 'strong.numeric', function(){ - var prop = $(this).attr('rel'), - data = wmgui.numerics[prop], - prop_id = data[0], - units = data[1], - min = data[2], - max = data[3], - step = data[4]; - var nblocks = $('div.slider_numerics').length; - if (nblocks >= 2) wmgui.notify('Too little phases have all these properties reported — expect no results'); - if (nblocks >= 8) - return; - create_floating_slider(prop, prop_id, units, min, max, step); - }); - - $('strong.numeric').click(function(){ - var prop = $(this).attr('rel'), - data = wmgui.numerics[prop], - prop_id = data[0], - units = data[1], - min = data[2], - max = data[3], - step = data[4]; - create_floating_slider(prop, prop_id, units, min, max, step); - }); - - $('#hy_options > li').click(function(){ - var that = $(this), - desttab = that.attr('rev'); - if (desttab == 'hy_vis'){ - window.open(wmgui.static_host + '/labs/ontology'); - return; - } - that.addClass('working').siblings().removeClass('working'); - $('div.hy_tabs').hide(); - $('#' + desttab).show(); - }); - - $('#dtypes > ul > li').click(function(){ - var that = $(this), - facet = that.data('facet'), - term = that.data('term'); - - if (facet == 'classes'){ - if (wmgui.search.classes) // FIXME? - wmgui.search.classes = wmgui.search.classes.replace('peer-reviewed', '').replace('peer-review', '').replace('machine-learning', '').replace('machine learning', '').replace('ab initio calculations', '').split(',').map(function(x){ return x.trim() }).filter(function(x){ return x }).join(', '); - //wmgui.inquiries.forEach(function(item){ - // if (wmgui.search[item]) delete wmgui.search[item]; - //}); - } - window.location.hash = wmgui.aug_search_cmd(facet, term); - }); - - $('#dtypes_phid > ul > li').click(function(){ - var that = $(this), - rankfilter = that.data('rankfilter'), - active = that.hasClass('active'), - legend = that.text(); - request_search({'phid': wmgui.search.phid, 'rankfilter': active ? null : rankfilter}, legend + ' of phase ' + wmgui.search.phid, true); - $('#dtypes_phid > ul > li').removeClass('active'); - active ? this.classList.remove('active') : this.classList.add('active'); - }); - - $(window).scroll(wmgui.debounce(function(){ - if (wmgui.view_mode == 2){ - if (wmgui.unfinished_page){ - if ($('#footer').offset().top - $(window).scrollTop() - $(window).height() < 50){ // footer pos - scrolling - window height - - wmgui.unfinished_page = false; - var cur_search = {offset: wmgui.quick_page_size}; - $.extend(cur_search, wmgui.search); - - // NB no abort of the other requests! - wmgui.active_ajax = $.ajax({ - type: 'GET', - url: wmgui.search_endpoint, - data: { - q: JSON.stringify(cur_search), - strict: wmgui.ctx_strict_phases, - //subphases: wmgui.ctx_subphases, - sid: wmgui.sid - }, - beforeSend: wmgui.show_preloader - - }).always(wmgui.hide_preloader).done(function(data){ - if (data.error) return wmgui.notify(data.error); - $('div.context_msg').hide(); - show_hints(); - if (!data.out.length) - return; - if (wmgui.thumbed_display){ - $('#databrowser tr td').append(build_thumbs(data.out)); - } else { - $('#databrowser tbody').append(build_cells(data.out)); - $('#databrowser').trigger('update'); - } - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Connection to server is lost, please try to reload'); - }); - } - } - var iframe = $('#iframe'); - if (iframe.length && !wmgui.is_inview(iframe)) close_vibox(); - - } else if (wmgui.ptable.activated){ - - var scroll_pos = window.scrollY; - //console.log(scroll_pos); - - if (scroll_pos > 40){ - document.getElementById('ptable_dtypes_box').classList.remove('resulted'); - document.getElementById('legend').style.display = 'none'; - - (wmgui.ptable.vis_fixed && scroll_pos > 550) ? document.getElementById('ptable_vis').classList.add('fixed') : - document.getElementById('ptable_vis').classList.remove('fixed'); - - } else { - document.getElementById('ptable_dtypes_box').classList.add('resulted'); - document.getElementById('legend').style.display = 'block'; - document.getElementById('ptable_vis').classList.remove('fixed'); - } - } - }, 300)); - - $('#userbox').click(function(){ - var that = $(this); - if (window.location.hash == that.data('saved_hash')) - that.data('saved_hash', false); - - if (that.data('saved_hash')){ - window.location.replace(that.data('saved_hash')); - that.data('saved_hash', false); - - } else { - if (window.location.hash.indexOf('modal') !== -1){ - window.location.replace('#start'); - } else { - that.data('saved_hash', window.location.hash); - - if (wmgui.sid) window.location.replace('#modal/menu'); - else window.location.replace('#modal/login'); - } - } - }); - - $('span.href[rel]').click(function(){ - window.location.replace($(this).attr('rel')); - }); - - $('div.spinoff_pane').on('click', 'span.extd', function(){ - var that = $(this); - that.siblings('span.legend').toggle(); - that.text() == 'Show more info...' ? that.text('Hide more info...') : that.text('Show more info...'); - }); - - $('#interpret').on('click', 'li', function(){ - var that = $(this), - link = that.attr('rel'); - if (!!link){ // search only ... arity - window.location.hash = link; - return; - } - - var csscls = that.attr('class'); - - if (csscls.indexOf('numeric') !== -1){ - window.location.hash = '#hierarchy'; - - } else if (csscls.indexOf('authors') !== -1 || csscls.indexOf('years') !== -1 || csscls.indexOf('codens') !== -1 || csscls.indexOf('doi') !== -1 || csscls.indexOf('geos') !== -1 || csscls.indexOf('orgs') !== -1){ - $('#advstab_options li').removeClass('working'); - $('#advstab_options li[rev=advstab_bib]').addClass('working'); - $('div.advstab').hide(); - $('#advstab_bib').show(); - show_advsbox(); - - } else if (csscls.indexOf('formulae') !== -1 || csscls.indexOf('props') !== -1 || csscls.indexOf('elements') !== -1 || csscls.indexOf('classes') !== -1) { - $('#advstab_options li').removeClass('working'); - $('#advstab_options li[rev=advstab_main]').addClass('working'); - $('div.advstab').hide(); - $('#advstab_main').show(); - show_advsbox(); - - } else { - $('#advstab_options li').removeClass('working'); - $('#advstab_options li[rev=advstab_cry]').addClass('working'); - $('div.advstab').hide(); - $('#advstab_cry').show(); - show_advsbox(); - if (wmgui.search.aetypes) show_aetmap(wmgui.search.aetypes); - } - }); - - $('#tab_links > li').click(function(){ - try { wmgui.active_ajax.abort() } catch(e){} - try { wmgui.quick_ajax.abort() } catch(e){} - - var that = $(this), - desttab = that.attr('rev'); - - that.addClass('working').siblings().removeClass('working'); - $('div.menu_tabs').hide(); - $('#' + desttab).show(); - - if (desttab == 'usr_tab_api_key'){ - $('#hintsbox_msg').html(wmgui.api_msg); - - wmgui.active_ajax = $.ajax({ - type: 'POST', - url: wmgui.api_key_endpoint, - data: {sid: wmgui.sid}, - beforeSend: wmgui.show_preloader - - }).always(wmgui.hide_preloader).done(function(data){ - if (data.error) return wmgui.notify(data.error); - $('#usr_api_key').html(data.msg); - if (data.revokable) $('#revoke_usr_api_key_holder').show(); - else if (data.creatable) $('#create_usr_api_key_holder').show(); - else return wmgui.notify('Your session ended: please, log in again'); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Your session ended: please, log in again'); - $('#usr_api_key').html('authentication error'); - }); - - } else if (desttab == 'usr_tab_perms'){ - $('#hintsbox_msg').html(wmgui.get_random_term(wmgui.welcome_msgs)); - - var locals = JSON.parse(window.localStorage.getItem(wmgui.store_user_key) || '{}'); - - wmgui.active_ajax = $.ajax({ - type: 'POST', - url: locals.ipbased ? wmgui.ip_perms_endpoint : wmgui.perms_endpoint, - data: {sid: wmgui.sid}, - beforeSend: wmgui.show_preloader - - }).always(wmgui.hide_preloader).done(function(data){ - if (data.error) return wmgui.notify(data.error); - if (!data.hasOwnProperty('gui') || !data.hasOwnProperty('api')) return wmgui.notify('Your session ended: please, log in again'); - $('#perms_view').html(describe_perms(data)); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Your session ended: please, log in again'); - $('#perms_view').html('authentication error'); - }); - - } else if (desttab == 'usr_tab_ctrl'){ // redirect to an external app - window.location.href = '/ctrl/?' + Math.floor(Math.random() * 1000); - - } else if (desttab == 'usr_tab_absolidix'){ // redirect to an external app - window.location.href = wmgui.mydata_addr; - - } else if (desttab == 'usr_tab_account'){ - $('#hintsbox_msg').html(wmgui.get_random_term(wmgui.welcome_msgs)); - } - }); - - $('#advstab_options > li').click(function(){ - var that = $(this), - desttab = that.attr('rev'); - - that.addClass('working').siblings().removeClass('working'); - - $('div.advstab').hide(); - $('#' + desttab).show(); - }); - - $('a.link_adjuster').click(function(){ - // hash-hack FIXME? - if (window.location.hash == '#polyhedra'){ window.location.hash = '#polyhedra/'; return false; } - else if (window.location.hash == '#polyhedra/'){ window.location.hash = '#polyhedra'; return false; } - else return true; - }); - - $('#create_usr_api_key').click(function(){ - $(this).parent().hide(); - try { wmgui.active_ajax.abort() } catch(e){} - - wmgui.active_ajax = $.ajax({ - type: 'POST', - url: wmgui.api_key_endpoint, - data: {sid: wmgui.sid, create: true}, - beforeSend: wmgui.show_preloader - - }).always(wmgui.hide_preloader).done(function(data){ - if (data.error) return wmgui.notify(data.error); - $('#usr_api_key').html(data.msg); - $('#revoke_usr_api_key_holder').show(); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Your session ended: please, log in again'); - }); - }); - $('#revoke_usr_api_key').click(function(){ - $(this).parent().hide(); - try { wmgui.active_ajax.abort() } catch(e){} - - wmgui.active_ajax = $.ajax({ - type: 'POST', - url: wmgui.api_key_endpoint, - data: {sid: wmgui.sid, revoke: true}, - beforeSend: wmgui.show_preloader - - }).always(wmgui.hide_preloader).done(function(data){ - if (data.error) return wmgui.notify(data.error); - $('#usr_api_key').html('Successfully revoked'); - $('#create_usr_api_key_holder').show(); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Your session ended: please, log in again'); - }); - }); - - $('#login_trigger').click(function(){ - if ($(this).data('busy')) return; - $(this).data('busy', true); - $(this).text('In process...'); - - try { wmgui.active_ajax.abort() } catch(e){} - - wmgui.active_ajax = $.ajax({ - type: 'POST', - url: wmgui.login_endpoint, - data: {login: $('#login_email').val().trim(), pass: $('#login_password').val(), ed: wmgui.edition}, - beforeSend: wmgui.show_preloader - - }).always(function(){ - $('#login_trigger').data('busy', false); - $('#login_trigger').text('Login'); - wmgui.hide_preloader(); - - }).done(function(data){ - if (data.error) return wmgui.notify(data.error); - if (!data.sid || !data.name || !data.acclogin) return wmgui.notify('Connection to server is lost, please try to reload'); - user_login(data.sid, data.name, data.acclogin, data.admin, data.oauths); - $('#userbox').trigger('click'); - - }).fail(function(xhr, textStatus, errorThrown){ - wmgui.notify("Login unsuccessful"); - }); - }); - - $('#factor_trigger').click(function(){ - if ($(this).data('busy')) return; - $(this).data('busy', true); - $(this).text('Sending...'); - - try { wmgui.active_ajax.abort() } catch(e){} - - wmgui.active_ajax = $.ajax({ - type: 'POST', - url: wmgui.factor_endpoint, - data: {login: $('#factor_by_email').val().trim()}, - beforeSend: wmgui.show_preloader - - }).always(function(){ - $('#factor_trigger').data('busy', false); - $('#factor_trigger').text('Send code'); - wmgui.hide_preloader(); - - }).done(function(data){ - if (data.error) return wmgui.notify(data.error); - wmgui.notify('Please, check your inbox (and spam)'); - - // handle factor log in step two... - document.getElementById('factor_trigger').style.display = 'none'; - document.getElementById('factor_form_step_one').style.display = 'none'; - document.getElementById('factor_form_step_two').style.display = 'block'; - document.getElementById('factor_form_resp_0').focus(); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Sorry, a network error occured. Please, try again'); - }); - }); - - $('#restore_trigger').click(function(){ - if ($(this).data('busy')) return; - $(this).data('busy', true); - $(this).text('Sending...'); - - try { wmgui.active_ajax.abort() } catch(e){} - - wmgui.active_ajax = $.ajax({ - type: 'POST', - url: wmgui.restore_endpoint, - data: {login: $('#restore_by_email').val().trim(), ed: wmgui.edition}, - beforeSend: wmgui.show_preloader - - }).always(function(){ - $('#restore_trigger').data('busy', false); - $('#restore_trigger').text('Send link'); - wmgui.hide_preloader(); - - }).done(function(data){ - if (data.error) return wmgui.notify(data.error); - wmgui.notify('Please, check your inbox (and spam)'); - $('#userbox').trigger('click'); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Sorry, a network error occured. Please, try again'); - }); - }); - - $('#accpass_trigger').click(function(){ - - if ($(this).hasClass('disabled')) return false; - - $('#account_pass_change').toggle(); - }); - - $('#password_trigger').click(function(){ - var p1 = $("#new_password_1").val(), - p2 = $("#new_password_2").val(); - if (!p1 || !p2) return wmgui.notify("Please, type your new password in both fields"); - if (p1 !== p2) return wmgui.notify("Passwords do not match (typo?)"); - - if ($(this).data('busy')) return; - $(this).data('busy', true); - $(this).text('Changing...'); - - try { wmgui.active_ajax.abort() } catch(e){} - - wmgui.active_ajax = $.ajax({ - type: 'POST', - url: wmgui.password_endpoint, - data: {new_password: p2, sid: wmgui.sid, ed: wmgui.edition}, - beforeSend: wmgui.show_preloader - - }).always(function(){ - $('#password_trigger').data('busy', false); - $('#password_trigger').text('Change'); - wmgui.hide_preloader(); - - }).done(function(data){ - if (data.error) return wmgui.notify(data.error); - user_login(data.sid, data.name, data.acclogin, data.admin, data.oauths); - window.location.replace('#start'); - $('#account_pass_change').hide(); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Your session ended: please, log in again'); - }); - }); - - $('#logout_trigger').click(function(){ - - if ($(this).hasClass('disabled')) return false; - - $.ajax({ - type: 'POST', - url: wmgui.logout_endpoint, - data: {sid: wmgui.sid} - - }).done(function(data){}).fail(function(xhr, textStatus, errorThrown){}); - user_logout(); - $('#userbox').trigger('click'); - }); - $('#notifybox').on('click', 'span.relogin', force_relogin); - - var resps = document.getElementsByClassName('factor_form_resp'); - for (var i = 0; i < resps.length; i++) { - - resps[i].addEventListener('keyup', function(evt) { - - // back, left arrow - if (evt.keyCode == 8 || evt.keyCode == 37) { - var prev = this.previousElementSibling; - if (prev) { - prev.focus(); - prev.select(); - } - - } else if (evt.keyCode > 47 && evt.keyCode < 58) { - - submit_factor_form_resp(); - - var next = this.nextElementSibling; - if (next) { - next.focus(); - next.select(); - } - } - }); - - resps[i].addEventListener('paste', function(evt) { - var pasted = (evt.clipboardData || window.clipboardData).getData("text"); - if (!pasted || !pasted.length) - return false; - - for (var i = 0; i < 6; i++) { - document.getElementById('factor_form_resp_' + i).value = pasted.charAt(i); - } - submit_factor_form_resp(); - }); - } - - $('#search_holder').keydown(function(e){ - var key = window.event ? e.keyCode : e.which; - if (key == 13) $('#search_trigger').trigger('click'); - }); - - // switch sliders: first row abf - $('#control_a').click(function(){ // entries - ///re_view_request(0); - var orepr = {}; - for (var key in wmgui.search){ - if (['search_type', 'phid'].indexOf(key) !== -1) continue; - orepr[key] = wmgui.search[key]; - } - - wmgui.search_type = 0; - wmgui.search.search_type = wmgui.search_type; - - var urlstr = $.param(orepr); - if (urlstr.slice(-1) == '=') urlstr = urlstr.substr(0, urlstr.length - 1); - else urlstr += '='; - - window.location.hash = '#inquiry_entries/' + urlstr; - }); - $('#control_b').click(function(){ // phases - ///re_view_request(1); - var orepr = {}; - for (var key in wmgui.search){ - if (['search_type', 'phid'].indexOf(key) !== -1) continue; - orepr[key] = wmgui.search[key]; - } - - wmgui.search_type = 1; - wmgui.search.search_type = wmgui.search_type; - - var urlstr = $.param(orepr); - if (urlstr.slice(-1) == '=') urlstr = urlstr.substr(0, urlstr.length - 1); - else urlstr += '='; - - window.location.hash = '#inquiry_phases/' + urlstr; - }); - $('#control_f').click(function(){ // articles - ///re_view_request(2); - var orepr = {}; - for (var key in wmgui.search){ - if (['search_type', 'phid'].indexOf(key) !== -1) continue; - orepr[key] = wmgui.search[key]; - } - - wmgui.search_type = 2; - wmgui.search.search_type = wmgui.search_type; - - var urlstr = $.param(orepr); - if (urlstr.slice(-1) == '=') urlstr = urlstr.substr(0, urlstr.length - 1); - else urlstr += '='; - - window.location.hash = '#inquiry_articles/' + urlstr; - }); - - // switch sliders: second row cde - $('#control_c').click(function(){ // table - wmgui.visavis_terminating = true; - wmgui.thumbed_display = false; - if (wmgui.visavis_working){ - var orepr = {}; - for (var key in wmgui.search){ - if (['search_type', 'phid', 'numeric'].indexOf(key) !== -1) continue; - orepr[key] = wmgui.search[key]; - } - var urlstr = $.param(orepr); - if (window.location.hash == '#inquiry/' + urlstr){ - // hash-hack FIXME? - if (urlstr.slice(-1) == '=') urlstr = urlstr.substr(0, urlstr.length - 1); - else urlstr += '='; - } - window.location.hash = '#inquiry/' + urlstr; - - } else re_view_request(wmgui.search_type); - wmgui.chosen_table_browser = true; - }); - $('#control_d').click(function(){ // previews - wmgui.visavis_terminating = true; - wmgui.thumbed_display = true; - if (wmgui.visavis_working){ - var orepr = {}; - for (var key in wmgui.search){ - if (['search_type', 'phid', 'numeric'].indexOf(key) !== -1) continue; - orepr[key] = wmgui.search[key]; - } - var urlstr = $.param(orepr); - if (window.location.hash == '#inquiry/' + urlstr){ - // hash-hack FIXME? - if (urlstr.slice(-1) == '=') urlstr = urlstr.substr(0, urlstr.length - 1); - else urlstr += '='; - } - window.location.hash = '#inquiry/' + urlstr; - - } else re_view_request(wmgui.search_type); - wmgui.chosen_table_browser = true; - }); - $('#control_e').click(function(){ // plotting - var orepr = {}; - for (var key in wmgui.search){ - if (['search_type', 'phid', 'numeric'].indexOf(key) !== -1) continue; - orepr[key] = wmgui.search[key]; - } - while (true){ - var plot_type = wmgui.get_random_term(['matrix', 'cube']); // the most interesting visualization types - if (plot_type != wmgui.visavis_curtype) break; - } - window.location.hash = '#plot/' + plot_type + '/inquiry/' + $.param(orepr); - }); - - $('#ctx_strict_phases_trigger').change(function(e){ - //$('#ctx_subphases_trigger').prop('checked', false); - - if (!wmgui.search.elements){ - wmgui.cancel_event(e); - return false; - } - - var arity_kwd = wmutils.arity_keys[wmgui.search.elements.split('-').length], - kwd_exists = false; - - if (wmgui.search.classes){ - $.each(wmutils.arity_keys.slice(1), function(num, value){ - - if (num == 6) - return false; - - if (wmgui.search.classes.indexOf(value) !== -1){ - kwd_exists = true; - return false; - } - }); - - if (!kwd_exists){ - wmgui.search.classes += ', ' + arity_kwd; - wmgui.multiselects['main'].write({'classes': arity_kwd}); - } - - } else { - wmgui.search.classes = arity_kwd; - wmgui.multiselects['main'].write({'classes': arity_kwd}); - } - - wmgui.ctx_strict_phases = $('#ctx_strict_phases_trigger').is(':checked') ? '' : '1'; - re_view_request(wmgui.search_type); - }); - /*$('#ctx_subphases_trigger').change(function(){ - //$('#ctx_strict_phases_trigger').prop('checked', false); - wmgui.ctx_subphases = wmgui.search.elements && $('#ctx_subphases_trigger').is(':checked') ? '1' : ''; - re_view_request(wmgui.search_type); - });*/ - - // visavis ctx - $('#ctxpanel_matrix > ul > li').click(function(){ - var that = $(this); - if (that.hasClass('embodied') || that.hasClass('ss_y')) return; - var type = that.attr('id').split('_')[1], - y_id = $('#ctxpanel_matrix > ul > li.ss_y'); - $('#ctxpanel_matrix > ul > li.embodied').removeClass('embodied'); - if (y_id.length) y_id.removeClass('ss_y'); - that.addClass('embodied'); - $('span.sops').remove(); - - document.getElementById('visavis_iframe').contentWindow.matrix_order(type); - }); - $('#ctxpanel_cube > ul > li').click(function(){ - var that = $(this); - if (that.hasClass('embodied') || that.hasClass('ss_y') || that.hasClass('ss_z')) return; - var type = that.attr('id').split('_')[1], - y_id = $('#ctxpanel_cube > ul > li.ss_y'), - z_id = $('#ctxpanel_cube > ul > li.ss_z'); - $('#ctxpanel_cube > ul > li.embodied').removeClass('embodied'); - if (y_id.length) y_id.removeClass('ss_y'); - if (z_id.length) z_id.removeClass('ss_z'); - that.addClass('embodied'); - $('span.sops').remove(); - - if (document.getElementById('visavis_iframe').contentWindow.location.hash.indexOf('fixel=1') !== -1) - document.getElementById('visavis_iframe').contentWindow.matrix_order(type); - else - document.getElementById('visavis_iframe').contentWindow.cube_order(type, type, type); - }); - $('#ctxpanel_graph > ul > li').click(function(){ - var that = $(this); - if (that.hasClass('embodied')) return; - var type = that.attr('id').split('_')[1]; - $('#ctxpanel_graph > ul > li.embodied').removeClass('embodied'); - that.addClass('embodied'); - - document.getElementById('visavis_iframe').contentWindow.graph_rebuild(type); - }); - $('#select_cmp_trigger').change(function(){ - var value = $(this).val(), - selected = $('#select_cmp_trigger option:selected'), - title = selected.text(); - - wmgui.dc_ctrl_flag = true; - - if (value == 'X') - return; - else if (value == 'Y'){ - document.getElementById('visavis_iframe').contentWindow.cmp_discard(wmgui.visavis_curtype); - return; - } - - if (['matrix', 'cube', 'discovery'].indexOf(wmgui.visavis_curtype) == -1) - return; - - var url = wmgui.vis_endpoint + '/' + wmgui.visavis_curtype + '?q=' + value; - document.getElementById('visavis_iframe').contentWindow.cmp_download(url, wmgui.visavis_curtype); - }); - $('li.discovery_custom').click(function(){ - if (!document.getElementById('visavis_iframe') || !document.getElementById('visavis_iframe').contentWindow) - return false; - - var list = document.getElementById('visavis_iframe').contentWindow.visavis.elementals_on, - html_list_on = '', - html_list_off = ''; - - for (var prop in wmgui.elemental_names){ - if (list.indexOf(prop) !== -1) - html_list_on += '
    ' + wmgui.elemental_names[prop] + ' (−)
    '; - else - html_list_off += '
    ' + wmgui.elemental_names[prop] + ' (+)
    '; - } - if (html_list_off) $('#discovery_disabled').html(html_list_off); - - $('#discovery_enabled').html(html_list_on); - $('#discovery_custom_box, #overlay').show(); - }); - $('#discovery_custom_box').on('click', 'div.rearrange', function(){ - var that = $(this), - prop = that.attr('rel'), - idx = document.getElementById('visavis_iframe').contentWindow.visavis.elementals_on.indexOf(prop); - if (that.parent().attr('id') == 'discovery_enabled'){ - if ($('#discovery_enabled div.rearrange').length == 1) - return false; - if (idx !== -1) document.getElementById('visavis_iframe').contentWindow.visavis.elementals_on.splice(idx, 1); - $('#discovery_disabled').append('
    ' + wmgui.elemental_names[prop] + ' (+)
    '); - $('#dc_' + prop).hide(); - } else { - if (idx == -1) document.getElementById('visavis_iframe').contentWindow.visavis.elementals_on.push(prop); - $('#discovery_enabled').append('
    ' + wmgui.elemental_names[prop] + ' (−)
    '); - $('#dc_' + prop).show(); - } - that.remove(); - }); - $('#ss_gear_matrix, #ss_gear_cube').click(function(){ - var domain = $(this).attr('id').substr(8); // ss_gear_ - if (domain == 'matrix'){ - $('#ss_z, #sops_z').hide(); - $('#ss_x, #ss_y, #sops_x, #sops_y').css('width', '50%'); - } else { - $('#ss_x, #ss_y, #ss_z, #sops_x, #sops_y, #sops_z').css('width', '33%'); - $('#ss_z, #sops_z').show(); - } - - // ss_ logic - var common_type = $('#ctxpanel_' + domain + ' > ul > li.embodied').attr('id').split('_')[1], // NB embodied, not ss_x - y_id = $('#ctxpanel_' + domain + ' > ul > li.ss_y'), - z_id = $('#ctxpanel_' + domain + ' > ul > li.ss_z'), - x_type = common_type, - y_type = y_id.length ? y_id.attr('id').split('_')[1] : common_type, - z_type = z_id.length ? z_id.attr('id').split('_')[1] : common_type, - x_orders_html = '', y_orders_html = '', z_orders_html = ''; - - $('#ctxpanel_' + domain + ' > ul > li').each(function(){ - var that = $(this), - type = that.attr('id').split('_')[1], - label = that.contents().filter(function(){ return this.nodeType !== 1 })[0].data.substr(3), // filter text only, then cut "by " - cls_html = (type == x_type) ? ' class="ss_x"' : ''; - x_orders_html += '
  • ' + label + '
  • '; - cls_html = (type == y_type) ? ' class="ss_y"' : ''; - y_orders_html += '
  • ' + label + '
  • '; - if (domain == 'matrix') - return true; - cls_html = (type == z_type) ? ' class="ss_z"' : ''; - z_orders_html += '
  • ' + label + '
  • '; - }); - - $('#ss_x > ul').html(x_orders_html); - $('#ss_y > ul').html(y_orders_html); - if (domain == 'cube') $('#ss_z > ul').html(z_orders_html); - - // sops_ logic - $('li.sops_x').removeClass('sops_x'); - $('li.sops_y').removeClass('sops_y'); - $('li.sops_z').removeClass('sops_z'); - - var sops_types = ['x', 'y', 'z']; - $('span.sops').each(function(){ - var that = $(this), - op = that.text(), - type = that.attr('rel'); - $('#sops_' + type + ' > ul > li:contains("' + op + '")').addClass('sops_' + type); - sops_types = sops_types.filter(function(x){ return x !== type }); - }); - sops_types.forEach(function(item){ - $('#sops_' + item + ' > ul > li:contains("none")').addClass('sops_' + item); - }); - - $('#ss_custom_box, #overlay').show(); - }); - $('div.ss_col').on('click', 'li', function(){ - var that = $(this), - rowid = that.attr('rev'), - rel_dat = that.attr('rel').split('_'), - axis = rel_dat[0], - clsname = (axis == 'x') ? 'ss_x' : ((axis == 'y') ? 'ss_y' : 'ss_z'); - $('#' + rowid + ' > ul > li.' + clsname).removeClass(clsname); - that.addClass(clsname); - }); - $('div.sops_col').on('click', 'li', function(){ - var that = $(this), - rowid = that.parent().parent().attr('id'), - axis = rowid.split('_')[1], - clsname = (axis == 'x') ? 'sops_x' : ((axis == 'y') ? 'sops_y' : 'sops_z'); - $('#' + rowid + ' > ul > li.' + clsname).removeClass(clsname); - that.addClass(clsname); - }); - - $('#tips_trigger').click(function(){ - wmgui.tooltip_counter = 0; - show_tooltip(wmgui.tooltips[wmgui.tooltip_landing]); - return false; - }); - - // numeric search - $('#numericbox').on('click', 'div.slider_close', function(){ - if ($('div.slider_numerics').length == 1){ - destroy_numericbox(); - delete wmgui.search.numeric; - $('#search_field-selectized').val(''); - wmgui.multiselects['main'].clear(); - wmgui.multiselects['main'].write(wmgui.search); - return false; - } - var that = $(this); - that.siblings('div.slider').children('div.slider_numerics')[0].noUiSlider.destroy(); - that.parent('li').fadeOut(250, function(){ $(this).remove() }); - }); - - $('#numericbox_do_trigger').click(function(){ - - var sliders_numerics = document.getElementsByClassName('slider_numerics'), - numeric = []; - - for (var i = 0; i < sliders_numerics.length; i++){ - var sdata = sliders_numerics[i].noUiSlider.get(), - srange = sliders_numerics[i].noUiSlider.options.range, - srange = [srange.min, srange.max]; - //if (sdata[0] == srange[0] && sdata[1] == srange[1]) continue; - //console.log(sdata); - - var prop = sliders_numerics[i].getAttribute('rel'); - numeric.push([prop, '>', sdata[0]]); - numeric.push([prop, '<', sdata[1]]); - } - - if (numeric.length) wmgui.search.numeric = numeric; - - if ($('#advsbox').is(':visible')) - $('#advsearch_do_trigger').trigger('click'); - else - $('#search_trigger').trigger('click'); - }); - - $('#numericbox_drop_trigger').click(function(){ - - var sliders_numerics = document.getElementsByClassName('slider_numerics'); - - //console.log(sliders_numerics); - - for (var i = 0; i < sliders_numerics.length; i++){ - var srange = sliders_numerics[i].noUiSlider.options.range; - sliders_numerics[i].noUiSlider.set([srange.min, srange.max]); - } - }); - - $('#close_numericbox').click(function(){ - destroy_numericbox(); - delete wmgui.search.numeric; - $('#search_field-selectized').val(''); - wmgui.multiselects['main'].clear(); - wmgui.multiselects['main'].write(wmgui.search); - }); - - // mobile version switching - /*$('#mobilebox span').click(function(){ - window.location.href = '/m/' + window.location.hash; - }); - $('#mobilebox a').click(function(){ - $('#mobilebox').remove(); - return false; - });*/ - - // keys press - $(document).keydown(function(e){ - var key = window.event ? e.keyCode : e.which; - if (key == 13){ // ENTER: input must trigger submit button via two parent divs! - var focused = $(':focus'); - //console.log(focused); - - if (focused.hasClass('submitter')){ - focused.parent().parent().find('div.def_submittable').trigger('click'); - - } else if (focused.hasClass('advs_input') || (focused.attr('id') || "").startswith('advs_fct_')){ - $('#advsearch_do_trigger').trigger('click'); - } - } else if (key == 27){ // ESC - var target = $('div.cross:visible'); - if (target.length) target.trigger('click'); - } - }); - - $(window).bind('hashchange', url_redraw_react); - - // execute a command in all the active GUI windows (except the current) e.g. setting a new state - $(window).bind('storage', function(ev){ - if (ev.originalEvent.key != wmgui.store_comm_exec_key) - return; - - var runnable_name = ev.originalEvent.newValue; - if (runnable_name && window[runnable_name]) window[runnable_name](); - }); - - /*$(window).resize(function(){ - //document.title = document.body.clientWidth + ' px'; - if (document.body.clientWidth < 1000) $('#mobilebox').show(); - else $('#mobilebox').hide(); - });*/ - - document.querySelector('#ptable_previews').addEventListener('click', function(event){ - if (event.target.classList.contains('subphases_trigger')){ - var state = parseInt(event.target.getAttribute('data-state')), - req = Object.assign({}, wmgui.ptable.query), - param; - - if (state === 1){ - param = 'strict=1'; - - } else { - param = 'subphases=1'; - delete req.classes; - } - ajax_download(wmgui.ptable.active_ajax, wmgui.search_endpoint + '?q=' + JSON.stringify(req) + '&' + param, render_left); - wmgui.ptable.subphases_set(state); - } - }); - - // theme switcher - document.getElementById('darkmode_trigger').onclick = function(){ - wmgui.darkmode.toggle(); - document.getElementById('darkmode_trigger').innerHTML = wmgui.darkmode.isActivated() ? 'enabled' : 'disabled'; - document.getElementById('comms').contentWindow.postMessage(JSON.stringify({darkmode: wmgui.darkmode.isActivated() ? 1 : 2}), '*'); - } - - // cross-site comms - window.addEventListener('message', function(message){ - //if (message.origin === 'https://trusted.com') { - var received = {}; - try { - received = JSON.parse(message.data); - } catch (ignore){} - var darkmode = received.darkmode; - if (darkmode !== undefined){ - darkmode = (darkmode === 1); - if (darkmode !== wmgui.darkmode.isActivated()) wmgui.darkmode.toggle(); - document.getElementById('darkmode_trigger').innerHTML = wmgui.darkmode.isActivated() ? 'enabled' : 'disabled'; - } - //} - }); - // EOF register_events -} diff --git a/src_js/main_logic.js b/src_js/main_logic.js deleted file mode 100755 index 7f6cc64..0000000 --- a/src_js/main_logic.js +++ /dev/null @@ -1,1634 +0,0 @@ -"use strict"; - -var wmgui = window.wmgui || {}; - -wmgui.notify = function(msg){ - var delay = 0; - if (wmgui.notify_counter){ - clearInterval(wmgui.notify_counter); - wmgui.notify_counter = null; - delay = 1500; - } - setTimeout(function(){ - $('#notifybox').html(wmgui.clean(msg)).show(); - wmgui.notify_counter = setTimeout(function(){ $('#notifybox').hide() }, 4000); - }, delay); -} - -// external API function -wmgui.aug_search_cmd = function(new_fct, new_val){ - - // Take care of mutually exclusive facets - var checks = [['elements', 'formulae'], ['formulae', 'elements'], ['lattices', 'sgs'], ['sgs', 'lattices'], ['protos', 'sgs'], ['sgs', 'protos'], ['lattices', 'protos'], ['protos', 'lattices']]; - for (var i = 0; i < checks.length; i++){ - if (wmgui.search[checks[i][0]] && new_fct == checks[i][1]){ delete wmgui.search[checks[i][0]]; break; } - } - - var orepr = {}; - - $.each(wmgui.facets, function(n, fct){ - if (wmgui.search[fct] && fct == new_fct){ - if (wmgui.multi_facets.indexOf(fct) !== -1) - orepr[fct] = wmgui.search[fct] + ',' + new_val; - else - orepr[fct] = new_val; - - } else if (wmgui.search[fct]){ - orepr[fct] = wmgui.search[fct]; - - } else if (fct == new_fct){ - orepr[fct] = new_val; - } - }); - return '#inquiry/' + $.param(orepr); -} - -// reading the selectize at the main search input (landing) -wmgui._selectize_read_main = function(){ - var result = {}; - - $('#search_holder div.selectize-input.items').children().each(function(){ - if (this.tagName !== 'DIV') - return; - - var facet = this.getAttribute('data-facet'); - - if (wmgui.other_facets.indexOf(facet) !== -1 && wmgui.search[facet]) - result[facet] = wmgui.search[facet]; - - else if (facet == 'numeric'){ - if (wmgui.search[facet]){ - result[facet] = ''; - wmgui.search[facet].forEach(function(item){ - result[facet] += serialize_numeric.apply(this, item); // unpack - }); - if (result[facet].length) result[facet] = result[facet].substr(0, result[facet].length - 1); - } // NB else just skip! - } - - else if (result[facet] && facet == 'elements') - result[facet] += '-' + this.getAttribute('data-term'); - - else if (result[facet] && wmgui.multi_facets.indexOf(facet) !== -1) - result[facet] += ', ' + this.getAttribute('data-term'); - - else if (facet == 'formulae') - result[facet] = this.getAttribute('data-term').replaceAll('', '').replaceAll('', ''); - - else - result[facet] = this.getAttribute('data-term'); - }); - - return result; -} - -// reading the selectize at the *wmgui.multi_facets* categories -wmgui._selectize_read_facet = function(fct){ - var result = {}, - selector = 'div.advs_' + fct; - - $(selector + ' div.selectize-input.items').children().each(function(){ - if (this.tagName !== 'DIV') - return; - - var facet = this.getAttribute('data-facet'); - - if (result[facet]) - result[facet] += ', ' + this.getAttribute('data-term'); - else - result[facet] = this.getAttribute('data-term'); - return; - }); - - return result; -} - -wmgui._selectize_write = function($this, name, search_obj){ - - wmgui.selectize_emit = false; - - var given_search = {}; - $.extend(given_search, search_obj); - - if (name == 'main'){ - name = ['formulae', 'props', 'elements', 'classes', 'lattices', 'aetypes']; - - for (var i = 0; i < wmgui.other_facets.length; i++){ - if (given_search[wmgui.other_facets[i]]){ - $this.display(wmgui.other_facets[i], wmgui.facet_names[wmgui.other_facets[i]].toLowerCase()); // stub display - } - } - - if (given_search.numeric) $this.display('numeric', 'range search'); - - } else name = [name]; - - name.forEach(function(facet){ - // facets supported for multiselect autocomplete - if (!given_search[facet]) - return; - - else if (facet == 'elements' && given_search[facet].indexOf('-') > 0){ - given_search[facet].split('-').forEach(function(part){ - $this.display(facet, part); - }); - } else if (wmgui.multi_facets.indexOf(facet) !== -1 && given_search[facet].indexOf(',') > 0){ - given_search[facet].split(',').forEach(function(part){ - $this.display(facet, part); - }); - } else if (facet == 'formulae'){ - given_search[facet] = wmgui.to_formula(given_search[facet]); - $this.display(facet, given_search[facet]); - - } else $this.display(facet, given_search[facet]); - }); - - $this.clearOptions(); - wmgui.selectize_emit = true; -} - -wmgui._selectize_display = function($this, facet, term){ - var random_id = Math.floor((Math.random() * 1000)); - $this.addOption({facet: facet, label: term, id: random_id}); - $this.addItem(random_id); -} - -function show_interpretation(search){ - // FIXME only allow pre-defined props - $('#interpret').html( - wmgui.clean(wmgui.get_interpretation(search, wmgui.facet_names, wmgui.numerics)) - ); -} - -// re-loading without history affection -function re_view_request(search_type){ - var caption_items = []; - $.each(wmgui.search, function(k, v){ - if (k == 'search_type') return true; - caption_items.push(v); - }); - if (!caption_items.length) return; - - wmgui.search_type = search_type; - wmgui.search.search_type = search_type; - request_search(wmgui.search, caption_items.join(" ").replaceAll(",", " "), true); - $('#dtypes_phid > ul > li').removeClass('active'); -} - -function request_search(search, caption, without_history){ - if (manage_visavis(rebuild_history_box, search, caption)) return; - - try { wmgui.active_ajax.abort() } catch(e){} - try { wmgui.quick_ajax.abort() } catch(e){} - - wmgui.active_ajax = $.ajax({ - type: 'GET', - url: wmgui.search_endpoint, - data: { - q: JSON.stringify(search), - strict: wmgui.ctx_strict_phases, - //subphases: wmgui.ctx_subphases, - sid: wmgui.sid - }, - beforeSend: wmgui.show_preloader - - }).always(wmgui.hide_preloader).done(function(data){ - if (data.error) - return wmgui.notify(data.error); - - caption = caption.replaceAll('%2F', '/'); - - if (!data.out.length) - return wmgui.notify('No hits for ' + caption); - - wmgui.fuzzyout = false; - if (data.fuzzy_notice){ - wmgui.fuzzyout = true; - wmgui.notify(data.fuzzy_notice); - } - - var res_str = (data.estimated_count == 1) ? ' result' : ' results', - notice = (data.estimated_count > 150) ? 'At least ' : ''; - document.title = notice + data.estimated_count + res_str; // + ' (' + wmgui.estimate + ')'; - //console.log('Obtained: '+data.estimated_count+', expected: '+wmgui.estimate); - switch_view_mode(2); - - if (!wmgui.chosen_table_browser) // TODO add smarter check? - wmgui.thumbed_display = (data.out.length > wmgui.ntab_tolerance); - - if (wmgui.thumbed_display){ - var $db = $('#databrowser'); - $db.removeClass().addClass('thumbed').empty().append('' + build_thumbs(data.out) + ''); - $('#results').slideDown(250); - - } else { - var $db = $('#databrowser'); - $db.removeClass().addClass('tabled').empty().append(build_cells(data.out, '', '')); - $('#results').slideDown(250); - - if (wmgui.search_type == 2){ - $db.addClass('tablesorter').tablesorter({ sortMultiSortKey: 'ctrlKey', headers: { - 0: {sorter: 'doi'}, - 5: {sorter: false} - }, selectorHeaders: '#dataheader_articles > thead > tr > th', selectorHeaderParent: 'dataheader_articles' }); - $('#header_articles').show(); - - } else if (wmgui.search_type == 1){ - $db.addClass('tablesorter').tablesorter({ sortMultiSortKey: 'ctrlKey', headers: { - 0: {sorter: 'chemical'}, - 1: {sorter: 'digit'}, - 2: {sorter: 'digit'}, - 3: {sorter: 'digit'}, - 4: {sorter: false} - }, selectorHeaders: '#dataheader_phases > thead > tr > th', selectorHeaderParent: 'dataheader_phases' }); - $('#header_phases').show(); - - } else { - $db.addClass('tablesorter').tablesorter({ sortMultiSortKey: 'ctrlKey', headers: { - 0: {sorter: 'chemical'}, - 1: {sorter: false}, - 5: {sorter: 'doi'} - }, selectorHeaders: '#dataheader_entries > thead > tr > th', selectorHeaderParent: 'dataheader_entries' }); - $('#header_entries').show(); - } - } - - // count & show ctx - wmgui.unfinished_page = false; - if (wmgui.search_type || search.phid){ - if (data.estimated_count >= wmgui.quick_page_size * 3) $('#toomuch span').html('other').parent().show(); - show_hints(search.entry || search.interlinkage); - - } else { - if (data.estimated_count > wmgui.quick_page_size + wmgui.fetch_page_size){ - $('#toomuch span').html('nearly ' + (data.estimated_count - wmgui.quick_page_size)).parent().show(); - show_hints(search.entry, data.estimated_count); - - } else if (data.estimated_count > wmgui.quick_page_size){ - $('#loadscroll').show(); - wmgui.unfinished_page = true; - - } else show_hints(search.entry, data.estimated_count); - } - - // switchers - if (wmgui.visavis_terminating) stop_visavis(); - - if (wmgui.search_type || search.phid || search.bid || search.entry || search.interlinkage || search.doi || search.numeric){ - - if (search.phid || search.bid || search.entry){ - switch_control_mode(9, 11, 'a', 'c'); - show_dunit_info(search.phid, search.bid, search.entry); - - } else if (search.interlinkage){ - switch_control_mode(9, 11, 'a', 'c'); - show_examples('#examples', true, true); - $('#dtypes').hide(); - - } else if (search.numeric){ - switch_control_mode(1, 12, 'b', false); - //console.log(search.numeric); - destroy_numericbox(); - $.each(get_sliders_ranges(search.numeric, wmgui.numerics), function(n, item){ create_floating_slider.apply(this, item) }); // unpack - show_examples('#examples', true, true); - - } else { - switch_control_mode(1, 10, false, false); - show_examples('#examples', true, true); - } - - if (search.entry){ - var that = $('#e__' + search.entry); - if (search.entry.indexOf('-') == -1 && !that.length) that = $('#e__' + search.entry + '-1'); - if (that.length && that.attr('data-rank') != 0){ // NB "!=", not "!==" - that.removeClass('busy_entry'); - open_context(that, true); - } - } - - } else { - wmgui.fuzzyout ? switch_control_mode(1, 11, 'a', false) : switch_control_mode(0, 10, false, false); - request_refinement(search, (data.estimated_count > wmgui.quick_page_size)); - } - - //console.log(search); - if (!search.numeric){ - destroy_numericbox(); - delete wmgui.search.numeric; - } - if (search.props && wmgui.numerics[search.props]){ // making a hint - var data = wmgui.numerics[search.props], - prop_id = data[0], - units = data[1], - min = data[2], - max = data[3], - step = data[4]; - create_floating_slider(search.props, prop_id, units, min, max, step); - } - if (!without_history) rebuild_history_box(search, caption); - wmgui.search.elements && wmgui.search_type == 1 ? $('#phases_ctx').show() : $('#phases_ctx').hide(); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Connection to server is lost, please try to reload'); - }); -} - -function rebuild_history_box(search, caption){ - var orepr = {}; - wmgui.facets.forEach(function(item){ - if (search[item]) orepr[item] = search[item]; - }); - - var inquiry = false; - $.each(wmgui.inquiries, function(m, i){ if (orepr[i]){ inquiry = true; return false; } }); - - var title = []; - for (var prop in orepr){ title.push(orepr[prop].toLowerCase()) } - title.sort(); - var fingerprint = title.join(" "), - search_log = JSON.parse(window.localStorage.getItem(wmgui.store_history_key) || '[]'), - chk_searches = []; - if (search_log.length > 8) search_log = search_log.slice(0, 7); - $.each(search_log, function(n, item){ - var title = []; - for (var p in item){ title.push(item[p].toLowerCase()) } - title.sort(); - chk_searches.push(title.join(" ")); - }); - if (chk_searches.indexOf(fingerprint) == -1){ - var item; - if (inquiry) item = '' + caption + ''; - else item = '' + caption + ''; - - $('#history ul').prepend('
  • ' + wmgui.clean(item) + '
  • '); - search_log.unshift(orepr); - window.localStorage.setItem(wmgui.store_history_key, JSON.stringify(search_log)); - if ($('#history ul li').length > 8) $('#history ul li:last').remove(); - } - wmgui.tooltip_counter++; - if (wmgui.tooltip_counter == 1){ - setTimeout(function(){ show_tooltip(wmgui.tooltips['interpretation']) }, 3000); - } -} - -function rotate_interesting(){ - $('#legend').html('e.g. ' + wmgui.get_interesting()['text'].replace(/\d/g, "Ȉ$&;") + ''); -} - -function show_examples(box, more_examples, fix_rfn_header){ - if (wmgui.cliff_counter === null) wmgui.cliff_counter = Math.floor(Math.random() * wmgui.cliffhangers.length); - var html = ''; - for (var i = 0; i < (more_examples ? 7 : 3); i++){ - wmgui.cliff_counter += 1; - if (wmgui.cliff_counter > wmgui.cliffhangers.length-1) wmgui.cliff_counter = 0; - html += '
  • ' + wmgui.cliffhangers[wmgui.cliff_counter].charAt(0).toUpperCase() + wmgui.cliffhangers[wmgui.cliff_counter].slice(1) + '
  • '; - - var legend = wmgui.get_interesting()['text']; - html += '
  • ' + legend.charAt(0).toUpperCase() + legend.slice(1).replace(/\d/g, "Ȉ$&;") + '
  • '; - } - $(box + ' > ul').empty().append(html); - $(box).show(); - - if (fix_rfn_header){ - $('#refine_col > div.col_title, #refine_col > ul').hide(); - $('#refine_col').show(); - } -} - -function arrange_menu_collateral(){ - $('#hintsbox_msg, #tagcloudbox').empty(); - - var links_html = ''; - for (var i = 0; i < wmgui.collateral_links.length; i++){ - var rel = wmgui.collateral_links[i][1], - cls = wmgui.collateral_links[i][1] ? 'collateral' : false, - target = '', - lbr = ''; - if (i % 2){ - cls = cls ? cls + ' violet' : 'violet'; - lbr = '
    '; - } - if (wmgui.collateral_links[i][3]) target = ' target="_blank"'; - links_html += '' + wmgui.collateral_links[i][2] + '' + lbr; - }; - $('#tagcloudbox').append(links_html); - - $('#hintsbox_msg').append(wmgui.get_random_term(wmgui.welcome_msgs)); -} - -function switch_view_mode(mode){ - wmgui.view_mode = mode; - $('div.autocomplete-suggestions').hide(); - $('#results, #header_entries, #header_phases, #header_articles').hide(); - $('div.context_msg').hide(); - close_vibox(); - - if (mode == 1){ - stop_visavis(); - document.title = 'Materials Platform for Data Science'; - $('body').addClass('noscroll'); - $('#search_box').removeClass('fluid'); - - $('div.side_cols').hide(); - $('#legend').show(); - - $('#search_holder').removeClass('prolonged').focus(); - $('#search_area').removeClass('prolonged'); - $('#ermac_logo').removeClass('cornered'); - - wmgui.ptable.decide(); - if (wmgui.ptable.activated) document.getElementById('ptable_dtypes_box').classList.add('resulted'); - - } else if (mode == 2){ - - $('#legend').hide(); - $('#ctx_col').hide(); - if (wmgui.passive_sim_col) $('#sim_col').hide(); - - $('body').removeClass('noscroll'); - $('#search_box').addClass('fluid'); - - $('#right_col').show(); - $('#dtypes').show(); - $('#search_holder, #search_area').addClass('prolonged'); - $('#ermac_logo').addClass('cornered'); - - wmgui.ptable.hide(); - document.getElementById('ptable_dtypes_box').classList.remove('resulted'); - } - // hook back into a parent integration - wmgui.mpdsgui.view(mode); -} - -function switch_control_mode(mode, next_mode, active_abf, active_cde){ // NB (0, 10) is the most common 6-button layout - if (mode == 0){ // cde, second - $('#control_c, #control_d, #control_e').css('width', '33.3%').show(); - - } else if (mode == 1){ // cde, second - $('#control_e').hide(); - $('#control_c, #control_d').css('width', '50%').show(); - - } else if (mode == 9){ // cde, second - $('#control_e, #control_d').hide(); - $('#control_c').css('width', '100%').show(); - - } else if (mode == 10){ // abf, first - $('#control_a, #control_b, #control_f').css('width', '33.3%').show(); - - } else if (mode == 11){ // abf, first - $('#control_b, #control_f').hide(); - $('#control_a').css('width', '100%').show(); - - } else if (mode == 12){ // abf, first - $('#control_a, #control_f').hide(); - $('#control_b').css('width', '100%').show(); - } - if (!next_mode) return; - - if (!active_abf) active_abf = ({0: 'a', 1: 'b', 2: 'f'})[wmgui.search_type]; - if (!active_cde) active_cde = wmgui.thumbed_display ? 'd' : 'c'; - - $('div.controlswitch > div').removeClass(); - $('#control_' + active_abf + ', #control_' + active_cde).addClass('active'); - - switch_control_mode(next_mode); -} - -function build_cells(json, header, footer){ - var cls_map = {7: 'ml_data', 8: 'ab_data', 9: 'ab_data', 10: 'ab_data', 11: 'ab_data', 13: 'deactivated'}, - result_html = ''; - - if (header) result_html += header; - - if (wmgui.search_type == 2){ - if (json[0].length != 6){ wmgui.notify('Rendering error, please try to reload'); return ''; } - - var act_link = ''; - - $.each(json, function(k, row){ - - act_link = 'Show'; - - row[0] = parseInt(row[0]); - if (row[0] == 999999){ - row[4] = wmgui.mockyear; // special *ref_id*, only handled in GUI - act_link = ' '; - } - result_html += '[' + row[0] + ']' + row[1] + '' + row[2] + '' + row[5] + '' + row[4] + '' + act_link + ''; - }); - } else if (wmgui.search_type == 1){ - if (json[0].length != 5){ wmgui.notify('Rendering error, please try to reload'); return ''; } - - $.each(json, function(k, row){ - result_html += '' + row[1] + '' + row[2] + '' + row[3] + '' + row[4] + 'Show entries'; - }); - } else { - if (json[0].length != 8){ wmgui.notify('Rendering error, please try to reload'); return ''; } - - $.each(json, function(k, row){ - row[7] = parseInt(row[7]); - var dtype = row[0].substr(0, 1), - preview = (row[3] == 4 || row[3] == 5 || row[3] == 6 || row[3] == 9 || row[3] == 10 || row[3] == 12) ? 'Show' : ' ', // FIXME? w.r.t. open_context - biblio_html = (row[7] == 999999) ? '—' + wmgui.mockyear + '—' : - '' + row[5] + '' + row[6] + '[' + row[7] + ']'; // special *ref_id*, only handled in GUI - - result_html += '' + row[1] + '' + preview + '' + row[2] + '' + biblio_html + ''; - }); - } - if (footer) result_html += footer; - return result_html; -} - -function build_thumbs(json){ - var cls_map = {6: 'pd_full', 7: 'ml_data', 8: 'ab_data', 9: 'ab_data', 10: 'ab_data', 11: 'ab_data', 13: 'deactivated'}, - result_html = ''; - - if (wmgui.search_type == 2){ - if (json[0].length != 6){ wmgui.notify('Rendering error, please try to reload'); return ''; } - - json.sort(function(a, b){ - return a[4] > b[4] ? 1 : a[4] < b[4] ? -1 : 0; // pubyear - }); - - var title_html = '', - full_display = !!wmgui.sid, - act_link = ''; - - $.each(json, function(k, row){ - - act_link = 'Show entries'; - - row[0] = parseInt(row[0]); - if (row[0] == 999999){ - row[4] = wmgui.mockyear; // special *ref_id*, only handled in GUI - act_link = 'Too many to show...'; - } - if (full_display) title_html = (row[1].length > 60 ? row[1].substr(0, 60) + '…' : row[1]) + ', ' + (row[2].length > 80 ? row[2].substr(0, 80) + '…' : row[2]) + ''; - else title_html = '📖'; // book icon - - result_html += ''; - }); - } else if (wmgui.search_type == 1){ - if (json[0].length != 5){ wmgui.notify('Rendering error, please try to reload'); return ''; } - - json.sort(function(a, b){ - return a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0; - }); - $.each(json, function(k, row){ - result_html += ''; - }); - } else { - if (json[0].length != 8){ wmgui.notify('Rendering error, please try to reload'); return ''; } - - json.sort(function(a, b){ - var dtype_a = a[0].substr(0, 1), - dtype_b = b[0].substr(0, 1); - - if (dtype_a == 'S'){ - if (dtype_b == 'S') return a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0; - return -1; - } - if (dtype_a == 'C'){ - if (dtype_b == 'C') return a[7] > b[7] ? 1 : a[7] < b[7] ? -1 : 0; - if (dtype_b == 'S') return 1; - if (dtype_b == 'P') return -1; - } - if (dtype_a == 'P'){ - if (dtype_b == 'P') return a[2].toUpperCase() > b[2].toUpperCase() ? 1 : a[2].toUpperCase() < b[2].toUpperCase() ? -1 : 0; - return 1; - } - }); - $.each(json, function(k, row){ - row[7] = parseInt(row[7]); - var dtype = row[0].substr(0, 1), - content, - biblio_html = (row[7] == 999999) ? '
    —' : - '
    [' + row[5] + '’' + row[6].toString().substr(2, 2) + ']'; // special *ref_id*, only handled in GUI - - if (dtype == 'P') - content = '
    ' + row[2] + '
    '; - else if (dtype == 'S') - content = '' + row[0] + ''; - else { - // FIXME - row[2] = row[2].split(';')[0]; - row[2] = row[2].split(' ')[row[2].split(' ').length - 1]; - var url_dest = (row[3] == 12) ? (row[2].split('-').length == 3 ? '/prism' : '/tetrahedron') : '/pd_thumbs/' + row[0].split('-')[0]; - content = '' + row[0] + '

    ' + row[2] + '

    '; - } - result_html += ''; - }); - } - return result_html; -} - -function request_refinement(query_obj, is_heavy){ - $('#examples, #ind_col').hide(); - $('#ind_col > span').empty(); - $('#refine_col > ul').empty().parent().show(); - $('#refine_col > div.col_title').show(); - - var given_search = {is_heavy: is_heavy}; - $.extend(given_search, query_obj); - try { wmgui.active_ajax.abort() } catch(e){} - - //console.log(given_search); - wmgui.active_ajax = $.ajax({ - type: 'GET', - url: wmgui.rfn_endpoint, - data: {q: JSON.stringify(given_search)}, - beforeSend: function(){ $('#rfn_preloader').show() } - - }).always(function(){ $('#rfn_preloader').hide() }).done(function(data){ - if (data.error) return wmgui.notify(data.error); - - var was_facet = null, - refine_html = '', - classes_chk = [], - num_terms = 0; - delete given_search['is_heavy']; - - if (given_search.classes){ // no whitespace in multiple classes - classes_chk = given_search.classes.split(',').map(function(x){ return x.trim() }); - given_search.classes = classes_chk.join(','); - } - - var inquiry = false; - $.each(wmgui.inquiries, function(n, i){ if (given_search[i]){ inquiry = true; return false; } }); - - $.each(data.payload, function(i, found_obj){ - if (query_obj.formulae && found_obj.facet == 'elements') return true; // NB no sense to show elements in this context - - var link_base = '', - //count_text = ' ('+found_obj.count+')', - nested_skip = false, - orepr = {}; - - $.each(given_search, function(key, val){ - if (['search_type', 'phid', 'numeric'].indexOf(key) !== -1) - return true; - else if (found_obj.facet == 'elements' && (key == 'elements' || key == 'formulae')) - return true; - else if (found_obj.facet == 'props' && key == 'props') - return true; - - link_base += val + ' '; - - if (orepr[key]) orepr[key] += ', ' + val; - else orepr[key] = val; - }); - //if (found_obj.facet == 'elements') count_text = ''; - if (query_obj.classes && found_obj.facet == 'classes'){ - $.each(classes_chk, function(n, cls){ - if (cls == found_obj.value){ nested_skip = true; return false; } - }); - } - if (nested_skip) return true; - - if (found_obj.facet != was_facet){ - if (was_facet && is_heavy) refine_html += '
  • Show more 
  • '; - refine_html += '
  • ' + wmgui.facet_names[found_obj.facet] + '
  • '; - was_facet = found_obj.facet; - } - if (found_obj.facet == 'props'){ - found_obj.value = found_obj.value.replace(/\(|\)/g, "").replace(/\/[\w\-]*/g, ""); // FIXME - } - - if (orepr[found_obj.facet]) orepr[found_obj.facet] += ', ' + found_obj.value; - else orepr[found_obj.facet] = found_obj.value; - - if (orepr['elements']) orepr['elements'] = orepr['elements'].replaceAll(', ', '-'); - - if (inquiry) refine_html += '
  • ' + found_obj.value + '
  • '; - else refine_html += '
  • ' + found_obj.value + '
  • '; - num_terms++; - }); - - if (is_heavy) refine_html += '
  • Show more 
  • '; - - if (num_terms == 0) show_examples('#examples', true, true); - else { - $('#refine_col > ul').show().append(wmgui.clean(refine_html)); - if (num_terms <= 10) show_examples('#examples', false, false); - } - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Connection to server is lost, please try to reload'); - }); -} - -/** - * NB: Ranks legend - * 0 - bib-ref (unproc) + P-entries data on - * 1 - textual (diagrammatic) P-entry - * 2 - scalar (numeric) P-entry - * 3 - C-phase - * 4 - SD-entry (P-array) - * 5 - S-entry - * 6 - C-diagram - * 7 - ML P-entry - * 8 - ab initio entry (scalar) - * 9 - ab initio entry (P-array) electron spectra - * 10 - ab initio entry (P-array) phonon spectra - * 11 - ab initio data in progress (unproc) - * 12 - 3d combination of C-diagrams - * 13 - deactivated entries - */ -function open_context(el, launch_ext){ - close_vibox(); - if (el.hasClass('busy_entry')){ - el.removeClass('busy_entry'); - $('#ctx_col, #sim_col').hide(); - try { wmgui.quick_ajax.abort() } catch(e){} - - } else { - var entry = el.attr('id').substr(3), - rank = parseInt(el.attr('data-rank')), - entype = entry.substr(0, 1), - orig_id = entry.split('-')[0]; - - $('.busy_entry').removeClass('busy_entry'); - el.addClass('busy_entry'); - - if (entype == 'Z' || entype == 'B') return; - - $('#entryno').html('' + orig_id + ''); - - $('#ctx_col').show(); - $('#visualize').attr('data-rank', rank); - $('#xrpdize').attr('data-rank', 99); // FIXME hack - //$('#visualize, #xrpdize, #absolidize, div.spinoff_pane, li.d_icon').hide(); - $('#visualize, #xrpdize, div.spinoff_pane, li.d_icon').hide(); - - open_sim_col(entry, entype, rank); - - if (rank == 0){ - $('#download_bib').show(); - - } else if (rank == 1){ - $('#download_bib, #download_pdf').show(); - $.ajax({ - type: 'GET', - url: wmgui.path_pp_ping + entry, - }).done(function(data){ - $('#visualize, #download_png, #download_json').show(); - }).fail(function(xhr, textStatus, errorThrown){}); - - } else if (rank == 2){ - $('#download_bib, #download_pdf, #download_json').show(); - - } else if (rank == 3){ - $('#download_bib, #download_png, #download_cdr').show(); - - } else if (rank == 4){ - $('#download_bib, #download_json, #visualize').show(); - - } else if (rank == 5){ - //$('#absolidize, #download_bib, #download_pdf, #visualize, #xrpdize, #absolidize, #download_cif, #download_inp, #download_json').show(); - $('#download_bib, #download_pdf, #visualize, #xrpdize, #absolidize, #download_cif, #download_inp, #download_json').show(); - - } else if (rank == 6){ - $('#download_bib, #download_pdf, #visualize, #download_png, #download_cdr, #download_json').show(); - - } else if (rank == 7){ - $('#ml_data, #download_pdf, #download_json').show(); - - } else if (rank == 8){ - $('#ab_data, #download_pdf, #download_json, #download_raw').show(); - - } else if (rank == 9){ - $('#ab_data, #download_pdf, #download_json, #visualize, #download_png, #download_raw').show(); - - } else if (rank == 10){ - $('#ab_data, #download_pdf, #download_json, #visualize, #download_raw').show(); - - } else if (rank == 11){ - $('#ab_promise, #download_json').show(); - - } else if (rank == 12){ - $('#pd3d_data, #visualize').show(); - - } else if (rank == 13){ - $('#deactivated_data, #download_bib').show(); - } - $('#ctx_col > ul > li.d_icon > a').each(function(){ - var fmt = $(this).attr('rel'), - link_add = (entype == 'S') ? '&export=1' : '', - link_sid = (fmt == 'raw') ? 'null' : wmgui.sid, - link_url = wmgui.dd_addr_tpl + '/' + entype.toLowerCase() + '?q=' + entry + '&fmt=' + fmt + '&sid=' + link_sid + link_add + '&ed=' + wmgui.edition; - - $(this).attr('href', link_url); - }); - - //(wmgui.mydata_history.indexOf(entry) == -1) ? $('#absolidize').addClass('wmbutton') : $('#absolidize').removeClass('wmbutton'); - - if (launch_ext) launch_db_iframed(rank); - } -} - -function open_sim_col(entry, entype, rank){ - $('#sim_col > ul, #sim_legend').empty(); - $('.sim_col_ctx').hide(); - $('#sim_col').show(); - - var cur_obj = {q: entry}, - allpurpose = ([0, 1, 4, 9].indexOf(rank) !== -1); - if (allpurpose) cur_obj.allpurpose = true; - - try { wmgui.quick_ajax.abort() } catch(e){} - - wmgui.quick_ajax = $.ajax({ - type: 'GET', - url: wmgui.sim_endpoint, - data: cur_obj, - beforeSend: function(){ $('#sim_preloader').show() } - - }).always(function(){ $('#sim_preloader').hide() }).done(function(data){ - if (data.error) return wmgui.notify(data.error); - var counter = 0, - sim_html = ''; - - if (allpurpose){ - $.each(data.out.sim, function(k, row){ - if (counter == 7) return false; - if (row[4]) sim_html += '
  • ' + row[0] + '
  • '; - else sim_html += '
  • ' + row[0] + '
  • '; - counter++; - }); - - } else if (entype == 'C' || entype == 'S'){ - if (rank > 3){ - $.each(data.out.sim, function(k, row){ - if (counter == 8) return false; - sim_html += '
  • ' + row[0] + '
  • '; - counter++; - }); - if (entype == 'C') $('#pd_legend').show(); - else if (counter == 1) counter = 0; - } - } else { - // FIXME this is fragile - var prop = wmgui.thumbed_display ? $('div.busy_entry > div.gallery_img > div').text().split(';')[0] : $('tr.busy_entry > td.c2').text().split(';')[0]; - - $.each(data.out.sim, function(k, row){ - if (counter == 8) return false; - sim_html += '
  • ' + row[0] + '
  • '; - counter++; - }); - } - - if (counter){ - if (allpurpose) $('#sim_legend').removeClass('apparent').text('Also studied by these authors:'); - else if (entype == 'C') $('#sim_legend').removeClass('apparent').text('Phases at the diagram:'); - else if (entype == 'S') $('#sim_legend').removeClass('apparent').text('The same prototype structures:'); - else $('#sim_legend').removeClass('apparent').text('Similar ' + prop + ':'); - - if (counter > 7){ - //var link = (entype == 'C') ? '#entry/' + $('#entryno').text() : '#interlinkage/' + entry; - $('#sim_trigger').attr('href', '#interlinkage/' + entry).show(); - } - $('#sim_col > ul').html(sim_html); - - } else { - if (allpurpose) - $('#sim_legend').addClass('apparent').text('No cross-links found'); - - else if (entype == 'C' && rank == 3){ - // FIXME this is fragile - var els, - html_3d = ''; - - if (wmgui.thumbed_display){ - els = $('div.busy_entry > div.gallery_img > p').text().split('-'); - } else { - els = $('tr.busy_entry > td.c2').text().replace('; ', '').split(' '); - els = els[els.length - 1].split('-'); - } - if (els.length == 3 || els.length == 4) - html_3d = '

    3d
    3d phase diagram
    '; - - $('#sim_legend').addClass('apparent').html('
    C-entry
    Full phase diagram
    ' + html_3d); - - } else if (entype == 'C' && rank == 5) - $('#sim_legend').addClass('apparent').text('No links to other phases found.'); - - else if (entype == 'C' && rank == 12) - $('#sim_legend').addClass('apparent').text('Hover the binary or ternary diagrams for more data.'); - - else if (entype == 'S') - $('#sim_legend').addClass('apparent').text('No other structures for this prototype found.'); - - else - $('#sim_legend').addClass('apparent').text('No similar values found.'); - } - - if (data.out.own.length && !wmgui.search.phid) - $('#own_phase').html('Phase
    Linked ' + (entype == 'S' ? 'distinct phase' : 'crystalline structure') + '
    ').show(); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Connection to server is lost, please try to reload'); - }); -} - -function close_vibox(){ - var iframe = $('#iframe'); - if (iframe.length){ - if (wmgui.thumbed_display) $('#iframe').slideUp(function(){ $('#iframe').remove() }); - else $('#iframe').remove(); - $('#vibox').hide(); - return true; - } - return false; -} - -function launch_db_iframed(rank){ - var that = $('.busy_entry'); - if (!that.length) return; - - var entry = that.attr('id').substr(3), - entype = entry.substr(0, 1), - iframe_src, - iframe_height; - - if (entype == 'S'){ - if (rank == 99){ - iframe_src = wmgui.engines_addrs['visavis'] + wmgui.path_s_xrpd + entry, iframe_height = 550; - - } else - iframe_src = wmgui.engines_addrs['cifplayer'] + wmgui.path_s_entry + entry, iframe_height = 650; - - } else if (entype == 'P'){ - if (rank == 1){ - iframe_src = wmgui.engines_addrs['visavis'] + wmgui.path_pp_plot + entry, iframe_height = 550; - wmgui.notify('P-curves are in beta-testing'); - - } else if (rank == 4) - iframe_src = wmgui.engines_addrs['visavis'] + wmgui.path_sd_plot + entry, iframe_height = 550; - - else if (rank == 9) - iframe_src = wmgui.v_pd_user_addr + wmgui.api_host + '/download/p?fmt=png&q=' + entry, iframe_height = 600; - - else if (rank == 10) - iframe_src = wmgui.v_ab_vis_addr + entry, iframe_height = 600; - - else return; - - } else { - if (rank == 12){ - var triple = wmgui.thumbed_display ? $('div.busy_entry > div.gallery_img > p').text() : $('tr.busy_entry > td.c1').text().split(' ')[0]; - iframe_src = wmgui.v_pd_3d_addr + triple, iframe_height = 550; - - } else if (rank == 6) - iframe_src = (wmgui.sid ? wmgui.v_pd_user_addr + wmgui.api_host + '/download/c?fmt=png&q=' : wmgui.engines_addrs['visavis'] + wmgui.path_c_entry) + entry, iframe_height = 600; - - else return; - - if (wmgui.entries_messages[entry]) - wmgui.notify(wmgui.entries_messages[entry]); - } - - if (wmgui.sid) iframe_src += '&sid=' + wmgui.sid; - - var iframe_html = ''; - if (wmgui.thumbed_display) iframe_html = '
    ' + iframe_html + '
    '; - else iframe_html = '' + iframe_html + ''; - - that.after(iframe_html); - $(window).scrollTop(that.position().top - 95); -} - -function start_visavis(plot_type){ - - destroy_numericbox(); - delete wmgui.search.numeric; - if (plot_type) wmgui.visavis_curtype = plot_type; - - $('div.ctxpanel').hide(); - var toshow = $('#ctxpanel_' + wmgui.visavis_curtype); - if (toshow.length) toshow.show(); - if (['matrix', 'cube', 'discovery'].indexOf(wmgui.visavis_curtype) !== -1) $('#cmppanel_plots').show(); - - if (wmgui.visavis_working) - return manage_visavis(); - - rebuild_visavis(); - - // visavis_col preparation - $('#visavis_col').show(); - $('#visavis').show(); - - switch_control_mode(0, 11, 'a', 'e'); - $('body').addClass('noscroll'); - - wmgui.search_type = 0; - wmgui.visavis_working = true; - - var cur_obj = {total_count: 1}; - $.extend(cur_obj, wmgui.search); - - try { - document.getElementById('visavis_iframe').contentWindow.location.replace(get_visavis_url(cur_obj)); - } catch (e){ - console.error('No iframe access'); - } -} - -function manage_visavis(callback_fn, param_a, param_b){ - if (wmgui.visavis_terminating || !wmgui.visavis_working){ - return false; - } - - if (wmgui.search.numeric){ // not supported for plotting yet! - wmgui.visavis_terminating = true; - return false; - } - - try { wmgui.active_ajax.abort() } catch(e){} - try { wmgui.quick_ajax.abort() } catch(e){} - - rebuild_visavis(); - - var cur_obj = {total_count: 1}; - $.extend(cur_obj, wmgui.search); - - try { - document.getElementById('visavis_iframe').contentWindow.location.replace(get_visavis_url(cur_obj)); - } catch (e){ - console.error('No iframe access'); - } - - if (callback_fn) callback_fn(param_a, param_b); - return true; -} - -function rebuild_visavis(){ - var extr = window.location.hash.indexOf('search/'); - if (extr == -1){ - var extr = window.location.hash.indexOf('inquiry/'); - if (extr == -1) return; - } - - var query = window.location.hash.substr(extr); - - $('a.pltcol_links').each(function(){ - var that = $(this), - plot_type = that.attr('rev'); - that.attr('href', wmgui.gui_host + window.location.pathname + '#plot/' + plot_type + '/' + query); - }); - - $('#visavis_col > ul > li').removeClass('embodied'); - $('#pltchoice_' + wmgui.visavis_curtype).addClass('embodied'); - - // ctx reset - if (['matrix', 'cube', 'discovery'].indexOf(wmgui.visavis_curtype) !== -1) - update_dc(); - - if (wmgui.visavis_curtype == 'matrix'){ - $('#ctxpanel_matrix > ul > li.embodied').removeClass('embodied'); - var y_id = $('#ctxpanel_matrix > ul > li.ss_y'); - if (y_id.length) y_id.removeClass('ss_y'); - $('#vismatrix_nump').addClass('embodied'); // set the default sort order, also in Visavis: TODO - $('span.sops').remove(); - - } else if (wmgui.visavis_curtype == 'cube'){ - $('#ctxpanel_cube > ul > li.embodied').removeClass('embodied'); - var y_id = $('#ctxpanel_cube > ul > li.ss_y'), - z_id = $('#ctxpanel_cube > ul > li.ss_z'); - if (y_id.length) y_id.removeClass('ss_y'); - if (z_id.length) z_id.removeClass('ss_z'); - $('#viscube_nump').addClass('embodied'); - $('span.sops').remove(); - - } else if (wmgui.visavis_curtype == 'graph'){ - $('#ctxpanel_graph > ul > li.embodied').removeClass('embodied'); - $('#visgraph_props').addClass('embodied'); - } - - try { - document.getElementById('visavis_iframe').contentWindow.fixel_manage(wmgui.visavis_curtype == 'cube' && wmgui.search.elements); - } catch (e){ - console.error('No iframe access'); - } -} - -function stop_visavis(){ - $('#visavis, #visavis_col').hide(); - wmgui.visavis_working = false; - wmgui.visavis_terminating = false; -} - -function get_visavis_url(request, type, height){ - if (wmgui.visavis_curtype == 'pie' && !type) - return wmgui.engines_addrs['visavis'] + '#' + wmgui.rfn_endpoint + '?q=' + encodeURIComponent(JSON.stringify(request)); - - var height_str = height ? ('&visavis_height=' + height) : ''; - - return wmgui.engines_addrs['visavis'] + '#' + wmgui.vis_endpoint + '/' + (type || wmgui.visavis_curtype) + '?q=' + encodeURIComponent(JSON.stringify(request)) + height_str; -} - -function describe_perms(perms){ - var out_gui = '

    Web-browser access = GUI

      ', - out_api = '

      Programmatic access = API

        '; - - if (perms.gui){ - if (perms.gui.root) out_gui += '
      • complete access
      • '; - else { - if (!$.isArray(perms.gui)) perms.gui = [perms.gui]; - $.each(perms.gui, function(m, ruleset){ - if (m > 3){ - out_gui += '
      • and ' + (perms.gui.length - 4) + ' more...
      • '; - return false; - } - $.each(wmgui.facets, function(n, item){ - if (ruleset[item]){ - try { - out_gui += '
      • ' + wmgui.facet_names[item] + ': ' + ruleset[item].map(function(x){return x.replace(', ', ' & ')}).join(', ') + '
      • '; - } catch(e){ return false } - } - }); - if (ruleset.refs == 'ALL') out_gui += '
      • full access to reference details
      • '; - else if (ruleset.refs == 'MENTIONED') out_gui += '
      • access to corresponding references
      • '; - else out_gui += '
      • no access to reference details
      • '; - out_gui += '

      • '; - }); - } - } else out_gui += '
      • only open data
      • '; - - if (perms.api){ - if (perms.api.root) out_api += '
      • complete access
      • '; - else if (perms.api.disabled) out_api += '
      • disabled — please check on the other device
      • '; - else { - if (!$.isArray(perms.api)) perms.api = [perms.api]; - $.each(perms.api, function(m, ruleset){ - if (m > 3){ - out_api += '
      • and ' + (perms.api.length - 4) + ' more...
      • '; - return false; - } - $.each(wmgui.facets, function(n, item){ - if (ruleset[item]){ - try { - out_api += '
      • ' + wmgui.facet_names[item] + ': ' + ruleset[item].map(function(x){ return x.replace(', ', ' & ') }).join(', ') + '
      • '; - } catch(e){ return false } - } - }); - out_api += '

      • '; - }); - } - } else out_api += '
      • only open data
      • '; - - return out_gui + '
      ' + out_api + '
    '; -} - -function show_advsbox(){ - - $('div.modal').hide(); - $('#advsbox, #overlay').show(); - - // show typed terms - if (!$.isEmptyObject(wmgui.search)){ - - $.each(wmgui.simple_facets, function(n, item){ - if (wmgui.search[item]){ - var value = wmgui.search[item]; - - if (item == "codens") value = wmgui.journal_converter.c2j(value); - else if (item == "doi") value = value.replaceAll('%2F', '/'); - - $('#advs_fct_' + item).val(decodeURIComponent(value.replace(/\+/g, "%20"))); - } else $('#advs_fct_' + item).val(''); - }); - - $.each(wmgui.multi_facets, function(n, item){ - - $('#advs_fct_' + item + '-selectized').val(''); - wmgui.multiselects[item].clear(); - - if (wmgui.search[item]){ - var obj = {}; - obj[item] = wmgui.search[item]; - wmgui.multiselects[item].write(obj); - //wmgui.multiselects[item].write({[item]: wmgui.search[item]}); - if (item == 'aetypes') show_aetmap(wmgui.search[item].split(',').pop().trim()); - } - }); - } - if (!show_advsbox.cached_aetmap){ - show_advsbox.cached_aetmap = new Image(); - show_advsbox.cached_aetmap.src = wmgui.aetmap_addr; - } -} - -function show_hints(disabled, res_count){ - - //$('#fdwidget').html('Were you satisfied with the data quality? Did everything work as expected? YesNo').show(); - - if (disabled || wmgui.search.numeric || wmgui.search.doi || wmgui.search.phid || wmgui.search.bid || wmgui.fuzzyout || wmgui.search_type == 2) - return; - - var cur_obj = {}; - $.extend(cur_obj, wmgui.search); - delete cur_obj.ignored; - delete cur_obj.search_type; - - var hint = JSON.stringify(cur_obj).replaceAll(' ', '+').replace('\{', '\\{').replace('\}', '\\}'); - $('#apihint kbd').html(hint).parent().show(); - - if (wmgui.search_type === 0 && (res_count > 3 || res_count === undefined)){ - $('a.plthint_links').each(function(){ - var that = $(this), - plot_type = that.attr('rev'); - that.attr('href', wmgui.gui_host + window.location.pathname + '#plot/' + plot_type + '/' + window.location.hash.substr(1)); - }); - $('#plthint').show(); - } -} - -function show_tooltip(info, forced){ - if (info.view_mode != wmgui.view_mode || (wmgui.visavis_working && !forced) || $('div.modal').is(':visible')) - return; - - var ref = $('#' + info.el).position(), - tooltip_el = document.getElementById('tooltip'); - - tooltip_el.style.left = (ref.left + info.oleft) + 'px'; - tooltip_el.style.top = (ref.top + info.otop) + 'px'; - tooltip_el.firstChild.innerHTML = info.text; - document.getElementById('tooltip').style.display = 'block'; -} - -function show_modal(which){ - - if (which == 'login'){ - - if ($("#factor_by_email").val()) $("#login_email").val($("#factor_by_email").val()); - else $("#login_email").val(''); - - $("#login_password").val(''); - $('#loginbox').show(); - $("#login_email").focus(); - - // for OAuth linking redirect only - // see email_chain.html - var u_email = window.localStorage.getItem(wmgui.store_oauth_email_key) || false; - if (u_email){ - $("#login_email").val(u_email); - window.localStorage.removeItem(wmgui.store_oauth_email_key); - } - - } else if (which == 'factor'){ - - if ($("#login_email").val()) $("#factor_by_email").val($("#login_email").val()); - else $("#factor_by_email").val(''); - - $('#factorbox').show(); - $("#factor_by_email").focus(); - - } else if (which == 'restore'){ - - if ($("#login_email").val()) $("#restore_by_email").val($("#login_email").val()); - else $("#restore_by_email").val(''); - - $('#restorebox').show(); - $("#restore_by_email").focus(); - } -} - -function init_user_login(){ - - // to prevent re-execution - var locals = JSON.parse(window.localStorage.getItem(wmgui.store_user_key) || '{}'); - if (locals.sid === wmgui.sid) - return; - - if (!locals.ipbased && locals.sid && locals.name && locals.acclogin){ - user_login(locals.sid, locals.name, locals.acclogin, locals.admin, locals.oauths, false); - - } else { - // attempt IP-based login - $.ajax({ - type: 'POST', - url: wmgui.ip_endpoint, - - }).done(function(data){ - if (data.sid && data.name && data.acclogin) - user_login(data.sid, data.name, data.acclogin, data.admin, data.oauths, true); - }); - } -} - -function user_login(sid, name, acclogin, admin, oauths, ipbased){ - - var corner_name = (name.length > 40) ? name.substr(0, 37) + '…' : name; - $('#auth_user').html(corner_name); - $('#account_holder_name').html('Hello ' + name + ' 👍'); - $('#account_holder_acclogin > span').html(ipbased ? 'location-based' : '' + acclogin + ''); - - wmgui.sid = sid; - wmgui.oauths = oauths; - - $('div.logged_out').hide(); - $('div.logged_in').show(); - $('#account_pass_change').hide(); - - window.localStorage.setItem(wmgui.store_user_key, JSON.stringify({ - sid: sid, - name: name, - acclogin: acclogin, - admin: admin, - ipbased: ipbased - })); // TODO? oauths: oauths - - (admin && (wmgui.edition == 0 || wmgui.edition == 1)) ? $('li.admin').show() : $('li.admin').hide(); - - if (ipbased){ - $('.only_regular').hide(); - $('#logout_trigger').addClass('disabled'); - $('#accpass_trigger').text('disabled').addClass('disabled'); - - } else { - $('.only_regular').show(); - $('#logout_trigger').removeClass('disabled'); - $('#accpass_trigger').text('change').removeClass('disabled'); - } - - try { - document.getElementById('visavis_iframe').contentWindow.location.reload(); - } catch (e){ - console.error('No iframe access'); - } - communicate_windows('tab_user_login'); - - wmgui.notify('Logged in as ' + name); - - // One-off redirection - var redir = window.localStorage.getItem(wmgui.store_redir_key); - if (redir){ - window.localStorage.removeItem(wmgui.store_redir_key); - return window.location.replace(redir); // FIXME? replace vs. href - } -} - -function tab_user_login(){ - - // to prevent re-execution - var locals = JSON.parse(window.localStorage.getItem(wmgui.store_user_key) || '{}'); - if (locals.sid === wmgui.sid) - return; - - window.location.reload(); -} - -function user_logout(silent){ - if (!wmgui.sid) - return; - - wmgui.sid = null; - wmgui.oauths = null; - $('li.admin').hide(); - $('div.logged_in').hide(); - $('div.logged_out').show(); - - window.localStorage.removeItem(wmgui.store_user_key); - - try { - document.getElementById('visavis_iframe').contentWindow.location.reload(); - } catch (e){ - console.error('No iframe access'); - } - communicate_windows('user_logout'); - - if (!silent) wmgui.notify('You are logged out'); -} - -function force_relogin(show_msg){ - $.ajax({ - type: 'POST', - url: wmgui.logout_endpoint, - data: {sid: wmgui.sid} - - }).done(function(data){}).fail(function(xhr, textStatus, errorThrown){}); - user_logout(true); - window.location.replace('#modal/login'); - if (show_msg) wmgui.notify(show_msg); -} - -function communicate_windows(runnable_name){ - // NB the active window doesn't receive a storage event - window.localStorage.setItem(wmgui.store_comm_exec_key, runnable_name); - setTimeout(function(){ - window.localStorage.removeItem(wmgui.store_comm_exec_key) - }, 0); -} - -function reset_factor_form() { - document.getElementById('factor_trigger').style.display = 'block'; - document.getElementById('factor_form_step_one').style.display = 'block'; - document.getElementById('factor_form_step_two').style.display = 'none'; - var resps = document.getElementsByClassName('factor_form_resp'); - for (var i = 0; i < resps.length; i++) { - resps[i].value = ""; - } -} - -function submit_factor_form_resp() { - var result = ""; - var resps = document.getElementsByClassName('factor_form_resp'); - for (var i = 0; i < resps.length; i++) { - result += resps[i].value; - } - if (result.length !== 6 || !Number.isInteger(parseInt(result))) return false; - - $.ajax({ - type: 'POST', - url: wmgui.factor_v_endpoint, - data: {a: result, ed: wmgui.edition} - - }).done(function(data){ - - if (data.error) return wmgui.notify(data.error); - if (!data.sid || !data.name || !data.acclogin){ - window.location.replace('#start'); - return wmgui.notify('Connection to server is lost, please try to reload'); - } - user_login(data.sid, data.name, data.acclogin, data.admin, data.oauths); - - reset_factor_form(); - - $('#userbox').trigger('click'); - - }).fail(function(xhr, textStatus, errorThrown){}); -} - -function update_dc(){ - var title = [], - orepr = {}; - for (var key in wmgui.search){ - if (['search_type', 'phid', 'numeric'].indexOf(key) !== -1) continue; - orepr[key] = wmgui.search[key]; - title.push(wmgui.search[key]) - } - title = title.join(" "); - - var count = 0, - cur_str = JSON.stringify(orepr), - cmp_html = ''; - - $.each(JSON.parse(window.localStorage.getItem(wmgui.store_history_key) || '[]'), function(n, past){ - if (count > 6) return false; - - var title = [], - past_str = JSON.stringify(past); - if (cur_str == past_str) return true; - - for (var prop in past){ title.push(past[prop]) } - title = title.join(" "); - cmp_html += ''; - count++; - }); - cmp_html += ''; - $('#select_cmp_trigger').empty().append(cmp_html); -} - -function show_aetmap(term){ - var coords = wmgui.aets[term]; - if (coords) - $('#aetmap').css('height', coords[1] + 'px').css('background', 'url(' + wmgui.aetmap_addr + ') 0 -' + coords[0] + 'px no-repeat').show(); - else - $('#aetmap').hide(); -} - -function render_all_polyhedra(){ - if (!$('#all_polyhedra_content').is(':empty')) return; - var aetypes_html = '', - defined_aetypes = Object.keys(wmgui.aets); - defined_aetypes.sort(function(a, b){ - var partsa = a.split('-vertex')[0].split(' '), - va = parseInt(partsa[partsa.length - 1]), - partsb = b.split('-vertex')[0].split(' '), - vb = parseInt(partsb[partsb.length - 1]); - return va > vb ? 1 : va < vb ? -1 : (a.length > b.length ? 1 : a.length < b.length ? -1 : 0); - }); - $.each(defined_aetypes, function(key, value){ - var coords = wmgui.aets[value]; - aetypes_html += ''; - }); - $('#all_polyhedra_content').html(aetypes_html); -} - -function show_dunit_info(phid, bid, entry){ - if (phid){ - $('#ind_title').html('Phase ' + phid); - $('#ind_link').attr('href', 'https://mpds.io/phase_id/' + phid).html('www.mpds.io/phase_id/' + phid); - - } else if (bid){ - $('#ind_title').html('Publication B' + bid); - $('#ind_link').attr('href', 'https://mpds.io/article/' + bid).html('www.mpds.io/article/' + bid); - - } else if (entry){ - $('#ind_title').html('Entry ' + entry); - $('#ind_link').attr('href', 'https://mpds.io/entry/' + entry).html('www.mpds.io/entry/' + entry); - } - - $('#refine_col, #ctx_col').hide(); - $('#phase_info, #ind_col > span').empty(); - - if (phid){ - $('#ind_col > span').html(''); - - wmgui.active_ajax = $.ajax({ - type: 'GET', - url: wmgui.phase_endpoint, - data: {phid: phid} - - }).done(function(data){ - if (data.error) return wmgui.notify(data.error); - - var html = '

    ' + data.out.formula_html.split(' ')[0] + ' ' + (data.out.spg || '?') + ' ' + (data.out.pearson || '—') + '

    '; - - if (data.out.mpid) html += '

    Materials Project mp-' + data.out.mpid + '

    '; - - html += '

    '; - if (data.out.articles_count) html += 'This phase was reported in ' + data.out.articles_count + ' article' + (data.out.articles_count > 1 ? 's' : '') + '.'; - if (data.out.sim_count > 1) html += ' There are ' + data.out.sim_count + ' structurally similar phases from other articles.'; - html += '

    '; - - $('#phase_info').html(html); - $('#dtypes_phid').show(); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Sorry, a network error occured. Please, try again'); - }); - - } else if (bid){ - $('#ind_col > span').html('📖'); // book icon - $('#phase_info').html('

    Ref. ' + bid + '

    Please make sure you are
    logged in to see all the details.

    '); - - wmgui.active_ajax = $.ajax({ - type: 'GET', - url: wmgui.refs_endpoint + '?noredir=1&fmt=bib&ref_id=' + bid + '&sid=' + wmgui.sid - - }).done(function(data){ - var citation = wmgui.parse_bib(data), - citation_html = '', - main_author = '', - links_html = ''; - - if (citation[0].length){ - citation[0].split(',').forEach(function(item, index){ - var author_name = item.trim().split('.')[0]; - author_name = author_name.substr(0, author_name.length - 2).replace("'", ""); - if (index === 0) main_author = author_name; - links_html += '' + author_name + ' or '; - }); - links_html = links_html.substr(0, links_html.length - 4); // " or " - if (citation[0].indexOf(',') !== -1) main_author += ' et al.'; - citation_html += ' ' + main_author + ', ' + citation[1] + '. ' + citation[2] + ' (' + citation[3] + ')'; - } - - if (bid == 999999){ - $('#phase_info').html('

    In-house data

    These data were generated automatically on the MPDS platform based on the original peer-reviewed Pauling File data. Please cite as ' + citation_html + '.

    '); - - } else { - var n_entries = wmgui.thumbed_display ? $('div.gallery_item').length : $('tr.tcell').length; - if (n_entries == 1000) n_entries = 'more than ' + n_entries; - $('#phase_info').html('

    Ref. ' + bid + '

    We have ' + (n_entries == 1 ? 'one entry' : n_entries + ' entries') + ' from this reference' + citation_html + '.

    ' + (links_html.length ? '

    Retrieve all data co-authored by ' + links_html + '.

    ' : '')); - } - - }).fail(function(xhr, textStatus, errorThrown){}); - - } else { - $('#ind_col > span').html('🔬'); // microscope icon - } - - $('#ind_col').show(); - $('#dtypes').hide(); -} - -function assign_edition(){ - - function run_edition(edition_key){ - edition_key = parseInt(edition_key); - if (!wmgui.editions[edition_key]) - edition_key = 0; - wmgui.edition = edition_key; - if (wmgui.editions[edition_key].css) wmgui.loadCSS(wmgui.editions[edition_key].css); - if (wmgui.editions[edition_key].actions) wmgui.editions[edition_key].actions(); - } - - $.each(wmgui.editions, function(key, value){ - if (wmgui.gui_host == value['prod_url'] || wmgui.gui_host == value['dev_url']){ - run_edition(key); - return false; - } - }); - - // for any unknown domain, ICDD MPDS is assumed - if (!wmgui.edition) run_edition(0); - - // for any third-party integrations, id="mpds_native" should not be used - wmgui.mpds_native = !!document.getElementById("mpds_native"); -} diff --git a/src_js/ptable.js b/src_js/ptable.js deleted file mode 100644 index 4cf22f5..0000000 --- a/src_js/ptable.js +++ /dev/null @@ -1,520 +0,0 @@ -"use strict"; - -var wmgui = window.wmgui || {}; - -wmgui.ptable = {}; -wmgui.ptable.update_selectize = false; -wmgui.ptable.active_ajax = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"); -wmgui.ptable.query = null; -wmgui.ptable.els_data = []; -wmgui.ptable.pdsvg_path = wmgui.static_host + '/pds_svgs'; -wmgui.ptable.crsvg_path = wmgui.static_host + '/crs_svgs'; -wmgui.ptable.ppsvg_path = wmgui.static_host + '/pps_svgs'; -wmgui.ptable.first_el = null; -wmgui.ptable.second_el = null; -wmgui.ptable.visible = false; // needed to debounce -wmgui.ptable.activated = false; // should it "jump" on top by input -wmgui.ptable.dtypes = 1; // 0, 1, 2, or 3, see #ptable_dtypes -wmgui.ptable.subphases_button = ''; -wmgui.ptable.vis_fixed = false; -wmgui.ptable.elements = ['X'].concat(wmutils.periodic_elements_cased); - -// patch display keyword unary to elementary -wmgui.ptable.arity_keys = wmutils.arity_keys.slice(); -wmgui.ptable.arity_keys[1] = 'elementary'; - -wmgui.ptable.show = function(){ - if (wmgui.ptable.visible) - return; - document.getElementById('ptable_holder').style.display = 'block'; - wmgui.ptable.visible = true; -}; - -wmgui.ptable.hide = function(){ - if (!wmgui.ptable.visible) - return; - document.getElementById('ptable_holder').style.display = 'none'; - wmgui.ptable.visible = false; -}; - -wmgui.ptable.activate = function(){ - wmgui.ptable.activated = true; - document.getElementById('ermac_logo').classList.add('resulted'); - document.getElementById('ptable_holder').classList.add('resulted'); - if (window.scrollY <= 40) document.getElementById('ptable_dtypes_box').classList.add('resulted'); - wmgui.mpdsgui.ptable_activate(); -}; - -wmgui.ptable.deactivate = function(){ - wmgui.ptable.activated = false; - document.getElementById('ermac_logo').classList.remove('resulted'); - document.getElementById('ptable_holder').classList.remove('resulted'); - document.getElementById('ptable_dtypes_box').classList.remove('resulted'); - wmgui.mpdsgui.ptable_deactivate(); -}; - -wmgui.ptable.decide = function(){ - const scroll_pos = window.scrollY; - //console.log(scroll_pos); - - if (scroll_pos > 60) // forward to intro_stats screen - wmgui.ptable.hide(); - - else // back to ptable screen - wmgui.ptable.show(); -} - -wmgui.ptable.subphases_set = function(state){ - if (!state){ - wmgui.ptable.subphases_button = ''; - - } else if (state === 1){ - wmgui.ptable.subphases_button = '
    Load binary and ternary phases ↑
    '; - - } else { - wmgui.ptable.subphases_button = '
    Load ternary phases only ↑
    '; - } -} - -function read_ptable_html(){ - let unaries_data = [{}]; // NB zero-th element (X) - - wmgui.ptable.elements.forEach(function(_, idx){ - if (idx == 0 || idx > 103) // X - Lr - return; - - const item = document.querySelector('#ptable_area > ul > li[data-pos="' + idx + '"]'); - let elem_data = {pos: idx, classes: []}; // NB prop html: - - item.classList.forEach(function(cls){ - elem_data.classes.push(cls); - }); - - unaries_data.push(elem_data); - }); - return unaries_data; -} - -function removeAllCls(cls){ - const collection = document.getElementsByClassName(cls); - while (collection.length) - collection[0].classList.remove(cls); -} - -function clear_results_area(){ - try { wmgui.ptable.active_ajax.abort() } catch(e){} - document.getElementById('ptable_previews').innerHTML = ''; - document.getElementById('ptable_vis').innerHTML = ''; - wmgui.ptable.deactivate(); -} - -function refresh_ptable_results(elA, elB, elC){ - - if (wmgui.view_mode !== 1) return; - - //console.log('Refreshing table with ' + [elA, elB, elC]); - - const els = [elA, elB, elC].filter(function(item){ return !!item }), - query_ph = els.length ? {search_type: 1, classes: wmutils.arity_keys[els.length], elements: els.join('-')} : false; - - if (wmgui.ptable.update_selectize){ - wmgui.ptable.update_selectize = false; - - wmgui.multiselects['main'].clear(); - wmgui.multiselects['main'].write({'elements': els.join('-')}); - } - - wmgui.ptable.subphases_set(); - - if (query_ph){ - wmgui.ptable.query = query_ph; - wmgui.ptable.vis_fixed = false; - - let iframe_addr, - iframe_height = 900; - - if (els.length == 1){ - - if (wmgui.ptable.dtypes == 2){ - iframe_addr = wmgui.engines_addrs['cifplayer']; - wmgui.ptable.vis_fixed = true; - - } else if (wmgui.ptable.dtypes == 3){ - iframe_addr = wmgui.engines_addrs['visavis']; - wmgui.ptable.vis_fixed = true; - - } else - document.getElementById('ptable_vis').innerHTML = ''; - - } else if (els.length == 2) { - iframe_height = 800; - - if (wmgui.ptable.dtypes == 1){ - const query_pds = {search_type: 0, classes: wmutils.arity_keys[els.length], elements: els.join('-'), props: 'phase diagram'}; - ajax_download(null, wmgui.search_endpoint + '?q=' + JSON.stringify(query_pds), render_right); - - } else if (wmgui.ptable.dtypes == 2){ - iframe_addr = wmgui.engines_addrs['cifplayer']; - wmgui.ptable.vis_fixed = true; - - } else if (wmgui.ptable.dtypes == 3){ - iframe_addr = wmgui.engines_addrs['visavis']; - wmgui.ptable.vis_fixed = true; - - } else - document.getElementById('ptable_vis').innerHTML = ''; - - } else { - wmgui.ptable.subphases_set(1); - iframe_height = window.innerHeight - 200; - wmgui.ptable.vis_fixed = true; - - if (wmgui.ptable.dtypes == 1){ - iframe_addr = wmgui.v_pd_3d_addr + els.join('-'); - - } else if (wmgui.ptable.dtypes == 2){ - iframe_addr = wmgui.engines_addrs['cifplayer']; - - } else if (wmgui.ptable.dtypes == 3){ - iframe_addr = wmgui.engines_addrs['visavis']; - - } else - document.getElementById('ptable_vis').innerHTML = ''; - } - ajax_download(wmgui.ptable.active_ajax, wmgui.search_endpoint + '?q=' + JSON.stringify(query_ph) + '&strict=1', render_left); - - if (iframe_addr) - document.getElementById('ptable_vis').innerHTML = ''; - - wmgui.ptable.activate(); - - } else clear_results_area(); -} - -function ajax_download(api, url, callback){ - wmgui.show_preloader(); - const xmlhttp = api ? api : (window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP")); - xmlhttp.onreadystatechange = function(){ - if (xmlhttp.readyState == 4){ - wmgui.hide_preloader(); - if (xmlhttp.status == 200) callback(xmlhttp.responseText); - else { - console.error("Error: HTTP " + xmlhttp.status + " status received during data retrieval from the server"); - } - } - } - xmlhttp.open("GET", url); - xmlhttp.withCredentials = true; - xmlhttp.send(1); -} - -function render_left(data){ - data = JSON.parse(data); - if (data.error) - return wmgui.notify(data.error); - - const header = '

    Reported phases of ' + wmgui.ptable.arity_keys[wmutils.arity_keys.indexOf(wmgui.ptable.query.classes)] + ' ' + wmgui.ptable.query.elements + (wmgui.ptable.query.elements.indexOf('-') == -1 ? '' : ' system') + '

    '; - - const parent = document.getElementById('ptable_previews'); - parent.className = ""; - parent.classList.add('ptable_dtype_' + wmgui.ptable.dtypes); - parent.innerHTML = header + (data.out.length ? build_thumbs_ph(data.out) : '

    No results

    ') + wmgui.ptable.subphases_button; - - if (data.out.length < 10) wmgui.ptable.vis_fixed = false; // prevent screen jumping - - if (wmgui.ptable.dtypes == 2){ - const els = document.querySelectorAll('#ptable_results div.gallery_img.renderable'); - if (els.length){ - const rnd_i = Math.floor(Math.random() * els.length); - els[rnd_i].parentNode.classList.add('active'); - const phid = els[rnd_i].getAttribute('rel'), - target = document.querySelector('#ptable_vis > iframe'), - target_addr = '#' + wmgui.phase_endpoint + '?phid=' + phid + '&struct=1'; - - if (target) target.contentWindow.location.hash = target_addr; - else document.getElementById('ptable_vis').innerHTML = ''; - - } else document.getElementById('ptable_vis').innerHTML = ''; - - } else if (wmgui.ptable.dtypes == 3){ - const els = document.querySelectorAll('#ptable_results div.gallery_img.renderable'); - if (els.length){ - const rnd_i = Math.floor(Math.random() * els.length); - els[rnd_i].parentNode.classList.add('active'); - const phid = els[rnd_i].getAttribute('rel'), - target = document.querySelector('#ptable_vis > iframe'), - target_addr = get_visavis_url({phid: phid}, 'graph', window.innerHeight - 50); - - if (target) target.contentWindow.location.replace(target_addr); - else document.getElementById('ptable_vis').innerHTML = ''; - - } else document.getElementById('ptable_vis').innerHTML = ''; - } -} - -function render_right(data){ - data = JSON.parse(data); - if (data.error) - return wmgui.notify(data.error); - - if (data.fuzzy_notice || !data.out.length) - document.getElementById('ptable_vis').innerHTML = ''; - else - document.getElementById('ptable_vis').innerHTML = '

    Reported phase diagrams of ' + wmgui.ptable.query.elements + ' system

    ' + build_thumbs_pd(data.out); -} - -function render_unaries(){ - - if (!wmgui.ptable.first_el) - return; - - wmgui.ptable.els_data.forEach(function(elem_data){ - if (!elem_data.pos) - return; - - const that = document.querySelector('#ptable_area > ul > li[data-pos="' + elem_data.pos + '"]'); - that.style.backgroundImage = "none"; - //that.innerHTML = elem_data.html; - that.className = ""; - that.classList.add(...elem_data.classes); - }); - - wmgui.ptable.first_el = null; -} - -function render_binaries(elA, elB){ - - //console.log('RENDERING BINARIES FOR: ' + [elA, elB]); - - document.querySelectorAll('#ptable_area > ul > li').forEach(function(item){ - if (!item.hasAttribute('data-pos')) - return; - - const current_el = wmgui.ptable.elements[parseInt(item.getAttribute('data-pos'))]; - - if (wmgui.ptable.dtypes == 1){ - - if (current_el != elA && current_el != elB){ - item.style.backgroundImage = "url('" + wmgui.ptable.pdsvg_path + "/bin/" + elA + "-" + current_el + ".svg')"; - item.className = "active_a"; - } - } else if (wmgui.ptable.dtypes == 2){ - - if (current_el != elA && current_el != elB){ - let pair = [elA, current_el]; - pair.sort(); - item.style.backgroundImage = "url('" + wmgui.ptable.crsvg_path + "/bin/" + pair.join("-") + ".svg')"; - item.className = "active_a"; - } - } else if (wmgui.ptable.dtypes == 3){ - - if (current_el != elA && current_el != elB){ - let pair = [elA, current_el]; - pair.sort(); - item.style.backgroundImage = "url('" + wmgui.ptable.ppsvg_path + "/bin/" + pair.join("-") + ".svg')"; - item.className = "active_a"; - } - } else { - if (current_el != elA && current_el != elB){ - item.style.backgroundImage = "none"; - item.className = "active_a"; - - } else if (current_el == elA) { - item.className = "selected_a"; - item.classList.add(...wmgui.ptable.els_data[parseInt(item.getAttribute('data-pos'))].classes); - } - } - }); -} - -function render_ternaries(elA, elB){ - - //console.log('RENDERING TERNARIES FOR: ' + [elA, elB]); - - document.querySelectorAll('#ptable_area > ul > li').forEach(function(item){ - if (!item.hasAttribute('data-pos')) - return; - - const current_el = wmgui.ptable.elements[parseInt(item.getAttribute('data-pos'))]; - - if (wmgui.ptable.dtypes == 1){ - - if (current_el != elA && current_el != elB){ - let triple = [elA, elB, current_el]; - triple.sort(); - item.style.backgroundImage = "url('" + wmgui.ptable.pdsvg_path + "/ter/" + triple.join("-") + ".svg')"; - item.classList.add('active_b'); - } - } else if (wmgui.ptable.dtypes == 2){ - - if (current_el != elA && current_el != elB){ - let triple = [elA, elB, current_el]; - triple.sort(); - item.style.backgroundImage = "url('" + wmgui.ptable.crsvg_path + "/ter/" + triple.join("-") + ".svg')"; - item.classList.add('active_b'); - } - } else if (wmgui.ptable.dtypes == 3){ - - if (current_el != elA && current_el != elB){ - let triple = [elA, elB, current_el]; - triple.sort(); - item.style.backgroundImage = "url('" + wmgui.ptable.ppsvg_path + "/ter/" + triple.join("-") + ".svg')"; - item.classList.add('active_b'); - } - } else { - if (current_el != elA && current_el != elB){ - item.style.backgroundImage = "none"; - item.classList.add('active_b'); - - } else if (current_el == elA) { - item.className = "selected_a"; - item.classList.add(...wmgui.ptable.els_data[parseInt(item.getAttribute('data-pos'))].classes); - - } else if (current_el == elB) { - item.className = "selected_b"; - } - } - }); -} - -function build_thumbs_ph(json){ // FIXME duplicates another function *build_thumbs* - let result_html = ''; - - json.sort(function(a, b){ - return a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0; - }); - - json.forEach(function(row){ - result_html += ''; - }); - return result_html; -} - -function build_thumbs_pd(json){ // FIXME duplicates another function *build_thumbs* - let result_html = ''; - - json.sort(function(a, b){ - return a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0; - }); - - json.forEach(function(row){ - if (row[3] == 0) // filter unprocs - return; - row[2] = row[2].split(';')[0]; - row[2] = row[2].split(' ')[row[2].split(' ').length - 1]; - const content = '' + row[0] + '

    ' + row[2] + '

    '; - - result_html += ''; - }); - return result_html; -} - -function select_ptable_el(selected_el, dom_el){ - //console.log('Selected element is ' + selected_el); - - if (!dom_el){ - const dom_el = document.querySelector('#ptable_area > ul > li[data-pos="' + wmgui.ptable.elements.indexOf(selected_el) + '"]'); - if (!dom_el) return wmgui.notify('Sorry, wrong element: ' + selected_el); - } - - if (dom_el.classList.contains('selected_a')){ - // first element removal - dom_el.classList.remove('selected_a'); - render_unaries(); - refresh_ptable_results(); - - } else if (dom_el.classList.contains('selected_b')){ - // second element removal - dom_el.classList.remove('selected_b'); - render_binaries(wmgui.ptable.first_el, selected_el); - wmgui.ptable.second_el = null; - refresh_ptable_results(wmgui.ptable.first_el); - - } else if (dom_el.classList.contains('selected_c')){ - // third element removal - dom_el.classList.remove('selected_c'); - refresh_ptable_results(wmgui.ptable.first_el, wmgui.ptable.second_el); - - } else if (dom_el.classList.contains('active_b')){ - // third element selection - removeAllCls('selected_c'); - dom_el.classList.add('selected_c'); - refresh_ptable_results(wmgui.ptable.first_el, wmgui.ptable.second_el, selected_el); - - } else if (dom_el.classList.contains('active_a')){ - // second element selection - removeAllCls('selected_b'); - dom_el.classList.add('selected_b'); - render_ternaries(wmgui.ptable.first_el, selected_el); - wmgui.ptable.second_el = selected_el; - refresh_ptable_results(wmgui.ptable.first_el, selected_el); - - } else { - // first element selection - dom_el.classList.add('selected_a'); - wmgui.ptable.first_el = selected_el; - render_binaries(wmgui.ptable.first_el, selected_el); - refresh_ptable_results(selected_el); - } -} - -function select_ptable_series(els){ - //console.log('Received for TABLE DRAW: ' + els); - if (!els){ - render_unaries(); - clear_results_area(); - return; - } - - els = els.split('-'); - if (els.length > 3) - els = els.slice(0, 3); - - wmgui.ptable.first_el = els[0]; - wmgui.ptable.second_el = els[1] || null; - - const domelA = document.querySelector('#ptable_area > ul > li[data-pos="' + wmgui.ptable.elements.indexOf(els[0]) + '"]'); - - if (domelA){ - removeAllCls('selected_a'); - domelA.classList.add('selected_a'); - } - - if (els.length == 1){ - render_binaries(els[0], els[0]); - - } else if (els.length == 2){ - const domelB = document.querySelector('#ptable_area > ul > li[data-pos="' + wmgui.ptable.elements.indexOf(els[1]) + '"]'); - - if (domelB){ - removeAllCls('selected_b'); - domelB.classList.add('selected_b'); - domelB.classList.add(...wmgui.ptable.els_data[parseInt(domelB.getAttribute('data-pos'))].classes); - domelB.style.backgroundImage = "none"; - } - render_ternaries(els[0], els[1]); - - } else { - const domelB = document.querySelector('#ptable_area > ul > li[data-pos="' + wmgui.ptable.elements.indexOf(els[1]) + '"]'), - domelC = document.querySelector('#ptable_area > ul > li[data-pos="' + wmgui.ptable.elements.indexOf(els[2]) + '"]'); - - if (domelB){ - removeAllCls('selected_b'); - domelB.classList.add('selected_b'); - domelB.classList.add(...wmgui.ptable.els_data[parseInt(domelB.getAttribute('data-pos'))].classes); - domelB.style.backgroundImage = "none"; - } - if (domelC){ - removeAllCls('selected_c'); - domelC.classList.add('selected_c'); - } - render_ternaries(els[0], els[1]); - } - refresh_ptable_results(...els); -} diff --git a/src_js/router.js b/src_js/router.js deleted file mode 100755 index e8dbc8d..0000000 --- a/src_js/router.js +++ /dev/null @@ -1,434 +0,0 @@ -"use strict"; - -var wmgui = window.wmgui || {}; - -function url_redraw_react(){ - var anchors = window.location.hash.substr(1).split('/'); - - if (!anchors.length) return; - $('#overlay, #aetmap, #dtypes_phid, div.modal, div.menu_collateral').hide(); - $('#dtypes_phid > ul > li').removeClass('active'); - - try { wmgui.active_ajax.abort() } catch(e){} - try { wmgui.quick_ajax.abort() } catch(e){} - - if (window['url__' + anchors[0]]) window['url__' + anchors[0]](anchors.slice(1).join('/')); - else wmgui.notify('Sorry, unknown route requested'); -} - -/** - * The main landing route /#start - */ -function url__start(arg){ - switch_view_mode(1); - if (wmgui.tooltip_counter < 2) setTimeout(function(){ show_tooltip(wmgui.tooltips[wmgui.tooltip_landing]) }, 4000); -} - -/** - * A free-form fuzzy search /#search/arg - * given by the OptimadeNLP wmutils - */ -function url__search(arg, no_sync){ - var query = decodeURIComponent(arg), - parsed = wmutils.guess(query); - //console.log(parsed); - - if (parsed.numeric) wmgui.search_type = 1; - - show_interpretation(parsed); - delete parsed.ignored; - - $('#search_field-selectized').val(''); - wmgui.multiselects['main'].clear(); - wmgui.multiselects['main'].write(parsed); - - wmgui.search = parsed; - parsed.search_type = wmgui.search_type; - - if (!no_sync) request_search(parsed, query, wmgui.search_type); -} - -/** - * The parameters-based exact search /#inquiry/arg - */ -function url__inquiry(arg, no_sync){ - var inquiry = arg.split("&").map( function(n){ return n = n.split("="), this[n[0]] = n[1], this }.bind({}) )[0]; - - wmgui.facets.forEach(function(item){ - if (inquiry[item]) inquiry[item] = decodeURIComponent(inquiry[item].replaceAll('+', ' ')); - }); - - // re-inventing serialization for numeric nested arrays - if (inquiry.numeric){ - inquiry.numeric = decodeURIComponent(inquiry.numeric).split(';').map(function(item){ return item.split(',') }); - inquiry.numeric = inquiry.numeric.filter(function(item){ return item.length == 3 }); - wmgui.search_type = 1; // force phases search type - } - //console.log(inquiry); - - show_interpretation(inquiry); - delete inquiry.ignored; - - var caption_items = []; - $.each(inquiry, function(k, v){ caption_items.push(v) }); - - $('#search_field-selectized').val(''); - wmgui.multiselects['main'].clear(); - wmgui.multiselects['main'].write(inquiry); - - wmgui.search = inquiry; - inquiry.search_type = wmgui.search_type; - - if (!no_sync) request_search(inquiry, caption_items.join(" ").replaceAll(",", " "), wmgui.search_type); -} - -/** - * The 3 brothers routing exact search into the search_type (TODO?) - */ -function url__inquiry_entries(arg){ - wmgui.search_type = 0; - return url__inquiry(arg); -} -function url__inquiry_phases(arg){ - wmgui.search_type = 1; - return url__inquiry(arg); -} -function url__inquiry_articles(arg){ - wmgui.search_type = 2; - return url__inquiry(arg); -} - -/** - * The plotting subsystem (Vis-a-vis) /#plot/arg - */ -function url__plot(arg){ - var q = arg.split('/'), - plot_type = q[0], - search_verb = q[1], - query = q[2]; - - if (!plot_type || !search_verb || !query) - return wmgui.notify('Sorry, unknown route: ' + arg); - - if (search_verb == 'search') - url__search(query, true); - - else if (search_verb == 'inquiry') - url__inquiry(query, true); - - else - return wmgui.notify('Sorry, unknown route: ' + arg); - - wmgui.visavis_curtype = plot_type; - - //if (wmgui.view_mode == 1) - switch_view_mode(2); - - setTimeout(function(){ - start_visavis(plot_type); - }, 0); - - if (wmgui.tooltip_counter < 2 && (plot_type == 'matrix' || plot_type == 'cube')){ - setTimeout(function(){ show_tooltip(wmgui.tooltips['ss_axes'], true) }, 3000); - } -} - -/** - * The individual entry display /#entry/ID - */ -function url__entry(arg){ - wmgui.search_type = 0; - wmgui.visavis_terminating = true; - request_search({'entry': arg}, 'entry ' + arg, true); - wmgui.search = {}; // mockup to reset previous properties - wmgui.passive_sim_col = true; - $('#search_field-selectized').val(''); - wmgui.multiselects['main'].clear(); - show_interpretation(); -} - -/** - * The individual phase display /#phase_id/integer - */ -function url__phase_id(arg){ - wmgui.search_type = 0; - if (!wmgui.ptable.visible){ - $('#search_field-selectized').val(''); - wmgui.multiselects['main'].clear(); - } - show_interpretation(); - var phid = parseInt(arg); - wmgui.search = {'phid': phid}; - wmgui.search.search_type = wmgui.search_type; - request_search({'phid': phid}, 'phase ' + phid, true); -} - -/** - * The individual phase display /#phase/ID - */ -function url__phase(arg){ - var phase_data = arg.split('/'), - formula = phase_data[0], - spg = phase_data[1], - pearson = phase_data[2]; - - if (formula && spg && pearson){ - wmgui.active_ajax = $.ajax({ - type: 'GET', - url: wmgui.phph_endpoint, - data: {phase: [formula, spg, pearson].join('/')}, - beforeSend: wmgui.show_preloader - - }).always(wmgui.hide_preloader).done(function(data){ - if (data.error) return wmgui.notify(data.error); - window.location.replace('#phase_id/' + data.phid); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - wmgui.notify('Sorry, a network error occured. Please, try again'); - }); - - } else return wmgui.notify('Sorry, wrong phase given'); -} - -/** - * The individual B-entry display /#article/integer - */ -function url__article(arg){ - wmgui.search_type = 0; - $('#search_field-selectized').val(''); - wmgui.multiselects['main'].clear(); - show_interpretation(); - var bentry = parseInt(arg); - wmgui.search = {'bid': bentry}; - wmgui.search.search_type = wmgui.search_type; - request_search({'bid': bentry}, 'B' + bentry, true); -} - -/** - * The display of menu with all the physical props - */ -function url__hierarchy(){ - $('body').removeClass('noscroll'); - $('#overlay').show(); - window.scrollTo(0, 0); - $('#hy_box').show(); -} - -/** - * The different types of modal windows - */ -function url__modal(arg){ - - //var url_params = new URLSearchParams(window.location.search), - // redir = url_params.get('redir'); - - if (arg == "login"){ - if (wmgui.sid) return window.location.replace('#modal/menu'); - - // edition-based OAuth login (mpdsgui only) - if (wmgui.edition == 1){ - return window.location.replace('oauth/asm.html'); // NB history replacement - } - show_modal(arg); - - } else if (arg == "restore" || arg == "factor"){ - if (wmgui.sid) return window.location.replace('#modal/menu'); - show_modal(arg); - - } else if (arg == "menu"){ - if (!wmgui.sid) return window.location.replace('#modal/login'); - $("#new_password_1, #new_password_2").val(''); - arrange_menu_collateral(); - $('#menubox, div.menu_collateral').show(); - - } else return wmgui.notify("Sorry, unknown modal window"); - - $('#overlay').show(); -} - -/** - * Retrieving the access via email by the secret link - */ -function url__access(arg){ - $.ajax({ - type: 'POST', - url: wmgui.access_endpoint, - data: {a: arg, ed: wmgui.edition} - - }).done(function(data){ - if (data.error){ - window.location.replace('#start'); - return wmgui.notify(data.error); - } - if (!data.sid || !data.name || !data.acclogin){ - window.location.replace('#start'); - return wmgui.notify('Connection to server is lost, please try to reload'); - } - user_login(data.sid, data.name, data.acclogin, data.admin, data.oauths); - window.location.replace('#start'); - - }).fail(function(xhr, textStatus, errorThrown){ - window.location.replace('#start'); - return wmgui.notify('Sorry, a network error occured. Please, try again'); - }); -} - -/** - * Confirming the access via email by the secret link - */ -function url__ratify(arg){ - $.ajax({ - type: 'POST', - url: wmgui.ratify_endpoint, - data: {a: arg, ed: wmgui.edition} - - }).done(function(data){ - if (data.error){ - window.location.replace('#start'); - return wmgui.notify(data.error); - } - if (!data.sid || !data.name || !data.acclogin){ - window.location.replace('#start'); - return wmgui.notify('Connection to server is lost, please try to reload'); - } - user_login(data.sid, data.name, data.acclogin, data.admin, data.oauths); - window.location.replace('#modal/menu'); - - }).fail(function(xhr, textStatus, errorThrown){ - window.location.replace('#start'); - return wmgui.notify('Sorry, a network error occured. Please, try again'); - }); -} - -/** - * A special display of the related entries - */ -function url__interlinkage(arg){ - wmgui.search_type = 1; - request_search({interlinkage: arg}, 'linked phases for ' + arg, true); - wmgui.search = {numeric: true}; // mockup FIXME? - //$('#search_field-selectized').val(''); - //wmgui.multiselects['main'].clear(); - show_interpretation(); -} - -/** - * All polyhedra menu - */ -function url__polyhedra(arg){ - $('body').removeClass('noscroll'); - $('#overlay').show(); - window.scrollTo(0, 0); - render_all_polyhedra(); - $('#all_polyhedra_box').show(); -} - -/** - * Access denied route: trying to identify the reason - */ -function url__junction(arg){ - if (!wmgui.sid) - return window.location.replace('#products'); - - var locals = JSON.parse(window.localStorage.getItem(wmgui.store_user_key) || '{}'); - - wmgui.active_ajax = $.ajax({ - type: 'POST', - url: locals.ipbased ? wmgui.ip_perms_endpoint : wmgui.perms_endpoint, - data: {sid: wmgui.sid}, - beforeSend: wmgui.show_preloader - - }).always(wmgui.hide_preloader).done(function(data){ - - if (data.error) - return wmgui.notify(data.error); - - if (!data.hasOwnProperty('gui') || !data.hasOwnProperty('api')) - return force_relogin('Please, re-login'); - - window.location.replace('#modal/menu'); - $('#tab_links > li').removeClass('working'); - $('#tab_links > li[rev=usr_tab_perms]').addClass('working'); - $('div.menu_tabs').hide(); - $('#usr_tab_perms').show(); - $('#perms_view').html(describe_perms(data)); - setTimeout(function(){ - wmgui.notify('Please, check your data access.'); - }, 1500); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') - return force_relogin('Please, re-login'); - }); -} - -/** - * Moved from mpdsgui - */ -function url__products(arg){ - if (!wmgui.mpds_native) - window.location.href = wmgui.static_host + '/#products'; - - if (wmgui.edition === 1){ - // NB no history replacement and no new windows - window.location.href = 'https://www.asminternational.org/asm-materials-platform-for-data-science-api'; - - } else { - $('#overlay').show(); - window.scrollTo(0, 0); - $('#productbox').show(); - } -} - -/** - * Moved from mpdsgui - */ -function url__formal(arg){ - if (!wmgui.mpds_native) - window.location.href = wmgui.static_host + '/#formal/' + arg; - - var header = '', - addr = ''; - - if (arg == 'terms') - header = 'Website Terms & Conditions', addr = '/terms.json'; - - else if (arg == 'api') - header = 'MPDS API Terms & Conditions', addr = '/api.json'; - - else if (arg == 'usfed') - header = 'Procurement Details', addr = '/usfed.json'; - - else if (arg == 'refunds') - header = 'Refund Policy', addr = '/refunds.json'; - - else if (arg == 'privacy') - header = 'Privacy Policy', addr = '/privacy.json'; - - else - return wmgui.notify('Sorry, unknown document requested'); - - wmgui.show_preloader(); - - $('#formalbox_navi > ul > li').removeClass('working'); - $('a[href="#formal/' + arg + '"]').parent().addClass('working'); - - $.ajax({ - url: addr, - type: 'GET', - data: {nocache: Math.floor(Math.random() * 1000)}, - beforeSend: wmgui.show_preloader - - }).always(wmgui.hide_preloader).done(function(answer){ - var html = '

    ' + header + '

    '; - $.each(answer, function(n, value){ - html += '§' + (n + 1) + '. ' + value.header + '

    ' + value.content + '

    '; - }); - $('#formalbox_content').html(html); - $('#formalbox, #overlay').show(); - window.scrollTo(0, 0); - wmgui.hide_preloader(); - - }).fail(function(xhr, textStatus, errorThrown){}); -} diff --git a/src_js/run.js b/src_js/run.js deleted file mode 100755 index 86b45c1..0000000 --- a/src_js/run.js +++ /dev/null @@ -1,14 +0,0 @@ -"use strict"; - -// now, run everything - -assign_edition(); - -register_html(); - -satisfy_requirements(); - -register_events(); - -// use MPDS API, please -console.log("%cWeb-scraping or automated usage apart of the public MPDS API is in violation of our ToS (https://mpds.io/formal/terms) and results in banned account.", "color:red;font-size:16px;") diff --git a/src_js/sliders.js b/src_js/sliders.js deleted file mode 100755 index 13cc4da..0000000 --- a/src_js/sliders.js +++ /dev/null @@ -1,102 +0,0 @@ -"use strict"; - -var wmgui = window.wmgui || {}; - -function create_floating_slider(prop_name, prop_id, units, p_min, p_max, p_step, p_start, p_end){ - // FIXME compatibilize with *wmgui.numerics* - - if ($('#slider_' + prop_id).length){ - console.log('Attempted to create an existing slider id' + prop_id); - return; - } - - //console.log(prop_name, prop_id, units, p_min, p_max, p_step, p_start, p_end); - - var html = '
  • '; - html += '
    '; - html += (wmgui.numerics[prop_name][5] || prop_name) + (units ? (', ' + units + '') : ''); - html += '
    '; - html += '
    '; - html += '
    '; // #numericbox > ul > li > div.slider - html += ''; - html += '
    '; - html += '
  • '; - - $('#numericbox').show(); - $('#numericbox > ul').prepend(html); - - var decimals = p_step ? Math.abs(Math.log10(p_step)) : Math.max(p_min.count_decimals(), p_max.count_decimals()); - //console.log('decimals = ', decimals); - - noUiSlider.create(document.getElementById('slider_' + prop_id), { - start: [p_start || p_min, p_end || p_max], - step: p_step || ((p_max - p_min) / 250), - tooltips: [wNumb({decimals: decimals}), wNumb({decimals: decimals})], - connect: true, - behaviour: 'drag', - range: {'min': p_min, 'max': p_max}, - format: { - to: function (value){ return value }, - from: function(value){ return Number(value) } - } - }); -} - -function destroy_numericbox(){ - if ($('#numericbox').is(':visible')){ - $('#numericbox > ul > li').each(function(){ - var that = $(this); - that.find('div.slider_numerics')[0].noUiSlider.destroy(); - that.remove(); - }); - $('#numericbox').hide(); - } -} - -function get_sliders_ranges(url_num_obj, num_database){ - // given by: - // (1.) wmutils.guess, or - // (2.) from re-inventing serialization for numeric nested arrays, or - // (3.) by the user - var props = {}, - output = []; - - for (var i = 0; i < url_num_obj.length; i++){ - if (url_num_obj[i][1] !== '>' && url_num_obj[i][1] !== '<') - continue; - - var prop = (url_num_obj[i][1] == '>' ? 'start' : 'end'); - - if (!props[ url_num_obj[i][0] ]) props[url_num_obj[i][0]] = {}; - - props[url_num_obj[i][0]][prop] = parseFloat(url_num_obj[i][2]); // TODO? consequent series like > 100, > 200, etc. - } - //console.log(props); - for (var key in props){ - if (!num_database[key]){ console.log("Unsupported key: " + key); continue; } - - if (!props[key]['start']) props[key]['start'] = num_database[key][2]; // min - else if (!props[key]['end']) props[key]['end'] = num_database[key][3]; // max - - if (props[key]['end'] < props[key]['start']) throw new Error("The end of range is lower than the start of range!"); - output.push([ - key, - num_database[key][0], - num_database[key][1], - num_database[key][2], - num_database[key][3], - num_database[key][4], - props[key]['start'], - props[key]['end'] - ]); - } - output.sort(function(a, b){ - return a[1] > b[1] ? 1 : -1; // prop_id - }); - return output; -} - -function serialize_numeric(prop, sign, value){ // re-inventing serialization for numeric nested arrays - return prop + ',' + sign + ',' + value + ';'; -} diff --git a/src_js/startup.js b/src_js/startup.js deleted file mode 100755 index ae2a486..0000000 --- a/src_js/startup.js +++ /dev/null @@ -1,402 +0,0 @@ -"use strict"; - -var wmgui = window.wmgui || {}; - -function satisfy_requirements(){ - - $('#notifybox, #preloader').hide(); - //document.title = document.body.clientWidth + ' px'; - $('#absolidize > span.disabled > span.href').attr('rel', wmgui.mydata_addr); - - wmgui.ptable.els_data = read_ptable_html(); - - init_user_login(); - - // building history box - var history_html = ''; - $.each(JSON.parse(window.localStorage.getItem(wmgui.store_history_key) || '[]'), function(n, past){ - wmgui.tooltip_counter++; - - if (n > 5) - return false; - - var title = [], - inquiry = false; - - for (var prop in past){ title.push(past[prop]) } - title = title.join(" "); - $.each(wmgui.inquiries, function(m, item){ if (past[item]){ inquiry = true; return false; } }); - - if (inquiry) history_html += '
  • ' + title + '
  • '; - else history_html += '
  • ' + title + '
  • '; - }); - $('#history ul').append(history_html); - - $.each(JSON.parse(window.localStorage.getItem(wmgui.store_bids_key) || '[]'), function(n, item){ - wmgui.bid_history.push(parseInt(item)); - }); - - $.each(JSON.parse(window.localStorage.getItem(wmgui.store_mydata_key) || '[]'), function(n, item){ - wmgui.mydata_history.push(item); - }); - - // set client-side data features - $.ajax({ - url: wmgui.wmdata_endpoint, - type: 'GET' - //data: {nocache: Math.floor(Math.random() * 1000)} - - }).done(function(answer){ - - var i = 0, len = answer.props_ref.length; - for (i; i < len; i++){ - if (!answer.props_ref[i]) answer.props_ref[i] = answer.props[i]; - } - - // local search algo - // #1 - $.each(['props', 'lattices', 'sgs', 'protos', 'codens', 'geos', 'orgs'], function(idx, fct){ - wmgui.create_autocomplete({ - custom_type: fct, - selector: 'advs_fct_' + fct, minChars: 1, cache: 1, - source: function(term, fct_type, suggest){ - // other names are used, define them first here - var fct_src = fct_type, - fct_chk = fct_type, - anypos = false; - - if (fct_type !== 'lattices'){ - anypos = true; - if (fct_type == 'props') fct_src = 'props_ref'; - else if (fct_type == 'codens'){ - fct_src = 'jfull'; - fct_chk = 'jfull'; - } - } - - var suggestions = [], - cnt = 0, - checks = [], - i = 0, - len = answer[fct_chk].length; - - term = term.toLowerCase(); - for (i; i < len; i++){ - if (answer[fct_chk][i].toLowerCase().startswith(term)){ - suggestions.push(answer[fct_src][i]); - if (anypos) checks.push(answer[fct_src][i]); - cnt++; - if (cnt > 12) break; - } - } - if (anypos && suggestions.length < 6){ - for (i = 0; i < len; i++){ - if (answer[fct_chk][i].toLowerCase().indexOf(term) != -1 && checks.indexOf(answer[fct_src][i]) == -1){ - suggestions.push(answer[fct_src][i]); - cnt++; - if (cnt > 12) break; - } - } - } - suggest(suggestions); - }, - renderItem: function (item, search){ - return '
    ' + item + '
    '; - } - }); - }); - - // local search algo - // #2 - $.each(wmgui.multi_facets, function(idx, fct){ - wmgui.multiselects[fct] = $('#advs_fct_' + fct).selectize({ - plugins: ['remove_button', 'preserve_on_blur'], - valueField: 'id', - labelField: 'label', - searchField: 'label', - create: false, - highlight: false, - maxItems: 5, - closeAfterSelect: true, - diacritics: false, - options: [], - onChange: function(value){ - if (fct == 'aetypes'){ - var term = (wmgui.multiselects['aetypes'].read()['aetypes'] || "").split(', ').pop(); - show_aetmap(term); - if ($('#aet_limit').is(':checked')) $('#aet_limit').trigger('click'); - - } else if (fct == 'wyckoff'){ - var terms = (wmgui.multiselects['wyckoff'].read()['wyckoff'] || "").split(',').map(function(x){ return x.trim() }); - if (terms && terms[0] && terms.length > 1){ - var cmp = wmgui.is_wyckoff_position(terms[0]); - if (!terms.every(function(x){ return cmp === wmgui.is_wyckoff_position(x) })) wmgui.notify('Wyckoff sequence and positions are mutually exclusive'); - } - } - }, - onItemRemove: function(value){ - var input = this; - setTimeout(function(){ - input.close(); - }, 750); - }, - load: function(term, callback){ - this.clearOptions(); - if (!term.length) return callback(); - - var suggestions = [], - cnt = 0, - checks = [], - i = 0, - len = answer[fct].length; - - term = term.toLowerCase(); - for (i; i < len; i++){ - if (answer[fct][i].toLowerCase().startswith(term)){ - suggestions.push({'facet': fct, 'label': answer[fct][i], 'id': fct + i}); - checks.push(answer[fct][i]); - cnt++; - if (cnt > 12) break; - } - } - if (suggestions.length < 6){ - for (i = 0; i < len; i++){ - if (answer[fct][i].toLowerCase().indexOf(term) != -1 && checks.indexOf(answer[fct][i]) == -1){ - suggestions.push({'facet': fct, 'label': answer[fct][i], 'id': fct + i}); - cnt++; - if (cnt > 12) break; - } - } - } - callback(suggestions); - }, - score: function(){ return function(){ return 1 } }, // no client scoring - render: { - option: function(item, escape){ - return '
    ' + item.label + '
    '; - }, - item: function(item, escape){ - return '
    ' + item.label + '
    '; - } - } - })[0].selectize; - - wmgui.multiselects[fct].read = function(){ - return wmgui._selectize_read_facet(fct); - } - wmgui.multiselects[fct].write = function(search_obj){ - wmgui._selectize_write(wmgui.multiselects[fct], fct, search_obj); - } - wmgui.multiselects[fct].display = function(facet, term){ - wmgui._selectize_display(wmgui.multiselects[fct], facet, term); - } - }); - - wmgui.journal_converter.j2c = function(x){ - var fi = answer.jfull.indexOf(x); - if (fi == -1){ - wmgui.notify("Sorry, unknown journal: " + x); - return x; - } - return answer.codens[fi]; - } - wmgui.journal_converter.c2j = function(x){ - var fi = answer.codens.indexOf(x); - if (fi == -1){ - wmgui.notify("Sorry, unknown CODEN: " + x); - return x; - } - return answer.jfull[fi]; - } - - var html_scalars = '', - html_complex = '', - html_arrays = '', - counter = 0; - - $.each(answer.hy_scalars, function(term, content){ - term = parseInt(term); - //console.log(term); - term = answer.props_ref[term] ? answer.props_ref[term] : answer.props[term]; - //console.log(term); - counter += 1; - html_scalars += '
  • ' + term + ' (expand)
      '; - $.each(content, function(sub_term, sub_content){ - sub_term = parseInt(sub_term); - //console.log(sub_term); - sub_term = answer.props_ref[sub_term] ? answer.props_ref[sub_term] : answer.props[sub_term]; - //console.log('----' + sub_term); - html_scalars += '
    • ' + sub_term + '
        '; - $.each(sub_content, function(n, item){ - item = parseInt(item); - var prop = answer.props_ref[item] ? answer.props_ref[item] : answer.props[item], - specs = answer.numerics[item]; // NB object vs. array - //console.log('---------' + item + ' ' + prop); - html_scalars += '
      • ' + prop + ''; - if (specs){ - html_scalars += '' + (specs[0] || '') + '  [' + specs[1] + ' ↔ ' + specs[2] + '] 🔍'; - wmgui.numerics[prop] = [item, specs[0], specs[1], specs[2], specs[3]]; // prop_name: [client_prop_id, units, min, max, ?step, ?origname] - } - html_scalars += '
      • '; - }); - html_scalars += '
    • '; - }); - html_scalars += '
  • '; - }); - $('#hy_scalars > ul').append(html_scalars); - - $.each(wmgui.hy_complex, function(n, item){ - // FIXME cannot process with optimade NLP parser - html_complex += '
  • ' + item + '
  • '; - }); - $('#hy_complex > ul').append(html_complex); - - $.each(answer.hy_textual, function(term, content){ - term = parseInt(term); - term = answer.props_ref[term] ? answer.props_ref[term] : answer.props[term]; - counter += 1; - html_arrays += '
  • ' + term + ' (expand)
      '; - $.each(content, function(sub_term, sub_content){ - sub_term = parseInt(sub_term); - sub_term = answer.props_ref[sub_term] ? answer.props_ref[sub_term] : answer.props[sub_term]; - html_arrays += '
    • ' + sub_term + '
        '; - $.each(sub_content, function(n, item){ - item = parseInt(item); - item = answer.props_ref[item] ? answer.props_ref[item] : answer.props[item]; - html_arrays += '
      • ' + item + '
      • '; - }); - html_arrays += '
    • '; - }); - html_arrays += '
  • '; - }); - $('#hy_arrays > ul').append(html_arrays); - - wmgui.create_autocomplete({ - selector: 'hy_suggest', minChars: 1, cache: 1, - source: function(term, fct_type, suggest){ - var fct_src = 'props_ref', - term = term.toLowerCase(), - suggestions = [], - cnt = 0, - checks = [], - i = 0, - len = answer[fct_type].length; - for (i; i < len; i++){ - if (answer[fct_type][i].startswith(term)){ - suggestions.push(answer[fct_src][i]); - checks.push(answer[fct_src][i]); - cnt++; - if (cnt > 18) break; - } - } - if (suggestions.length < 12){ - for (i = 0; i < len; i++){ - if (answer[fct_type][i].indexOf(term) != -1 && checks.indexOf(answer[fct_src][i]) == -1){ - suggestions.push(answer[fct_src][i]); - cnt++; - if (cnt > 18) break; - } - } - } - suggest(suggestions); - }, - renderItem: function (item, search){ - return '
    ' + item + '
    '; - }, - onSelect: function (e, term, item){ - var numerics = wmgui.numerics[term]; - - if ($('#numericbox').is(':visible') && numerics) - create_floating_slider(term, numerics[0], numerics[1], numerics[2], numerics[3], numerics[4]); - else - window.location.hash = wmgui.aug_search_cmd("props", term); - - $('#hy_suggest').val(''); - } - }); - - rotate_interesting(); - setInterval(rotate_interesting, 2000); - - window.location.hash ? url_redraw_react() : window.location.replace('#start'); - - }).fail(function(xhr, textStatus, errorThrown){ - console.error(errorThrown); - throw new Error("Failed to load GUI"); - }); - - // set server-side data features - wmgui.multiselects['main'] = $('#search_field').selectize({ - plugins: ['remove_button', 'preserve_on_blur'], - valueField: 'id', - labelField: 'label', - searchField: 'label', - create: false, - highlight: false, - maxItems: 10, - closeAfterSelect: true, - diacritics: false, - options: [], - onInitialize: function(){ - $('#search_field-selectized').focus(); - }, - onItemAdd: function(){ - if (wmgui.selectize_emit){ - var check = wmgui.multiselects['main'].read(); - select_ptable_series(check.elements); - } - }, - onItemRemove: function(){ - var check = wmgui.multiselects['main'].read(), - input = this; - if (!check.numeric){ - destroy_numericbox(); - delete wmgui.search.numeric; - if (wmgui.selectize_emit) select_ptable_series(check.elements); - } - setTimeout(function(){ - input.close(); - }, 750); - }, - load: function(query, callback){ - this.clearOptions(); - if (!query.length) return callback(); - $.ajax({ - url: wmgui.auto_endpoint + '?q=' + encodeURIComponent(query), - type: 'GET', - error: callback, - success: function(res){ - if (!res.length){ - return; - } - callback(res); - } - }); - }, - score: function(){ return function(){ return 1 } }, // no client scoring - render: { - option: function(item, escape){ - return '
    ' + item.label + '
    '; - }, - item: function(item, escape){ - return '
    ' + item.label + '
    '; - } - } - })[0].selectize; - - wmgui.multiselects['main'].read = function(){ - return wmgui._selectize_read_main(); - } - wmgui.multiselects['main'].write = function(search_obj){ - wmgui._selectize_write(wmgui.multiselects['main'], 'main', search_obj); - } - wmgui.multiselects['main'].display = function(facet, term){ - wmgui._selectize_display(wmgui.multiselects['main'], facet, term); - } - - wmgui.darkmode = new Darkmode({saveInCookies: false}); - document.getElementById('darkmode_trigger').innerHTML = wmgui.darkmode.isActivated() ? 'enabled' : 'disabled'; - - //create_floating_slider('density', 42, 'Mg/m3', 10, 900, 10); - // EOF satisfy_requirements -} diff --git a/src_js/third_party/autocomplete.js b/src_js/third_party/autocomplete.js deleted file mode 100755 index 433d142..0000000 --- a/src_js/third_party/autocomplete.js +++ /dev/null @@ -1,205 +0,0 @@ - -// spin-off from https://github.com/Pixabay/JavaScript-autoComplete - -var wmgui = window.wmgui || {}; - -wmgui.create_autocomplete = (function(){ - function autoComplete(options){ - if (!document.querySelector) return; - - // helpers - function hasClass(el, className){ return el.classList ? el.classList.contains(className) : new RegExp('\\b' + className + '\\b').test(el.className); } - - function addEvent(el, type, handler){ - if (el.attachEvent) el.attachEvent('on' + type, handler); - else el.addEventListener(type, handler); - } - function removeEvent(el, type, handler){ - // if (el.removeEventListener) not working in IE11 - if (el.detachEvent) el.detachEvent('on' + type, handler); - else el.removeEventListener(type, handler); - } - function live(elClass, event, cb, context){ - addEvent(context || document, event, function(e){ - var found, el = e.target || e.srcElement; - while (el && !(found = hasClass(el, elClass))) el = el.parentElement; - if (found) cb.call(el, e); - }); - } - - var o = { - selector: 0, - source: 0, - minChars: 3, - delay: 150, - offsetLeft: 0, - offsetTop: 1, - cache: 1, - menuClass: '', - renderItem: function (item, search){}, - onSelect: function(e, term, item){}, - arrow_pressed: false, - custom_type: false - }; - for (var k in options){ if (options.hasOwnProperty(k)) o[k] = options[k]; } - - // init - var that = document.getElementById(o.selector), - fct_type = that.getAttribute("rel"); - - // create suggestions container "sc" - that.sc = document.createElement('div'); - that.sc.className = 'autocomplete-suggestions ' + o.menuClass; - - that.autocompleteAttr = that.getAttribute('autocomplete'); - that.setAttribute('autocomplete', 'off'); - that.cache = {}; - that.last_val = ''; - - that.updateSC = function(resize, next){ - var rect = that.getBoundingClientRect(); - that.sc.style.left = Math.round(rect.left + (window.pageXOffset || document.documentElement.scrollLeft) + o.offsetLeft) + 'px'; - that.sc.style.top = Math.round(rect.bottom + (window.pageYOffset || document.documentElement.scrollTop) + o.offsetTop) + 'px'; - that.sc.style.width = Math.round(rect.right - rect.left) + 'px'; // outerWidth - if (!resize){ - that.sc.style.display = 'block'; - if (!that.sc.maxHeight){ that.sc.maxHeight = parseInt((window.getComputedStyle ? getComputedStyle(that.sc, null) : that.sc.currentStyle).maxHeight); } - if (!that.sc.suggestionHeight) that.sc.suggestionHeight = that.sc.querySelector('.autocomplete-suggestion').offsetHeight; - if (that.sc.suggestionHeight) - if (!next) that.sc.scrollTop = 0; - else { - var scrTop = that.sc.scrollTop, selTop = next.getBoundingClientRect().top - that.sc.getBoundingClientRect().top; - if (selTop + that.sc.suggestionHeight - that.sc.maxHeight > 0) - that.sc.scrollTop = selTop + that.sc.suggestionHeight + scrTop - that.sc.maxHeight; - else if (selTop < 0) - that.sc.scrollTop = selTop + scrTop; - } - } - } - addEvent(window, 'resize', that.updateSC); - document.body.appendChild(that.sc); - - live('autocomplete-suggestion', 'mouseleave', function(e){ - var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); - if (sel) setTimeout(function(){ sel.className = sel.className.replace('selected', '') }, 20); - }, that.sc); - - live('autocomplete-suggestion', 'mouseover', function(e){ - var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); - if (sel) sel.className = sel.className.replace('selected', ''); - this.className += ' selected'; - - // account aetypes aetmap - if (o.custom_type == 'aetypes' && show_aetmap) show_aetmap(this.innerText); - }, that.sc); - - live('autocomplete-suggestion', 'mousedown', function(e){ - if (hasClass(this, 'autocomplete-suggestion')){ // else outside click - var v = this.getAttribute('data-val'); - that.value = v; - o.onSelect(e, v, this); - that.sc.style.display = 'none'; - } - }, that.sc); - - that.blurHandler = function(){ - try { var over_sb = document.querySelector('.autocomplete-suggestions:hover'); } catch(e){ var over_sb = 0; } - if (!over_sb){ - that.last_val = that.value; - that.sc.style.display = 'none'; - setTimeout(function(){ that.sc.style.display = 'none'; }, 350); // hide suggestions on fast input - } else if (that !== document.activeElement) setTimeout(function(){ that.focus() }, 20); - }; - addEvent(that, 'blur', that.blurHandler); - - var suggest = function(data){ - o.arrow_pressed = false; - var val = that.value; - that.cache[val] = data; - if (data.length && val.length >= o.minChars){ - var s = ''; - for (var i = 0; i < data.length; i++) s += o.renderItem(data[i], val); - that.sc.innerHTML = s; - that.updateSC(0); - } - else - that.sc.style.display = 'none'; - } - - that.keydownHandler = function(e){ - var key = window.event ? e.keyCode : e.which; - // down (40), up (38) - if ((key == 40 || key == 38) && that.sc.innerHTML){ - o.arrow_pressed = true; - var next, sel = that.sc.querySelector('.autocomplete-suggestion.selected'); - if (!sel){ - next = (key == 40) ? that.sc.querySelector('.autocomplete-suggestion') : that.sc.childNodes[that.sc.childNodes.length - 1]; // first : last - next.className += ' selected'; - that.value = next.getAttribute('data-val'); - } else { - next = (key == 40) ? sel.nextSibling : sel.previousSibling; - if (next){ - sel.className = sel.className.replace('selected', ''); - next.className += ' selected'; - that.value = next.getAttribute('data-val'); - } - else { - sel.className = sel.className.replace('selected', ''); - that.value = that.last_val; - next = 0; - } - } - that.updateSC(0, next); - return false; - } - // esc - else if (key == 27){ that.value = that.last_val; that.sc.style.display = 'none'; } - // enter - else if (key == 13 || key == 9){ - var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); - if (sel && that.sc.style.display != 'none' && o.arrow_pressed){ - o.onSelect(e, sel.getAttribute('data-val'), sel); - that.sc.style.display = 'none'; - //setTimeout(function(){ that.sc.style.display = 'none'; }, 20); - } - } - }; - addEvent(that, 'keydown', that.keydownHandler); - - that.keyupHandler = function(e){ - var key = window.event ? e.keyCode : e.which; - if (!key || (key < 35 || key > 40) && key != 13 && key != 27){ - var val = that.value; - if (val.length >= o.minChars){ - if (val != that.last_val){ - that.last_val = val; - clearTimeout(that.timer); - if (o.cache){ - if (val in that.cache){ - suggest(that.cache[val]); - return; - } - // no requests if previous suggestions were empty - for (var i = 1; i < val.length - o.minChars; i++){ - var part = val.slice(0, val.length - i); - if (part in that.cache && !that.cache[part].length){ suggest([]); return; } - } - } - that.timer = setTimeout(function(){ o.source(val, fct_type, suggest) }, o.delay); - } - } else { - that.last_val = val; - that.sc.style.display = 'none'; - } - } - }; - addEvent(that, 'keyup', that.keyupHandler); - - that.focusHandler = function(e){ - that.last_val = '\n'; - that.keyupHandler(e); - }; - if (!o.minChars) addEvent(that, 'focus', that.focusHandler); - } - return autoComplete; -})(); \ No newline at end of file diff --git a/src_js/third_party/jquery.min.js b/src_js/third_party/jquery.min.js deleted file mode 100644 index 7f37b5d..0000000 --- a/src_js/third_party/jquery.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
    ",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0 thead > tr > th', /// - selectorHeaderParent: 'dataheader_entries', /// - debug: false - }; - - /* debuging utils */ - - function benchmark(s, d) { - log(s + "," + (new Date().getTime() - d.getTime()) + "ms"); - } - - this.benchmark = benchmark; - - function log(s) { - if (typeof console != "undefined" && typeof console.debug != "undefined") { - console.log(s); - } else { - alert(s); - } - } - - /* parsers utils */ - - function buildParserCache(table, $headers) { - - if (table.config.debug) { - var parsersDebug = ""; - } - - if (table.tBodies.length == 0) return; // In the case of empty tables - var rows = table.tBodies[0].rows; - - if (rows[0]) { - - var list = [], - cells = rows[0].cells, - l = cells.length; - - for (var i = 0; i < l; i++) { - - var p = false; - - if ($.metadata && ($($headers[i]).metadata() && $($headers[i]).metadata().sorter)) { - - p = getParserById($($headers[i]).metadata().sorter); - - } else if ((table.config.headers[i] && table.config.headers[i].sorter)) { - - p = getParserById(table.config.headers[i].sorter); - } - if (!p) { - - p = detectParserForColumn(table, rows, -1, i); - } - - if (table.config.debug) { - parsersDebug += "column:" + i + " parser:" + p.id + "\n"; - } - - list.push(p); - } - } - - if (table.config.debug) { - log(parsersDebug); - } - - return list; - }; - - function detectParserForColumn(table, rows, rowIndex, cellIndex) { - var l = parsers.length, - node = false, - nodeValue = false, - keepLooking = true; - while (nodeValue == '' && keepLooking) { - rowIndex++; - if (rows[rowIndex]) { - node = getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex); - nodeValue = trimAndGetNodeText(table.config, node); - if (table.config.debug) { - log('Checking if value was empty on row:' + rowIndex); - } - } else { - keepLooking = false; - } - } - for (var i = 1; i < l; i++) { - if (parsers[i].is(nodeValue, table, node)) { - return parsers[i]; - } - } - // 0 is always the generic parser (text) - return parsers[0]; - } - - function getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex) { - return rows[rowIndex].cells[cellIndex]; - } - - function trimAndGetNodeText(config, node) { - return $.trim(getElementText(config, node)); - } - - function getParserById(name) { - var l = parsers.length; - for (var i = 0; i < l; i++) { - if (parsers[i].id.toLowerCase() == name.toLowerCase()) { - return parsers[i]; - } - } - return false; - } - - /* utils */ - - function buildCache(table) { - - if (table.config.debug) { - var cacheTime = new Date(); - } - - var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0, - totalCells = (table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length) || 0, - parsers = table.config.parsers, - cache = { - row: [], - normalized: [] - }; - - for (var i = 0; i < totalRows; ++i) { - - /* Add the table data to main data array */ - var c = $(table.tBodies[0].rows[i]), - cols = []; - - // if this is a child row, add it to the last row's children and - // continue to the next row - if (c.hasClass(table.config.cssChildRow)) { - cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add(c); - // go to the next for loop - continue; - } - - cache.row.push(c); - - for (var j = 0; j < totalCells; ++j) { - cols.push(parsers[j].format(getElementText(table.config, c[0].cells[j]), table, c[0].cells[j])); - } - - cols.push(cache.normalized.length); // add position for rowCache - cache.normalized.push(cols); - cols = null; - }; - - if (table.config.debug) { - benchmark("Building cache for " + totalRows + " rows:", cacheTime); - } - - return cache; - }; - - function getElementText(config, node) { - - if (!node) return ""; - - var $node = $(node), - data = $node.attr('data-sort-value'); - if (data !== undefined) return data; - - var text = ""; - - if (!config.supportsTextContent) config.supportsTextContent = node.textContent || false; - - if (config.textExtraction == "simple") { - if (config.supportsTextContent) { - text = node.textContent; - } else { - if (node.childNodes[0] && node.childNodes[0].hasChildNodes()) { - text = node.childNodes[0].innerHTML; - } else { - text = node.innerHTML; - } - } - } else { - if (typeof(config.textExtraction) == "function") { - text = config.textExtraction(node); - } else { - text = $(node).text(); - } - } - return text; - } - - function appendToTable(table, cache) { - - if (table.config.debug) { - var appendTime = new Date(); - } - - var c = cache, - r = c.row, - n = c.normalized, - totalRows = n.length, - checkCell = (n[0].length - 1), - tableBody = $(table.tBodies[0]), - rows = []; - - for (var i = 0; i < totalRows; i++) { - var pos = n[i][checkCell]; - - rows.push(r[pos]); - - if (!table.config.appender) { - - //var o = ; - var l = r[pos].length; - for (var j = 0; j < l; j++) { - tableBody[0].appendChild(r[pos][j]); - } - } - } - - if (table.config.appender) { - - table.config.appender(table, rows); - } - - rows = null; - - if (table.config.debug) { - benchmark("Rebuilt table:", appendTime); - } - - // apply table widgets - ///applyWidget(table); - - // trigger sortend - setTimeout(function () { - $(table).trigger("sortEnd"); - }, 0); - - }; - - function buildHeaders(table) { - - if (table.config.debug) { - var time = new Date(); - } - - var meta = ($.metadata) ? true : false; - - var header_index = computeTableHeaderCellIndexes(document.getElementById(table.config.selectorHeaderParent)); - - var $tableHeaders = $(table.config.selectorHeaders).each(function (index) { /// $(, table) - - this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex]; - // this.column = index; - this.order = formatSortingOrder(table.config.sortInitialOrder); - - this.count = this.order; - - if (checkHeaderMetadata(this) || checkHeaderOptions(table, index)) this.sortDisabled = true; - if (checkHeaderOptionsSortingLocked(table, index)) this.order = this.lockedOrder = checkHeaderOptionsSortingLocked(table, index); - - if (!this.sortDisabled) { - var $th = $(this).addClass(table.config.cssHeader); - if (table.config.onRenderHeader) table.config.onRenderHeader.apply($th); - } - - // add cell to headerList - table.config.headerList[index] = this; - }); - - if (table.config.debug) { - benchmark("Built headers:", time); - log($tableHeaders); - } - - return $tableHeaders; - - }; - - // from: - // http://www.javascripttoolbox.com/lib/table/examples.php - // http://www.javascripttoolbox.com/temp/table_cellindex.html - - function computeTableHeaderCellIndexes(t) { - var matrix = []; - var lookup = {}; - var thead = t.getElementsByTagName('THEAD')[0]; - var trs = thead.getElementsByTagName('TR'); - - for (var i = 0; i < trs.length; i++) { - var cells = trs[i].cells; - for (var j = 0; j < cells.length; j++) { - var c = cells[j]; - - var rowIndex = c.parentNode.rowIndex; - var cellId = rowIndex + "-" + c.cellIndex; - var rowSpan = c.rowSpan || 1; - var colSpan = c.colSpan || 1 - var firstAvailCol; - if (typeof(matrix[rowIndex]) == "undefined") { - matrix[rowIndex] = []; - } - // Find first available column in the first row - for (var k = 0; k < matrix[rowIndex].length + 1; k++) { - if (typeof(matrix[rowIndex][k]) == "undefined") { - firstAvailCol = k; - break; - } - } - lookup[cellId] = firstAvailCol; - for (var k = rowIndex; k < rowIndex + rowSpan; k++) { - if (typeof(matrix[k]) == "undefined") { - matrix[k] = []; - } - var matrixrow = matrix[k]; - for (var l = firstAvailCol; l < firstAvailCol + colSpan; l++) { - matrixrow[l] = "x"; - } - } - } - } - return lookup; - } - - function checkCellColSpan(table, rows, row) { - var arr = [], - r = document.getElementById(table.config.selectorHeaderParent).tHead.rows, - c = r[row].cells; - - for (var i = 0; i < c.length; i++) { - var cell = c[i]; - - if (cell.colSpan > 1) { - arr = arr.concat(checkCellColSpan(table, headerArr, row++)); - } else { - if (table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row + 1])) { - arr.push(cell); - } - // headerArr[row] = (i+row); - } - } - return arr; - }; - - function checkHeaderMetadata(cell) { - if (($.metadata) && ($(cell).metadata().sorter === false)) { - return true; - }; - return false; - } - - function checkHeaderOptions(table, i) { - if ((table.config.headers[i]) && (table.config.headers[i].sorter === false)) { - return true; - }; - return false; - } - - function checkHeaderOptionsSortingLocked(table, i) { - if ((table.config.headers[i]) && (table.config.headers[i].lockedOrder)) return table.config.headers[i].lockedOrder; - return false; - } - - function formatSortingOrder(v) { - if (typeof(v) != "Number") { - return (v.toLowerCase() == "desc") ? 1 : 0; - } else { - return (v == 1) ? 1 : 0; - } - } - - function isValueInArray(v, a) { - var i = 0, l = a.length; - for (i; i < l; i++) { - if (a[i][0] == v) { - return true; - } - } - return false; - } - - function setHeadersCss(table, $headers, list, css) { - // remove all header information - $headers.removeClass(css[0]).removeClass(css[1]); - - var h = []; - $headers.each(function (offset) { - if (!this.sortDisabled) { - h[this.column] = $(this); - } - }); - - var i = 0, l = list.length; - for (i; i < l; i++) { - h[list[i][0]].addClass(css[list[i][1]]); - } - } - - function fixColumnWidth(table, $headers) { - var c = table.config; - if (c.widthFixed) { - var colgroup = $(''); - $("tr:first td", table.tBodies[0]).each(function () { - colgroup.append($('').css('width', $(this).width())); - }); - $(table).prepend(colgroup); - }; - } - - function updateHeaderSortCount(table, sortList) { - var c = table.config, - l = sortList.length; - for (var i = 0; i < l; i++) { - var s = sortList[i], - o = c.headerList[s[0]]; - o.count = s[1]; - o.count++; - } - } - - /* sorting methods */ - var sortWrapper; - - function multisort(table, sortList, cache) { - - if (table.config.debug) { - var sortTime = new Date(); - } - - var dynamicExp = "sortWrapper = function(a,b) {", - l = sortList.length; - - // TODO: inline functions. - for (var i = 0; i < l; i++) { - - var c = sortList[i][0]; - var order = sortList[i][1]; - // var s = (getCachedSortType(table.config.parsers,c) == "text") ? - // ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ? - // "sortNumeric" : "sortNumericDesc"); - // var s = (table.config.parsers[c].type == "text") ? ((order == 0) - // ? makeSortText(c) : makeSortTextDesc(c)) : ((order == 0) ? - // makeSortNumeric(c) : makeSortNumericDesc(c)); - var s = (table.config.parsers[c].type == "text") ? ((order == 0) ? makeSortFunction("text", "asc", c) : makeSortFunction("text", "desc", c)) : ((order == 0) ? makeSortFunction("numeric", "asc", c) : makeSortFunction("numeric", "desc", c)); - var e = "e" + i; - - dynamicExp += "var " + e + " = " + s; // + "(a[" + c + "],b[" + c - // + "]); "; - dynamicExp += "if(" + e + ") { return " + e + "; } "; - dynamicExp += "else { "; - - } - - // if value is the same keep orignal order - var orgOrderCol = cache.normalized[0].length - 1; - dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];"; - - for (var i = 0; i < l; i++) { - dynamicExp += "}; "; - } - - dynamicExp += "return 0; "; - dynamicExp += "}; "; - - if (table.config.debug) { - benchmark("Evaling expression:" + dynamicExp, new Date()); - } - - eval(dynamicExp); - - cache.normalized.sort(sortWrapper); - - if (table.config.debug) { - benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time:", sortTime); - } - - return cache; - }; - - function makeSortFunction(type, direction, index) { - var a = "a[" + index + "]", - b = "b[" + index + "]"; - if (type == 'text' && direction == 'asc') { - return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + a + " < " + b + ") ? -1 : 1 )));"; - } else if (type == 'text' && direction == 'desc') { - return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + b + " < " + a + ") ? -1 : 1 )));"; - } else if (type == 'numeric' && direction == 'asc') { - return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + a + " - " + b + "));"; - } else if (type == 'numeric' && direction == 'desc') { - return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + b + " - " + a + "));"; - } - }; - - function makeSortText(i) { - return "((a[" + i + "] < b[" + i + "]) ? -1 : ((a[" + i + "] > b[" + i + "]) ? 1 : 0));"; - }; - - function makeSortTextDesc(i) { - return "((b[" + i + "] < a[" + i + "]) ? -1 : ((b[" + i + "] > a[" + i + "]) ? 1 : 0));"; - }; - - function makeSortNumeric(i) { - return "a[" + i + "]-b[" + i + "];"; - }; - - function makeSortNumericDesc(i) { - return "b[" + i + "]-a[" + i + "];"; - }; - - function sortText(a, b) { - if (table.config.sortLocaleCompare) return a.localeCompare(b); - return ((a < b) ? -1 : ((a > b) ? 1 : 0)); - }; - - function sortTextDesc(a, b) { - if (table.config.sortLocaleCompare) return b.localeCompare(a); - return ((b < a) ? -1 : ((b > a) ? 1 : 0)); - }; - - function sortNumeric(a, b) { - return a - b; - }; - - function sortNumericDesc(a, b) { - return b - a; - }; - - function getCachedSortType(parsers, i) { - return parsers[i].type; - }; - /* public methods */ - this.construct = function (settings) { - return this.each(function () { - // if no thead or tbody quit. - if (!this.tBodies) return; //if (!this.tHead || !this.tBodies) return; - // declare - var $this, $document, $headers, cache, config, shiftDown = 0, - sortOrder; - // new blank config object - this.config = {}; - // merge and extend. - config = $.extend(this.config, $.tablesorter.defaults, settings); - // store common expression for speed - $this = $(this); - // save the settings where they read - $.data(this, "tablesorter", config); - // build headers - $headers = buildHeaders(this); - // try to auto detect column type, and store in tables config - this.config.parsers = buildParserCache(this, $headers); - // build the cache for the tbody cells - cache = buildCache(this); - // get the css class names, could be done else where. - var sortCSS = [config.cssDesc, config.cssAsc]; - // fixate columns if the users supplies the fixedWidth option - fixColumnWidth(this); - // apply event handling to headers - // this is to big, perhaps break it out? - $headers.unbind(); - $headers.click(function (e){ - if (window.iframe) return false; - var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0; - if (!this.sortDisabled && totalRows > 0) { - // Only call sortStart if sorting is - // enabled. - $this.trigger("sortStart"); - // store exp, for speed - var $cell = $(this); - // get current column index - var i = this.column; - // get current column sort order - this.order = this.count++ % 2; - // always sort on the locked order. - if(this.lockedOrder) this.order = this.lockedOrder; - - // user only whants to sort on one - // column - if (!e[config.sortMultiSortKey]) { - // flush the sort list - config.sortList = []; - if (config.sortForce != null) { - var a = config.sortForce; - for (var j = 0; j < a.length; j++) { - if (a[j][0] != i) { - config.sortList.push(a[j]); - } - } - } - // add column to sort list - config.sortList.push([i, this.order]); - // multi column sorting - } else { - // the user has clicked on an all - // ready sortet column. - if (isValueInArray(i, config.sortList)) { - // revers the sorting direction - // for all tables. - for (var j = 0; j < config.sortList.length; j++) { - var s = config.sortList[j], - o = config.headerList[s[0]]; - if (s[0] == i) { - o.count = s[1]; - o.count++; - s[1] = o.count % 2; - } - } - } else { - // add column to sort list array - config.sortList.push([i, this.order]); - } - }; - setTimeout(function () { - // set css for headers - setHeadersCss($this[0], $headers, config.sortList, sortCSS); - appendToTable( - $this[0], multisort($this[0], config.sortList, cache) - ); - }, 1); - // stop normal event by returning false - return false; - } - // cancel selection - }).mousedown(function () { - if (config.cancelSelection) { - this.onselectstart = function () { - return false; - }; - return false; - } - }); - // apply easy methods that trigger binded events - $this.unbind("update updateCell sorton appendCache"); - $this.bind("update", function () { - var me = this; - setTimeout(function () { - // rebuild parsers. - me.config.parsers = buildParserCache(me, $headers); - // rebuild the cache map - cache = buildCache(me); - }, 1); - }).bind("updateCell", function (e, cell) { - var config = this.config; - // get position from the dom. - var pos = [(cell.parentNode.rowIndex - 1), cell.cellIndex]; - // update cache - cache.normalized[pos[0]][pos[1]] = config.parsers[pos[1]].format(getElementText(config, cell), cell); - }).bind("sorton", function (e, list) { - $(this).trigger("sortStart"); - config.sortList = list; - // update and store the sortlist - var sortList = config.sortList; - // update header count index - updateHeaderSortCount(this, sortList); - // set css for headers - setHeadersCss(this, $headers, sortList, sortCSS); - // sort the table and append it to the dom - appendToTable(this, multisort(this, sortList, cache)); - }).bind("appendCache", function () { - appendToTable(this, cache); - }); - if ($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) { - config.sortList = $(this).metadata().sortlist; - } - // if user has supplied a sort list to constructor. - if (config.sortList.length > 0) { - $this.trigger("sorton", [config.sortList]); - } - // apply widgets - ///applyWidget(this); - }); - }; - this.addParser = function (parser) { - var l = parsers.length, - a = true; - for (var i = 0; i < l; i++) { - if (parsers[i].id.toLowerCase() == parser.id.toLowerCase()) { - a = false; - } - } - if (a) { - parsers.push(parser); - }; - }; - this.formatFloat = function (s) { - var i = parseFloat(s); - return (isNaN(i)) ? 0 : i; - }; - this.formatInt = function (s) { - var i = parseInt(s); - return (isNaN(i)) ? 0 : i; - }; - this.isDigit = function (s, config) { - // replace all an wanted chars and match. - return /^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g, ''))); - }; - } - }); - - // extend plugin scope - $.fn.extend({ - tablesorter: $.tablesorter.construct - }); - - // make shortcut - var ts = $.tablesorter; - - // add default parsers - ts.addParser({ - id: "text", - is: function (s) { - return true; - }, format: function (s) { - return $.trim(s.toLocaleLowerCase()); - }, type: "text" - }); - - ts.addParser({ - id: "chemical", - is: function (s) { - return true; - }, format: function (s) { - return $.trim(s.replace("[", "").replace("(", "")); - }, type: "text" - }); - - ts.addParser({ - id: "digit", - is: function (s, table) { - var c = table.config; - return $.tablesorter.isDigit(s, c); - }, format: function (s) { - return $.tablesorter.formatFloat(s); - }, type: "numeric" - }); - - ts.addParser({ - id: "url", - is: function (s) { - return /^(https?|ftp|file):\/\/$/.test(s); - }, format: function (s) { - return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//), '')); - }, type: "text" - }); - - ts.addParser({ - id: "doi", - is: function (s) { - return true; - }, format: function (s) { - return $.tablesorter.formatInt(s.replace("[", "").replace("]", "")); - }, type: "numeric" - }); - - ts.addParser({ - id: "metadata", - is: function (s) { - return false; - }, format: function (s, table, cell) { - var c = table.config, - p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName; - return $(cell).metadata()[p]; - }, type: "numeric" - }); -})(jQuery); diff --git a/src_js/third_party/selectize.js b/src_js/third_party/selectize.js deleted file mode 100644 index e9b3971..0000000 --- a/src_js/third_party/selectize.js +++ /dev/null @@ -1,3684 +0,0 @@ -/** - * sifter.js - * Copyright (c) 2013 Brian Reavis & contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at: - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF - * ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - * - * @author Brian Reavis - */ - -(function(root, factory) { - if (typeof define === 'function' && define.amd) { - define('sifter', factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.Sifter = factory(); - } -}(this, function() { - - /** - * Textually searches arrays and hashes of objects - * by property (or multiple properties). Designed - * specifically for autocomplete. - * - * @constructor - * @param {array|object} items - * @param {object} items - */ - var Sifter = function(items, settings) { - this.items = items; - this.settings = settings || {diacritics: true}; - }; - - /** - * Splits a search string into an array of individual - * regexps to be used to match results. - * - * @param {string} query - * @returns {array} - */ - Sifter.prototype.tokenize = function(query) { - query = trim(String(query || '').toLowerCase()); - if (!query || !query.length) return []; - - var i, n, regex, letter; - var tokens = []; - var words = query.split(/ +/); - - for (i = 0, n = words.length; i < n; i++) { - regex = escape_regex(words[i]); - if (this.settings.diacritics) { - for (letter in DIACRITICS) { - if (DIACRITICS.hasOwnProperty(letter)) { - regex = regex.replace(new RegExp(letter, 'g'), DIACRITICS[letter]); - } - } - } - tokens.push({ - string : words[i], - regex : new RegExp(regex, 'i') - }); - } - - return tokens; - }; - - /** - * Iterates over arrays and hashes. - * - * ``` - * this.iterator(this.items, function(item, id) { - * // invoked for each item - * }); - * ``` - * - * @param {array|object} object - */ - Sifter.prototype.iterator = function(object, callback) { - var iterator; - if (is_array(object)) { - iterator = Array.prototype.forEach || function(callback) { - for (var i = 0, n = this.length; i < n; i++) { - callback(this[i], i, this); - } - }; - } else { - iterator = function(callback) { - for (var key in this) { - if (this.hasOwnProperty(key)) { - callback(this[key], key, this); - } - } - }; - } - - iterator.apply(object, [callback]); - }; - - /** - * Returns a function to be used to score individual results. - * - * Good matches will have a higher score than poor matches. - * If an item is not a match, 0 will be returned by the function. - * - * @param {object|string} search - * @param {object} options (optional) - * @returns {function} - */ - Sifter.prototype.getScoreFunction = function(search, options) { - var self, fields, tokens, token_count, nesting; - - self = this; - search = self.prepareSearch(search, options); - tokens = search.tokens; - fields = search.options.fields; - token_count = tokens.length; - nesting = search.options.nesting; - - /** - * Calculates how close of a match the - * given value is against a search token. - * - * @param {mixed} value - * @param {object} token - * @return {number} - */ - var scoreValue = function(value, token) { - var score, pos; - - if (!value) return 0; - value = String(value || ''); - pos = value.search(token.regex); - if (pos === -1) return 0; - score = token.string.length / value.length; - if (pos === 0) score += 0.5; - return score; - }; - - /** - * Calculates the score of an object - * against the search query. - * - * @param {object} token - * @param {object} data - * @return {number} - */ - var scoreObject = (function() { - var field_count = fields.length; - if (!field_count) { - return function() { return 0; }; - } - if (field_count === 1) { - return function(token, data) { - return scoreValue(getattr(data, fields[0], nesting), token); - }; - } - return function(token, data) { - for (var i = 0, sum = 0; i < field_count; i++) { - sum += scoreValue(getattr(data, fields[i], nesting), token); - } - return sum / field_count; - }; - })(); - - if (!token_count) { - return function() { return 0; }; - } - if (token_count === 1) { - return function(data) { - return scoreObject(tokens[0], data); - }; - } - - if (search.options.conjunction === 'and') { - return function(data) { - var score; - for (var i = 0, sum = 0; i < token_count; i++) { - score = scoreObject(tokens[i], data); - if (score <= 0) return 0; - sum += score; - } - return sum / token_count; - }; - } else { - return function(data) { - for (var i = 0, sum = 0; i < token_count; i++) { - sum += scoreObject(tokens[i], data); - } - return sum / token_count; - }; - } - }; - - /** - * Returns a function that can be used to compare two - * results, for sorting purposes. If no sorting should - * be performed, `null` will be returned. - * - * @param {string|object} search - * @param {object} options - * @return function(a,b) - */ - Sifter.prototype.getSortFunction = function(search, options) { - var i, n, self, field, fields, fields_count, multiplier, multipliers, get_field, implicit_score, sort; - - self = this; - search = self.prepareSearch(search, options); - sort = (!search.query && options.sort_empty) || options.sort; - - /** - * Fetches the specified sort field value - * from a search result item. - * - * @param {string} name - * @param {object} result - * @return {mixed} - */ - get_field = function(name, result) { - if (name === '$score') return result.score; - return getattr(self.items[result.id], name, options.nesting); - }; - - // parse options - fields = []; - if (sort) { - for (i = 0, n = sort.length; i < n; i++) { - if (search.query || sort[i].field !== '$score') { - fields.push(sort[i]); - } - } - } - - // the "$score" field is implied to be the primary - // sort field, unless it's manually specified - if (search.query) { - implicit_score = true; - for (i = 0, n = fields.length; i < n; i++) { - if (fields[i].field === '$score') { - implicit_score = false; - break; - } - } - if (implicit_score) { - fields.unshift({field: '$score', direction: 'desc'}); - } - } else { - for (i = 0, n = fields.length; i < n; i++) { - if (fields[i].field === '$score') { - fields.splice(i, 1); - break; - } - } - } - - multipliers = []; - for (i = 0, n = fields.length; i < n; i++) { - multipliers.push(fields[i].direction === 'desc' ? -1 : 1); - } - - // build function - fields_count = fields.length; - if (!fields_count) { - return null; - } else if (fields_count === 1) { - field = fields[0].field; - multiplier = multipliers[0]; - return function(a, b) { - return multiplier * cmp( - get_field(field, a), - get_field(field, b) - ); - }; - } else { - return function(a, b) { - var i, result, a_value, b_value, field; - for (i = 0; i < fields_count; i++) { - field = fields[i].field; - result = multipliers[i] * cmp( - get_field(field, a), - get_field(field, b) - ); - if (result) return result; - } - return 0; - }; - } - }; - - /** - * Parses a search query and returns an object - * with tokens and fields ready to be populated - * with results. - * - * @param {string} query - * @param {object} options - * @returns {object} - */ - Sifter.prototype.prepareSearch = function(query, options) { - if (typeof query === 'object') return query; - - options = extend({}, options); - - var option_fields = options.fields; - var option_sort = options.sort; - var option_sort_empty = options.sort_empty; - - if (option_fields && !is_array(option_fields)) options.fields = [option_fields]; - if (option_sort && !is_array(option_sort)) options.sort = [option_sort]; - if (option_sort_empty && !is_array(option_sort_empty)) options.sort_empty = [option_sort_empty]; - - return { - options : options, - query : String(query || '').toLowerCase(), - tokens : this.tokenize(query), - total : 0, - items : [] - }; - }; - - /** - * Searches through all items and returns a sorted array of matches. - * - * The `options` parameter can contain: - * - * - fields {string|array} - * - sort {array} - * - score {function} - * - filter {bool} - * - limit {integer} - * - * Returns an object containing: - * - * - options {object} - * - query {string} - * - tokens {array} - * - total {int} - * - items {array} - * - * @param {string} query - * @param {object} options - * @returns {object} - */ - Sifter.prototype.search = function(query, options) { - var self = this, value, score, search, calculateScore; - var fn_sort; - var fn_score; - - search = this.prepareSearch(query, options); - options = search.options; - query = search.query; - - // generate result scoring function - fn_score = options.score || self.getScoreFunction(search); - - // perform search and sort - if (query.length) { - self.iterator(self.items, function(item, id) { - score = fn_score(item); - if (options.filter === false || score > 0) { - search.items.push({'score': score, 'id': id}); - } - }); - } else { - self.iterator(self.items, function(item, id) { - search.items.push({'score': 1, 'id': id}); - }); - } - - fn_sort = self.getSortFunction(search, options); - if (fn_sort) search.items.sort(fn_sort); - - // apply limits - search.total = search.items.length; - if (typeof options.limit === 'number') { - search.items = search.items.slice(0, options.limit); - } - - return search; - }; - - // utilities - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - var cmp = function(a, b) { - if (typeof a === 'number' && typeof b === 'number') { - return a > b ? 1 : (a < b ? -1 : 0); - } - a = asciifold(String(a || '')); - b = asciifold(String(b || '')); - if (a > b) return 1; - if (b > a) return -1; - return 0; - }; - - var extend = function(a, b) { - var i, n, k, object; - for (i = 1, n = arguments.length; i < n; i++) { - object = arguments[i]; - if (!object) continue; - for (k in object) { - if (object.hasOwnProperty(k)) { - a[k] = object[k]; - } - } - } - return a; - }; - - /** - * A property getter resolving dot-notation - * @param {Object} obj The root object to fetch property on - * @param {String} name The optionally dotted property name to fetch - * @param {Boolean} nesting Handle nesting or not - * @return {Object} The resolved property value - */ - var getattr = function(obj, name, nesting) { - if (!obj || !name) return; - if (!nesting) return obj[name]; - var names = name.split("."); - while(names.length && (obj = obj[names.shift()])); - return obj; - }; - - var trim = function(str) { - return (str + '').replace(/^\s+|\s+$|/g, ''); - }; - - var escape_regex = function(str) { - return (str + '').replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1'); - }; - - var is_array = Array.isArray || (typeof $ !== 'undefined' && $.isArray) || function(object) { - return Object.prototype.toString.call(object) === '[object Array]'; - }; - - var DIACRITICS = { - 'a': '[aḀḁĂăÂâǍǎȺⱥȦȧẠạÄäÀàÁáĀāÃãÅåąĄÃąĄ]', - 'b': '[b␢βΒB฿𐌁ᛒ]', - 'c': '[cĆćĈĉČčĊċC̄c̄ÇçḈḉȻȼƇƈɕᴄCc]', - 'd': '[dĎďḊḋḐḑḌḍḒḓḎḏĐđD̦d̦ƉɖƊɗƋƌᵭᶁᶑȡᴅDdð]', - 'e': '[eÉéÈèÊêḘḙĚěĔĕẼẽḚḛẺẻĖėËëĒēȨȩĘęᶒɆɇȄȅẾếỀềỄễỂểḜḝḖḗḔḕȆȇẸẹỆệⱸᴇEeɘǝƏƐε]', - 'f': '[fƑƒḞḟ]', - 'g': '[gɢ₲ǤǥĜĝĞğĢģƓɠĠġ]', - 'h': '[hĤĥĦħḨḩẖẖḤḥḢḣɦʰǶƕ]', - 'i': '[iÍíÌìĬĭÎîǏǐÏïḮḯĨĩĮįĪīỈỉȈȉȊȋỊịḬḭƗɨɨ̆ᵻᶖİiIıɪIi]', - 'j': '[jȷĴĵɈɉʝɟʲ]', - 'k': '[kƘƙꝀꝁḰḱǨǩḲḳḴḵκϰ₭]', - 'l': '[lŁłĽľĻļĹĺḶḷḸḹḼḽḺḻĿŀȽƚⱠⱡⱢɫɬᶅɭȴʟLl]', - 'n': '[nŃńǸǹŇňÑñṄṅŅņṆṇṊṋṈṉN̈n̈ƝɲȠƞᵰᶇɳȵɴNnŊŋ]', - 'o': '[oØøÖöÓóÒòÔôǑǒŐőŎŏȮȯỌọƟɵƠơỎỏŌōÕõǪǫȌȍՕօ]', - 'p': '[pṔṕṖṗⱣᵽƤƥᵱ]', - 'q': '[qꝖꝗʠɊɋꝘꝙq̃]', - 'r': '[rŔŕɌɍŘřŖŗṘṙȐȑȒȓṚṛⱤɽ]', - 's': '[sŚśṠṡṢṣꞨꞩŜŝŠšŞşȘșS̈s̈]', - 't': '[tŤťṪṫŢţṬṭƮʈȚțṰṱṮṯƬƭ]', - 'u': '[uŬŭɄʉỤụÜüÚúÙùÛûǓǔŰűŬŭƯưỦủŪūŨũŲųȔȕ∪]', - 'v': '[vṼṽṾṿƲʋꝞꝟⱱʋ]', - 'w': '[wẂẃẀẁŴŵẄẅẆẇẈẉ]', - 'x': '[xẌẍẊẋχ]', - 'y': '[yÝýỲỳŶŷŸÿỸỹẎẏỴỵɎɏƳƴ]', - 'z': '[zŹźẐẑŽžŻżẒẓẔẕƵƶ]' - }; - - var asciifold = (function() { - var i, n, k, chunk; - var foreignletters = ''; - var lookup = {}; - for (k in DIACRITICS) { - if (DIACRITICS.hasOwnProperty(k)) { - chunk = DIACRITICS[k].substring(2, DIACRITICS[k].length - 1); - foreignletters += chunk; - for (i = 0, n = chunk.length; i < n; i++) { - lookup[chunk.charAt(i)] = k; - } - } - } - var regexp = new RegExp('[' + foreignletters + ']', 'g'); - return function(str) { - return str.replace(regexp, function(foreignletter) { - return lookup[foreignletter]; - }).toLowerCase(); - }; - })(); - - - // export - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - return Sifter; -})); - - - -/** - * microplugin.js - * Copyright (c) 2013 Brian Reavis & contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at: - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF - * ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - * - * @author Brian Reavis - */ - -(function(root, factory) { - if (typeof define === 'function' && define.amd) { - define('microplugin', factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.MicroPlugin = factory(); - } -}(this, function() { - var MicroPlugin = {}; - - MicroPlugin.mixin = function(Interface) { - Interface.plugins = {}; - - /** - * Initializes the listed plugins (with options). - * Acceptable formats: - * - * List (without options): - * ['a', 'b', 'c'] - * - * List (with options): - * [{'name': 'a', options: {}}, {'name': 'b', options: {}}] - * - * Hash (with options): - * {'a': { ... }, 'b': { ... }, 'c': { ... }} - * - * @param {mixed} plugins - */ - Interface.prototype.initializePlugins = function(plugins) { - var i, n, key; - var self = this; - var queue = []; - - self.plugins = { - names : [], - settings : {}, - requested : {}, - loaded : {} - }; - - if (utils.isArray(plugins)) { - for (i = 0, n = plugins.length; i < n; i++) { - if (typeof plugins[i] === 'string') { - queue.push(plugins[i]); - } else { - self.plugins.settings[plugins[i].name] = plugins[i].options; - queue.push(plugins[i].name); - } - } - } else if (plugins) { - for (key in plugins) { - if (plugins.hasOwnProperty(key)) { - self.plugins.settings[key] = plugins[key]; - queue.push(key); - } - } - } - - while (queue.length) { - self.require(queue.shift()); - } - }; - - Interface.prototype.loadPlugin = function(name) { - var self = this; - var plugins = self.plugins; - var plugin = Interface.plugins[name]; - - if (!Interface.plugins.hasOwnProperty(name)) { - throw new Error('Unable to find "' + name + '" plugin'); - } - - plugins.requested[name] = true; - plugins.loaded[name] = plugin.fn.apply(self, [self.plugins.settings[name] || {}]); - plugins.names.push(name); - }; - - /** - * Initializes a plugin. - * - * @param {string} name - */ - Interface.prototype.require = function(name) { - var self = this; - var plugins = self.plugins; - - if (!self.plugins.loaded.hasOwnProperty(name)) { - if (plugins.requested[name]) { - throw new Error('Plugin has circular dependency ("' + name + '")'); - } - self.loadPlugin(name); - } - - return plugins.loaded[name]; - }; - - /** - * Registers a plugin. - * - * @param {string} name - * @param {function} fn - */ - Interface.define = function(name, fn) { - Interface.plugins[name] = { - 'name' : name, - 'fn' : fn - }; - }; - }; - - var utils = { - isArray: Array.isArray || function(vArg) { - return Object.prototype.toString.call(vArg) === '[object Array]'; - } - }; - - return MicroPlugin; -})); - -/** - * selectize.js (v0.12.6) - * Copyright (c) 2013–2015 Brian Reavis & contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at: - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF - * ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - * - * @author Brian Reavis - */ - -/*jshint curly:false */ -/*jshint browser:true */ - -(function(root, factory) { - if (typeof define === 'function' && define.amd) { - define('selectize', ['jquery','sifter','microplugin'], factory); - } else if (typeof exports === 'object') { - module.exports = factory(require('jquery'), require('sifter'), require('microplugin')); - } else { - root.Selectize = factory(root.jQuery, root.Sifter, root.MicroPlugin); - } -}(this, function($, Sifter, MicroPlugin) { - 'use strict'; - - var highlight = function($element, pattern) { - if (typeof pattern === 'string' && !pattern.length) return; - var regex = (typeof pattern === 'string') ? new RegExp(pattern, 'i') : pattern; - - var highlight = function(node) { - var skip = 0; - // Wrap matching part of text node with highlighting , e.g. - // Soccer -> Soccer for regex = /soc/i - if (node.nodeType === 3) { - var pos = node.data.search(regex); - if (pos >= 0 && node.data.length > 0) { - var match = node.data.match(regex); - var spannode = document.createElement('span'); - spannode.className = 'highlight'; - var middlebit = node.splitText(pos); - var endbit = middlebit.splitText(match[0].length); - var middleclone = middlebit.cloneNode(true); - spannode.appendChild(middleclone); - middlebit.parentNode.replaceChild(spannode, middlebit); - skip = 1; - } - } - // Recurse element node, looking for child text nodes to highlight, unless element - // is childless, + + + \ No newline at end of file diff --git a/parity/oauth b/parity/oauth new file mode 120000 index 0000000..6f0f860 --- /dev/null +++ b/parity/oauth @@ -0,0 +1 @@ +/home/lionheart/Documents/ermac/oauth \ No newline at end of file diff --git a/parity/old.html b/parity/old.html new file mode 100644 index 0000000..f41ae14 --- /dev/null +++ b/parity/old.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/parity/run_parity.py b/parity/run_parity.py new file mode 100644 index 0000000..75144f4 --- /dev/null +++ b/parity/run_parity.py @@ -0,0 +1,599 @@ +#!/usr/bin/env python3 +""" +Ermac parity test: automated comparative testing of the refactored GUI +against the previously deployed version (https://mpds-io.github.io/ermac), +without any manual inspection. + +How it works: + 1. the OLD reference bundle is fetched from the deployed demo (cached in + parity/reference/); the NEW bundle is rebuilt from the current sources; + 2. both are served side-by-side under parity/old.html and parity/new.html, + on a "localhost" origin, so BOTH run in development mode and all their + API calls go through deploy/dev_api_proxy.py, which LOGS every request; + 3. every scenario (hash route, or a route + a scripted click) is executed + in headless Chrome twice: once for the old bundle, once for the new one. + A determinism stub (parity/harness.js) makes Math.random() identical + on both sides, so random legends/examples/picks cannot create noise; + 4. three comparison layers, old vs new: + - API request logs (the app must talk to the MPDS API identically); + - semantic DOM state (title, tables, interpretation, history, + multiselect items, context columns, links, visibility); + - rendered pixels (screenshots, with a tolerance). + +Usage: + python3 parity/run_parity.py [--only name1,name2] [--no-pixels] + +Artifacts are written to parity/out// (old/new DOM dumps, +screenshots, proxy logs, pixel-diff overlays). Requires google-chrome, +python3, and Pillow for the pixel layer. +""" + +import argparse +import hashlib +import os +import re +import shutil +import subprocess +import sys +import time +import urllib.request + +try: + from PIL import Image, ImageChops + PIL_AVAILABLE = True +except ImportError: + PIL_AVAILABLE = False + +HERE = os.path.dirname(os.path.abspath(__file__)) +ROOT = os.path.dirname(HERE) +GUI_PORT = 5560 +API_PORT = 7070 +CHROME = 'google-chrome' +VIEW_W, VIEW_H = 1280, 2400 +OLD_URL = 'https://mpds-io.github.io/ermac/ermac.min.js' +TOL = 2 # per-channel pixel tolerance +PIXEL_FAIL = 0.001 # strict scenarios fail above this fraction of differing pixels + +# (name, route hash, act, budget ms, pixel strict) +SCENARIOS = [ + ('start', '#start', None, 30000, True), + ('search', '#search/Ag-O', None, 30000, True), + ('inquiry_oxide', '#inquiry/elements=Ag-O&classes=oxide', None, 30000, True), + ('inquiry_tabled', '#inquiry/formulae=Ag2O&props=crystal%20structure', None, 30000, True), + ('phases', '#inquiry_phases/elements=Ag-O&classes=oxide', None, 30000, True), + ('articles', '#inquiry_articles/elements=Ag-O&classes=oxide', None, 30000, True), + ('numeric', '#inquiry/numeric=volume%2C%3E%2C3000%3B', None, 30000, True), + ('entry', '#entry/S1410618', None, 40000, False), + ('phase_id', '#phase_id/{phid}', None, 30000, True), + ('article', '#article/{bid}', None, 30000, True), + ('interlinkage', '#interlinkage/{phid}', None, 30000, True), + ('hierarchy', '#hierarchy', None, 30000, True), + ('polyhedra', '#polyhedra', None, 30000, True), + ('modal_login', '#modal/login', None, 30000, True), + ('plot_pie', '#plot/pie/inquiry/elements=Ag-O', None, 40000, False), + ('click_advsearch','#search/Ag-O', 'advsearch', 40000, True), + ('click_entry_ctx','#inquiry/formulae=Ag2O&props=crystal%20structure', 'open_entry_ctx', 40000, True), + ('click_sort', '#inquiry/formulae=Ag2O&props=crystal%20structure', 'sort_col1', 40000, True), + ('click_sort_desc','#inquiry/formulae=Ag2O&props=crystal%20structure', 'sort_col1_twice', 40000, True), + ('click_refine', '#search/Ag-O', 'refine_expand', 40000, True), +] + + +def banner(text): + print('\n' + '=' * 72 + '\n ' + text + '\n' + '=' * 72) + + +def die(message): + sys.exit('FATAL: ' + message) + + +# ---------------------------------------------------------------------------- +# setup +# ---------------------------------------------------------------------------- + +def setup(): + os.makedirs(os.path.join(HERE, 'reference'), exist_ok=True) + os.makedirs(os.path.join(HERE, 'out'), exist_ok=True) + + # NB refuse to run over leftover processes: they corrupt the captures + for label, port in (('static server', GUI_PORT), ('API proxy', API_PORT)): + if not port_free(port): + die('port %d is busy (%s): stop the leftover process first, e.g. ' + 'ps aux | grep -E "http.server %d|dev_api_proxy"' % (port, label, port)) + + # NB leftover headless chrome processes holding our profile dirs would + # poison the run; detect and refuse rather than capture garbage + stale = subprocess.run(['ps', '-eo', 'pid,args'], capture_output=True, text=True).stdout + stale_chrome = [line for line in stale.splitlines() + if 'headless' in line and 'parity/out/profile' in line] + if stale_chrome: + for line in stale_chrome: + print('stale headless chrome:', line.strip()[:120]) + die('stale headless chrome processes are holding the parity profiles; ' + 'kill them first (see the PIDs above)') + + # 1. the NEW bundle must be fresh + print('building the new bundle...') + subprocess.check_call([sys.executable, os.path.join(ROOT, 'deploy', 'build_js.py')]) + + # 2. the OLD reference bundle, fetched from the deployed demo + reference = os.path.join(HERE, 'reference', 'ermac_old.min.js') + if not os.path.exists(reference): + print('fetching the OLD reference bundle from', OLD_URL, '...') + with urllib.request.urlopen(OLD_URL, timeout=60) as response: + data = response.read() + with open(reference, 'wb') as f: + f.write(data) + with open(reference, 'rb') as f: + print('reference bundle: %d bytes, sha1 %s' % ( + os.path.getsize(reference), hashlib.sha1(f.read()).hexdigest()[:12])) + + # 3. shared assets under parity/ (app_folder is /parity for these pages) + links = { + 'webassets': os.path.join(ROOT, 'webassets'), + 'labs': os.path.join(ROOT, 'labs'), + 'oauth': os.path.join(ROOT, 'oauth'), + 'ermac.min.js': os.path.join(ROOT, 'ermac.min.js') + } + for name, target in links.items(): + link = os.path.join(HERE, name) + if os.path.islink(link) and os.readlink(link) != target: + os.remove(link) + if not os.path.exists(link): + os.symlink(target, link) + print('symlinked', name, '->', os.path.relpath(target, HERE)) + + +def port_free(port): + import socket + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + try: + s.bind(('127.0.0.1', port)) + return True + except OSError: + return False + + +# ---------------------------------------------------------------------------- +# server / proxy / chrome plumbing +# ---------------------------------------------------------------------------- + +class StaticServer(object): + def __init__(self): + self.process = None + + def start(self): + if not port_free(GUI_PORT): + die('port %d is busy: stop whatever serves it first' % GUI_PORT) + self.process = subprocess.Popen( + [sys.executable, '-m', 'http.server', str(GUI_PORT)], + cwd=ROOT, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + wait_for_port(GUI_PORT, 5) + print('static server: http://localhost:%d' % GUI_PORT) + + def stop(self): + if self.process: + self.process.terminate() + self.process.wait() + + +class ApiProxy(object): + def __init__(self, log_path, cache_dir=None): + self.log_path = log_path + self.cache_dir = cache_dir + self.process = None + + def start(self): + if not port_free(API_PORT): + die('port %d is busy: stop deploy/dev_api_proxy.py first' % API_PORT) + self.log = open(self.log_path, 'w') + cmd = [sys.executable, '-u', os.path.join(ROOT, 'deploy', 'dev_api_proxy.py')] + if self.cache_dir: + cmd += ['--cache', self.cache_dir] + self.process = subprocess.Popen(cmd, stdout=self.log, stderr=subprocess.STDOUT) + wait_for_port(API_PORT, 5) + + def stop(self): + if self.process: + self.process.terminate() + self.process.wait() + if hasattr(self, 'log') and self.log: + self.log.close() + + +def wait_for_port(port, timeout): + import socket + deadline = time.time() + timeout + while time.time() < deadline: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.settimeout(0.2) + try: + s.connect(('127.0.0.1', port)) + return + except OSError: + time.sleep(0.05) + die('port %d did not open in time' % port) + + +def run_chrome(url, dom_path, shot_path, user_data_dir, budget, attempts=3): + cmd = [ + CHROME, '--headless=new', '--disable-gpu', '--no-sandbox', + '--hide-scrollbars', '--window-size=%d,%d' % (VIEW_W, VIEW_H), + '--force-device-scale-factor=1', '--default-background-color=FFFFFFFF', + # NB external static assets (thumbnails, ptable SVGs) are blocked so + # that rendering is deterministic: they fail identically on both sides + '--host-resolver-rules=MAP mpds.io 127.0.0.1, MAP *.mpds.io 127.0.0.1', + # NB the HTTP cache must be off, otherwise wmdata is not re-requested + '--disk-cache-size=1', '--media-cache-size=1', + '--user-data-dir=' + user_data_dir, + '--virtual-time-budget=%d' % budget, + '--screenshot=' + shot_path, + '--dump-dom', url + ] + last_error = None + for attempt in range(attempts): + # NB a leftover chrome process may still hold the profile directory: + # retry the removal instead of silently continuing with a dirty profile + for _ in range(4): + if not os.path.exists(user_data_dir): + break + shutil.rmtree(user_data_dir, ignore_errors=True) + time.sleep(0.5) + if os.path.exists(user_data_dir): + last_error = IOError('cannot clean the profile dir ' + user_data_dir) + break + try: + result = subprocess.run(cmd, capture_output=True, timeout=300) + with open(dom_path, 'wb') as f: + f.write(result.stdout) + if os.path.exists(shot_path) and len(result.stdout) > 10000: + return # a plausible DOM dump and a screenshot + last_error = IOError('incomplete capture (dom %d bytes, shot %s)' % ( + len(result.stdout), os.path.exists(shot_path))) + except subprocess.TimeoutExpired as error: + last_error = error + print(' (chrome attempt %d failed (%s), retrying)' % (attempt + 1, last_error)) + die('chrome failed for %s: %s' % (url, last_error)) + + +# ---------------------------------------------------------------------------- +# comparison layers +# ---------------------------------------------------------------------------- + +def normalize_requests(log_path): + """Parse the proxy log into a comparable list of API requests.""" + requests = [] + with open(log_path) as f: + for line in f: + if not line.startswith('proxy: '): + continue + match = re.search(r'"(GET|POST|HEAD) (\S+)', line) + if not match: + continue + method, target = match.group(1), match.group(2) + target = re.sub(r' HTTP/\d\.\d$', '', target) + path, _, query = target.partition('?') + # NB the anonymous IP-based login is a best-effort fire-and-forget + # request which races with the page teardown in headless capture, + # and is already covered by the DOM comparison (the logged-in UI) + if path == '/users/ip': + continue + pairs = sorted(query.split('&')) if query else [] + requests.append(method + ' ' + path + '?' + '&'.join(pairs)) + return requests + + +def region(html, open_pattern, close_pattern=''): + match = re.search(open_pattern + r'(.*?)' + close_pattern, html, re.S) + return collapse(match.group(1)) if match else None + + +def collapse(text): + return re.sub(r'\s+', ' ', text).strip() + + +def extract_semantics(html): + """Extract the behaviorally meaningful DOM state from a dump.""" + html = html.replace('old.html', 'app.html').replace('new.html', 'app.html') + keys = {} + + def set_key(name, value): + if value is not None: + keys[name] = value + + match = re.search(r'(.*?)', html, re.S) + set_key('title', match.group(1) if match else '') + + set_key('body_class', re.search(r']*>', r'')) + notify_style = re.search(r'
    ')) + + browser = re.search(r']*>', '
    '))) + + set_key('multiselect_items', ' | '.join( + a + ':' + b for a, b in re.findall(r'data-facet="([^"]*)" data-term="([^"]*)"', html))) + set_key('search_input_rest', re.search(r'id="search_field-selectized"[^>]*value="([^"]*)"', html).group(1) + if re.search(r'id="search_field-selectized"[^>]*value="([^"]*)"', html) else '') + + set_key('refine_links', ' '.join(collapse(a) for a in re.findall(r'
  • ', html))) + # NB random-content elements are compared by SHAPE, not content: + # the old bundle's jQuery/Sizzle internals consume extra random values, + # so the exact example/legend strings legitimately differ per side + examples = re.findall(r'', + region(html, r'
    ') or '') + set_key('examples_shape', '%d links, all valid: %s' % ( + len(examples), + all(link.startswith('#search/') for link in examples))) + set_key('history_links', ' '.join(re.findall( + r'', region(html, r'
    ') or ''))) + + for element in ['entryno', 'ind_title', 'phase_info', 'sim_legend', 'own_phase', 'ind_link']: + set_key(element, outer_of(html, element)) + + set_key('d_icon_hrefs', ' '.join(re.findall(r']* src="([^"]*)"', html))) + + # NB class attribute is optional: the old jQuery left class="" behind, + # the new code omits the attribute entirely - both mean "no class" + set_key('active_controls', ' '.join(sorted( + m[0] + '=' + (m[1] or '') + for m in re.findall(r'
    ]*style="([^"]*)"'), + ('advsbox', r'
    ]*style="([^"]*)"'), + ('loginbox', r'
    ]*style="([^"]*)"'), + ('overlay', r'
    ', r'
    \s*
  • ', html))) - # NB random-content elements are compared by SHAPE, not content: - # the old bundle's jQuery/Sizzle internals consume extra random values, - # so the exact example/legend strings legitimately differ per side - examples = re.findall(r'', - region(html, r'
    ') or '') + match = re.search(r'id="search_field-selectized"[^>]*value="([^"]*)"', html) + set_key('search_input_rest', match.group(1) if match else '') + set_key('refine_links', ' '.join(collapse(a) for a in re.findall( + r'
  • ', html))) + examples = re.findall(r'', region(html, r'
    ') or '') set_key('examples_shape', '%d links, all valid: %s' % ( - len(examples), - all(link.startswith('#search/') for link in examples))) - set_key('history_links', ' '.join(re.findall( - r'', region(html, r'
    ') or ''))) - + len(examples), all(link.startswith('#search/') for link in examples))) + set_key('history_links', ' '.join(re.findall(r'', region(html, r'
    ') or ''))) for element in ['entryno', 'ind_title', 'phase_info', 'sim_legend', 'own_phase', 'ind_link']: set_key(element, outer_of(html, element)) - set_key('d_icon_hrefs', ' '.join(re.findall(r']* src="([^"]*)"', html))) - - # NB class attribute is optional: the old jQuery left class="" behind, - # the new code omits the attribute entirely - both mean "no class" set_key('active_controls', ' '.join(sorted( - m[0] + '=' + (m[1] or '') - for m in re.findall(r'
    ', r'
    \s*