From ac9de3a585b2bc8b77e4e347a65a75eddc9fdadb Mon Sep 17 00:00:00 2001 From: Delphinus8821 <73083035+Delphinus8821@users.noreply.github.com> Date: Wed, 5 Feb 2025 12:43:52 +1030 Subject: [PATCH] Add Search to Online and Offline Help (#2262) * Add search to online and offline help * Fix code smells * Requested changes --- ATTRIBUTION.md | 3 + .../ext/bootstrap/assets/HelpTemplate.html | 226 ++++ .../ext/bootstrap/assets/css/search.css | 130 +++ .../modules/ext/bootstrap/js/index.min.js | 8 + .../help/ConstellationHelpDisplayer.java | 315 +++--- .../help/utilities/Generator.java | 15 +- .../ConstellationHelpDisplayerNGTest.java | 8 +- .../constellation/views/whatsnew/whatsnew.txt | 4 + bootstrap/assets/css/search.css | 130 +++ bootstrap/js/index.min.js | 8 + build_help.sh | 26 - move_help.sh | 23 - onlinePandocTemplate.txt | 163 ++- search.json | 967 ++++++++++++++++++ toc_update.sh | 19 - 15 files changed, 1793 insertions(+), 252 deletions(-) create mode 100644 CoreHelp/release/modules/ext/bootstrap/assets/HelpTemplate.html create mode 100644 CoreHelp/release/modules/ext/bootstrap/assets/css/search.css create mode 100644 CoreHelp/release/modules/ext/bootstrap/js/index.min.js create mode 100644 bootstrap/assets/css/search.css create mode 100644 bootstrap/js/index.min.js delete mode 100644 build_help.sh delete mode 100644 move_help.sh create mode 100644 search.json delete mode 100644 toc_update.sh diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index 1a0f9951c3..a9ee060330 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -46,6 +46,9 @@ website shares free icons to download. (https://www.shareicon.net/tos) - [Flat Icons](https://www.flaticon.com/packs/countrys-flags) under the license (https://file000.flaticon.com/downloads/license/license.pdf) +- [MiniSearch](https://github.com/lucaong/minisearch) under the license +(https://github.com/lucaong/minisearch/blob/master/LICENSE.txt) + The following is a list of third-party libraries used in the development of Constellation. diff --git a/CoreHelp/release/modules/ext/bootstrap/assets/HelpTemplate.html b/CoreHelp/release/modules/ext/bootstrap/assets/HelpTemplate.html new file mode 100644 index 0000000000..08c0cd5ade --- /dev/null +++ b/CoreHelp/release/modules/ext/bootstrap/assets/HelpTemplate.html @@ -0,0 +1,226 @@ + + + + + + SCRIPTS + +
+
+
+ + TABLE_OF_CONTENTS +
+
+
+ +
+ + +
    +
    + + MAIN_PAGE +
    +
    + + + + + + diff --git a/CoreHelp/release/modules/ext/bootstrap/assets/css/search.css b/CoreHelp/release/modules/ext/bootstrap/assets/css/search.css new file mode 100644 index 0000000000..8cba8e12a1 --- /dev/null +++ b/CoreHelp/release/modules/ext/bootstrap/assets/css/search.css @@ -0,0 +1,130 @@ +.SearchBox { + position: relative; +} + +.Search { + position: relative; +} + +.Search button.clear { + position: absolute; + top: 0; + bottom: 0.2em; + right: 0.5em; + font-size: 1.5em; + line-height: 1; + z-index: 20; + border: none; + background: none; + outline: none; + margin: 0; + padding: 0; + color: black; +} + +.Search input { + position: relative; + width: 100%; + padding: 0.5em; + left: 40px; + font-size: 16px; + border: 1px solid #ccc; + border-radius: 3px; + outline: none; + color: #555; + box-shadow: none; +} + +.Search button.icon { + position: absolute; + top: 0; + bottom: 0.2em; + left: 0; + font-size: 1.5em; + line-height: 1; + z-index: 20; + border: none; + background: none; + outline: none; + margin: 0; + padding: 0; +} + +.hasResults .Explanation { + display: none; +} + +.ResultList { + margin: 1em 0 0 0; + padding: 0; + list-style: none; + flex-grow: 1; + position: relative; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; +} + +.ResultList:before { + content: ''; + display: block; + position: sticky; + z-index: 10; + left: 0; + right: 0; + top: -1px; + width: 100%; + height: 0.7em; + margin-bottom: -0.7em; + background: linear-gradient(white, rgba(255, 255, 255, 0)); +} + +.ResultList:after { + content: ''; + display: block; + position: sticky; + z-index: 10; + left: 0; + right: 0; + bottom: -1px; + width: 100%; + height: 0.7em; + margin-bottom: -0.7em; + background: linear-gradient(rgba(255, 255, 255, 0), white); +} + +.SuggestionList { + display: none; + list-style: none; + padding: 0; + border: 1px solid #ccc; + border-top: 0; + margin: 0 0 0.2em 0; + border-radius: 3px; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); + background: rgba(255, 255, 255, 0.93); + position: absolute; + z-index: 20; + left: 0; + right: 0; +} + +.hasSuggestions .SuggestionList { + display: block; +} + +.Suggestion { + padding: 0.5em 1em; + border-bottom: 1px solid #eee; +} + +.Suggestion:last-child { + border: none; +} + +.Suggestion.selected { + background: rgba(240, 240, 240, 0.95); +} + +.Suggestion:hover:not(.selected) { + background: rgba(250, 250, 250, 0.95); +} \ No newline at end of file diff --git a/CoreHelp/release/modules/ext/bootstrap/js/index.min.js b/CoreHelp/release/modules/ext/bootstrap/js/index.min.js new file mode 100644 index 0000000000..bb6421491b --- /dev/null +++ b/CoreHelp/release/modules/ext/bootstrap/js/index.min.js @@ -0,0 +1,8 @@ +/** + * Minified by jsDelivr using Terser v5.19.2. + * Original file: /npm/minisearch@7.1.1/dist/umd/index.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).MiniSearch=e()}(this,(function(){"use strict";function t(t,e,s,i){return new(s||(s=Promise))((function(n,o){function r(t){try{u(i.next(t))}catch(t){o(t)}}function c(t){try{u(i.throw(t))}catch(t){o(t)}}function u(t){var e;t.done?n(t.value):(e=t.value,e instanceof s?e:new s((function(t){t(e)}))).then(r,c)}u((i=i.apply(t,e||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;const e="KEYS",s="VALUES",i="";class n{constructor(t,e){const s=t._tree,i=Array.from(s.keys());this.set=t,this._type=e,this._path=i.length>0?[{node:s,keys:i}]:[]}next(){const t=this.dive();return this.backtrack(),t}dive(){if(0===this._path.length)return{done:!0,value:void 0};const{node:t,keys:e}=o(this._path);if(o(e)===i)return{done:!1,value:this.result()};const s=t.get(o(e));return this._path.push({node:s,keys:Array.from(s.keys())}),this.dive()}backtrack(){if(0===this._path.length)return;const t=o(this._path).keys;t.pop(),t.length>0||(this._path.pop(),this.backtrack())}key(){return this.set._prefix+this._path.map((({keys:t})=>o(t))).filter((t=>t!==i)).join("")}value(){return o(this._path).node.get(i)}result(){switch(this._type){case s:return this.value();case e:return this.key();default:return[this.key(),this.value()]}}[Symbol.iterator](){return this}}const o=t=>t[t.length-1],r=(t,e,s,n,o,c,u,h)=>{const d=c*u;t:for(const a of t.keys())if(a===i){const e=o[d-1];e<=s&&n.set(h,[t.get(a),e])}else{let i=c;for(let t=0;ts)continue t}r(t.get(a),e,s,n,o,i,u,h+a)}};class c{constructor(t=new Map,e=""){this._size=void 0,this._tree=t,this._prefix=e}atPrefix(t){if(!t.startsWith(this._prefix))throw new Error("Mismatched prefix");const[e,s]=u(this._tree,t.slice(this._prefix.length));if(void 0===e){const[e,n]=m(s);for(const s of e.keys())if(s!==i&&s.startsWith(n)){const i=new Map;return i.set(s.slice(n.length),e.get(s)),new c(i,t)}}return new c(e,t)}clear(){this._size=void 0,this._tree.clear()}delete(t){return this._size=void 0,a(this._tree,t)}entries(){return new n(this,"ENTRIES")}forEach(t){for(const[e,s]of this)t(e,s,this)}fuzzyGet(t,e){return((t,e,s)=>{const i=new Map;if(void 0===e)return i;const n=e.length+1,o=n+s,c=new Uint8Array(o*n).fill(s+1);for(let t=0;t{if(0===e.length||null==t)return[t,s];for(const n of t.keys())if(n!==i&&e.startsWith(n))return s.push([t,n]),u(t.get(n),e.slice(n.length),s);return s.push([t,e]),u(void 0,"",s)},h=(t,e)=>{if(0===e.length||null==t)return t;for(const s of t.keys())if(s!==i&&e.startsWith(s))return h(t.get(s),e.slice(s.length))},d=(t,e)=>{const s=e.length;t:for(let n=0;t&&n{const[s,n]=u(t,e);if(void 0!==s)if(s.delete(i),0===s.size)l(n);else if(1===s.size){const[t,e]=s.entries().next().value;f(n,t,e)}},l=t=>{if(0===t.length)return;const[e,s]=m(t);if(e.delete(s),0===e.size)l(t.slice(0,-1));else if(1===e.size){const[s,n]=e.entries().next().value;s!==i&&f(t.slice(0,-1),s,n)}},f=(t,e,s)=>{if(0===t.length)return;const[i,n]=m(t);i.set(n+e,s),i.delete(n)},m=t=>t[t.length-1],g="or";class _{constructor(t){if(null==(null==t?void 0:t.fields))throw new Error('MiniSearch: option "fields" must be provided');const e=null==t.autoVacuum||!0===t.autoVacuum?O:t.autoVacuum;this._options=Object.assign(Object.assign(Object.assign({},v),t),{autoVacuum:e,searchOptions:Object.assign(Object.assign({},x),t.searchOptions||{}),autoSuggestOptions:Object.assign(Object.assign({},z),t.autoSuggestOptions||{})}),this._index=new c,this._documentCount=0,this._documentIds=new Map,this._idToShortId=new Map,this._fieldIds={},this._fieldLength=new Map,this._avgFieldLength=[],this._nextId=0,this._storedFields=new Map,this._dirtCount=0,this._currentVacuum=null,this._enqueuedVacuum=null,this._enqueuedVacuumConditions=I,this.addFields(this._options.fields)}add(t){const{extractField:e,tokenize:s,processTerm:i,fields:n,idField:o}=this._options,r=e(t,o);if(null==r)throw new Error(`MiniSearch: document does not have ID field "${o}"`);if(this._idToShortId.has(r))throw new Error(`MiniSearch: duplicate ID ${r}`);const c=this.addDocumentId(r);this.saveStoredFields(c,t);for(const o of n){const n=e(t,o);if(null==n)continue;const r=s(n.toString(),o),u=this._fieldIds[o],h=new Set(r).size;this.addFieldLength(c,u,this._documentCount-1,h);for(const t of r){const e=i(t,o);if(Array.isArray(e))for(const t of e)this.addTerm(u,c,t);else e&&this.addTerm(u,c,e)}}}addAll(t){for(const e of t)this.add(e)}addAllAsync(t,e={}){const{chunkSize:s=10}=e,i={chunk:[],promise:Promise.resolve()},{chunk:n,promise:o}=t.reduce((({chunk:t,promise:e},i,n)=>(t.push(i),(n+1)%s==0?{chunk:[],promise:e.then((()=>new Promise((t=>setTimeout(t,0))))).then((()=>this.addAll(t)))}:{chunk:t,promise:e})),i);return o.then((()=>this.addAll(n)))}remove(t){const{tokenize:e,processTerm:s,extractField:i,fields:n,idField:o}=this._options,r=i(t,o);if(null==r)throw new Error(`MiniSearch: document does not have ID field "${o}"`);const c=this._idToShortId.get(r);if(null==c)throw new Error(`MiniSearch: cannot remove document with ID ${r}: it is not in the index`);for(const o of n){const n=i(t,o);if(null==n)continue;const r=e(n.toString(),o),u=this._fieldIds[o],h=new Set(r).size;this.removeFieldLength(c,u,this._documentCount,h);for(const t of r){const e=s(t,o);if(Array.isArray(e))for(const t of e)this.removeTerm(u,c,t);else e&&this.removeTerm(u,c,e)}}this._storedFields.delete(c),this._documentIds.delete(c),this._idToShortId.delete(r),this._fieldLength.delete(c),this._documentCount-=1}removeAll(t){if(t)for(const e of t)this.remove(e);else{if(arguments.length>0)throw new Error("Expected documents to be present. Omit the argument to remove all documents.");this._index=new c,this._documentCount=0,this._documentIds=new Map,this._idToShortId=new Map,this._fieldLength=new Map,this._avgFieldLength=[],this._storedFields=new Map,this._nextId=0}}discard(t){const e=this._idToShortId.get(t);if(null==e)throw new Error(`MiniSearch: cannot discard document with ID ${t}: it is not in the index`);this._idToShortId.delete(t),this._documentIds.delete(e),this._storedFields.delete(e),(this._fieldLength.get(e)||[]).forEach(((t,s)=>{this.removeFieldLength(e,s,this._documentCount,t)})),this._fieldLength.delete(e),this._documentCount-=1,this._dirtCount+=1,this.maybeAutoVacuum()}maybeAutoVacuum(){if(!1===this._options.autoVacuum)return;const{minDirtFactor:t,minDirtCount:e,batchSize:s,batchWait:i}=this._options.autoVacuum;this.conditionalVacuum({batchSize:s,batchWait:i},{minDirtCount:e,minDirtFactor:t})}discardAll(t){const e=this._options.autoVacuum;try{this._options.autoVacuum=!1;for(const e of t)this.discard(e)}finally{this._options.autoVacuum=e}this.maybeAutoVacuum()}replace(t){const{idField:e,extractField:s}=this._options,i=s(t,e);this.discard(i),this.add(t)}vacuum(t={}){return this.conditionalVacuum(t)}conditionalVacuum(t,e){return this._currentVacuum?(this._enqueuedVacuumConditions=this._enqueuedVacuumConditions&&e,null!=this._enqueuedVacuum||(this._enqueuedVacuum=this._currentVacuum.then((()=>{const e=this._enqueuedVacuumConditions;return this._enqueuedVacuumConditions=I,this.performVacuuming(t,e)}))),this._enqueuedVacuum):!1===this.vacuumConditionsMet(e)?Promise.resolve():(this._currentVacuum=this.performVacuuming(t),this._currentVacuum)}performVacuuming(e,s){return t(this,void 0,void 0,(function*(){const t=this._dirtCount;if(this.vacuumConditionsMet(s)){const s=e.batchSize||S.batchSize,i=e.batchWait||S.batchWait;let n=1;for(const[t,e]of this._index){for(const[t,s]of e)for(const[i]of s)this._documentIds.has(i)||(s.size<=1?e.delete(t):s.delete(i));0===this._index.get(t).size&&this._index.delete(t),n%s==0&&(yield new Promise((t=>setTimeout(t,i)))),n+=1}this._dirtCount-=t}yield null,this._currentVacuum=this._enqueuedVacuum,this._enqueuedVacuum=null}))}vacuumConditionsMet(t){if(null==t)return!0;let{minDirtCount:e,minDirtFactor:s}=t;return e=e||O.minDirtCount,s=s||O.minDirtFactor,this.dirtCount>=e&&this.dirtFactor>=s}get isVacuuming(){return null!=this._currentVacuum}get dirtCount(){return this._dirtCount}get dirtFactor(){return this._dirtCount/(1+this._documentCount+this._dirtCount)}has(t){return this._idToShortId.has(t)}getStoredFields(t){const e=this._idToShortId.get(t);if(null!=e)return this._storedFields.get(e)}search(t,e={}){const{searchOptions:s}=this._options,i=Object.assign(Object.assign({},s),e),n=this.executeQuery(t,e),o=[];for(const[t,{score:e,terms:s,match:r}]of n){const n=s.length||1,c={id:this._documentIds.get(t),score:e*n,terms:Object.keys(r),queryTerms:s,match:r};Object.assign(c,this._storedFields.get(t)),(null==i.filter||i.filter(c))&&o.push(c)}return t===_.wildcard&&null==i.boostDocument||o.sort(k),o}autoSuggest(t,e={}){e=Object.assign(Object.assign({},this._options.autoSuggestOptions),e);const s=new Map;for(const{score:i,terms:n}of this.search(t,e)){const t=n.join(" "),e=s.get(t);null!=e?(e.score+=i,e.count+=1):s.set(t,{score:i,terms:n,count:1})}const i=[];for(const[t,{score:e,terms:n,count:o}]of s)i.push({suggestion:t,terms:n,score:e/o});return i.sort(k),i}get documentCount(){return this._documentCount}get termCount(){return this._index.size}static loadJSON(t,e){if(null==e)throw new Error("MiniSearch: loadJSON should be given the same options used when serializing the index");return this.loadJS(JSON.parse(t),e)}static loadJSONAsync(e,s){return t(this,void 0,void 0,(function*(){if(null==s)throw new Error("MiniSearch: loadJSON should be given the same options used when serializing the index");return this.loadJSAsync(JSON.parse(e),s)}))}static getDefault(t){if(v.hasOwnProperty(t))return p(v,t);throw new Error(`MiniSearch: unknown option "${t}"`)}static loadJS(t,e){const{index:s,documentIds:i,fieldLength:n,storedFields:o,serializationVersion:r}=t,c=this.instantiateMiniSearch(t,e);c._documentIds=j(i),c._fieldLength=j(n),c._storedFields=j(o);for(const[t,e]of c._documentIds)c._idToShortId.set(e,t);for(const[t,e]of s){const s=new Map;for(const t of Object.keys(e)){let i=e[t];1===r&&(i=i.ds),s.set(parseInt(t,10),j(i))}c._index.set(t,s)}return c}static loadJSAsync(e,s){return t(this,void 0,void 0,(function*(){const{index:t,documentIds:i,fieldLength:n,storedFields:o,serializationVersion:r}=e,c=this.instantiateMiniSearch(e,s);c._documentIds=yield V(i),c._fieldLength=yield V(n),c._storedFields=yield V(o);for(const[t,e]of c._documentIds)c._idToShortId.set(e,t);let u=0;for(const[e,s]of t){const t=new Map;for(const e of Object.keys(s)){let i=s[e];1===r&&(i=i.ds),t.set(parseInt(e,10),yield V(i))}++u%1e3==0&&(yield T(0)),c._index.set(e,t)}return c}))}static instantiateMiniSearch(t,e){const{documentCount:s,nextId:i,fieldIds:n,averageFieldLength:o,dirtCount:r,serializationVersion:u}=t;if(1!==u&&2!==u)throw new Error("MiniSearch: cannot deserialize an index created with an incompatible version");const h=new _(e);return h._documentCount=s,h._nextId=i,h._idToShortId=new Map,h._fieldIds=n,h._avgFieldLength=o,h._dirtCount=r||0,h._index=new c,h}executeQuery(t,e={}){if(t===_.wildcard)return this.executeWildcardQuery(e);if("string"!=typeof t){const s=Object.assign(Object.assign(Object.assign({},e),t),{queries:void 0}),i=t.queries.map((t=>this.executeQuery(t,s)));return this.combineResults(i,s.combineWith)}const{tokenize:s,processTerm:i,searchOptions:n}=this._options,o=Object.assign(Object.assign({tokenize:s,processTerm:i},n),e),{tokenize:r,processTerm:c}=o,u=r(t).flatMap((t=>c(t))).filter((t=>!!t)).map(b(o)).map((t=>this.executeQuerySpec(t,o)));return this.combineResults(u,o.combineWith)}executeQuerySpec(t,e){const s=Object.assign(Object.assign({},this._options.searchOptions),e),i=(s.fields||this._options.fields).reduce(((t,e)=>Object.assign(Object.assign({},t),{[e]:p(s.boost,e)||1})),{}),{boostDocument:n,weights:o,maxFuzzy:r,bm25:c}=s,{fuzzy:u,prefix:h}=Object.assign(Object.assign({},x.weights),o),d=this._index.get(t.term),a=this.termResults(t.term,t.term,1,t.termBoost,d,i,n,c);let l,f;if(t.prefix&&(l=this._index.atPrefix(t.term)),t.fuzzy){const e=!0===t.fuzzy?.2:t.fuzzy,s=e<1?Math.min(r,Math.round(t.term.length*e)):e;s&&(f=this._index.fuzzyGet(t.term,s))}if(l)for(const[e,s]of l){const o=e.length-t.term.length;if(!o)continue;null==f||f.delete(e);const r=h*e.length/(e.length+.3*o);this.termResults(t.term,e,r,t.termBoost,s,i,n,c,a)}if(f)for(const e of f.keys()){const[s,o]=f.get(e);if(!o)continue;const r=u*e.length/(e.length+o);this.termResults(t.term,e,r,t.termBoost,s,i,n,c,a)}return a}executeWildcardQuery(t){const e=new Map,s=Object.assign(Object.assign({},this._options.searchOptions),t);for(const[t,i]of this._documentIds){const n=s.boostDocument?s.boostDocument(i,"",this._storedFields.get(t)):1;e.set(t,{score:n,terms:[],match:{}})}return e}combineResults(t,e=g){if(0===t.length)return new Map;const s=e.toLowerCase(),i=y[s];if(!i)throw new Error(`Invalid combination operator: ${e}`);return t.reduce(i)||new Map}toJSON(){const t=[];for(const[e,s]of this._index){const i={};for(const[t,e]of s)i[t]=Object.fromEntries(e);t.push([e,i])}return{documentCount:this._documentCount,nextId:this._nextId,documentIds:Object.fromEntries(this._documentIds),fieldIds:this._fieldIds,fieldLength:Object.fromEntries(this._fieldLength),averageFieldLength:this._avgFieldLength,storedFields:Object.fromEntries(this._storedFields),dirtCount:this._dirtCount,index:t,serializationVersion:2}}termResults(t,e,s,i,n,o,r,c,u=new Map){if(null==n)return u;for(const h of Object.keys(o)){const d=o[h],a=this._fieldIds[h],l=n.get(a);if(null==l)continue;let f=l.size;const m=this._avgFieldLength[a];for(const n of l.keys()){if(!this._documentIds.has(n)){this.removeTerm(a,n,e),f-=1;continue}const o=r?r(this._documentIds.get(n),e,this._storedFields.get(n)):1;if(!o)continue;const g=l.get(n),_=this._fieldLength.get(n)[a],y=s*i*d*o*w(g,f,this._documentCount,_,m,c),b=u.get(n);if(b){b.score+=y,F(b.terms,t);const s=p(b.match,e);s?s.push(h):b.match[e]=[h]}else u.set(n,{score:y,terms:[t],match:{[e]:[h]}})}}return u}addTerm(t,e,s){const i=this._index.fetch(s,C);let n=i.get(t);if(null==n)n=new Map,n.set(e,1),i.set(t,n);else{const t=n.get(e);n.set(e,(t||0)+1)}}removeTerm(t,e,s){if(!this._index.has(s))return void this.warnDocumentChanged(e,t,s);const i=this._index.fetch(s,C),n=i.get(t);null==n||null==n.get(e)?this.warnDocumentChanged(e,t,s):n.get(e)<=1?n.size<=1?i.delete(t):n.delete(e):n.set(e,n.get(e)-1),0===this._index.get(s).size&&this._index.delete(s)}warnDocumentChanged(t,e,s){for(const i of Object.keys(this._fieldIds))if(this._fieldIds[i]===e)return void this._options.logger("warn",`MiniSearch: document with ID ${this._documentIds.get(t)} has changed before removal: term "${s}" was not present in field "${i}". Removing a document after it has changed can corrupt the index!`,"version_conflict")}addDocumentId(t){const e=this._nextId;return this._idToShortId.set(t,e),this._documentIds.set(e,t),this._documentCount+=1,this._nextId+=1,e}addFields(t){for(let e=0;eObject.prototype.hasOwnProperty.call(t,e)?t[e]:void 0,y={[g]:(t,e)=>{for(const s of e.keys()){const i=t.get(s);if(null==i)t.set(s,e.get(s));else{const{score:t,terms:n,match:o}=e.get(s);i.score=i.score+t,i.match=Object.assign(i.match,o),M(i.terms,n)}}return t},and:(t,e)=>{const s=new Map;for(const i of e.keys()){const n=t.get(i);if(null==n)continue;const{score:o,terms:r,match:c}=e.get(i);M(n.terms,r),s.set(i,{score:n.score+o,terms:n.terms,match:Object.assign(n.match,c)})}return s},and_not:(t,e)=>{for(const s of e.keys())t.delete(s);return t}},w=(t,e,s,i,n,o)=>{const{k:r,b:c,d:u}=o;return Math.log(1+(s-e+.5)/(e+.5))*(u+t*(r+1)/(t+r*(1-c+c*i/n)))},b=t=>(e,s,i)=>({term:e,fuzzy:"function"==typeof t.fuzzy?t.fuzzy(e,s,i):t.fuzzy||!1,prefix:"function"==typeof t.prefix?t.prefix(e,s,i):!0===t.prefix,termBoost:"function"==typeof t.boostTerm?t.boostTerm(e,s,i):1}),v={idField:"id",extractField:(t,e)=>t[e],tokenize:t=>t.split(L),processTerm:t=>t.toLowerCase(),fields:void 0,searchOptions:void 0,storeFields:[],logger:(t,e)=>{"function"==typeof(null===console||void 0===console?void 0:console[t])&&console[t](e)},autoVacuum:!0},x={combineWith:g,prefix:!1,fuzzy:!1,maxFuzzy:6,boost:{},weights:{fuzzy:.45,prefix:.375},bm25:{k:1.2,b:.7,d:.5}},z={combineWith:"and",prefix:(t,e,s)=>e===s.length-1},S={batchSize:1e3,batchWait:10},I={minDirtFactor:.1,minDirtCount:20},O=Object.assign(Object.assign({},S),I),F=(t,e)=>{t.includes(e)||t.push(e)},M=(t,e)=>{for(const s of e)t.includes(s)||t.push(s)},k=({score:t},{score:e})=>e-t,C=()=>new Map,j=t=>{const e=new Map;for(const s of Object.keys(t))e.set(parseInt(s,10),t[s]);return e},V=e=>t(void 0,void 0,void 0,(function*(){const t=new Map;let s=0;for(const i of Object.keys(e))t.set(parseInt(i,10),e[i]),++s%1e3==0&&(yield T(0));return t})),T=t=>new Promise((e=>setTimeout(e,t))),L=/[\n\r\p{Z}\p{P}]+/u;return _})); +//# sourceMappingURL=/sm/0f05ede3003a11c0848176daa6dae791d4aa6c5c93da9e99ae929f75084ce0d0.map \ No newline at end of file diff --git a/CoreHelp/src/au/gov/asd/tac/constellation/help/ConstellationHelpDisplayer.java b/CoreHelp/src/au/gov/asd/tac/constellation/help/ConstellationHelpDisplayer.java index 1670521c89..386691b510 100644 --- a/CoreHelp/src/au/gov/asd/tac/constellation/help/ConstellationHelpDisplayer.java +++ b/CoreHelp/src/au/gov/asd/tac/constellation/help/ConstellationHelpDisplayer.java @@ -18,13 +18,11 @@ import au.gov.asd.tac.constellation.help.preferences.HelpPreferenceKeys; import au.gov.asd.tac.constellation.help.utilities.Generator; import au.gov.asd.tac.constellation.help.utilities.HelpMapper; -import org.commonmark.node.Node; -import org.commonmark.parser.Parser; -import org.commonmark.renderer.html.HtmlRenderer; import java.awt.Desktop; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -35,13 +33,19 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.Logger; import java.util.prefs.Preferences; +import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; +import org.commonmark.node.Node; +import org.commonmark.parser.Parser; +import org.commonmark.renderer.html.HtmlRenderer; import org.openide.util.HelpCtx; import org.openide.util.NbPreferences; import org.openide.util.lookup.ServiceProvider; @@ -58,14 +62,15 @@ public class ConstellationHelpDisplayer implements HelpCtx.Displayer { private static final String OFFICIAL_CONSTELLATION_WEBSITE = "https://www.constellation-app.com/help"; private static final String NEWLINE = "\n"; + private static final Pattern SPLIT_REGEX = Pattern.compile(""); + private static final String SEP = File.separator; // Run in a different thread, not the JavaFX thread private static final ExecutorService pluginExecutor = Executors.newCachedThreadPool(); public static void copy(final String filePath, final OutputStream out) throws IOException { - final String sep = File.separator; final InputStream pageInput = getInputStream(filePath); - final InputStream tocInput = getInputStream(Generator.getBaseDirectory() + sep + Generator.getTOCDirectory()); + final InputStream tocInput = getInputStream(Generator.getBaseDirectory() + SEP + Generator.getTOCDirectory()); // avoid parsing utility files or images into html if (filePath.contains(".css") || filePath.contains(".js") || filePath.contains(".png") || filePath.contains(".jpg")) { @@ -73,7 +78,7 @@ public static void copy(final String filePath, final OutputStream out) throws IO return; } - out.write(generateHTMLOutput(sep, tocInput, pageInput).getBytes()); + out.write(generateHTMLOutput(tocInput, pageInput).getBytes()); } protected static InputStream getInputStream(final String filePath) throws FileNotFoundException { @@ -105,180 +110,86 @@ protected static String getPathString(final String helpFilePath) { * Generate a String which represents the table of contents, the currently displayed page, and the necessary html * tags for formatting. * - * @param separator * @param tocInput * @param pageInput * @return * @throws IOException */ - protected static String generateHTMLOutput(final String separator, final InputStream tocInput, final InputStream pageInput) throws IOException { + protected static String generateHTMLOutput(final InputStream tocInput, final InputStream pageInput) throws IOException { final StringBuilder html = new StringBuilder(); - - // HTML elements - final String startRowDiv = "
    "; - final String endDiv = "
    "; - final String startColDiv = "
    "; - final String startInnerColDiv = "
    "; + + final InputStream htmlTemplate = getInputStream(Generator.getBaseDirectory() + SEP + "ext" + SEP + "bootstrap" + SEP + "assets" + SEP + "HelpTemplate.html"); + final String templateHtml = new String(htmlTemplate.readAllBytes(), StandardCharsets.UTF_8); + html.append(templateHtml); + + // Create the css and js links and scripts final String stylesheetLink = ""; final String javascriptText = ""; - - final String css = String.format(stylesheetLink, getFileURLString(separator, Generator.getBaseDirectory(), "ext/bootstrap/assets/css/app.css")); - final String noScript = String.format(stylesheetLink, getFileURLString(separator, Generator.getBaseDirectory(), "ext/bootstrap/assets/css/noscript.css")); - final String cssBootstrap = String.format(stylesheetLink, getFileURLString(separator, Generator.getBaseDirectory(), "ext/bootstrap/css/bootstrap.css")); - final String jquery = String.format("", getFileURLString(separator, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/jquery.min.js")); - final String dropotron = String.format(javascriptText, getFileURLString(separator, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/jquery.dropotron.min.js")); - final String scrolly = String.format(javascriptText, getFileURLString(separator, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/jquery.scrolly.min.js")); - final String scrollex = String.format(javascriptText, getFileURLString(separator, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/jquery.scrollex.min.js")); - final String browser = String.format(javascriptText, getFileURLString(separator, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/browser.min.js")); - final String breakpoints = String.format(javascriptText, getFileURLString(separator, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/breakpoints.min.js")); - final String appJS = String.format(javascriptText, getFileURLString(separator, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/app.js")); - final String boostrapjs = String.format(javascriptText, getFileURLString(separator, Generator.getBaseDirectory(), "ext/bootstrap/js/bootstrap.js")); - final String cookiejs = String.format("", getFileURLString(separator, Generator.getBaseDirectory(), "ext/bootstrap/js/js.cookie.min.js")); - - final String scriptTag = ""; - - // Add items to StringBuilder - html.append(css); - html.append(NEWLINE); - html.append(noScript); - html.append(NEWLINE); - html.append(cssBootstrap); - html.append(NEWLINE); - html.append(jquery); - html.append(NEWLINE); - html.append(cookiejs); - html.append(NEWLINE); - html.append(dropotron); - html.append(NEWLINE); - html.append(scrolly); - html.append(NEWLINE); - html.append(scrollex); - html.append(NEWLINE); - html.append(browser); - html.append(NEWLINE); - html.append(breakpoints); - html.append(NEWLINE); - html.append(appJS); - html.append(NEWLINE); - html.append(boostrapjs); - html.append(NEWLINE); - html.append(startRowDiv); - html.append(NEWLINE); - html.append(startColDiv); - html.append(NEWLINE); + + final String css = String.format(stylesheetLink, getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/assets/css/app.css")); + final String noScript = String.format(stylesheetLink, getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/assets/css/noscript.css")); + final String cssBootstrap = String.format(stylesheetLink, getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/css/bootstrap.css")); + final String searchcss = String.format(stylesheetLink, getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/assets/css/search.css")); + final String jquery = String.format("", getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/jquery.min.js")); + final String dropotron = String.format(javascriptText, getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/jquery.dropotron.min.js")); + final String scrolly = String.format(javascriptText, getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/jquery.scrolly.min.js")); + final String scrollex = String.format(javascriptText, getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/jquery.scrollex.min.js")); + final String browser = String.format(javascriptText, getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/browser.min.js")); + final String breakpoints = String.format(javascriptText, getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/breakpoints.min.js")); + final String appJS = String.format(javascriptText, getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/assets/js/app.js")); + final String bootstrapjs = String.format(javascriptText, getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/js/bootstrap.js")); + final String cookiejs = String.format("", getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/js/js.cookie.min.js")); + final String searchjs = String.format(javascriptText, getFileURLString(SEP, Generator.getBaseDirectory(), "ext/bootstrap/js/index.min.js")); + + final StringBuilder scripts = new StringBuilder(); + scripts.append(css).append(NEWLINE); + scripts.append(noScript).append(NEWLINE); + scripts.append(cssBootstrap).append(NEWLINE); + scripts.append(searchcss).append(NEWLINE); + scripts.append(jquery).append(NEWLINE); + scripts.append(dropotron).append(NEWLINE); + scripts.append(scrolly).append(NEWLINE); + scripts.append(scrollex).append(NEWLINE); + scripts.append(browser).append(NEWLINE); + scripts.append(breakpoints).append(NEWLINE); + scripts.append(appJS).append(NEWLINE); + scripts.append(bootstrapjs).append(NEWLINE); + scripts.append(cookiejs).append(NEWLINE); + scripts.append(searchjs).append(NEWLINE); + + // Add in the links and scripts to the top of the file + final int scriptIndex = html.indexOf("SCRIPTS"); + html.replace(scriptIndex, scriptIndex + 7, scripts.toString()); + + + // Add in the TOC final String tocString = new String(tocInput.readAllBytes(), StandardCharsets.UTF_8); final Parser parser = Parser.builder().build(); final HtmlRenderer renderer = HtmlRenderer.builder().build(); final Node tocDocument = parser.parse(tocString); final String tocHtml = renderer.render(tocDocument); - html.append(tocHtml); - html.append(NEWLINE); - html.append(endDiv); - html.append(NEWLINE); - html.append(startInnerColDiv); - html.append(NEWLINE); + final int tocIndex = html.indexOf("TABLE_OF_CONTENTS"); + html.replace(tocIndex, tocIndex + 17, tocHtml); + + // Add in the help page final String rawInput = new String(pageInput.readAllBytes(), StandardCharsets.UTF_8); final Node pageDocument = parser.parse(rawInput); final String pageHtml = renderer.render(pageDocument); - html.append(pageHtml); - html.append(NEWLINE); - html.append(endDiv); - html.append(NEWLINE); - html.append(endDiv); - html.append(NEWLINE); - html.append(endDiv); - html.append(NEWLINE); - html.append(scriptTag); - - String htmlString = html.toString(); - final int headTagIndex = htmlString.indexOf(" -1) { - insertPos = htmlString.substring(headTagIndex).indexOf(">") + headTagIndex + 1; + final int pageIndex = html.indexOf("MAIN_PAGE"); + html.replace(pageIndex, pageIndex + 9, pageHtml); + + // Add in the list of documents to search + final List documents = createSearchDocument(tocHtml); + final StringBuilder documentString = new StringBuilder(); + documentString.append(documents.getFirst()); + for (int i = 1; i < documents.size(); i++) { + documentString.append(","); + documentString.append(documents.get(i)); } - final int metaIndex = htmlString.indexOf("" + htmlString.substring(insertPos); - } else { - // check the meta tag - final int metaTagEnd = htmlString.substring(metaIndex).indexOf(">"); - String metaString = htmlString.substring(metaIndex, metaIndex + metaTagEnd + 1); - final int contentIndex = metaString.indexOf("content=\""); - if (contentIndex > -1) { - final int endContentPos = metaString.substring(contentIndex+9).indexOf("\""); - String contentString = metaString.substring(contentIndex + 9, contentIndex + 9 + endContentPos); - final int charsetIndex = contentString.indexOf("charset="); - if (charsetIndex > -1) { - // find end of charset info and overwrite it - int charsetEndIndex = contentString.substring(charsetIndex).indexOf(";"); - // a value of -1 means id was the last entry of the content attribute - if (charsetEndIndex == -1) { - charsetEndIndex = contentString.length(); - } - // replace the charset value with utf-8 - contentString = contentString.substring(0, charsetIndex + 8) + "utf-8" + contentString.substring(charsetEndIndex); - } else { - // no charset specified in the content attribute, add it to the content string - contentString = contentString + "; charset=utf-8"; - } - // insert new content string into metastring - metaString = metaString.substring(0, contentIndex + 9) + contentString + metaString.substring(contentIndex + 9 + endContentPos); - } else { - // no content attribute - // check for charset attribute - final int charsetAttrIndex = metaString.indexOf("charset=\""); - if (charsetAttrIndex > -1) { - int charsetEndIndex = metaString.substring(charsetAttrIndex + 9).indexOf("\""); - if (charsetEndIndex > -1) { - // put utf-8 in the charset string - metaString = metaString.substring(0, charsetAttrIndex + 9) + "utf-8" + metaString.substring(charsetAttrIndex + 9 + charsetEndIndex); - } - } else { - // add a content attribute to the metaString - metaString = metaString.substring(0, metaString.lastIndexOf("\"") + 1) + " content=\"text/html; charset=utf-8\">"; - } - } - // insert the new/updated metastring into htmlString - final String nonMetaHtml = htmlString.substring(0, metaIndex) + htmlString.substring(metaIndex + metaTagEnd + 1); - htmlString = nonMetaHtml.substring(0, insertPos) + metaString + nonMetaHtml.substring(insertPos); - } - return htmlString; + final int documentsIndex = html.indexOf("HELP_PAGES"); + html.replace(documentsIndex, documentsIndex + 10, documentString.toString()); + + return html.toString(); } /** @@ -289,16 +200,14 @@ protected static String generateHTMLOutput(final String separator, final InputSt */ @Override public boolean display(final HelpCtx helpCtx) { - final String sep = File.separator; - final Preferences prefs = NbPreferences.forModule(HelpPreferenceKeys.class); final boolean isOnline = prefs.getBoolean(HelpPreferenceKeys.HELP_KEY, HelpPreferenceKeys.ONLINE_HELP); final String helpId = helpCtx.getHelpID(); LOGGER.log(Level.INFO, "display help for: {0}", helpId); - final String helpDefaultPath = sep + "ext" + sep + "docs" + sep + "CoreFunctionality" + sep + "src" + sep + "au" + sep + "gov" - + sep + "asd" + sep + "tac" + sep + "constellation" + sep + "functionality" + sep + "about-constellation.md"; + final String helpDefaultPath = SEP + "ext" + SEP + "docs" + SEP + "CoreFunctionality" + SEP + "src" + SEP + "au" + SEP + "gov" + + SEP + "asd" + SEP + "tac" + SEP + "constellation" + SEP + "functionality" + SEP + "about-constellation.md"; final String helpAddress = HelpMapper.getHelpAddress(helpId); // use the requested help file, or the About Constellation page if one is not given @@ -312,7 +221,7 @@ public boolean display(final HelpCtx helpCtx) { } url = OFFICIAL_CONSTELLATION_WEBSITE + helpLink.replace(".md", ".html"); } else { - final File file = new File(Generator.getBaseDirectory() + sep + helpLink); + final File file = new File(Generator.getBaseDirectory() + SEP + helpLink); final URL fileUrl = file.toURI().toURL(); final int currentPort = HelpWebServer.start(); url = String.format("http://localhost:%d/%s", currentPort, fileUrl); @@ -352,4 +261,74 @@ public static Future browse(final URI uri) { } }); } + + public static List createSearchDocument(final String toc) { + // Creates json file of documents to search + // Each entry has an id, title, category and link + final List documents = new ArrayList<>(); + + final String[] elements = SPLIT_REGEX.split(toc); + int index = 0; + String category = ""; + String pageName = ""; + String link = ""; + + for (final String element : elements) { + if (element.contains("data-target")) { + final int dataIndex = element.indexOf("data-target"); + final String categoryString = element.substring(dataIndex); + final int beginningIndex = categoryString.indexOf(">"); + final int endIndex = categoryString.indexOf("<"); + category = categoryString.substring(beginningIndex + 1, endIndex); + } + if (element.contains("a href")) { + final int hrefIndex = element.indexOf("a href"); + final String linkString = element.substring(hrefIndex + 7); + final int quoteIndex = linkString.indexOf("\""); + final int endIndex = linkString.indexOf(">"); + link = linkString.substring(quoteIndex + 1, endIndex - 1); + // Changing this to a replace instead of replaceAll stops the search from working as the links require double \ + link = link.replaceAll("\\\\", "\\\\\\\\"); + pageName = linkString.substring(endIndex + 1); + + final String page = String.format(""" + { + "id": %s, + "title": "%s", + "category": "%s", + "link": "%s" + } + """, index, pageName, category, link); + documents.add(page); + index++; + + } + } + + // To update the online help search file change the boolean to true + // Must also run adaptors when updating online help so those results aren't removed from the search file + // Reset back to false after updating the search file + final boolean updateOnlineHelp = false; + + if (updateOnlineHelp) { + // Create a json file for the online help search + final String path = Generator.getOnlineHelpTOCDirectory(Generator.getBaseDirectory()) + "search.json"; + try (final FileWriter search = new FileWriter(path)) { + final StringBuilder documentString = new StringBuilder(); + documentString.append("["); + documentString.append(documents.getFirst()); + for (int i = 1; i < documents.size(); i++) { + documentString.append(","); + documentString.append(documents.get(i)); + } + documentString.append("]"); + search.write(documentString.toString()); + + } catch (final IOException ex) { + LOGGER.log(Level.SEVERE, ex.getLocalizedMessage()); + } + } + + return documents; + } } diff --git a/CoreHelp/src/au/gov/asd/tac/constellation/help/utilities/Generator.java b/CoreHelp/src/au/gov/asd/tac/constellation/help/utilities/Generator.java index 093bffb21a..c9bb6652d9 100644 --- a/CoreHelp/src/au/gov/asd/tac/constellation/help/utilities/Generator.java +++ b/CoreHelp/src/au/gov/asd/tac/constellation/help/utilities/Generator.java @@ -77,7 +77,7 @@ public void run() { final boolean updateOnlineHelp = false; if (updateOnlineHelp) { - onlineTocDirectory = getOnlineHelpTOCDirectory(baseDirectory); + onlineTocDirectory = getOnlineHelpTOCDirectory(baseDirectory) + TOC_FILE_NAME; // First: create the TOCFile in the base directory for ONLINE help // Create the online root node for application-wide table of contents @@ -106,7 +106,7 @@ public void run() { } /** - * get the directory that the table of contents is saved to + * Get the directory that the table of contents is saved to * * @return a String path for the file location */ @@ -116,7 +116,7 @@ public static String getTOCDirectory() { } /** - * get a list of the xml files using a lookup + * Get a list of the xml files using a lookup * * @param baseDirectory * @return @@ -168,19 +168,14 @@ protected static String getResource() throws IllegalArgumentException { return newPath != null ? newPath + File.separator + "ext" : ""; } - protected static String getOnlineHelpTOCDirectory(final String filePath) { + public static String getOnlineHelpTOCDirectory(final String filePath) { // include "modules" in the check, because looking for "constellation" alone can match earlier in the path // ie. /home/constellation/test/rc1/constellation/modules/ext/ int index = filePath.indexOf("constellation" + File.separator + "modules"); if (index <= 0) { index = filePath.indexOf("constellation" + File.separator); } - if (index <= 0) { - return filePath + TOC_FILE_NAME; - } else { - final String newPath = filePath.substring(0, index + 14); - return newPath + TOC_FILE_NAME; - } + return index <= 0 ? filePath : filePath.substring(0, index + 14); } } diff --git a/CoreHelp/test/unit/src/au/gov/asd/tac/constellation/help/ConstellationHelpDisplayerNGTest.java b/CoreHelp/test/unit/src/au/gov/asd/tac/constellation/help/ConstellationHelpDisplayerNGTest.java index 64cfd7a90b..f5b992e832 100644 --- a/CoreHelp/test/unit/src/au/gov/asd/tac/constellation/help/ConstellationHelpDisplayerNGTest.java +++ b/CoreHelp/test/unit/src/au/gov/asd/tac/constellation/help/ConstellationHelpDisplayerNGTest.java @@ -127,7 +127,7 @@ public void testCopy() { try (MockedStatic mockedHelpDisplayerStatic = Mockito.mockStatic(ConstellationHelpDisplayer.class)) { mockedHelpDisplayerStatic.when(() -> ConstellationHelpDisplayer.copy(Mockito.anyString(), Mockito.any())).thenCallRealMethod(); mockedHelpDisplayerStatic.when(() -> ConstellationHelpDisplayer.getInputStream(Mockito.anyString())).thenCallRealMethod(); - mockedHelpDisplayerStatic.when(() -> ConstellationHelpDisplayer.generateHTMLOutput(Mockito.anyString(), Mockito.any(), Mockito.any())).thenReturn(returnHTML); + mockedHelpDisplayerStatic.when(() -> ConstellationHelpDisplayer.generateHTMLOutput(Mockito.any(), Mockito.any())).thenReturn(returnHTML); ConstellationHelpDisplayer.copy(filePath, out); out.flush(); @@ -175,7 +175,7 @@ public void testCopyReturnEarly() throws IOException { try (MockedStatic mockedHelpDisplayerStatic2 = Mockito.mockStatic(ConstellationHelpDisplayer.class)) { mockedHelpDisplayerStatic2.when(() -> ConstellationHelpDisplayer.copy(Mockito.anyString(), Mockito.any())).thenCallRealMethod(); mockedHelpDisplayerStatic2.when(() -> ConstellationHelpDisplayer.getInputStream(Mockito.anyString())).thenReturn(fis); - mockedHelpDisplayerStatic2.when(() -> ConstellationHelpDisplayer.generateHTMLOutput(Mockito.anyString(), Mockito.any(), Mockito.any())).thenReturn(""); + mockedHelpDisplayerStatic2.when(() -> ConstellationHelpDisplayer.generateHTMLOutput(Mockito.any(), Mockito.any())).thenReturn(""); ConstellationHelpDisplayer.copy("anypath.css", os); mockedHelpDisplayerStatic2.verify(() -> ConstellationHelpDisplayer.getInputStream(Mockito.anyString()), times(2)); @@ -186,11 +186,11 @@ public void testCopyReturnEarly() throws IOException { try (MockedStatic mockedHelpDisplayerStatic3 = Mockito.mockStatic(ConstellationHelpDisplayer.class)) { mockedHelpDisplayerStatic3.when(() -> ConstellationHelpDisplayer.copy(Mockito.anyString(), Mockito.any())).thenCallRealMethod(); mockedHelpDisplayerStatic3.when(() -> ConstellationHelpDisplayer.getInputStream(Mockito.anyString())).thenReturn(fis); - mockedHelpDisplayerStatic3.when(() -> ConstellationHelpDisplayer.generateHTMLOutput(Mockito.anyString(), Mockito.any(), Mockito.any())).thenReturn(""); + mockedHelpDisplayerStatic3.when(() -> ConstellationHelpDisplayer.generateHTMLOutput(Mockito.any(), Mockito.any())).thenReturn(""); ConstellationHelpDisplayer.copy("anypath.txt", os); mockedHelpDisplayerStatic3.verify(() -> ConstellationHelpDisplayer.getInputStream(Mockito.anyString()), times(2)); - mockedHelpDisplayerStatic3.verify(() -> ConstellationHelpDisplayer.generateHTMLOutput(Mockito.anyString(), Mockito.eq(fis), Mockito.eq(fis)), times(1)); + mockedHelpDisplayerStatic3.verify(() -> ConstellationHelpDisplayer.generateHTMLOutput(Mockito.eq(fis), Mockito.eq(fis)), times(1)); Mockito.verify(os, times(1)).write(Mockito.eq(arr)); } } diff --git a/CoreWhatsNewView/src/au/gov/asd/tac/constellation/views/whatsnew/whatsnew.txt b/CoreWhatsNewView/src/au/gov/asd/tac/constellation/views/whatsnew/whatsnew.txt index c0dfd174b1..caf70a7198 100644 --- a/CoreWhatsNewView/src/au/gov/asd/tac/constellation/views/whatsnew/whatsnew.txt +++ b/CoreWhatsNewView/src/au/gov/asd/tac/constellation/views/whatsnew/whatsnew.txt @@ -1,6 +1,10 @@ == 3030-12-31 Getting Started

    If you're new to Constellation, read the getting started guide.

    +== 2025-02-03 Search Added to Online and Offline Help +

    A search has been added to the help documentation to make finding help pages easier.

    +

    This search uses the names of each help page and the category they are in for the table of contents to narrow down results.

    + == 2024-12-18 Animation updates

    Direction Indicators animation moved to Animations -> Experimental.

    New Color Warp animation added to Animations -> Experimental.

    diff --git a/bootstrap/assets/css/search.css b/bootstrap/assets/css/search.css new file mode 100644 index 0000000000..8cba8e12a1 --- /dev/null +++ b/bootstrap/assets/css/search.css @@ -0,0 +1,130 @@ +.SearchBox { + position: relative; +} + +.Search { + position: relative; +} + +.Search button.clear { + position: absolute; + top: 0; + bottom: 0.2em; + right: 0.5em; + font-size: 1.5em; + line-height: 1; + z-index: 20; + border: none; + background: none; + outline: none; + margin: 0; + padding: 0; + color: black; +} + +.Search input { + position: relative; + width: 100%; + padding: 0.5em; + left: 40px; + font-size: 16px; + border: 1px solid #ccc; + border-radius: 3px; + outline: none; + color: #555; + box-shadow: none; +} + +.Search button.icon { + position: absolute; + top: 0; + bottom: 0.2em; + left: 0; + font-size: 1.5em; + line-height: 1; + z-index: 20; + border: none; + background: none; + outline: none; + margin: 0; + padding: 0; +} + +.hasResults .Explanation { + display: none; +} + +.ResultList { + margin: 1em 0 0 0; + padding: 0; + list-style: none; + flex-grow: 1; + position: relative; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; +} + +.ResultList:before { + content: ''; + display: block; + position: sticky; + z-index: 10; + left: 0; + right: 0; + top: -1px; + width: 100%; + height: 0.7em; + margin-bottom: -0.7em; + background: linear-gradient(white, rgba(255, 255, 255, 0)); +} + +.ResultList:after { + content: ''; + display: block; + position: sticky; + z-index: 10; + left: 0; + right: 0; + bottom: -1px; + width: 100%; + height: 0.7em; + margin-bottom: -0.7em; + background: linear-gradient(rgba(255, 255, 255, 0), white); +} + +.SuggestionList { + display: none; + list-style: none; + padding: 0; + border: 1px solid #ccc; + border-top: 0; + margin: 0 0 0.2em 0; + border-radius: 3px; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); + background: rgba(255, 255, 255, 0.93); + position: absolute; + z-index: 20; + left: 0; + right: 0; +} + +.hasSuggestions .SuggestionList { + display: block; +} + +.Suggestion { + padding: 0.5em 1em; + border-bottom: 1px solid #eee; +} + +.Suggestion:last-child { + border: none; +} + +.Suggestion.selected { + background: rgba(240, 240, 240, 0.95); +} + +.Suggestion:hover:not(.selected) { + background: rgba(250, 250, 250, 0.95); +} \ No newline at end of file diff --git a/bootstrap/js/index.min.js b/bootstrap/js/index.min.js new file mode 100644 index 0000000000..bb6421491b --- /dev/null +++ b/bootstrap/js/index.min.js @@ -0,0 +1,8 @@ +/** + * Minified by jsDelivr using Terser v5.19.2. + * Original file: /npm/minisearch@7.1.1/dist/umd/index.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).MiniSearch=e()}(this,(function(){"use strict";function t(t,e,s,i){return new(s||(s=Promise))((function(n,o){function r(t){try{u(i.next(t))}catch(t){o(t)}}function c(t){try{u(i.throw(t))}catch(t){o(t)}}function u(t){var e;t.done?n(t.value):(e=t.value,e instanceof s?e:new s((function(t){t(e)}))).then(r,c)}u((i=i.apply(t,e||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;const e="KEYS",s="VALUES",i="";class n{constructor(t,e){const s=t._tree,i=Array.from(s.keys());this.set=t,this._type=e,this._path=i.length>0?[{node:s,keys:i}]:[]}next(){const t=this.dive();return this.backtrack(),t}dive(){if(0===this._path.length)return{done:!0,value:void 0};const{node:t,keys:e}=o(this._path);if(o(e)===i)return{done:!1,value:this.result()};const s=t.get(o(e));return this._path.push({node:s,keys:Array.from(s.keys())}),this.dive()}backtrack(){if(0===this._path.length)return;const t=o(this._path).keys;t.pop(),t.length>0||(this._path.pop(),this.backtrack())}key(){return this.set._prefix+this._path.map((({keys:t})=>o(t))).filter((t=>t!==i)).join("")}value(){return o(this._path).node.get(i)}result(){switch(this._type){case s:return this.value();case e:return this.key();default:return[this.key(),this.value()]}}[Symbol.iterator](){return this}}const o=t=>t[t.length-1],r=(t,e,s,n,o,c,u,h)=>{const d=c*u;t:for(const a of t.keys())if(a===i){const e=o[d-1];e<=s&&n.set(h,[t.get(a),e])}else{let i=c;for(let t=0;ts)continue t}r(t.get(a),e,s,n,o,i,u,h+a)}};class c{constructor(t=new Map,e=""){this._size=void 0,this._tree=t,this._prefix=e}atPrefix(t){if(!t.startsWith(this._prefix))throw new Error("Mismatched prefix");const[e,s]=u(this._tree,t.slice(this._prefix.length));if(void 0===e){const[e,n]=m(s);for(const s of e.keys())if(s!==i&&s.startsWith(n)){const i=new Map;return i.set(s.slice(n.length),e.get(s)),new c(i,t)}}return new c(e,t)}clear(){this._size=void 0,this._tree.clear()}delete(t){return this._size=void 0,a(this._tree,t)}entries(){return new n(this,"ENTRIES")}forEach(t){for(const[e,s]of this)t(e,s,this)}fuzzyGet(t,e){return((t,e,s)=>{const i=new Map;if(void 0===e)return i;const n=e.length+1,o=n+s,c=new Uint8Array(o*n).fill(s+1);for(let t=0;t{if(0===e.length||null==t)return[t,s];for(const n of t.keys())if(n!==i&&e.startsWith(n))return s.push([t,n]),u(t.get(n),e.slice(n.length),s);return s.push([t,e]),u(void 0,"",s)},h=(t,e)=>{if(0===e.length||null==t)return t;for(const s of t.keys())if(s!==i&&e.startsWith(s))return h(t.get(s),e.slice(s.length))},d=(t,e)=>{const s=e.length;t:for(let n=0;t&&n{const[s,n]=u(t,e);if(void 0!==s)if(s.delete(i),0===s.size)l(n);else if(1===s.size){const[t,e]=s.entries().next().value;f(n,t,e)}},l=t=>{if(0===t.length)return;const[e,s]=m(t);if(e.delete(s),0===e.size)l(t.slice(0,-1));else if(1===e.size){const[s,n]=e.entries().next().value;s!==i&&f(t.slice(0,-1),s,n)}},f=(t,e,s)=>{if(0===t.length)return;const[i,n]=m(t);i.set(n+e,s),i.delete(n)},m=t=>t[t.length-1],g="or";class _{constructor(t){if(null==(null==t?void 0:t.fields))throw new Error('MiniSearch: option "fields" must be provided');const e=null==t.autoVacuum||!0===t.autoVacuum?O:t.autoVacuum;this._options=Object.assign(Object.assign(Object.assign({},v),t),{autoVacuum:e,searchOptions:Object.assign(Object.assign({},x),t.searchOptions||{}),autoSuggestOptions:Object.assign(Object.assign({},z),t.autoSuggestOptions||{})}),this._index=new c,this._documentCount=0,this._documentIds=new Map,this._idToShortId=new Map,this._fieldIds={},this._fieldLength=new Map,this._avgFieldLength=[],this._nextId=0,this._storedFields=new Map,this._dirtCount=0,this._currentVacuum=null,this._enqueuedVacuum=null,this._enqueuedVacuumConditions=I,this.addFields(this._options.fields)}add(t){const{extractField:e,tokenize:s,processTerm:i,fields:n,idField:o}=this._options,r=e(t,o);if(null==r)throw new Error(`MiniSearch: document does not have ID field "${o}"`);if(this._idToShortId.has(r))throw new Error(`MiniSearch: duplicate ID ${r}`);const c=this.addDocumentId(r);this.saveStoredFields(c,t);for(const o of n){const n=e(t,o);if(null==n)continue;const r=s(n.toString(),o),u=this._fieldIds[o],h=new Set(r).size;this.addFieldLength(c,u,this._documentCount-1,h);for(const t of r){const e=i(t,o);if(Array.isArray(e))for(const t of e)this.addTerm(u,c,t);else e&&this.addTerm(u,c,e)}}}addAll(t){for(const e of t)this.add(e)}addAllAsync(t,e={}){const{chunkSize:s=10}=e,i={chunk:[],promise:Promise.resolve()},{chunk:n,promise:o}=t.reduce((({chunk:t,promise:e},i,n)=>(t.push(i),(n+1)%s==0?{chunk:[],promise:e.then((()=>new Promise((t=>setTimeout(t,0))))).then((()=>this.addAll(t)))}:{chunk:t,promise:e})),i);return o.then((()=>this.addAll(n)))}remove(t){const{tokenize:e,processTerm:s,extractField:i,fields:n,idField:o}=this._options,r=i(t,o);if(null==r)throw new Error(`MiniSearch: document does not have ID field "${o}"`);const c=this._idToShortId.get(r);if(null==c)throw new Error(`MiniSearch: cannot remove document with ID ${r}: it is not in the index`);for(const o of n){const n=i(t,o);if(null==n)continue;const r=e(n.toString(),o),u=this._fieldIds[o],h=new Set(r).size;this.removeFieldLength(c,u,this._documentCount,h);for(const t of r){const e=s(t,o);if(Array.isArray(e))for(const t of e)this.removeTerm(u,c,t);else e&&this.removeTerm(u,c,e)}}this._storedFields.delete(c),this._documentIds.delete(c),this._idToShortId.delete(r),this._fieldLength.delete(c),this._documentCount-=1}removeAll(t){if(t)for(const e of t)this.remove(e);else{if(arguments.length>0)throw new Error("Expected documents to be present. Omit the argument to remove all documents.");this._index=new c,this._documentCount=0,this._documentIds=new Map,this._idToShortId=new Map,this._fieldLength=new Map,this._avgFieldLength=[],this._storedFields=new Map,this._nextId=0}}discard(t){const e=this._idToShortId.get(t);if(null==e)throw new Error(`MiniSearch: cannot discard document with ID ${t}: it is not in the index`);this._idToShortId.delete(t),this._documentIds.delete(e),this._storedFields.delete(e),(this._fieldLength.get(e)||[]).forEach(((t,s)=>{this.removeFieldLength(e,s,this._documentCount,t)})),this._fieldLength.delete(e),this._documentCount-=1,this._dirtCount+=1,this.maybeAutoVacuum()}maybeAutoVacuum(){if(!1===this._options.autoVacuum)return;const{minDirtFactor:t,minDirtCount:e,batchSize:s,batchWait:i}=this._options.autoVacuum;this.conditionalVacuum({batchSize:s,batchWait:i},{minDirtCount:e,minDirtFactor:t})}discardAll(t){const e=this._options.autoVacuum;try{this._options.autoVacuum=!1;for(const e of t)this.discard(e)}finally{this._options.autoVacuum=e}this.maybeAutoVacuum()}replace(t){const{idField:e,extractField:s}=this._options,i=s(t,e);this.discard(i),this.add(t)}vacuum(t={}){return this.conditionalVacuum(t)}conditionalVacuum(t,e){return this._currentVacuum?(this._enqueuedVacuumConditions=this._enqueuedVacuumConditions&&e,null!=this._enqueuedVacuum||(this._enqueuedVacuum=this._currentVacuum.then((()=>{const e=this._enqueuedVacuumConditions;return this._enqueuedVacuumConditions=I,this.performVacuuming(t,e)}))),this._enqueuedVacuum):!1===this.vacuumConditionsMet(e)?Promise.resolve():(this._currentVacuum=this.performVacuuming(t),this._currentVacuum)}performVacuuming(e,s){return t(this,void 0,void 0,(function*(){const t=this._dirtCount;if(this.vacuumConditionsMet(s)){const s=e.batchSize||S.batchSize,i=e.batchWait||S.batchWait;let n=1;for(const[t,e]of this._index){for(const[t,s]of e)for(const[i]of s)this._documentIds.has(i)||(s.size<=1?e.delete(t):s.delete(i));0===this._index.get(t).size&&this._index.delete(t),n%s==0&&(yield new Promise((t=>setTimeout(t,i)))),n+=1}this._dirtCount-=t}yield null,this._currentVacuum=this._enqueuedVacuum,this._enqueuedVacuum=null}))}vacuumConditionsMet(t){if(null==t)return!0;let{minDirtCount:e,minDirtFactor:s}=t;return e=e||O.minDirtCount,s=s||O.minDirtFactor,this.dirtCount>=e&&this.dirtFactor>=s}get isVacuuming(){return null!=this._currentVacuum}get dirtCount(){return this._dirtCount}get dirtFactor(){return this._dirtCount/(1+this._documentCount+this._dirtCount)}has(t){return this._idToShortId.has(t)}getStoredFields(t){const e=this._idToShortId.get(t);if(null!=e)return this._storedFields.get(e)}search(t,e={}){const{searchOptions:s}=this._options,i=Object.assign(Object.assign({},s),e),n=this.executeQuery(t,e),o=[];for(const[t,{score:e,terms:s,match:r}]of n){const n=s.length||1,c={id:this._documentIds.get(t),score:e*n,terms:Object.keys(r),queryTerms:s,match:r};Object.assign(c,this._storedFields.get(t)),(null==i.filter||i.filter(c))&&o.push(c)}return t===_.wildcard&&null==i.boostDocument||o.sort(k),o}autoSuggest(t,e={}){e=Object.assign(Object.assign({},this._options.autoSuggestOptions),e);const s=new Map;for(const{score:i,terms:n}of this.search(t,e)){const t=n.join(" "),e=s.get(t);null!=e?(e.score+=i,e.count+=1):s.set(t,{score:i,terms:n,count:1})}const i=[];for(const[t,{score:e,terms:n,count:o}]of s)i.push({suggestion:t,terms:n,score:e/o});return i.sort(k),i}get documentCount(){return this._documentCount}get termCount(){return this._index.size}static loadJSON(t,e){if(null==e)throw new Error("MiniSearch: loadJSON should be given the same options used when serializing the index");return this.loadJS(JSON.parse(t),e)}static loadJSONAsync(e,s){return t(this,void 0,void 0,(function*(){if(null==s)throw new Error("MiniSearch: loadJSON should be given the same options used when serializing the index");return this.loadJSAsync(JSON.parse(e),s)}))}static getDefault(t){if(v.hasOwnProperty(t))return p(v,t);throw new Error(`MiniSearch: unknown option "${t}"`)}static loadJS(t,e){const{index:s,documentIds:i,fieldLength:n,storedFields:o,serializationVersion:r}=t,c=this.instantiateMiniSearch(t,e);c._documentIds=j(i),c._fieldLength=j(n),c._storedFields=j(o);for(const[t,e]of c._documentIds)c._idToShortId.set(e,t);for(const[t,e]of s){const s=new Map;for(const t of Object.keys(e)){let i=e[t];1===r&&(i=i.ds),s.set(parseInt(t,10),j(i))}c._index.set(t,s)}return c}static loadJSAsync(e,s){return t(this,void 0,void 0,(function*(){const{index:t,documentIds:i,fieldLength:n,storedFields:o,serializationVersion:r}=e,c=this.instantiateMiniSearch(e,s);c._documentIds=yield V(i),c._fieldLength=yield V(n),c._storedFields=yield V(o);for(const[t,e]of c._documentIds)c._idToShortId.set(e,t);let u=0;for(const[e,s]of t){const t=new Map;for(const e of Object.keys(s)){let i=s[e];1===r&&(i=i.ds),t.set(parseInt(e,10),yield V(i))}++u%1e3==0&&(yield T(0)),c._index.set(e,t)}return c}))}static instantiateMiniSearch(t,e){const{documentCount:s,nextId:i,fieldIds:n,averageFieldLength:o,dirtCount:r,serializationVersion:u}=t;if(1!==u&&2!==u)throw new Error("MiniSearch: cannot deserialize an index created with an incompatible version");const h=new _(e);return h._documentCount=s,h._nextId=i,h._idToShortId=new Map,h._fieldIds=n,h._avgFieldLength=o,h._dirtCount=r||0,h._index=new c,h}executeQuery(t,e={}){if(t===_.wildcard)return this.executeWildcardQuery(e);if("string"!=typeof t){const s=Object.assign(Object.assign(Object.assign({},e),t),{queries:void 0}),i=t.queries.map((t=>this.executeQuery(t,s)));return this.combineResults(i,s.combineWith)}const{tokenize:s,processTerm:i,searchOptions:n}=this._options,o=Object.assign(Object.assign({tokenize:s,processTerm:i},n),e),{tokenize:r,processTerm:c}=o,u=r(t).flatMap((t=>c(t))).filter((t=>!!t)).map(b(o)).map((t=>this.executeQuerySpec(t,o)));return this.combineResults(u,o.combineWith)}executeQuerySpec(t,e){const s=Object.assign(Object.assign({},this._options.searchOptions),e),i=(s.fields||this._options.fields).reduce(((t,e)=>Object.assign(Object.assign({},t),{[e]:p(s.boost,e)||1})),{}),{boostDocument:n,weights:o,maxFuzzy:r,bm25:c}=s,{fuzzy:u,prefix:h}=Object.assign(Object.assign({},x.weights),o),d=this._index.get(t.term),a=this.termResults(t.term,t.term,1,t.termBoost,d,i,n,c);let l,f;if(t.prefix&&(l=this._index.atPrefix(t.term)),t.fuzzy){const e=!0===t.fuzzy?.2:t.fuzzy,s=e<1?Math.min(r,Math.round(t.term.length*e)):e;s&&(f=this._index.fuzzyGet(t.term,s))}if(l)for(const[e,s]of l){const o=e.length-t.term.length;if(!o)continue;null==f||f.delete(e);const r=h*e.length/(e.length+.3*o);this.termResults(t.term,e,r,t.termBoost,s,i,n,c,a)}if(f)for(const e of f.keys()){const[s,o]=f.get(e);if(!o)continue;const r=u*e.length/(e.length+o);this.termResults(t.term,e,r,t.termBoost,s,i,n,c,a)}return a}executeWildcardQuery(t){const e=new Map,s=Object.assign(Object.assign({},this._options.searchOptions),t);for(const[t,i]of this._documentIds){const n=s.boostDocument?s.boostDocument(i,"",this._storedFields.get(t)):1;e.set(t,{score:n,terms:[],match:{}})}return e}combineResults(t,e=g){if(0===t.length)return new Map;const s=e.toLowerCase(),i=y[s];if(!i)throw new Error(`Invalid combination operator: ${e}`);return t.reduce(i)||new Map}toJSON(){const t=[];for(const[e,s]of this._index){const i={};for(const[t,e]of s)i[t]=Object.fromEntries(e);t.push([e,i])}return{documentCount:this._documentCount,nextId:this._nextId,documentIds:Object.fromEntries(this._documentIds),fieldIds:this._fieldIds,fieldLength:Object.fromEntries(this._fieldLength),averageFieldLength:this._avgFieldLength,storedFields:Object.fromEntries(this._storedFields),dirtCount:this._dirtCount,index:t,serializationVersion:2}}termResults(t,e,s,i,n,o,r,c,u=new Map){if(null==n)return u;for(const h of Object.keys(o)){const d=o[h],a=this._fieldIds[h],l=n.get(a);if(null==l)continue;let f=l.size;const m=this._avgFieldLength[a];for(const n of l.keys()){if(!this._documentIds.has(n)){this.removeTerm(a,n,e),f-=1;continue}const o=r?r(this._documentIds.get(n),e,this._storedFields.get(n)):1;if(!o)continue;const g=l.get(n),_=this._fieldLength.get(n)[a],y=s*i*d*o*w(g,f,this._documentCount,_,m,c),b=u.get(n);if(b){b.score+=y,F(b.terms,t);const s=p(b.match,e);s?s.push(h):b.match[e]=[h]}else u.set(n,{score:y,terms:[t],match:{[e]:[h]}})}}return u}addTerm(t,e,s){const i=this._index.fetch(s,C);let n=i.get(t);if(null==n)n=new Map,n.set(e,1),i.set(t,n);else{const t=n.get(e);n.set(e,(t||0)+1)}}removeTerm(t,e,s){if(!this._index.has(s))return void this.warnDocumentChanged(e,t,s);const i=this._index.fetch(s,C),n=i.get(t);null==n||null==n.get(e)?this.warnDocumentChanged(e,t,s):n.get(e)<=1?n.size<=1?i.delete(t):n.delete(e):n.set(e,n.get(e)-1),0===this._index.get(s).size&&this._index.delete(s)}warnDocumentChanged(t,e,s){for(const i of Object.keys(this._fieldIds))if(this._fieldIds[i]===e)return void this._options.logger("warn",`MiniSearch: document with ID ${this._documentIds.get(t)} has changed before removal: term "${s}" was not present in field "${i}". Removing a document after it has changed can corrupt the index!`,"version_conflict")}addDocumentId(t){const e=this._nextId;return this._idToShortId.set(t,e),this._documentIds.set(e,t),this._documentCount+=1,this._nextId+=1,e}addFields(t){for(let e=0;eObject.prototype.hasOwnProperty.call(t,e)?t[e]:void 0,y={[g]:(t,e)=>{for(const s of e.keys()){const i=t.get(s);if(null==i)t.set(s,e.get(s));else{const{score:t,terms:n,match:o}=e.get(s);i.score=i.score+t,i.match=Object.assign(i.match,o),M(i.terms,n)}}return t},and:(t,e)=>{const s=new Map;for(const i of e.keys()){const n=t.get(i);if(null==n)continue;const{score:o,terms:r,match:c}=e.get(i);M(n.terms,r),s.set(i,{score:n.score+o,terms:n.terms,match:Object.assign(n.match,c)})}return s},and_not:(t,e)=>{for(const s of e.keys())t.delete(s);return t}},w=(t,e,s,i,n,o)=>{const{k:r,b:c,d:u}=o;return Math.log(1+(s-e+.5)/(e+.5))*(u+t*(r+1)/(t+r*(1-c+c*i/n)))},b=t=>(e,s,i)=>({term:e,fuzzy:"function"==typeof t.fuzzy?t.fuzzy(e,s,i):t.fuzzy||!1,prefix:"function"==typeof t.prefix?t.prefix(e,s,i):!0===t.prefix,termBoost:"function"==typeof t.boostTerm?t.boostTerm(e,s,i):1}),v={idField:"id",extractField:(t,e)=>t[e],tokenize:t=>t.split(L),processTerm:t=>t.toLowerCase(),fields:void 0,searchOptions:void 0,storeFields:[],logger:(t,e)=>{"function"==typeof(null===console||void 0===console?void 0:console[t])&&console[t](e)},autoVacuum:!0},x={combineWith:g,prefix:!1,fuzzy:!1,maxFuzzy:6,boost:{},weights:{fuzzy:.45,prefix:.375},bm25:{k:1.2,b:.7,d:.5}},z={combineWith:"and",prefix:(t,e,s)=>e===s.length-1},S={batchSize:1e3,batchWait:10},I={minDirtFactor:.1,minDirtCount:20},O=Object.assign(Object.assign({},S),I),F=(t,e)=>{t.includes(e)||t.push(e)},M=(t,e)=>{for(const s of e)t.includes(s)||t.push(s)},k=({score:t},{score:e})=>e-t,C=()=>new Map,j=t=>{const e=new Map;for(const s of Object.keys(t))e.set(parseInt(s,10),t[s]);return e},V=e=>t(void 0,void 0,void 0,(function*(){const t=new Map;let s=0;for(const i of Object.keys(e))t.set(parseInt(i,10),e[i]),++s%1e3==0&&(yield T(0));return t})),T=t=>new Promise((e=>setTimeout(e,t))),L=/[\n\r\p{Z}\p{P}]+/u;return _})); +//# sourceMappingURL=/sm/0f05ede3003a11c0848176daa6dae791d4aa6c5c93da9e99ae929f75084ce0d0.map \ No newline at end of file diff --git a/build_help.sh b/build_help.sh deleted file mode 100644 index 44e652a2bd..0000000000 --- a/build_help.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -# remove any existing markdown files -#find */src/ -path '*/docs/*' -name \*.md | -# xargs rm - -# convert html to markdown -find */src/ -path '*/docs/*' -name *.html | - while read x - do - pandoc -f html -t commonmark $x > "$x".md - done - -find */src/ -path '*/docs/*' -name *.html.md | - while read x - do - mv "$x" "${x%.html.md}".md - done - -# remove the old html files -find */src/ -path '*/docs/*' -name *.html | while read x; do rm "$x"; done - -# add files to git -git add *.html -git add *.png -git add \*.md diff --git a/move_help.sh b/move_help.sh deleted file mode 100644 index 6d79c27ae9..0000000000 --- a/move_help.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -# convert markdown to html & add headers -#find */src/ -path '*/docs/*' -name "*.md" | -# while read x -# do -# pandoc --template="onlinePandocTemplate.txt" -f commonmark -t html $x > "$x".html -# done - -#echo "renaming all .md.html to .html" -#find */src -path '*/docs/*' -name "*.md.html" | -# while read x -# do - # mv "$x" "${x%.md.html}".html - # done - - -# move all html files to the docs folder -find */src -path '*/docs/*' -name "*md" | xargs cp --parents -t HelpDocumentation - -# move all of the png & jpegs to the docs folder structure -find */src -path '*/docs/*' -name "*.png" | xargs cp --parents -t HelpDocumentation -find */src -path '*/docs/*' -name "*.jpg" | xargs cp --parents -t HelpDocumentation diff --git a/onlinePandocTemplate.txt b/onlinePandocTemplate.txt index 3988c6866b..b9493b72f7 100644 --- a/onlinePandocTemplate.txt +++ b/onlinePandocTemplate.txt @@ -6,6 +6,7 @@ + @@ -20,6 +21,7 @@ + @@ -51,6 +53,20 @@
    + +
    + + +
      +
      + $body$
      @@ -77,7 +93,7 @@ @@ -86,7 +102,6 @@ + + \ No newline at end of file diff --git a/search.json b/search.json new file mode 100644 index 0000000000..7ab970473f --- /dev/null +++ b/search.json @@ -0,0 +1,967 @@ +[{ + "id": 0, + "title": "About Constellation", + "category": "Overview", + "link": "..\\ext\\docs\\CoreFunctionality\\src\\au\\gov\\asd\\tac\\constellation\\functionality\\about-constellation.md" +} +,{ + "id": 1, + "title": "Getting Started", + "category": "Overview", + "link": "..\\ext\\docs\\CoreFunctionality\\src\\au\\gov\\asd\\tac\\constellation\\functionality\\getting-started.md" +} +,{ + "id": 2, + "title": "The Graph Window", + "category": "Overview", + "link": "..\\ext\\docs\\CoreFunctionality\\src\\au\\gov\\asd\\tac\\constellation\\functionality\\the-graph-window.md" +} +,{ + "id": 3, + "title": "The Constellation Graph Model", + "category": "Graph", + "link": "..\\ext\\docs\\CoreGraphFramework\\src\\au\\gov\\asd\\tac\\constellation\\graph\\graph-model.md" +} +,{ + "id": 4, + "title": "Attributes", + "category": "Graph", + "link": "..\\ext\\docs\\CoreGraphFramework\\src\\au\\gov\\asd\\tac\\constellation\\graph\\attributes.md" +} +,{ + "id": 5, + "title": "Types", + "category": "Graph", + "link": "..\\ext\\docs\\CoreGraphFramework\\src\\au\\gov\\asd\\tac\\constellation\\graph\\types.md" +} +,{ + "id": 6, + "title": "Schemas", + "category": "Graph", + "link": "..\\ext\\docs\\CoreGraphFramework\\src\\au\\gov\\asd\\tac\\constellation\\graph\\schemas.md" +} +,{ + "id": 7, + "title": "Expressions Framework", + "category": "Graph", + "link": "..\\ext\\docs\\CoreGraphFramework\\src\\au\\gov\\asd\\tac\\constellation\\graph\\expressions-framework.md" +} +,{ + "id": 8, + "title": "The Constellation File Format", + "category": "I/O", + "link": "..\\ext\\docs\\CoreGraphFramework\\src\\au\\gov\\asd\\tac\\constellation\\graph\\constellation-file-format.md" +} +,{ + "id": 9, + "title": "Example Constellation File Reader", + "category": "I/O", + "link": "..\\ext\\docs\\CoreGraphFramework\\src\\au\\gov\\asd\\tac\\constellation\\graph\\example-file-reader-python.md" +} +,{ + "id": 10, + "title": "Example Constellation File Writer", + "category": "I/O", + "link": "..\\ext\\docs\\CoreGraphFramework\\src\\au\\gov\\asd\\tac\\constellation\\graph\\example-file-writer-python.md" +} +,{ + "id": 11, + "title": "Autosave", + "category": "File Operations", + "link": "..\\ext\\docs\\CoreGraphFile\\src\\au\\gov\\asd\\tac\\constellation\\graph\\file\\autosave.md" +} +,{ + "id": 12, + "title": "Nebula", + "category": "File Operations", + "link": "..\\ext\\docs\\CoreGraphFile\\src\\au\\gov\\asd\\tac\\constellation\\graph\\file\\nebula.md" +} +,{ + "id": 13, + "title": "New Graph", + "category": "File Operations", + "link": "..\\ext\\docs\\CoreGraphFile\\src\\au\\gov\\asd\\tac\\constellation\\graph\\file\\new-graph.md" +} +,{ + "id": 14, + "title": "Open Graph", + "category": "File Operations", + "link": "..\\ext\\docs\\CoreGraphFile\\src\\au\\gov\\asd\\tac\\constellation\\graph\\file\\open-graph.md" +} +,{ + "id": 15, + "title": "Save Graph", + "category": "File Operations", + "link": "..\\ext\\docs\\CoreGraphFile\\src\\au\\gov\\asd\\tac\\constellation\\graph\\file\\save-graph.md" +} +,{ + "id": 16, + "title": "Add and Selection Modes", + "category": "Editing", + "link": "..\\ext\\docs\\CoreInteractiveGraph\\src\\au\\gov\\asd\\tac\\constellation\\graph\\interaction\\add-and-selection-modes.md" +} +,{ + "id": 17, + "title": "Cut, Copy, Paste", + "category": "Editing", + "link": "..\\ext\\docs\\CoreInteractiveGraph\\src\\au\\gov\\asd\\tac\\constellation\\graph\\interaction\\cut-copy-paste.md" +} +,{ + "id": 18, + "title": "Composite Nodes", + "category": "Editing", + "link": "..\\ext\\docs\\CoreInteractiveGraph\\src\\au\\gov\\asd\\tac\\constellation\\graph\\interaction\\composite-nodes.md" +} +,{ + "id": 19, + "title": "Decorators", + "category": "Visualisation", + "link": "..\\ext\\docs\\CoreUtilities\\src\\au\\gov\\asd\\tac\\constellation\\utilities\\decorators.md" +} +,{ + "id": 20, + "title": "Icons", + "category": "Visualisation", + "link": "..\\ext\\docs\\CoreUtilities\\src\\au\\gov\\asd\\tac\\constellation\\utilities\\icons.md" +} +,{ + "id": 21, + "title": "General Selection", + "category": "Selection", + "link": "..\\ext\\docs\\CoreVisualGraph\\src\\au\\gov\\asd\\tac\\constellation\\graph\\visual\\general-selection.md" +} +,{ + "id": 22, + "title": "Blaze Selection", + "category": "Selection", + "link": "..\\ext\\docs\\CoreVisualGraph\\src\\au\\gov\\asd\\tac\\constellation\\graph\\visual\\blaze-selection.md" +} +,{ + "id": 23, + "title": "Dimmed Selection", + "category": "Selection", + "link": "..\\ext\\docs\\CoreVisualGraph\\src\\au\\gov\\asd\\tac\\constellation\\graph\\visual\\dimmed-selection.md" +} +,{ + "id": 24, + "title": "Structure Selection", + "category": "Selection", + "link": "..\\ext\\docs\\CoreVisualGraph\\src\\au\\gov\\asd\\tac\\constellation\\graph\\visual\\structure-selection.md" +} +,{ + "id": 25, + "title": "Induced Subgraph", + "category": "Selection", + "link": "..\\ext\\docs\\CoreVisualGraph\\src\\au\\gov\\asd\\tac\\constellation\\graph\\visual\\induced-subgraph.md" +} +,{ + "id": 26, + "title": "Hop Out", + "category": "Selection", + "link": "..\\ext\\docs\\CoreVisualGraph\\src\\au\\gov\\asd\\tac\\constellation\\graph\\visual\\hop-out.md" +} +,{ + "id": 27, + "title": "Shortest Paths", + "category": "Selection", + "link": "..\\ext\\docs\\CoreAlgorithmPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\algorithms\\shortest-paths.md" +} +,{ + "id": 28, + "title": "Compare Graph", + "category": "Tools", + "link": "..\\ext\\docs\\CoreVisualGraph\\src\\au\\gov\\asd\\tac\\constellation\\graph\\visual\\compare-graph.md" +} +,{ + "id": 29, + "title": "Merge Nodes", + "category": "Tools", + "link": "..\\ext\\docs\\CoreVisualGraph\\src\\au\\gov\\asd\\tac\\constellation\\graph\\visual\\merge-nodes-tool.md" +} +,{ + "id": 30, + "title": "Complete With Schema", + "category": "Tools", + "link": "..\\ext\\docs\\CoreVisualSchema\\src\\au\\gov\\asd\\tac\\constellation\\graph\\schema\\visual\\complete-with-schema.md" +} +,{ + "id": 31, + "title": "Chinese Whispers", + "category": "Cluster", + "link": "..\\ext\\docs\\CoreAlgorithmPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\algorithms\\chinese-whispers.md" +} +,{ + "id": 32, + "title": "K-Truss", + "category": "Cluster", + "link": "..\\ext\\docs\\CoreAlgorithmPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\algorithms\\k-truss.md" +} +,{ + "id": 33, + "title": "Hierarchical", + "category": "Cluster", + "link": "..\\ext\\docs\\CoreAlgorithmPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\algorithms\\hierarchical-clustering.md" +} +,{ + "id": 34, + "title": "Info Map", + "category": "Cluster", + "link": "..\\ext\\docs\\CoreAlgorithmPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\algorithms\\info-map-clustering.md" +} +,{ + "id": 35, + "title": "About The Jupyter Notebook Server", + "category": "Jupyter", + "link": "..\\ext\\docs\\CoreUtilities\\src\\au\\gov\\asd\\tac\\constellation\\utilities\\about-jupyter-notebook-server.md" +} +,{ + "id": 36, + "title": "About The Constellation REST Server", + "category": "Jupyter", + "link": "..\\ext\\docs\\CoreUtilities\\src\\au\\gov\\asd\\tac\\constellation\\utilities\\about-rest-server.md" +} +,{ + "id": 37, + "title": "Analytic View", + "category": "Views", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-view.md" +} +,{ + "id": 38, + "title": "Connects the Network Best?", + "category": "Questions", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\question-best-connects-network.md" +} +,{ + "id": 39, + "title": "Has Closest Relationship?", + "category": "Questions", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\question-has-closest-relationship.md" +} +,{ + "id": 40, + "title": "Most Central?", + "category": "Questions", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\question-most-central.md" +} +,{ + "id": 41, + "title": "Most Communicants?", + "category": "Questions", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\question-most-communicants.md" +} +,{ + "id": 42, + "title": "Most Easily Reached?", + "category": "Questions", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\question-most-easily-reached.md" +} +,{ + "id": 43, + "title": "Most Influential?", + "category": "Questions", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\question-most-influential.md" +} +,{ + "id": 44, + "title": "Most Likely Correlated?", + "category": "Questions", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\question-most-likely-correlated.md" +} +,{ + "id": 45, + "title": "Betweenness Centrality", + "category": "Analytics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-betweenness-centrality.md" +} +,{ + "id": 46, + "title": "Closeness Centrality", + "category": "Analytics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-closeness-centrality.md" +} +,{ + "id": 47, + "title": "Degree Centrality", + "category": "Analytics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-degree-centrality.md" +} +,{ + "id": 48, + "title": "Eigenvector Centrality", + "category": "Analytics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-eigenvector-centrality.md" +} +,{ + "id": 49, + "title": "HITS Centrality", + "category": "Analytics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-hits-centrality.md" +} +,{ + "id": 50, + "title": "Katz Centrality", + "category": "Analytics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-katz-centrality.md" +} +,{ + "id": 51, + "title": "Pagerank Centrality", + "category": "Analytics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-pagerank-centrality.md" +} +,{ + "id": 52, + "title": "Average Degree", + "category": "Global", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-average-degree.md" +} +,{ + "id": 53, + "title": "Component Count", + "category": "Global", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-component-count.md" +} +,{ + "id": 54, + "title": "Global Clustering Coefficient", + "category": "Global", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-global-clustering-coefficient.md" +} +,{ + "id": 55, + "title": "Graph Density", + "category": "Global", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-graph-density.md" +} +,{ + "id": 56, + "title": "Graph Distance", + "category": "Global", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-graph-distance.md" +} +,{ + "id": 57, + "title": "Connectivity Degree", + "category": "Metrics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-connectivity-degree.md" +} +,{ + "id": 58, + "title": "Eccentricity", + "category": "Metrics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-eccentricity.md" +} +,{ + "id": 59, + "title": "Effective Resistance", + "category": "Metrics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-effective-resistance.md" +} +,{ + "id": 60, + "title": "Local Clustering Coefficient", + "category": "Metrics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-local-clustering-coefficient.md" +} +,{ + "id": 61, + "title": "Multiplexity", + "category": "Metrics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-multiplexity.md" +} +,{ + "id": 62, + "title": "Ratio of Reciprocity", + "category": "Metrics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-ratio-of-reciprocity.md" +} +,{ + "id": 63, + "title": "Weight", + "category": "Metrics", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-weight.md" +} +,{ + "id": 64, + "title": "Adamic-Adar Index", + "category": "Similarity", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-adamic-adar-index.md" +} +,{ + "id": 65, + "title": "Common Neighbours", + "category": "Similarity", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-common-neighbours.md" +} +,{ + "id": 66, + "title": "Cosine Similarity", + "category": "Similarity", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-cosine-similarity.md" +} +,{ + "id": 67, + "title": "Dice Similarity", + "category": "Similarity", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-dice-similarity.md" +} +,{ + "id": 68, + "title": "Jaccard Index", + "category": "Similarity", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-jaccard-index.md" +} +,{ + "id": 69, + "title": "Levenshtein Distance", + "category": "Similarity", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-levenshtein-distance.md" +} +,{ + "id": 70, + "title": "Preferential Attachment", + "category": "Similarity", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-preferential-attachment.md" +} +,{ + "id": 71, + "title": "Resource Allocation Index", + "category": "Similarity", + "link": "..\\ext\\docs\\CoreAnalyticView\\src\\au\\gov\\asd\\tac\\constellation\\views\\analyticview\\analytic-resource-allocation-index.md" +} +,{ + "id": 72, + "title": "Attribute Editor", + "category": "Attribute Editor", + "link": "..\\ext\\docs\\CoreAttributeEditorView\\src\\au\\gov\\asd\\tac\\constellation\\views\\attributeeditor\\attribute-editor.md" +} +,{ + "id": 73, + "title": "Conversation View", + "category": "Conversation View", + "link": "..\\ext\\docs\\CoreConversationView\\src\\au\\gov\\asd\\tac\\constellation\\views\\conversationview\\conversation-view.md" +} +,{ + "id": 74, + "title": "Error Report", + "category": "Error Report View", + "link": "..\\ext\\docs\\CoreErrorReportView\\src\\au\\gov\\asd\\tac\\constellation\\views\\errorreport\\error-report.md" +} +,{ + "id": 75, + "title": "Data Access View", + "category": "Data Access View", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\data-access-view.md" +} +,{ + "id": 76, + "title": "Data Access View: Options", + "category": "Data Access View", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\data-access-options.md" +} +,{ + "id": 77, + "title": "Extract Types from Text", + "category": "Import", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\extract-types-from-text.md" +} +,{ + "id": 78, + "title": "Extract Words from Text", + "category": "Import", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\extract-words-from-text.md" +} +,{ + "id": 79, + "title": "Import Graph File", + "category": "Import", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\import-graph-file.md" +} +,{ + "id": 80, + "title": "Import Entities From GDELT", + "category": "Import", + "link": "..\\..\\..\\..\\..\\constellation-adaptors\\build\\cluster\\modules\\ext\\docs\\AdaptorsDataAccessPlugins\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\adaptors\\import-entities-from-gdelt.md" +} +,{ + "id": 81, + "title": "Import Relationships From GDELT", + "category": "Import", + "link": "..\\..\\..\\..\\..\\constellation-adaptors\\build\\cluster\\modules\\ext\\docs\\AdaptorsDataAccessPlugins\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\adaptors\\import-relationships-from-gdelt.md" +} +,{ + "id": 82, + "title": "Merge Nodes", + "category": "Clean", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\merge-nodes.md" +} +,{ + "id": 83, + "title": "Merge Transactions", + "category": "Clean", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\merge-transactions.md" +} +,{ + "id": 84, + "title": "Remove Nodes", + "category": "Clean", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\remove-nodes.md" +} +,{ + "id": 85, + "title": "Remove Unused Attributes", + "category": "Clean", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\remove-unused-attributes.md" +} +,{ + "id": 86, + "title": "Split Nodes Based on Identifier", + "category": "Clean", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\split-nodes.md" +} +,{ + "id": 87, + "title": "Test Parameters", + "category": "Developer", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\test-parameters.md" +} +,{ + "id": 88, + "title": "Datetime Range", + "category": "Global Parameters", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\datetime-range.md" +} +,{ + "id": 89, + "title": "Select All", + "category": "Utility", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\select-all.md" +} +,{ + "id": 90, + "title": "Select Top N", + "category": "Utility", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\select-top-n.md" +} +,{ + "id": 91, + "title": "Extend From Pajek File", + "category": "Extend", + "link": "..\\..\\..\\..\\..\\constellation-adaptors\\build\\cluster\\modules\\ext\\docs\\AdaptorsDataAccessPlugins\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\adaptors\\extend-from-pajek-file.md" +} +,{ + "id": 92, + "title": "Extend From GraphML File", + "category": "Extend", + "link": "..\\..\\..\\..\\..\\constellation-adaptors\\build\\cluster\\modules\\ext\\docs\\AdaptorsDataAccessPlugins\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\adaptors\\extend-from-graphml-file.md" +} +,{ + "id": 93, + "title": "Extend From GML File", + "category": "Extend", + "link": "..\\..\\..\\..\\..\\constellation-adaptors\\build\\cluster\\modules\\ext\\docs\\AdaptorsDataAccessPlugins\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\adaptors\\extend-from-gml-file.md" +} +,{ + "id": 94, + "title": "Extend From GDELT Knowledge Graph", + "category": "Extend", + "link": "..\\..\\..\\..\\..\\constellation-adaptors\\build\\cluster\\modules\\ext\\docs\\AdaptorsDataAccessPlugins\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\adaptors\\extend-from-gdelt.md" +} +,{ + "id": 95, + "title": "Enrich From GraphML File", + "category": "Enrichment", + "link": "..\\..\\..\\..\\..\\constellation-adaptors\\build\\cluster\\modules\\ext\\docs\\AdaptorsDataAccessPlugins\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\adaptors\\enrich-from-graphml-file.md" +} +,{ + "id": 96, + "title": "Enrich From GML File", + "category": "Enrichment", + "link": "..\\..\\..\\..\\..\\constellation-adaptors\\build\\cluster\\modules\\ext\\docs\\AdaptorsDataAccessPlugins\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\adaptors\\enrich-from-gml-file.md" +} +,{ + "id": 97, + "title": "Gaffer Simple Query Options", + "category": "Example", + "link": "..\\..\\..\\..\\..\\constellation-adaptors\\build\\cluster\\modules\\ext\\docs\\AdaptorsDataAccessPlugins\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\adaptors\\query-from-gaffer.md" +} +,{ + "id": 98, + "title": "Find and Replace", + "category": "Find View", + "link": "..\\ext\\docs\\CoreFindView\\src\\au\\gov\\asd\\tac\\constellation\\views\\find\\find-view.md" +} +,{ + "id": 99, + "title": "Histogram", + "category": "Histogram View", + "link": "..\\ext\\docs\\CoreHistogramView\\src\\au\\gov\\asd\\tac\\constellation\\views\\histogram\\histogram-view.md" +} +,{ + "id": 100, + "title": "Layers View", + "category": "Layers View", + "link": "..\\ext\\docs\\CoreLayersView\\src\\au\\gov\\asd\\tac\\constellation\\views\\layers\\layers-view.md" +} +,{ + "id": 101, + "title": "Map View", + "category": "Map View", + "link": "..\\ext\\docs\\CoreMapView\\src\\au\\gov\\asd\\tac\\constellation\\views\\mapview\\map-view.md" +} +,{ + "id": 102, + "title": "Day / Night Layer", + "category": "Layers", + "link": "..\\ext\\docs\\CoreMapView\\src\\au\\gov\\asd\\tac\\constellation\\views\\mapview\\mapview-layers-day-night.md" +} +,{ + "id": 103, + "title": "Heatmap Layers", + "category": "Layers", + "link": "..\\ext\\docs\\CoreMapView\\src\\au\\gov\\asd\\tac\\constellation\\views\\mapview\\mapview-layers-heatmap.md" +} +,{ + "id": 104, + "title": "Paths Layers", + "category": "Layers", + "link": "..\\ext\\docs\\CoreMapView\\src\\au\\gov\\asd\\tac\\constellation\\views\\mapview\\mapview-layers-paths.md" +} +,{ + "id": 105, + "title": "Thiessen Polygons Layer", + "category": "Layers", + "link": "..\\ext\\docs\\CoreMapView\\src\\au\\gov\\asd\\tac\\constellation\\views\\mapview\\mapview-layers-thiessen-polygons.md" +} +,{ + "id": 106, + "title": "Info Overlay", + "category": "Overlays", + "link": "..\\ext\\docs\\CoreMapView\\src\\au\\gov\\asd\\tac\\constellation\\views\\mapview\\mapview-overlays-info.md" +} +,{ + "id": 107, + "title": "Tools Overlay", + "category": "Overlays", + "link": "..\\ext\\docs\\CoreMapView\\src\\au\\gov\\asd\\tac\\constellation\\views\\mapview\\mapview-overlays-tools.md" +} +,{ + "id": 108, + "title": "Overview Overlay", + "category": "Overlays", + "link": "..\\ext\\docs\\CoreMapView\\src\\au\\gov\\asd\\tac\\constellation\\views\\mapview\\mapview-overlays-overview.md" +} +,{ + "id": 109, + "title": "Named Selections", + "category": "Named Selection View", + "link": "..\\ext\\docs\\CoreNamedSelectionView\\src\\au\\gov\\asd\\tac\\constellation\\views\\namedselection\\named-selections-view.md" +} +,{ + "id": 110, + "title": "Notes View", + "category": "Notes View", + "link": "..\\ext\\docs\\CoreNotesView\\src\\au\\gov\\asd\\tac\\constellation\\views\\notes\\notes-view.md" +} +,{ + "id": 111, + "title": "Perspective Bookmarks (Experimental)", + "category": "Perspective Bookmarks", + "link": "..\\ext\\docs\\CoreGraphUtilities\\src\\au\\gov\\asd\\tac\\constellation\\graph\\utilities\\perspective-bookmarks-view.md" +} +,{ + "id": 112, + "title": "Plugin Reporter", + "category": "Plugin Reporter View", + "link": "..\\ext\\docs\\CorePluginReporterView\\src\\au\\gov\\asd\\tac\\constellation\\views\\pluginreporter\\plugin-reporter-view.md" +} +,{ + "id": 113, + "title": "Quality Control View", + "category": "Quality Control View", + "link": "..\\ext\\docs\\CoreQualityControlView\\src\\au\\gov\\asd\\tac\\constellation\\views\\qualitycontrol\\quality-control-view.md" +} +,{ + "id": 114, + "title": "Scatter Plot", + "category": "Scatter Plot View", + "link": "..\\ext\\docs\\CoreScatterPlotView\\src\\au\\gov\\asd\\tac\\constellation\\views\\scatterplot\\scatter-plot-view.md" +} +,{ + "id": 115, + "title": "Schema View", + "category": "Schema View", + "link": "..\\ext\\docs\\CoreSchemaView\\src\\au\\gov\\asd\\tac\\constellation\\views\\schemaview\\schema-view.md" +} +,{ + "id": 116, + "title": "Attributes", + "category": "Schema View Tabs", + "link": "..\\ext\\docs\\CoreSchemaView\\src\\au\\gov\\asd\\tac\\constellation\\views\\schemaview\\schema-view-attributes.md" +} +,{ + "id": 117, + "title": "Node Types", + "category": "Schema View Tabs", + "link": "..\\ext\\docs\\CoreSchemaView\\src\\au\\gov\\asd\\tac\\constellation\\views\\schemaview\\schema-view-node-types.md" +} +,{ + "id": 118, + "title": "Transaction Types", + "category": "Schema View Tabs", + "link": "..\\ext\\docs\\CoreSchemaView\\src\\au\\gov\\asd\\tac\\constellation\\views\\schemaview\\schema-view-transaction-types.md" +} +,{ + "id": 119, + "title": "Plugins", + "category": "Schema View Tabs", + "link": "..\\ext\\docs\\CoreSchemaView\\src\\au\\gov\\asd\\tac\\constellation\\views\\schemaview\\schema-view-plugins.md" +} +,{ + "id": 120, + "title": "Scripting View", + "category": "Scripting View", + "link": "..\\ext\\docs\\CoreScriptingView\\src\\au\\gov\\asd\\tac\\constellation\\views\\scripting\\scripting-view.md" +} +,{ + "id": 121, + "title": "Table View", + "category": "Table View", + "link": "..\\ext\\docs\\CoreTableView\\src\\au\\gov\\asd\\tac\\constellation\\views\\tableview\\table-view.md" +} +,{ + "id": 122, + "title": "Timeline", + "category": "Timeline View", + "link": "..\\ext\\docs\\CoreTimelineView\\src\\au\\gov\\asd\\tac\\constellation\\views\\timeline\\timeline-view.md" +} +,{ + "id": 123, + "title": "Word Cloud View", + "category": "Word Cloud View", + "link": "..\\ext\\docs\\CoreWordCloudView\\src\\au\\gov\\asd\\tac\\constellation\\views\\wordcloud\\word-cloud-view.md" +} +,{ + "id": 124, + "title": "Data Access Category", + "category": "Preferences", + "link": "..\\ext\\docs\\CoreDataAccessView\\src\\au\\gov\\asd\\tac\\constellation\\views\\dataaccess\\data-access-view-preferences.md" +} +,{ + "id": 125, + "title": "Application", + "category": "Preferences", + "link": "..\\ext\\docs\\CorePreferences\\src\\au\\gov\\asd\\tac\\constellation\\preferences\\application-preferences.md" +} +,{ + "id": 126, + "title": "Developer", + "category": "Preferences", + "link": "..\\ext\\docs\\CorePreferences\\src\\au\\gov\\asd\\tac\\constellation\\preferences\\developer-preferences.md" +} +,{ + "id": 127, + "title": "Graph", + "category": "Preferences", + "link": "..\\ext\\docs\\CorePreferences\\src\\au\\gov\\asd\\tac\\constellation\\preferences\\graph-preferences.md" +} +,{ + "id": 128, + "title": "Label Fonts", + "category": "Preferences", + "link": "..\\ext\\docs\\CoreOpenGLDisplay\\src\\au\\gov\\asd\\tac\\constellation\\visual\\opengl\\label-fonts-preferences.md" +} +,{ + "id": 129, + "title": "Online Help", + "category": "Preferences", + "link": "..\\ext\\docs\\CoreHelp\\src\\au\\gov\\asd\\tac\\constellation\\help\\help-options.md" +} +,{ + "id": 130, + "title": "Proxy", + "category": "Preferences", + "link": "..\\ext\\docs\\CoreSecurity\\src\\au\\gov\\asd\\tac\\constellation\\security\\proxy-preferences.md" +} +,{ + "id": 131, + "title": "Grid", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\grid-arrangement.md" +} +,{ + "id": 132, + "title": "Line", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\line-arrangement.md" +} +,{ + "id": 133, + "title": "Circle", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\circle-arrangement.md" +} +,{ + "id": 134, + "title": "Tree", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\tree-arrangement.md" +} +,{ + "id": 135, + "title": "Proximity", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\proximity-arrangement.md" +} +,{ + "id": 136, + "title": "Hierarchy", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\hierarchy-arrangement.md" +} +,{ + "id": 137, + "title": "Node Attribute", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\node-attribute-arrangement.md" +} +,{ + "id": 138, + "title": "Scatter 3D", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\scatter3d-arrangement.md" +} +,{ + "id": 139, + "title": "Sphere", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\sphere-arrangement.md" +} +,{ + "id": 140, + "title": "Bubble Tree 3D", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\bubble-tree-3d-arrangement.md" +} +,{ + "id": 141, + "title": "Spectral 3D", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\spectral-arrangement.md" +} +,{ + "id": 142, + "title": "HDE 3D", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\hde-arrangement.md" +} +,{ + "id": 143, + "title": "Flatten Z-Field", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\flatten-z-field.md" +} +,{ + "id": 144, + "title": "Contract Graph", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\contract-graph.md" +} +,{ + "id": 145, + "title": "Expand Graph", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\expand-graph.md" +} +,{ + "id": 146, + "title": "Uncollide", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\uncollide-arrangement.md" +} +,{ + "id": 147, + "title": "Layer by Time", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\layer-by-time.md" +} +,{ + "id": 148, + "title": "Pin and Unpin Nodes", + "category": "Arrangements", + "link": "..\\ext\\docs\\CoreArrangementPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\arrangements\\pin-unpin-nodes.md" +} +,{ + "id": 149, + "title": "Import From File", + "category": "Import/Export", + "link": "..\\ext\\docs\\CoreImportExportPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\importexport\\import-from-file.md" +} +,{ + "id": 150, + "title": "Import From Database", + "category": "Import/Export", + "link": "..\\ext\\docs\\CoreImportExportPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\importexport\\import-from-database.md" +} +,{ + "id": 151, + "title": "Add Hashmod (Experimental)", + "category": "Import/Export", + "link": "..\\ext\\docs\\CoreImportExportPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\importexport\\add-hashmod.md" +} +,{ + "id": 152, + "title": "Export From Constellation", + "category": "Export", + "link": "..\\ext\\docs\\CoreImportExportPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\importexport\\export-from-constellation.md" +} +,{ + "id": 153, + "title": "Export to Image", + "category": "Export", + "link": "..\\ext\\docs\\CoreImportExportPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\importexport\\export-to-png.md" +} +,{ + "id": 154, + "title": "Export to SVG", + "category": "Export", + "link": "..\\ext\\docs\\CoreImportExportPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\importexport\\export-to-svg.md" +} +,{ + "id": 155, + "title": "Export to Shapefile", + "category": "Export", + "link": "..\\ext\\docs\\CoreImportExportPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\importexport\\export-to-shapefile.md" +} +,{ + "id": 156, + "title": "Export to KML", + "category": "Export", + "link": "..\\ext\\docs\\CoreImportExportPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\importexport\\export-to-kml.md" +} +,{ + "id": 157, + "title": "Export to GeoJson", + "category": "Export", + "link": "..\\ext\\docs\\CoreImportExportPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\importexport\\export-to-geojson.md" +} +,{ + "id": 158, + "title": "Export to GeoPackage", + "category": "Export", + "link": "..\\ext\\docs\\CoreImportExportPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\importexport\\export-to-geopackage.md" +} +,{ + "id": 159, + "title": "Export to CSV", + "category": "Export", + "link": "..\\ext\\docs\\CoreImportExportPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\importexport\\export-to-csv.md" +} +,{ + "id": 160, + "title": "Export to XLSX", + "category": "Export", + "link": "..\\ext\\docs\\CoreImportExportPlugins\\src\\au\\gov\\asd\\tac\\constellation\\plugins\\importexport\\export-to-xlsx.md" +} +] \ No newline at end of file diff --git a/toc_update.sh b/toc_update.sh deleted file mode 100644 index 708fd2aaa8..0000000000 --- a/toc_update.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -# convert toc from markdown to html -echo "find toc.md and convert with pandoc" -pandoc -f commonmark -t html toc.md > "toc".html - -echo "rename toc.md.html to toc.html" -mv "$toc.md.html" "${toc.md.html}".html - - -echo "search and replace start" - -while read a; do - echo ${a//md/html} -done < toc.html > toc.html.t -mv toc.html{.t,} - -echo "search and replace end" -