diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..a2da00f
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,6 @@
+* -text
+*.woff binary
+*.woff2 binary
+*.ttf binary
+*.eot binary
+*.otf binary
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dc18eaa
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+-*
+node_modules
+.idea
+.DS_Store
diff --git a/CNAME b/CNAME
deleted file mode 100644
index 9130fc8..0000000
--- a/CNAME
+++ /dev/null
@@ -1 +0,0 @@
-absolute-zero.optimade.science
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..51e9826
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 reatailret
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README b/README
deleted file mode 100644
index 6e59993..0000000
--- a/README
+++ /dev/null
@@ -1 +0,0 @@
-Absolute Zero is the ultimate form of freezing and the point of cold at which the entropy hit its minimum level. Absolute Zero is also a secret character from a Mortal Kombat universe, related to Sub Zero. Finally, Absolute Zero is the mobile client for the MPDS materials science online database, to be rewritten in the $mol framework, as a part of the new HYOO contest.
diff --git a/absolute-zero.jpg b/absolute-zero.jpg
deleted file mode 100644
index 8c00150..0000000
Binary files a/absolute-zero.jpg and /dev/null differ
diff --git a/index.html b/index.html
deleted file mode 100644
index 3a549d0..0000000
--- a/index.html
+++ /dev/null
@@ -1,505 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-−273.15°C
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Email:
-
-
Password:
-
-
Login
-
-
-
-
-
Email:
-
-
Send link
-
-
-
-
-
-
-
-
-
-
Input
-
-
-
Data summary
-
-
-
Results
-
-
-
New search
-
-
-
-
-
-
-
-
diff --git a/jquery.min.js b/jquery.min.js
deleted file mode 100644
index 7f37b5d..0000000
--- a/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' + link_text + ' ';
- });
- $('a.extd_refine[rel=' + facet + ']').parent().hide().after(z(html));
-
- }).fail(function(xhr, textStatus, errorThrown){
- if (textStatus != 'abort') wmgui.notify('Connection to server is lost, please try to reload');
- });
- return false;
- });
-
- $('#navicon').click(function(){
- if ($(this).hasClass('opened')){
- $(this).removeClass('opened');
- $('#hamburger').addClass('closed');
- $('#overlay, #menu_content').hide();
- } else {
- $(this).addClass('opened');
- $('#hamburger').removeClass('closed');
- $('#overlay, #menu_content').show();
- }
- });
-
- $('#menu_content > ul > li > a').click(function(){
- $('#navicon').removeClass('opened');
- $('#hamburger').addClass('closed');
- $('#overlay, #menu_content').hide();
- return true;
- });
-
- $('#login_trigger').click(function(){
- if ($(this).data('busy')) return;
- $(this).data('busy', true);
- $.ajax({type: 'POST', url: wmgui.login_endpoint, data: {login: $('#login_email').val().trim(), pass: $('#login_password').val()}, beforeSend: show_preloader}).always(function(){
- $('#login_trigger').data('busy', false);
- 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);
- window.location.hash = '#start';
- $('#navicon').trigger('click');
- $('#loginbox, #restorebox').hide();
-
- }).fail(function(xhr, textStatus, errorThrown){
- wmgui.notify("Login unsuccessful");
- });
- });
-
- $('#restore_trigger').click(function(){
- if ($(this).data('busy')) return;
- $(this).data('busy', true);
- $.ajax({type: 'POST', url: wmgui.restore_endpoint, data: {login: $('#restore_by_email').val().trim()}, beforeSend: show_preloader}).always(function(){
- $('#restore_trigger').data('busy', false);
- hide_preloader();
-
- }).done(function(data){
- if (data.error) return wmgui.notify(data.error);
- wmgui.notify('Please, check your inbox (and spam)');
- $('#navicon').trigger('click');
- $('#loginbox, #restorebox').hide();
-
- }).fail(function(xhr, textStatus, errorThrown){
- if (textStatus != 'abort') wmgui.notify('A network error occured. Please, try again');
- });
- });
-
- $('div.cross').click(function(){
- window.location.hash = '#start';
- });
-
- $('#logout_item').click(function(){
- $.ajax({type: 'POST', url: wmgui.logout_endpoint, data: {sid: wmgui.sid}}).done(function(data){}).fail(function(xhr, textStatus, errorThrown){});
- user_logout();
- });
-
- $(document).keydown(function(e){
- var key = window.event ? e.keyCode : e.which;
- if (key == 13) $('#search_trigger').trigger('click');
- });
-
- $(window).bind('hashchange', url_redraw_react);
-}
diff --git a/mgui.js b/mgui.js
deleted file mode 100644
index e95a7a9..0000000
--- a/mgui.js
+++ /dev/null
@@ -1,327 +0,0 @@
-/**
- * Mobile GUI for the chemistry DB
- * Version: 0.5.5ce
- */
-"use strict";
-
-wmgui.notify = function(msg){
- console.log(msg);
- alert(msg);
- close_vibox();
-}
-
-function switch_viewmode(mode){
-
- wmgui.viewmode = mode;
-
- if (mode == 2){
- $('#branding').hide();
- $('#content').show();
- window.scrollTo(0, 0);
-
- $('#summary, #results, #summary_caption, #results_caption').hide();
-
- } else {
- $('#content').hide();
- $('#branding').show();
- $('#search_field-selectized').focus();
- }
-}
-
-function request_analysis(query_obj){
- var given_search = {};
- $.extend(given_search, query_obj);
- try { wmgui.active_ajax.abort() } catch(e){}
- wmgui.active_ajax = $.ajax({type: 'GET', url: wmgui.rfn_endpoint, data: {q: JSON.stringify(given_search)}, beforeSend: show_preloader}).always(hide_preloader).done(function(data){
- if (data.error) return wmgui.notify(data.error);
-
- var was_facet = null,
- refine_html = '',
- classes_chk = [],
- max_count = 0;
-
- if (query_obj.classes){ // no whitespace in multiple classes
- classes_chk = given_search.classes.split(',').map(function(i){ return i.trim() });
- given_search.classes = classes_chk.join(',');
- }
-
- $.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_text = found_obj.value,
- nested_skip = false,
- orepr = {};
-
- if (found_obj.count > max_count) max_count = found_obj.count;
-
- $.each(given_search, function(key, val){ // compile individual search link
- if (found_obj.facet == 'elements' && (key == 'elements' || key == 'formulae')) return true;
- else if (found_obj.facet == 'props' && key == 'props') return true;
- else if (orepr[key] && key == 'classes') val += ', ' + orepr[key];
- orepr[key] = val;
- });
-
- 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) 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!
- }
-
- // FIXME!!! lost classes in refinement: see #inquiry/classes=alkaline&years=2010-2018
- orepr[found_obj.facet] = found_obj.value;
- if (orepr['elements']) orepr['elements'] = orepr['elements'].replaceAll(', ', '-');
-
- refine_html += '' + link_text + ' ';
- });
-
- if (refine_html.length){
- refine_html += 'Show more ';
- if (max_count > 50){
- $('#summary > ul').empty().append(z(refine_html)).parent().show();
- $('#summary_caption').show();
- }
- }
-
- request_data(query_obj);
-
- }).fail(function(xhr, textStatus, errorThrown){
- if (textStatus != 'abort') wmgui.notify('Connection to server is lost, please try to reload');
- });
-}
-
-function request_data(query_obj){
- wmgui.active_ajax = $.ajax({type: 'GET', url: wmgui.srch_endpoint, data: {q: JSON.stringify(query_obj)}, beforeSend: show_preloader}).always(hide_preloader).done(function(data){
- if (data.error)
- return wmgui.notify(data.error);
- if (!data.out.length)
- return wmgui.notify('Nothing found!');
- if (data.notice)
- wmgui.notify(data.notice);
- if (data.fuzzy_notice)
- wmgui.notify(data.fuzzy_notice);
-
- var cls_map = {7: ' ml_data', 8: ' ab_data', 9: ' ab_data', 10: ' ab_data'}, // NB space
- result_cells = '';
-
- data.out.sort(function(a, b){
- var x = a[2].toLowerCase(),
- y = b[2].toLowerCase();
- return x < y ? -1 : x > y ? 1 : 0;
- });
-
- $.each(data.out, function(k, row){
- row[7] = parseInt(row[7]);
- var dtype = row[0].substr(0, 1),
- content,
- dlinks = 'Log in to access ',
- biblio_html = (row[7] == 999999) ? '' :
- ' [' + row[5] + '’' + row[6].toString().substr(2, 2) + ']'; // special *ref_id*, only handled in GUI
-
- if (wmgui.sid && biblio_html) dlinks = 'Ref. PDF ';
-
- if (dtype == 'P'){
- content = '' + row[2] + '
';
-
- } else if (dtype == 'C'){
- content = ' '; // NB handled remotely
- if (wmgui.sid) dlinks = 'PNG ';
-
- } else {
- content = ' '; // NB handled remotely
- dlinks = 'PNG anim ';
- }
-
- result_cells += ' ' + content + '
' + row[1] + biblio_html + '
' + dlinks + '
';
- });
-
- if (result_cells.length){
- $('#results').empty().append(result_cells).show();
- $('#results_caption').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){
- $('#iframe').remove();
- $('#overlay').hide();
- $('#hamburger').show();
- return true;
- }
- return false;
-}
-
-function rotate_example(){
- var example = WMCORE.generate_example();
- $('#legend').html('e.g. ' + example['text'].replace(/\d/g, "Ȉ$&;") + ' ');
-}
-
-function rotate_motto(){
- $('#motto > span').animate({ opacity: 'hide' }, 2500, function(){
- $('#motto > span').html(wmgui.mob_motto[ Math.floor(Math.random() * wmgui.mob_motto.length) ]).animate({ opacity: 'show' }, 1500, function(){
- setTimeout(rotate_motto, 2500);
- });
- });
-}
-
-function user_login(sid, name, acclogin, admin){
- $('#user_status > span').text(name);
- $('#login_item').hide();
- $('#logout_item').show();
- wmgui.sid = sid;
- window.localStorage.setItem('wm', JSON.stringify({sid: sid, name: name, acclogin: acclogin, admin: admin}));
-}
-
-function user_logout(){
- $('#user_status > span').text('Hi, guest');
- $('#logout_item').hide();
- $('#login_item').show();
- wmgui.sid = null;
- window.localStorage.removeItem('wm');
-}
-
-function satisfy_requirements(){
-
- var locals = JSON.parse(window.localStorage.getItem('wm') || '{}');
- if (locals.sid && locals.name && locals.acclogin){
- user_login(locals.sid, locals.name, locals.acclogin, locals.admin);
- }
-
- WMCORE = WMCORE();
-
- rotate_example();
- setInterval(rotate_example, 2250);
- $('#motto > span').html(wmgui.mob_motto[ Math.floor(Math.random() * wmgui.mob_motto.length) ]);
- setTimeout(rotate_motto, 2500);
-
- var control = $('#search_field').selectize({
- plugins: ['remove_button', 'preserve_on_blur'],
- dropdownParent: '#suggestions',
- valueField: 'id',
- labelField: 'label',
- searchField: 'label',
- create: false,
- maxItems: 5,
- closeAfterSelect: true,
- diacritics: false,
- options: [],
- onInitialize: function(){
- $('#searchbox > div.selectize-control').append('⇒ ');
- $('#search_field-selectized').focus();
- },
- load: function(query, callback){
- this.clearOptions();
- $('#selectize_msg').hide();
- if (!query.length) return callback();
- $.ajax({
- url: wmgui.api_host + '/search/selectize?q=' + encodeURIComponent(query),
- type: 'GET',
- error: callback,
- success: function(res){
- //console.log(res.length);
- $('#suggestions').show();
- if (!res.length){
- $('#selectize_msg').show();
- $('#search_trigger').hide();
- return;
- }
- callback(res);
- }
- });
- },
- score: function(){ return function(){ return 1 } }, // no client scoring
- onFocus: function(){
- if ($.isEmptyObject(this.renderCache)) return;
- $('#suggestions').show();
- },
- onBlur: function(){
- $('#suggestions').hide();
- },
- render: {
- option: function(item, escape){
- return '' + item.label + '
';
- },
- item: function(item, escape){
- return '' + item.label + '
';
- }
- },
- onItemAdd: function(value, item){
- $('#search_trigger').show();
- },
- onItemRemove: function(value){
- if ($.isEmptyObject(wmgui.selectize.read())) $('#search_trigger').hide();
- }
- });
- wmgui.selectize = control[0].selectize;
-
- wmgui.selectize.read = function(){
- var result = {};
- $('div.selectize-input.items').children().each(function(){
- if (this.tagName == 'DIV'){
- var facet = this.getAttribute('data-facet');
-
- if (result[facet] && facet == 'elements')
- result[facet] += '-' + this.getAttribute('data-term');
- else if (result[facet] && (facet == 'classes' || facet == 'aetypes'))
- 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;
- }
-
- wmgui.selectize.write = function(search_obj){
- var given_search = {};
- $.extend(given_search, search_obj);
-
- ['formulae', 'props', 'elements', 'classes', 'lattices', 'aetypes'].forEach(function(facet){
- if (!given_search[facet])
- return;
-
- else if (facet == 'elements' && given_search[facet].indexOf('-') > 0){
- given_search[facet].split('-').forEach(function(part){
- wmgui.selectize.display(facet, part);
- });
- } else if ((facet == 'classes' || facet == 'aetypes') && given_search[facet].indexOf(',') > 0){
- given_search[facet].split(',').forEach(function(part){
- wmgui.selectize.display(facet, part);
- });
- } else if (facet == 'formulae'){
- given_search[facet] = WMCORE.to_formula(given_search[facet]);
- wmgui.selectize.display(facet, given_search[facet]);
-
- } else wmgui.selectize.display(facet, given_search[facet]);
- });
- wmgui.selectize.clearOptions();
- }
-
- wmgui.selectize.display = function(facet, term){
- var random_id = Math.floor((Math.random() * 1000));
- wmgui.selectize.addOption({facet: facet, label: term, id: random_id});
- wmgui.selectize.addItem(random_id);
- }
-
- window.location.hash ? url_redraw_react() : window.location.replace('#start');
-}
-
-// now, fire in the holl!
-
-satisfy_requirements();
-
-register_events();
diff --git a/mrouter.js b/mrouter.js
deleted file mode 100644
index d38eeef..0000000
--- a/mrouter.js
+++ /dev/null
@@ -1,115 +0,0 @@
-/**
- * Mobile GUI for the chemistry DB
- * Version: 0.5.5ce
- */
-"use strict";
-
-function url_redraw_react(){
- var anchors = window.location.hash.substr(1).split('/');
-
- if (!anchors.length) return;
- $('#loginbox, #restorebox').hide();
- try { wmgui.active_ajax.abort() } catch(e){}
-
- if (window['url__' + anchors[0]]) window['url__' + anchors[0]](anchors.slice(1).join('/'));
- else window.location.hash = '#start';
-}
-
-function url__start(arg){
- switch_viewmode(1);
-}
-
-function url__search(arg){
- window.location.replace('#start');
-}
-
-function url__phase_id(arg){
- switch_viewmode(2);
- var phid = parseInt(arg);
- $('#input > ul').empty().append('Distinct phase #' + phid + ' ');
- request_data({'phid': phid});
-}
-
-function url__inquiry(arg){
- 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] = unescape(inquiry[item].replaceAll('\\+', ' '));
- });
-
- wmgui.search = inquiry;
-
- switch_viewmode(2);
-
- $('#input > ul').empty().append(
- z(WMCORE.get_interpretation(inquiry, wmgui.facet_names))
- );
-
- $('#search_field-selectized').val('');
- wmgui.selectize.clear();
- wmgui.selectize.write(inquiry);
-
- request_analysis(inquiry);
-}
-
-function url__modal(arg){
- if (arg == "login"){
- if (wmgui.sid){
- $('#navicon').trigger('click');
-
- } else {
- if ($("#restore_by_email").val()) $("#login_email").val($("#restore_by_email").val());
- else $("#login_email").val('');
- $("#login_password").val('');
- $('#restorebox').hide();
- $('#loginbox').show();
- }
-
- // for OAuth linking redirect only
- var u_email = window.localStorage.getItem('wm_u_email') || false;
- if (u_email){
- $("#login_email").val(u_email);
- window.localStorage.removeItem('wm_u_email');
- }
-
- } else if (arg == "restore"){
- if (wmgui.sid){
- $('#navicon').trigger('click');
-
- } else {
- if ($("#login_email").val()) $("#restore_by_email").val($("#login_email").val());
- else $("#restore_by_email").val('');
- $('#loginbox').hide();
- $('#restorebox').show();
- }
- }
-}
-
-function url__access(arg){
- $.ajax({type: 'POST', url: wmgui.access_endpoint, data: {a: arg}}).done(function(data){
- window.location.replace('#start');
- 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);
- $('#navicon').trigger('click');
- $('#loginbox, #restorebox').hide();
-
- }).fail(function(xhr, textStatus, errorThrown){
- return wmgui.notify('A network error occured. Please, try again');
- });
-}
-
-function url__entry(arg){
- switch_viewmode(2);
- $('#input > ul').empty().append('Entry ' + arg + ' ');
- request_data({'entry': arg});
-}
-
-function url__junction(arg){
- wmgui.notify('Please retry to log in');
- window.location.replace('#start');
-}
diff --git a/optimade/zero/api.ts b/optimade/zero/api.ts
new file mode 100644
index 0000000..fabaa5d
--- /dev/null
+++ b/optimade/zero/api.ts
@@ -0,0 +1,284 @@
+namespace $
+{
+
+
+
+ export class $optimade_zero_api extends $mol_object2
+ {
+
+
+ query_params = {
+
+ 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'
+ } as Record
+ @$mol_mem
+ NLP()
+ {
+ //@ts-ignore
+ const cl = require( 'optimade-mpds-nlp' ) as typeof import( 'optimade-mpds-nlp' )
+ return new cl()
+ }
+ @$mol_mem_key
+ string_to_facets( search: string )
+ {
+
+ return this.NLP().guess( search )
+ }
+ @$mol_mem_key
+ facet_array_to_dict( val: $optimade_zero_api_Facet[] )
+ {
+
+ const result = {} as Record
+ const result2 = {} as Record
+ for( const facet of val )
+ {
+ if( !result[ facet.facet ] ) result[ facet.facet ] = []
+ result[ facet.facet ].push( facet.label )
+ }
+ for( const key in result )
+ {
+ if( result[ key! ] && result[ key! ].length )
+ {
+ result2[ key ] = result[ key! ].join( ',' )
+ }
+ }
+ return result2
+ }
+ @$mol_mem_key
+ facet_dict_to_array( val: Record )
+ {
+ const res = [] as $optimade_zero_api_Facet[]
+
+ Object.keys( val ).map( ( el ) =>
+ {
+ if( val[ el ] )
+ {
+ const ar = val[ el ].split( ',' )
+ for( const element of ar )
+ {
+ res.push( { facet: el, label: element.trim() } )
+ }
+
+ }
+ } )
+ return res
+ }
+
+
+ uri_to_facets()
+ {
+ const res = [] as $optimade_zero_api_Facet[]
+ const dict =$mol_state_arg.dict()
+
+ Object.keys( this.query_params ).map( ( el ) =>
+ {
+ if( dict[ el ] )
+ {
+ const ar = dict[ el ].split( ',' )
+ for( const element of ar )
+ {
+ res.push( { facet: el, label: element.replaceAll( '-', ', ' ), id: '' } )
+ }
+
+ }
+ } )
+ return res
+ }
+ @$mol_action
+ selectize( search?: string ): $optimade_zero_api_Facet[]
+ {
+
+ if( search )
+ {
+ return $mol_fetch.json( this.selectize_endpoint() + '?' + new URLSearchParams( {
+ q: search
+ } ).toString() ) as unknown as $optimade_zero_api_Facet[]
+ }
+ return []
+
+ }
+
+ facet_dict_to_query(dict:object){
+ return new URLSearchParams( { q: JSON.stringify( dict ) } ).toString()
+ }
+ @$mol_action
+ refinement( search?: Record | null ): $optimade_zero_api_FacetSuggestResponse
+ {
+
+ if( search && Object.keys( search ).length )
+ {
+ return $mol_fetch.json( this.rfn_endpoint() + '?' + this.facet_dict_to_query(search)) as unknown as $optimade_zero_api_FacetSuggestResponse
+ }
+ return {
+ error: '',
+ payload: [],
+ total_count: 0,
+ use_visavis_type: ''
+ }
+
+ }
+
+ @$mol_action
+ results( search?: Record | null ): $optimade_zero_api_SearchResponse
+ {
+
+ if( search && Object.keys( search ).length )
+ {
+ const response = $mol_fetch.json( this.srch_endpoint() + '?' + this.facet_dict_to_query(search) ) as unknown as $optimade_zero_api_SearchResponse
+ if( response.out )
+ {
+ response.out = this.transform_results( response.out )
+ }
+ return response
+ }
+ return {
+ error: '',
+ fuzzy_notice: '',
+ out: [],
+ estimated_count: 0
+ }
+
+ }
+ transform_results( results: $optimade_zero_api_SearchResponse[ 'out' ] )
+ {
+ let out = results.sort( ( a, b ) =>
+ {
+ var x = a[ 2 ].toLowerCase(),
+ y = b[ 2 ].toLowerCase()
+ return x < y ? -1 : x > y ? 1 : 0
+ } )
+ return out
+
+ }
+ @$mol_mem
+ user_sid(next?: string):string
+ {
+ if(next !== undefined) {
+ $mol_state_session.value('sid', next)
+ }
+ return $mol_state_session.value('sid')??''
+ }
+ @$mol_action
+ login( login: string, pass: string )
+ {
+
+
+ const resp = $mol_fetch.text( this.login_endpoint(), {
+ method: 'POST',
+ body: new URLSearchParams( { login, pass } )
+
+ } ) as string
+ const data = JSON.parse(resp)
+ if(data.sid) {
+ this.user_sid(data.sid)
+ }
+ return resp
+
+
+ }
+
+ @$mol_action
+ logout() {
+ this.user_sid('')
+ }
+
+ cdn_host()
+ {
+ return 'https://mpds.io'
+ }
+ api_host()
+ {
+ return 'https://api.mpds.io/v0'
+ }
+
+ login_endpoint()
+ {
+ return this.api_host() + '/users/login'
+ }
+ logout_endpoint()
+ {
+ return this.api_host() + '/users/logout'
+ }
+ restore_endpoint()
+ {
+ return this.api_host() + '/users/lost_password'
+ }
+ access_endpoint()
+ {
+ return this.api_host() + '/users/access'
+ }
+ srch_endpoint()
+ {
+ return this.api_host() + '/search/facet'
+ }
+ selectize_endpoint()
+ {
+ return this.api_host() + '/search/selectize'
+ }
+ rfn_endpoint()
+ {
+ return this.api_host() + '/search/refinement'
+ }
+ phph_endpoint()
+ {
+ return this.api_host() + '/search/phase_phid'
+ }
+ refs_endpoint()
+ {
+ return this.api_host() + '/download/bib'
+ }
+ dd_addr_tpl()
+ {
+ return this.api_host() + '/download'
+ }
+
+
+ }
+
+ export type $optimade_zero_api_Facet = {
+ facet: string
+ label: string
+ id?: string
+ }
+
+ export type $optimade_zero_api_FacetSuggestResponse = {
+ error: null | string
+ payload: {
+ facet: string
+ value: string
+ count: number
+ }[]
+ total_count: number
+ use_visavis_type: string
+ }
+ export type $optimade_zero_api_SearchResponse = {
+ error: null | string
+ fuzzy_notice: null | string
+ out: [
+ id: string,
+ formula: string,
+ structure: string,
+ count: number,
+ unknown: boolean,
+ code: string,
+ year: number,
+ entry_id: number
+ ][]
+ estimated_count: number
+ }
+}
diff --git a/optimade/zero/app/app.meta.tree b/optimade/zero/app/app.meta.tree
new file mode 100644
index 0000000..5672050
--- /dev/null
+++ b/optimade/zero/app/app.meta.tree
@@ -0,0 +1,3 @@
+deploy \/optimade/zero/app/assets
+deploy \manifest.webmanifest
+include \/mol/offline/install
diff --git a/optimade/zero/app/app.view.css b/optimade/zero/app/app.view.css
new file mode 100644
index 0000000..2fd653f
--- /dev/null
+++ b/optimade/zero/app/app.view.css
@@ -0,0 +1,4 @@
+@font-face {
+ font-family: Exo2;
+ src: local('Exo 2 Regular'), local('Exo2-Regular'), url('data:font/woff;charset=utf-8;base64,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') format('woff');
+}
diff --git a/optimade/zero/app/app.view.css.ts b/optimade/zero/app/app.view.css.ts
new file mode 100644
index 0000000..adc0854
--- /dev/null
+++ b/optimade/zero/app/app.view.css.ts
@@ -0,0 +1,9 @@
+namespace $.$$
+{
+
+ $mol_style_define( $optimade_zero_app, {
+ font:{
+ family: 'Exo2',
+ }
+ })
+}
diff --git a/optimade/zero/app/app.view.tree b/optimade/zero/app/app.view.tree
new file mode 100644
index 0000000..84e6caf
--- /dev/null
+++ b/optimade/zero/app/app.view.tree
@@ -0,0 +1,20 @@
+$optimade_zero_app $mol_book2_catalog
+ plugins /
+ <= Theme $mol_theme_auto
+ param \optimade_zero_app_page
+ menu_title \Absolute zero
+ menu_tools /
+ <= Lighter $mol_lights_toggle
+ spreads *
+ search <= Search $optimade_zero_search
+ Spread_close <= Spread_close
+ Words => SearchField
+ profile <= Profile $optimade_zero_profile
+ tools /
+ <= Spread_close
+ about <= AboutPage $mol_page
+ title @ \About
+ tools /
+ <= Spread_close
+ body /
+ <= about_text @ \The largest and most comprehensive inorganic materials dataset
diff --git a/optimade/zero/app/app.view.ts b/optimade/zero/app/app.view.ts
new file mode 100644
index 0000000..50cd711
--- /dev/null
+++ b/optimade/zero/app/app.view.ts
@@ -0,0 +1,21 @@
+namespace $.$$ {
+ export class $optimade_zero_app extends $.$optimade_zero_app {
+
+ @$mol_mem
+ focus_to_search(){
+
+ if(this.$.$mol_mem_cached(()=>this.focus_to_search())){
+ return true
+ }
+ if(!this.$.$mol_state_arg.dict()[this.param()]){
+ this.$.$mol_state_arg.value(this.param(), 'search')
+ //this.SearchField().bring()
+ }
+ return true
+ }
+ auto(){
+ this.focus_to_search()
+ }
+
+ }
+}
diff --git a/optimade/zero/app/assets/apple-touch-icon-180x180.png b/optimade/zero/app/assets/apple-touch-icon-180x180.png
new file mode 100644
index 0000000..6a074b3
Binary files /dev/null and b/optimade/zero/app/assets/apple-touch-icon-180x180.png differ
diff --git a/optimade/zero/app/assets/icon.svg b/optimade/zero/app/assets/icon.svg
new file mode 100644
index 0000000..4848b65
--- /dev/null
+++ b/optimade/zero/app/assets/icon.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/optimade/zero/app/assets/manifest.webmanifest b/optimade/zero/app/assets/manifest.webmanifest
new file mode 100644
index 0000000..2163e75
--- /dev/null
+++ b/optimade/zero/app/assets/manifest.webmanifest
@@ -0,0 +1 @@
+{"name":"Absolute Zero","short_name":"Absolute Zero","start_url":"/","display":"standalone","background_color":"#ffffff","lang":"en","scope":"/","description":"The world's biggest high-quality curated database of materials","theme_color":"#ffffff","icons":[{"src":"pwa-192x192.png","sizes":"192x192","type":"image/png"},{"src":"pwa-512x512.png","sizes":"512x512","type":"image/png"},{"src":"pwa-512x512.png","sizes":"512x512","type":"image/png","purpose":"any"},{"src":"pwa-512x512.png","sizes":"512x512","type":"image/png","purpose":"maskable"}]}
diff --git a/optimade/zero/app/assets/pwa-192-192.png b/optimade/zero/app/assets/pwa-192-192.png
new file mode 100644
index 0000000..ece0d8b
Binary files /dev/null and b/optimade/zero/app/assets/pwa-192-192.png differ
diff --git a/optimade/zero/app/assets/pwa-512x512.png b/optimade/zero/app/assets/pwa-512x512.png
new file mode 100644
index 0000000..674bd46
Binary files /dev/null and b/optimade/zero/app/assets/pwa-512x512.png differ
diff --git a/optimade/zero/app/assets/pwa-64x64.png b/optimade/zero/app/assets/pwa-64x64.png
new file mode 100644
index 0000000..ad24e37
Binary files /dev/null and b/optimade/zero/app/assets/pwa-64x64.png differ
diff --git a/optimade/zero/app/index.html b/optimade/zero/app/index.html
new file mode 100644
index 0000000..45181b8
--- /dev/null
+++ b/optimade/zero/app/index.html
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ −273.15°C
+
+
+
+
+
+
diff --git a/optimade/zero/profile/profile.view.css.ts b/optimade/zero/profile/profile.view.css.ts
new file mode 100644
index 0000000..03e4416
--- /dev/null
+++ b/optimade/zero/profile/profile.view.css.ts
@@ -0,0 +1,31 @@
+namespace $.$$
+{
+
+ $mol_style_define( $optimade_zero_profile, {
+ flex: {
+ basis: '400px',
+ },
+ LoginCard: {
+ Content: {
+ flex: {
+ direction: 'column',
+ }
+ }
+ },
+
+ LoginRow: {
+
+ flex: {
+ direction: 'column',
+ }
+ },
+
+ LogoutRow: {
+
+ flex: {
+ direction: 'column',
+ }
+
+ }
+ } )
+}
diff --git a/optimade/zero/profile/profile.view.tree b/optimade/zero/profile/profile.view.tree
new file mode 100644
index 0000000..e7d4259
--- /dev/null
+++ b/optimade/zero/profile/profile.view.tree
@@ -0,0 +1,37 @@
+$optimade_zero_profile $mol_page
+ api $optimade_zero_api
+ login_endpoint => login_endpoint
+ title \Profile
+ body /
+ <= LoginCard $mol_card
+ status <= login_status \
+ content <= page_content /
+ LogoutRow $mol_row
+ sub /
+ <= login_title2 @ \Your profile
+ <= logout_button $mol_button_major
+ title <= logout_button_label @ \Logout
+ event_click? <=> event_logout? null
+ LoginRow $mol_row
+ sub /
+ <= login_title @ \Please login
+ <= Login $mol_form
+ form_fields /
+ <= email_field $mol_form_field
+ name <= email_label @ \Email
+ bid <= email_bid \
+ control <= Email_control $mol_string
+ value? <=> email? \
+ autocomplete_native \email
+ <= pass_field $mol_form_field
+ name <= pass_label @ \Password
+ bid <= password_bid \
+ control <= Pass_control $mol_string
+ value? <=> password? \
+ type \password
+ autocomplete_native \current-password
+ buttons /
+ <= Login_submit $mol_button_major
+ title <= login_submit_label @ \Submit
+ event_click? <=> event_login_submit? null
+ disabled <= login_submit_disabled true
diff --git a/optimade/zero/profile/profile.view.ts b/optimade/zero/profile/profile.view.ts
new file mode 100644
index 0000000..71b2f9c
--- /dev/null
+++ b/optimade/zero/profile/profile.view.ts
@@ -0,0 +1,63 @@
+namespace $.$$ {
+ export class $optimade_zero_profile extends $.$optimade_zero_profile {
+
+ @$mol_mem
+ email(next?: string) {
+
+ return next ?? ''
+ }
+
+ @$mol_mem
+ email_bid() {
+
+ try {
+ $mol_data_email(this.email())
+ return ''
+ } catch (error) {
+ return 'Enter valid email'
+ }
+ }
+
+ @$mol_mem
+ password_bid() {
+
+ return this.password() ? '' : 'Enter password'
+ }
+
+ @$mol_mem
+ login_submit_disabled() {
+
+ return !!this.email_bid() || !!this.password_bid()
+ }
+
+ @$mol_action
+ event_login_submit() {
+
+ try {
+ this.api().login(this.email(), this.password())
+ } catch (error) {
+ if($mol_promise_like(error)) {
+ $mol_fail_hidden(error);
+ } else {
+ this.login_status('Login failed')
+ console.log(error)
+ // set random sid
+ //this.api().user_sid($mol_guid(16))
+ }
+ }
+
+ }
+ @$mol_action
+ event_logout() {
+ this.api().logout()
+ }
+ @$mol_mem
+ login_status(next?: string) {
+ return next ?? (this.api().user_sid() ? 'logged in' : 'not logged in')
+ }
+ @$mol_mem
+ page_content(){
+ return this.api().user_sid() ? [this.LogoutRow()] : [this.LoginRow()]
+ }
+ }
+}
diff --git a/optimade/zero/readme b/optimade/zero/readme
new file mode 100644
index 0000000..b672639
--- /dev/null
+++ b/optimade/zero/readme
@@ -0,0 +1,4 @@
+contest app
+telegram @soundrmx
+desktop usage video https://drive.google.com/file/d/1MUHfX4wWMaCNvVTnEg845Yt7Dg89P8rj/view?usp=sharing
+PWA APP https://azero.milkyway-studio.ru/
diff --git a/optimade/zero/resultitem/resultitem.view.css.ts b/optimade/zero/resultitem/resultitem.view.css.ts
new file mode 100644
index 0000000..6622473
--- /dev/null
+++ b/optimade/zero/resultitem/resultitem.view.css.ts
@@ -0,0 +1,21 @@
+namespace $.$$
+{
+
+ $mol_style_define( $optimade_zero_resultitem, {
+ alignSelf: 'stretch',
+ Content:{
+ flex:{
+ direction: 'column',
+ }
+ },
+ Formula:{
+ font:{
+ size: '0.9rem',
+ },
+ display: 'block',
+ },
+ Title:{
+ display: 'block',
+ }
+ })
+}
diff --git a/optimade/zero/resultitem/resultitem.view.tree b/optimade/zero/resultitem/resultitem.view.tree
new file mode 100644
index 0000000..e5ea61a
--- /dev/null
+++ b/optimade/zero/resultitem/resultitem.view.tree
@@ -0,0 +1,45 @@
+$optimade_zero_resultitem $mol_card
+ minimal_width 210
+ minimal_height 100
+ data *
+ content <= calculated_content /
+ card_content /
+ <= Title $mol_html_view
+ html <= title \
+ <= Formula $mol_html_view
+ html <= formula \
+ minimal_height 30
+ image $mol_image
+ uri <= image_url \
+ title <= image_alt \
+ minimal_height 100
+ png_link $mol_link
+ uri <= png_link_url \
+ title \PNG
+ target \_blank
+ pdf_link $mol_link
+ uri <= pdf_link_url \
+ title \PDF
+ target \_blank
+ ref_link $mol_link
+ uri <= ref_link_url \
+ title \Ref.
+ target \_blank
+ anim_link $mol_link
+ uri <= anim_link_url \
+ title \anim
+ target \_blank
+ login_link $mol_link
+ arg *
+ show_login \1
+ title \Login to access
+ current false
+ hint <= login_hint @ \Login to access
+ text $mol_paragraph
+ title <= textcontent \
+ has_access \
+ cdn_host \
+ dd_addr_tpl \
+ user_sid \
+ refs_endpoint \
+
diff --git a/optimade/zero/resultitem/resultitem.view.ts b/optimade/zero/resultitem/resultitem.view.ts
new file mode 100644
index 0000000..5fc2260
--- /dev/null
+++ b/optimade/zero/resultitem/resultitem.view.ts
@@ -0,0 +1,95 @@
+namespace $.$$ {
+ export class $optimade_zero_resultitem extends $.$optimade_zero_resultitem {
+
+ @$mol_mem
+ data(next?:any)
+ {
+ return next ?? []
+ }
+
+ @$mol_mem
+ title(next?:string)
+ {
+ return next ?? (this.data().length ? this.data()[ 2 ] : '')
+ }
+ @$mol_mem
+ formula(next?:string)
+ {
+ return next ?? (this.data().length ? this.data()[ 1 ] : '')
+ }
+
+ @$mol_mem
+ contentblock(){
+
+ if(!this.data().length) return []
+ const row = this.data()
+ row[7] = parseInt(row[7]);
+ const dtype = row[0].substr(0, 1)
+ let content = [this.image()]
+ let dlinks = this.has_access() ? [] : [this.login_link()]
+
+ if(this.biblio_html() && this.has_access()){
+ dlinks = [this.ref_link(), this.pdf_link()]
+ }
+
+ if(dtype === 'P'){
+ content = []
+ }
+ else if(dtype === 'C'){
+
+ if(this.has_access()){
+ dlinks = [this.png_link()]
+ }
+ }
+ else{
+ dlinks = [this.png_link(),this.anim_link()]
+ }
+ return [...content,this.text(), ...dlinks]
+ }
+ @$mol_mem
+ calculated_content(){
+ return [...this.card_content(), ...this.contentblock()]
+ }
+ @$mol_mem
+ biblio_html(){
+ const row = this.data()
+ const biblio_html = (row[7] == 999999) ? '' :'[' + row[5] + '`' + row[6].toString().substr(2, 2) + ']'
+ return biblio_html
+ }
+ @$mol_mem
+ textcontent(){
+ return this.biblio_html()
+ }
+ @$mol_mem
+ dtype(){
+ return this.data()[ 0 ].substr(0, 1)
+ }
+ @$mol_mem
+ image_url(){
+ return this.cdn_host() + '/' + ((this.dtype() ==='C') ? 'pd_thumbs' : 'rd_thumbs') + '/' + this.data()[ 0 ].split('-')[0] + '.png'
+ }
+ @$mol_mem
+ image_alt(){
+ return this.data()[ 0 ]
+ }
+ @$mol_mem
+ png_link_url(){
+ return (this.dtype() ==='C') ?
+ this.dd_addr_tpl() + '/c?q=' + this.data()[ 0 ] + '&fmt=png&sid=' + this.user_sid():
+ this.dd_addr_tpl() + '/s?q=' + this.data()[ 0 ] + '&fmt=png'
+ }
+ @$mol_mem
+ anim_link_url(){
+ return this.dd_addr_tpl() + '/' + this.dtype().toLowerCase() + '?q=' + this.data()[ 0 ] + '&fmt=gif'
+ }
+ @$mol_mem
+ pdf_link_url(){
+ return this.dd_addr_tpl() + '/' + this.dtype().toLowerCase() + '?q=' + this.data()[ 0 ] + '&fmt=pdf&sid=' + this.user_sid()
+ }
+ @$mol_mem
+ ref_link_url(){
+ return this.refs_endpoint() + '?ref_id=' + this.data()[ 7 ] + '&sid=' + this.user_sid() + '&fmt=bib'
+ }
+
+ }
+}
diff --git a/optimade/zero/search/helpers.ts b/optimade/zero/search/helpers.ts
new file mode 100644
index 0000000..91c4b97
--- /dev/null
+++ b/optimade/zero/search/helpers.ts
@@ -0,0 +1,147 @@
+namespace $
+{
+ export class $optimade_zero_search_helper
+ {
+
+ static arity_keys = [ 'unary', 'binary', 'ternary', 'quaternary', 'quinary', 'multinary', 'multinary', 'multinary', 'multinary', 'multinary' ];
+
+ static periodic_elements = [ "h", "he", "li", "be", "b", "c", "n", "o", "f", "ne", "na", "mg", "al", "si", "p", "s", "cl", "ar", "k", "ca", "sc", "ti", "v", "cr", "mn", "fe", "co", "ni", "cu", "zn", "ga", "ge", "as", "se", "br", "kr", "rb", "sr", "y", "zr", "nb", "mo", "tc", "ru", "rh", "pd", "ag", "cd", "in", "sn", "sb", "te", "i", "xe", "cs", "ba", "la", "ce", "pr", "nd", "pm", "sm", "eu", "gd", "tb", "dy", "ho", "er", "tm", "yb", "lu", "hf", "ta", "w", "re", "os", "ir", "pt", "au", "hg", "tl", "pb", "bi", "po", "at", "rn", "fr", "ra", "ac", "th", "pa", "u", "np", "pu", "am", "cm", "bk", "cf", "es", "fm", "md", "no", "lr", "rg" ]; /* exact */
+
+ static periodic_elements_cased = this.periodic_elements.map( function( x ) { return x[ 0 ].toUpperCase() + x.slice( 1 ).toLowerCase() } );
+ static periodic_elements_xed = [ "x" ].concat( this.periodic_elements );
+
+ static periodic_element_names = [ "hydrogen", "helium", "lithium", "beryllium", "boron", "carbon", "nitrogen", "oxygen", "fluorine", "neon", "sodium", "magnesium", "aluminium", "silicon", "phosphorus", "sulfur", "chlorine", "argon", "potassium", "calcium", "scandium", "titanium", "vanadium", "chromium", "manganese", "iron", "cobalt", "nickel", "copper", "zinc", "gallium", "germanium", "arsenic", "selenium", "bromine", "krypton", "rubidium", "strontium", "yttrium", "zirconium", "niobium", "molybdenum", "technetium", "ruthenium", "rhodium", "palladium", "silver", "cadmium", "indium", "tin", "antimony", "tellurium", "iodine", "xenon", "caesium", "barium", "lanthanum", "cerium", "praseodymium", "neodymium", "promethium", "samarium", "europium", "gadolinium", "terbium", "dysprosium", "holmium", "erbium", "thulium", "ytterbium", "lutetium", "hafnium", "tantalum", "tungsten", "rhenium", "osmium", "iridium", "platinum", "gold", "mercury", "thallium", "lead", "bismuth", "polonium", "astatine", "radon", "francium", "radium", "actinium", "thorium", "protactinium", "uranium", "neptunium", "plutonium", "americium", "curium", "berkelium", "californium", "einsteinium", "fermium", "mendelevium", "nobelium", "lawrencium", "roentgenium" ]; /* fuzzy */
+
+ static lat_p2i = { 'cubic': 1, 'hexagonal': 2, 'trigonal': 3, 'tetragonal': 4, 'orthorhombic': 5, 'monoclinic': 6, 'triclinic': 7, 'rhombohedral': 3, 'cub': 1, 'hex': 2, 'hexag': 2, 'trig': 3, 'tet': 4, 'tetr': 4, 'tetrag': 4, 'orth': 5, 'ortho': 5, 'monocl': 6, 'tric': 7, 'tricl': 7, 'rhom': 3, 'rhomb': 3 }
+ static lat_fgrs = Object.keys( this.lat_p2i );
+ static lat_i2p = { 1: 'cubic', 2: 'hexagonal', 3: 'trigonal', 4: 'tetragonal', 5: 'orthorhombic', 6: 'monoclinic', 7: 'triclinic' }
+
+ static most_frequent_els = [ 'O', 'Si', 'Al', 'Fe', 'Ca', 'Na', 'Mg', 'K', 'Ti', 'H', 'Cl', 'S', 'Br', 'C' ];
+ static probable_els = this.periodic_elements_cased.slice( 0, 55 ).filter( el => el != 'Xe' && el != 'Tc' && el != 'Kr' && el != 'Ar' && el != 'Ne' && el != 'He' );
+
+
+ static classes_groups = [ 'transitional', 'chalcogen', 'rare earth', 'lanthanoid', 'metalloid', 'alkaline', 'halogen', 'pnictogen', 'alkali', 'actinoid' ]; // NB noble gas
+ static classes_families = [ 'metal', 'intermetallic', 'oxide', 'conductor', 'nonmetal', 'antiferromagnet', 'ferromagnet', 'semiconductor', 'intermediate valence', 'superconductor', 'close-packed', 'perovskite', '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' ]; // NB pyrite-marcasite, pyroelectric, clathrate, heavy fermion etc.
+ static most_frequent_classes = [ 'metal', 'oxide', 'conductor', 'nonmetal', 'antiferromagnet', 'semiconductor', 'perovskite', 'sulfide', 'paramagnet', 'ab initio literature', 'hydrate', 'chloride', 'spinel', 'fluorite', 'orthophosphate', 'silicate', 'machine learning', 'ab initio calculations' ];
+
+ static 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
+
+ static most_frequent_lats = [ 'cubic', 'tetragonal', 'orthorhombic', 'monoclinic' ];
+ static 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' ];
+
+ static 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' ];
+
+ /*
+ * Utilities:
+ */
+ static get_random_term( sequence: number[] | string[] )
+ {
+ return sequence[ Math.floor( Math.random() * sequence.length ) ]
+ }
+ static get_realistic( facet: string, cur_arity: number = 0 ): string
+ {
+ var term
+ if( facet == 'elements' )
+ {
+ var i = 0,
+ els = [],
+ prob_arity = [ 2, 3 ], // 4 is improbable
+ cur_arity = cur_arity || ( this.get_random_term( prob_arity ) as number )
+ while( i < cur_arity! )
+ {
+ var el
+ if( i < 2 )
+ el = this.get_random_term( this.probable_els )
+ else
+ el = this.get_random_term( this.most_frequent_els )
+ if( els.indexOf( el ) > -1 ) continue
+ els.push( el )
+ i++
+ }
+ term = els.join( '-' )
+
+ } else if( facet == 'formulae' )
+ {
+ term = this.get_random_term( this.most_frequent_formulae )
+
+ } else if( facet == 'anonymous' )
+ {
+ term = this.get_random_term( this.most_frequent_anonymous )
+
+ } else if( facet == 'props' )
+ {
+ term = this.get_random_term( this.most_frequent_props )
+
+ } else if( facet == 'classes' )
+ {
+ term = this.get_random_term( this.classes_families )
+
+ } else if( facet == 'lattices' )
+ {
+ term = this.get_random_term( this.most_frequent_lats )
+
+ } else return this.get_realistic( [ 'elements', 'formulae', 'props', 'classes', 'lattices' ][ Math.floor( Math.random() * 5 ) ] )
+
+ return term as string
+ }
+
+ static generate_example( scene: number | string = 0 )
+ {
+ var scenarios = [ 1, 2, 3, 4, 5, 6, 7, 8 ],
+ scene = scene || this.get_random_term( scenarios ),
+ result = { 'text': '', 'terms': [], 'facets': [] } as { text: string, terms: string[], facets: string[] }
+
+ if( scene == 1 )
+ { // classes-elements, 4% fails
+ result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'classes', 'elements' ] ]
+ result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_random_term( this.most_frequent_classes ) as string, this.get_realistic( 'elements', 2 ) as string ] ]
+ result[ 'text' ] += result[ 'terms' ][ 0 ] + ' ' + result[ 'terms' ][ 1 ]
+
+ } else if( scene == 2 )
+ { // classes-classes, 4.5% fails
+ result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'classes', 'classes' ] ]
+ result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_random_term( this.classes_groups ) as string, this.get_realistic( 'classes' ) as string ] ]
+ result[ 'text' ] += result[ 'terms' ][ 0 ] + ' group, ' + result[ 'terms' ][ 1 ]
+
+ } else if( scene == 3 )
+ { // formulae-lattices, 1% fails
+ result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'formulae', 'lattices' ] ]
+ result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_realistic( 'formulae' ), this.get_realistic( 'lattices' ) ] ]
+ result[ 'text' ] += result[ 'terms' ][ 0 ] + ' ' + result[ 'terms' ][ 1 ] + ' crystal'
+
+ } else if( scene == 4 )
+ { // props-classes, always correct
+ result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'props', 'classes' ] ]
+ result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_realistic( 'props' ), this.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' ] = [ ...result[ 'facets' ], ...[ 'classes', 'lattices' ] ]
+ result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_realistic( 'classes' ), this.get_realistic( 'lattices' ) ] ]
+ result[ 'text' ] += result[ 'terms' ][ 0 ] + ', ' + result[ 'terms' ][ 1 ] + ' crystal'
+
+ } else if( scene == 6 )
+ { // elements-lattices, 3% fails
+ result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'elements', 'lattices' ] ]
+ result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_realistic( 'elements' ), this.get_realistic( 'lattices' ) ] ]
+ result[ 'text' ] += result[ 'terms' ][ 0 ] + ', ' + result[ 'terms' ][ 1 ] + ' crystal'
+
+ } else if( scene == 7 )
+ { // props and anonymous formulae
+ result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'props', 'formulae' ] ]
+ result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_realistic( 'props' ), this.get_realistic( 'anonymous' ) ] ]
+ result[ 'text' ] += result[ 'terms' ][ 0 ] + ' ' + result[ 'terms' ][ 1 ]
+
+ } else
+ { // props-formulae, 4% fails
+ result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'props', 'formulae' ] ]
+ result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_realistic( 'props' ), this.get_realistic( 'formulae' ) ] ]
+ result[ 'text' ] += result[ 'terms' ][ 0 ] + ' of ' + result[ 'terms' ][ 1 ]
+ }
+ return result
+ }
+ }
+}
diff --git a/optimade/zero/search/search.view.css b/optimade/zero/search/search.view.css
new file mode 100644
index 0000000..62cc0ad
--- /dev/null
+++ b/optimade/zero/search/search.view.css
@@ -0,0 +1,27 @@
+[optimade_zero_search_searcherexamplelink] {
+ text-overflow: ellipsis;
+}
+[optimade_zero_search_refinementshowmorelink] {
+ font-size: 0.8rem;
+ font-weight: 500;
+}
+[optimade_zero_search_searcheregright] {
+ display: flex;
+ align-items: center;
+ font-size: 0.8rem;
+}
+[optimade_zero_search_searchertitle] {
+ color: var(--mol_theme_shade);
+}
+[optimade_zero_search_searcherlabelrow] {
+ justify-content: space-between;
+ flex-wrap: nowrap;
+ padding-bottom: 0;
+ padding-top: 0;
+ align-items: center;
+}
+[optimade_zero_search_searchinputrow]{
+ flex-wrap: nowrap;
+ padding-left: 0;
+ padding-right: 0;
+}
diff --git a/optimade/zero/search/search.view.css.ts b/optimade/zero/search/search.view.css.ts
new file mode 100644
index 0000000..27ae572
--- /dev/null
+++ b/optimade/zero/search/search.view.css.ts
@@ -0,0 +1,84 @@
+namespace $.$$
+{
+ const { vary } = $mol_style_func
+
+ $mol_style_define( $optimade_zero_search, {
+
+
+ FacetSelectorLabeler: {
+ Content: {
+ flex: {
+ direction: 'column',
+ }
+
+
+ }
+
+ },
+ SearchPage: {
+ flex: {
+ basis: '400px',
+ },
+ Body_content:{
+ padding: {
+ left: 0,
+ right: 0,
+ }
+ }
+ },
+ ResultsPage: {
+ flex: {
+ grow: 3,
+ },
+ Body_content:{
+ padding: {
+ left: 0,
+ right: 0,
+ }
+ }
+ },
+ SearchInputRow: {
+ width: '100%',
+ },
+ RefinementLabel: {
+ Content: {
+ flex: {
+ direction: 'column',
+ }
+ }
+ },
+ SearchLabel: {
+ Content: {
+ flex: {
+ direction: 'column',
+ }
+ }
+ },
+ FoundStr: {
+ font: {
+ size: '0.8rem',
+ weight: 500,
+ }
+ },
+ SearchSubRow: {
+ margin: 0,
+ padding: 0,
+ },
+ ShowResultsLink: {
+ font: {
+ size: '0.8rem',
+ weight: 500,
+
+ },
+ padding: 0
+ },
+ Results: {
+ display: 'grid',
+ gridTemplateColumns: 'repeat( auto-fit, minmax( 20rem, 1fr ) );',
+ },
+
+
+
+
+ } )
+}
diff --git a/optimade/zero/search/search.view.tree b/optimade/zero/search/search.view.tree
new file mode 100644
index 0000000..d4d05e6
--- /dev/null
+++ b/optimade/zero/search/search.view.tree
@@ -0,0 +1,100 @@
+$optimade_zero_search $mol_book2
+ api $optimade_zero_api
+ dd_addr_tpl => dd_addr_tpl
+ cdn_host => cdn_host
+ refs_endpoint => refs_endpoint
+ user_sid => user_sid
+ title <= page_title @ \Search page
+ pages <= visible_pages /
+ LoginPage $optimade_zero_profile
+ title @ \Login
+ tools /
+ <= Login_close_link $mol_link
+ arg *
+ show_login 0
+ hint <= close_hint @ \Close page
+ sub /
+ <= Spread_close_icon $mol_icon_close
+ SearchPage $mol_page
+ title @ \Search
+ tools /
+ <= Spread_close null
+ body /
+ <= auto_url
+ <= SearchLabel $mol_labeler
+ Label <= SearcherLabelRow $mol_row
+ minimal_height 32
+ sub /$mol_view_content
+ <= SearcherTitle $mol_view
+ sub / <= SearcherTitleInputText @ \Input:
+ <= SearcherEgRight $mol_view
+ sub /$mol_view_content
+ <= SearcherTitleEg @ \e.g.
+ <= SearcherExampleLink $mol_link
+ title <= example_link_title \
+ current false
+ event_click*?event <=> example_link_click*?event null
+ content /
+ <= SearchInputRow $mol_row
+ sub /
+ <= Words $mol_search
+ hint \Type property, elements, classes
+ query? <=> word? \
+ suggests <= suggests /
+ suggest_select*?event <=> suggest_select*?event null
+ <= SearchButton $mol_button_major
+ title <= sblabel @ \Search
+ click? <=> search_click? null
+ <= SearchSubRow $mol_row
+ sub /
+ <= FoundStr $mol_paragraph
+ sub /
+ <= found_str @ \Items found:
+ <= found_count
+ <= ShowResultsLink $mol_link
+ title <= show_results_title @ \Show results
+ arg *
+ results 1
+ <= ClassesPreselector $mol_check_list
+ options <= preselect_classes_options *
+ option_checked*? <=> preselect_classes_checked*? false
+ <= RefinementLabel $mol_labeler
+ title <= label2 @ \Data summary:
+ content <= facet_blocks /$mol_view_content
+ <= FacetSelectorLabeler*0 $mol_labeler
+ title <= facet_selector_label* \
+ content /$mol_view_content
+ <= FacetSelector* $mol_check_list
+ options <= refinement_options* *
+ option_checked*? <=> facets_checked*? false
+ <= RefinementShowMoreLink*?next $mol_link
+ title <= show_more_title @ \Show more
+ event_click <= show_more_click* null
+ current false
+ foot /
+ <= ClearSearchButton $mol_button_minor
+ title <= clear_search_title @ \New search
+ click* <=> clear_search* null
+ <= ReloadButton $mol_button_minor
+ title <= reload_title @ \Reload search
+ click* <=> reset* null
+ ResultsPage $mol_page
+ title @ \Results
+ tools /
+ <= Spread_close_link $mol_link
+ arg *
+ results 0
+ hint <= close_hint @ \Close page
+ sub /
+ <= Spread_close_icon $mol_icon_close
+ body /
+ <= Results $mol_row
+ sub <= result_items /
+ ResultItem* $optimade_zero_resultitem
+ data <= result_item* *
+ dd_addr_tpl <= dd_addr_tpl
+ cdn_host <= cdn_host
+ refs_endpoint <= refs_endpoint
+ user_sid <= user_sid
+ has_access <= user_sid
+
diff --git a/optimade/zero/search/search.view.ts b/optimade/zero/search/search.view.ts
new file mode 100644
index 0000000..c48894e
--- /dev/null
+++ b/optimade/zero/search/search.view.ts
@@ -0,0 +1,280 @@
+namespace $.$$
+{
+ export class $optimade_zero_search extends $.$optimade_zero_search
+ {
+ @$mol_mem
+ auto_url(){
+ if($mol_mem_cached(()=>this.auto_url()) === ''){
+ return ''
+ }
+ this.preselect_search_facets(this.api().uri_to_facets())
+ return ''
+ }
+ @$mol_mem
+ visible_pages()
+ {
+ const pages = $mol_state_arg.dict()[ 'results' ] ? [ this.SearchPage(), this.ResultsPage() ] : [ this.SearchPage() ]
+ if($mol_state_arg.dict()[ 'show_login' ] && !this.user_sid()){
+ pages.push(this.LoginPage())
+ }
+ return pages
+ }
+ @$mol_action
+ suggest_select( id: string, event?: MouseEvent )
+ {
+ const facets = this.selectizes().filter( el => el.label === id )
+ this.preselect_search_facets( [ ...this.preselect_search_facets(), ...facets ] )
+ this.Words().suggests_showed( false )
+
+ this.word( '' )
+
+ }
+ @$mol_mem
+ suggests()
+ {
+ return this.selectizes().filter( el => !this.preselect_search_facets().some( el2 => el2.id === el.id ) ).map( el => el.label )
+ }
+ @$mol_mem
+ selectizes()
+ {
+ this.reload_search()
+ this.$.$mol_wait_timeout( 200 )
+
+ return this.api().selectize( this.word() ).map( el => ({...el, label:el.label.replace(/<\/?(?:sup|sub)>/g, '')}) )
+ }
+
+ @$mol_action
+ search_click()
+ {
+
+ if( !this.word() ) return
+
+ const finded = this.api().string_to_facets( this.word() )
+ delete finded[ 'ignored' ]
+ if( Object.keys( finded ).length )
+ {
+ this.preselect_search_facets( this.api().facet_dict_to_array( finded ) )
+ }
+ }
+ @$mol_mem
+ reload_search( next?: number )
+ {
+ return next ?? Date.now()
+ }
+ @$mol_action
+ clear_search()
+ {
+ this.preselect_search_facets( [] )
+ this.Words().bring()
+ }
+ @$mol_action
+ reset()
+ {
+ this.reload_search( Date.now() )
+ }
+
+ @$mol_mem
+ combined_facets()
+ {
+ const dict = this.api().facet_array_to_dict( this.preselect_search_facets() )
+ for( const key in dict )
+ {
+ dict[ key ] = dict[ key ].replaceAll( ', ', '-' )
+ }
+ const old = $mol_mem_cached( () => this.combined_facets() )
+ $mol_state_arg.dict()
+ if( old )
+ {
+
+ for( const key in old )
+ {
+ $mol_state_arg.value( key, null )
+ }
+ }
+ for( const key in dict )
+ {
+
+ $mol_state_arg.value( key, dict[ key ] )
+ }
+ return dict
+ }
+ @$mol_mem
+ refinements()
+ {
+ this.reload_search()
+ this.$.$mol_wait_timeout( 200 )
+
+ const resp = this.api().refinement( this.combined_facets() )
+
+ return resp
+
+ }
+
+ @$mol_mem_key
+ override refinement_options( id: string )
+ {
+ const opts = {} as Record
+ this.facets_grouped()[ id ]?.map( ( el, index ) => opts[ `${ id }_${ el }` ] = el.charAt( 0 ).toUpperCase() + el.slice( 1 ) )
+ return opts
+ }
+
+ @$mol_mem_key
+ override facet_selector_label( el: string )
+ {
+ return this.api().query_params[ el ]
+ }
+
+ @$mol_mem
+ facets_grouped(next?: Record): Record
+ {
+ if(next){
+ return next
+ }
+
+ const resp = this.refinements()
+
+ if(resp.error)
+ {
+ throw new Error( resp.error )
+ }
+ if( Object.keys( this.preselect_classes_options() ).length )
+ {
+ const groups = {} as Record
+ resp.payload.map( el => groups[ el.facet ] ? groups[ el.facet ].push( el.value ) : groups[ el.facet ] = [ el.value ] )
+
+
+ return groups
+
+ }
+ else
+ {
+ return {}
+ }
+
+ }
+
+ @$mol_mem
+ override facet_blocks()
+ {
+
+ return Object.keys( this.facets_grouped() ).map( ( val ) =>
+ {
+ return this.FacetSelectorLabeler( val )
+ } )
+ }
+ @$mol_mem
+ found_count()
+ {
+ return this.results().length
+ }
+ @$mol_mem_key
+ override preselect_classes_checked( id: string, next?: any )
+ {
+
+ if( next === false )
+ {
+ const facetIndex = this.preselect_search_facets().findIndex( el => `${ el.facet }_${ el.label }` === id )
+ const spl = [ ...this.preselect_search_facets() ]
+ spl.splice( facetIndex, 1 )
+ this.preselect_search_facets( spl )
+ return next
+ }
+ return true
+ }
+ @$mol_mem_key
+ override facets_checked( id: string, next?: any )
+ {
+
+ if( next === true )
+ {
+ const [ key, val ] = id.split( '_' )
+ const facet = { facet: key, label: val, id: '' }
+ const spl = [ ...this.preselect_search_facets(), facet ]
+ this.preselect_search_facets( spl )
+
+ }
+ return this.preselect_classes_options()[ id ] ? this.preselect_classes_checked( id, next ) : false
+ }
+ @$mol_mem
+ result_items()
+ {
+ this.$.$mol_wait_timeout( 500 )
+ return this.results().map( ( el, index ) => this.ResultItem( index ) )
+ }
+ @$mol_mem_key
+ result_item( index?: number )
+ {
+ return this.results()[ index! ] ?? {}
+ }
+ @$mol_mem
+ results()
+ {
+ this.reload_search()
+ this.$.$mol_wait_timeout( 200 )
+ const response = this.api().results( this.combined_facets() )
+ return response.out ?? []
+
+
+ }
+
+ @$mol_mem
+ preselect_search_facets( next?: $optimade_zero_api_Facet[] )
+ {
+
+ return next ?? []
+ }
+ @$mol_mem
+ override preselect_classes_options()
+ {
+
+ const result = {
+ } as Record
+
+ this.preselect_search_facets().map( el =>
+ {
+ const label = el.label
+ result[ `${ el.facet }_${ label }` ] = label
+ } )
+ return result
+ }
+ @$mol_mem
+ example_link_title(){
+
+ return this.example_generated().text
+ }
+ @$mol_mem
+ example_generated(){
+ $mol_state_time.now(4000)
+ return $optimade_zero_search_helper.generate_example()
+ }
+ @$mol_action
+ example_link_click(){
+ const facets = [] as $optimade_zero_api_Facet[]
+ for (let index = 0; index < this.example_generated().facets.length; index++) {
+ const facet = this.example_generated().facets[index];
+ facets.push({
+ facet: facet,
+ label: this.example_generated().terms[index]
+ })
+ }
+ this.preselect_search_facets(facets)
+ }
+ @$mol_action
+ show_more_click(id: string){
+
+ const facets = this.combined_facets()
+ facets['extd_refine'] = id
+ const resp = this.api().refinement(facets)
+ if(!resp.error && resp.payload.length){
+ const groups = {...this.facets_grouped(),[id]:[...this.facets_grouped()[id],...(resp.payload as any[]).map(el=>el[0])]}
+
+ this.facets_grouped(groups)
+
+ }
+ this.RefinementShowMoreLink(id, null as unknown as undefined)
+ }
+
+
+
+ }
+}
diff --git a/readme b/readme
new file mode 100644
index 0000000..91e5314
--- /dev/null
+++ b/readme
@@ -0,0 +1,4 @@
+contest app
+telegram @soundrmx
+desktop usage video https://drive.google.com/file/d/1MUHfX4wWMaCNvVTnEg845Yt7Dg89P8rj/view?usp=sharing
+PWA APP https://azero.milkyway-studio.ru/
\ No newline at end of file
diff --git a/selectize.js b/selectize.js
deleted file mode 100644
index 39ebad5..0000000
--- a/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 -> Soc cer 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,