From e41c1cbe9f0476997eac7b4a3f17cbc6b2262faf Mon Sep 17 00:00:00 2001 From: Tim Baumann Date: Mon, 9 Oct 2017 18:33:09 +0200 Subject: Use
element for collapsibles (#690) * Remove unnecessary call to 'collapseSection' The call is unnecessary since there is no corresponding toggle for hiding the section of orphan instances. * Use
for collapsibles This makes them work even when JS is disabled. Closes #560. --- .../resources/html/Ocean.std-theme/ocean.css | 30 +- haddock-api/resources/html/haddock-bundle.min.js | 2 +- haddock-api/resources/html/js-src/cookies.ts | 20 + .../resources/html/js-src/details-helper.ts | 106 +++ haddock-api/resources/html/js-src/haddock-util.ts | 173 ---- haddock-api/resources/html/js-src/init.ts | 9 +- haddock-api/resources/html/js-src/style-menu.ts | 116 +++ haddock-api/src/Haddock/Backends/Xhtml.hs | 21 +- .../src/Haddock/Backends/Xhtml/DocMarkup.hs | 6 +- haddock-api/src/Haddock/Backends/Xhtml/Layout.hs | 14 +- haddock-api/src/Haddock/Backends/Xhtml/Utils.hs | 35 +- html-test/ref/A.html | 76 +- html-test/ref/B.html | 56 +- html-test/ref/Bold.html | 18 +- html-test/ref/Bug1.html | 26 +- html-test/ref/Bug201.html | 24 +- html-test/ref/Bug253.html | 18 +- html-test/ref/Bug26.html | 62 +- html-test/ref/Bug294.html | 50 +- html-test/ref/Bug298.html | 48 +- html-test/ref/Bug3.html | 22 +- html-test/ref/Bug308.html | 24 +- html-test/ref/Bug308CrossModule.html | 18 +- html-test/ref/Bug310.html | 38 +- html-test/ref/Bug313.html | 24 +- html-test/ref/Bug335.html | 44 +- html-test/ref/Bug387.html | 32 +- html-test/ref/Bug4.html | 22 +- html-test/ref/Bug6.html | 146 ++-- html-test/ref/Bug613.html | 94 +- html-test/ref/Bug7.html | 72 +- html-test/ref/BugDeprecated.html | 80 +- html-test/ref/BugExportHeadings.html | 80 +- html-test/ref/BundledPatterns.html | 150 ++-- html-test/ref/BundledPatterns2.html | 154 ++-- html-test/ref/DeprecatedClass.html | 46 +- html-test/ref/DeprecatedData.html | 70 +- html-test/ref/DeprecatedFunction.html | 32 +- html-test/ref/DeprecatedFunction2.html | 22 +- html-test/ref/DeprecatedFunction3.html | 22 +- html-test/ref/DeprecatedNewtype.html | 48 +- html-test/ref/DeprecatedReExport.html | 22 +- html-test/ref/DeprecatedRecord.html | 52 +- html-test/ref/DeprecatedTypeFamily.html | 48 +- html-test/ref/DeprecatedTypeSynonym.html | 40 +- html-test/ref/Examples.html | 26 +- html-test/ref/Extensions.html | 18 +- html-test/ref/GADTRecords.html | 92 +- html-test/ref/Hash.html | 146 ++-- html-test/ref/HiddenInstances.html | 86 +- html-test/ref/HiddenInstancesB.html | 68 +- html-test/ref/Hyperlinks.html | 22 +- html-test/ref/IgnoreExports.html | 32 +- html-test/ref/Instances.html | 320 ++++--- html-test/ref/Math.html | 22 +- html-test/ref/NamedDoc.html | 10 +- html-test/ref/Nesting.html | 72 +- html-test/ref/NoLayout.html | 22 +- html-test/ref/NonGreedy.html | 18 +- html-test/ref/Operators.html | 212 ++--- html-test/ref/OrphanInstances.html | 22 +- html-test/ref/PR643.html | 18 +- html-test/ref/PR643_1.html | 18 +- html-test/ref/PatternSyns.html | 200 ++--- html-test/ref/Properties.html | 26 +- html-test/ref/QuasiExpr.html | 40 +- html-test/ref/SpuriousSuperclassConstraints.html | 30 +- html-test/ref/Test.html | 952 +++++++++++---------- html-test/ref/Threaded.html | 22 +- html-test/ref/Threaded_TH.html | 18 +- html-test/ref/Ticket112.html | 18 +- html-test/ref/Ticket75.html | 36 +- html-test/ref/TitledPicture.html | 32 +- html-test/ref/TypeFamilies.html | 618 +++++++------ html-test/ref/TypeFamilies2.html | 134 +-- html-test/ref/Unicode.html | 22 +- 76 files changed, 3040 insertions(+), 2644 deletions(-) create mode 100644 haddock-api/resources/html/js-src/cookies.ts create mode 100644 haddock-api/resources/html/js-src/details-helper.ts delete mode 100644 haddock-api/resources/html/js-src/haddock-util.ts create mode 100644 haddock-api/resources/html/js-src/style-menu.ts diff --git a/haddock-api/resources/html/Ocean.std-theme/ocean.css b/haddock-api/resources/html/Ocean.std-theme/ocean.css index 20e37ca8..0852dea5 100644 --- a/haddock-api/resources/html/Ocean.std-theme/ocean.css +++ b/haddock-api/resources/html/Ocean.std-theme/ocean.css @@ -46,6 +46,14 @@ a[href].def:hover { color: rgb(78, 98, 114); } /* @end */ +/* @group Show and hide with JS */ + +body.js-enabled .hide-when-js-enabled { + display: none; +} + +/* @end */ + /* @group Fonts & Sizes */ /* Basic technique & IE workarounds from YUI 3 @@ -106,7 +114,7 @@ pre, code, kbd, samp, tt, .src { /* @group Common */ -.caption, h1, h2, h3, h4, h5, h6 { +.caption, h1, h2, h3, h4, h5, h6, summary { font-weight: bold; color: rgb(78,98,114); margin: 0.8em 0 0.4em; @@ -168,6 +176,16 @@ p.caption.expander { min-height: 9px; } +summary { + cursor: pointer; + outline: none; + list-style-image: url(plus.gif); + list-style-position: outside; +} + +details[open] > summary { + list-style-image: url(minus.gif); +} pre { padding: 0.25em; @@ -338,7 +356,8 @@ div#style-menu-holder { z-index: 1; } -#synopsis .caption { +#synopsis summary { + display: block; float: left; width: 29px; color: rgba(255,255,255,0); @@ -346,16 +365,13 @@ div#style-menu-holder { margin: 0; font-size: 1px; padding: 0; + background: url(synopsis.png) no-repeat 0px -8px; } -#synopsis p.caption.collapser { +#synopsis details[open] > summary { background: url(synopsis.png) no-repeat -64px -8px; } -#synopsis p.caption.expander { - background: url(synopsis.png) no-repeat 0px -8px; -} - #synopsis ul { height: 100%; overflow: auto; diff --git a/haddock-api/resources/html/haddock-bundle.min.js b/haddock-api/resources/html/haddock-bundle.min.js index 64357c4a..2badbc56 100644 --- a/haddock-api/resources/html/haddock-bundle.min.js +++ b/haddock-api/resources/html/haddock-bundle.min.js @@ -1,2 +1,2 @@ -!function e(t,n,o){function r(s,a){if(!n[s]){if(!t[s]){var l="function"==typeof require&&require;if(!a&&l)return l(s,!0);if(i)return i(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var u=n[s]={exports:{}};t[s][0].call(u.exports,function(e){var n=t[s][1][e];return r(n||e)},u,u.exports,e,t,n,o)}return n[s].exports}for(var i="function"==typeof require&&require,s=0;s=0}function s(e,t){var n=o(e.className||"");n.indexOf(" "+t+" ")<0&&(e.className=r(n+" "+t))}function a(e,t){var n=o(e.className||"");n=n.replace(" "+t+" "," "),e.className=r(n)}function l(e,t,n,o){return null==o&&(o=!i(e,t)),o?(a(e,n),s(e,t)):(a(e,t),s(e,n)),o}function c(e,t){return function(n,o){return l(n,e,t,o)}}function u(e){var t=b(document.getElementById("section."+e));return x(document.getElementById("control."+e),t),h(e),t}function h(e){S[e]?delete S[e]:S[e]=!0;var t=[];for(var n in S)S.hasOwnProperty(n)&&t.push(n);document.cookie="collapsed="+encodeURIComponent(t.join("+"))}function d(e,t){document.cookie=e+"="+encodeURIComponent(t)+";path=/;"}function p(e){document.cookie=e+"=;path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT;"}function f(e){for(var t=e+"=",n=document.cookie.split(";"),o=0;o"+e.title+""}),e.length>1&&v("")},n.resetStyle=function(){var e=f("haddock-style");e&&g(e)}},{}],2:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var o=e("./haddock-util"),r=e("./quick-jump");!function(e){"interactive"===document.readyState?e():document.addEventListener("readystatechange",function(){"interactive"===document.readyState&&e()})}(function(){o.addStyleMenu(),o.resetStyle(),o.restoreCollapsed(),r.init()})},{"./haddock-util":1,"./quick-jump":3}],3:[function(e,t,n){"use strict";function o(e,t,n){var o=new XMLHttpRequest;o.onreadystatechange=function(){o.readyState===XMLHttpRequest.DONE&&(200===o.status?t&&t(JSON.parse(o.responseText)):n&&n(o))},o.open("GET",e,!0),o.send()}function r(e){var t=document.querySelector("#page-menu"),n=document.createElement("li");t.insertBefore(n,t.firstChild),d.render(p(v,{onClick:e,title:"Quick Jump"}),t,n)}function i(e,t){return t.length<=e?t:t.slice(0,e)}function s(){return p("table",{class:"keyboard-shortcuts"},p("tr",null,p("th",null,"Key"),p("th",null,"Shortcut")),p("tr",null,p("td",null,p("span",{class:"key"},"s")),p("td",null,"Open this search box")),p("tr",null,p("td",null,p("span",{class:"key"},"esc")),p("td",null,"Close this search box")),p("tr",null,p("td",null,p("span",{class:"key"},"↓"),",",p("span",{class:"key"},"ctrl")," + ",p("span",{class:"key"},"j")),p("td",null,"Move down in search results")),p("tr",null,p("td",null,p("span",{class:"key"},"↑"),",",p("span",{class:"key"},"ctrl")," + ",p("span",{class:"key"},"k")),p("td",null,"Move up in search results")),p("tr",null,p("td",null,p("span",{class:"key"},"↵")),p("td",null,"Go to active search result")))}function a(){return p("p",null,"You can find any exported type, constructor, class, function or pattern defined in this package by (approximate) name.")}function l(e){var t=[p("p",null,"Your search for '",e.searchString,"' produced the following list of results: ",p("code",null,"[]"),"."),p("p",null,p("code",null,"Nothing")," matches your query for '",e.searchString,"'."),p("p",null,p("code",null,"Left \"no matches for '",e.searchString,"'\" :: Either String (NonEmpty SearchResult)"))];return t[(e.searchString||"a").charCodeAt(0)%t.length]}function c(e,t){d.render(p(m,{baseUrl:e||".",showHideTrigger:t||r}),document.body)}var u=this&&this.__extends||function(){var e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])};return function(t,n){function o(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(o.prototype=n.prototype,new o)}}();Object.defineProperty(n,"__esModule",{value:!0});var h=e("fuse.js"),d=e("preact"),p=d.h,f=d.Component,v=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return u(t,e),t.prototype.render=function(e){return p("li",null,p("a",{href:"#",onClick:function(t){t.preventDefault(),e.onClick()}},e.title))},t}(f),m=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.linkIndex=0,t.focusPlease=!1,t.navigatedByKeyboard=!1,t}return u(t,e),t.prototype.componentWillMount=function(){var e=this;this.setState({searchString:"",isVisible:!1,expanded:{},activeLinkIndex:-1,moduleResults:[]}),o(this.props.baseUrl+"/doc-index.json",function(t){e.setState({fuse:new h(t,{threshold:.4,caseSensitive:!0,includeScore:!0,tokenize:!0,keys:["name","module"]}),moduleResults:[]})},function(t){console&&console.error("could not load 'doc-index.json' for searching",t),e.setState({failedLoading:!0})}),document.addEventListener("mousedown",this.hide.bind(this)),document.addEventListener("keydown",function(t){e.state.isVisible&&("Escape"===t.key?e.hide():"ArrowUp"===t.key||"k"===t.key&&t.ctrlKey?(t.preventDefault(),e.navigateLinks(-1)):"ArrowDown"===t.key||"j"===t.key&&t.ctrlKey?(t.preventDefault(),e.navigateLinks(1)):"Enter"===t.key&&e.state.activeLinkIndex>=0&&e.followActiveLink()),"s"===t.key&&"input"!==t.target.tagName.toLowerCase()&&(t.preventDefault(),e.show())})},t.prototype.hide=function(){this.setState({isVisible:!1})},t.prototype.show=function(){this.state.isVisible||(this.focusPlease=!0,this.setState({isVisible:!0,activeLinkIndex:-1}))},t.prototype.toggleVisibility=function(){this.state.isVisible?this.hide():this.show()},t.prototype.navigateLinks=function(e){var t=Math.max(-1,Math.min(this.linkIndex-1,this.state.activeLinkIndex+e));this.navigatedByKeyboard=!0,this.setState({activeLinkIndex:t})},t.prototype.followActiveLink=function(){this.activeLinkAction&&this.activeLinkAction()},t.prototype.updateResults=function(){var e=this.input&&this.input.value||"",t={};this.state.fuse.search(e).forEach(function(e){var n=e.item.module;(t[n]||(t[n]=[])).push(e)});var n=[];for(var o in t)!function(e){var o=t[e],r=0;o.forEach(function(e){r+=1/e.score}),n.push({module:e,totalScore:1/r,items:o})}(o);n.sort(function(e,t){return e.totalScore-t.totalScore}),this.setState({searchString:e,isVisible:!0,moduleResults:n})},t.prototype.componentDidUpdate=function(){if(this.searchResults&&this.activeLink&&this.navigatedByKeyboard){var e=this.activeLink.getClientRects()[0],t=this.searchResults.getClientRects()[0].top;e.bottom>window.innerHeight?this.searchResults.scrollTop+=e.bottom-window.innerHeight+80:e.topn)return i(e,this.pattern,o);var r=this.options,a=r.location,l=r.distance,c=r.threshold,u=r.findAllMatches,h=r.minMatchCharLength;return s(e,this.pattern,this.patternAlphabet,{location:a,distance:l,threshold:c,findAllMatches:u,minMatchCharLength:h})}}]),e}();e.exports=l},function(e,t,n){"use strict";var o=n(0),r=function e(t,n,r){if(n){var i=n.indexOf("."),s=n,a=null;-1!==i&&(s=n.slice(0,i),a=n.slice(i+1));var l=t[s];if(null!==l&&void 0!==l)if(a||"string"!=typeof l&&"number"!=typeof l)if(o(l))for(var c=0,u=l.length;c0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=[],o=-1,r=-1,i=0,s=e.length;i=t&&n.push([o,r]),o=-1)}return e[i-1]&&i-o>=t&&n.push([o,i-1]),n}},function(e,t,n){"use strict";e.exports=function(e){for(var t={},n=e.length,o=0;o2&&void 0!==arguments[2]?arguments[2]:/ +/g,r=new RegExp(t.replace(o,"\\$&").replace(n,"|")),i=e.match(r),s=!!i,a=[];if(s)for(var l=0,c=i.length;l=E;P-=1){var R=P-1,U=n[e.charAt(R)];if(U&&(b[R]=1),j[P]=(j[P+1]<<1|1)&U,0!==N&&(j[P]|=(L[P+1]|L[P])<<1|1|L[P+1]),j[P]&I&&(C=o(t,{errors:N,currentLocation:R,expectedLocation:m,distance:c}))<=y){if(y=C,(_=R)<=m)break;E=Math.max(1,2*m-_)}}if(o(t,{errors:N+1,currentLocation:m,expectedLocation:m,distance:c})>y)break;L=j}return{isMatch:_>=0,score:0===C?.001:C,matchedIndices:r(b,v)}}},function(e,t,n){"use strict";function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var r=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:"",t=[];if(this.options.tokenize)for(var n=e.split(this.options.tokenSeparator),o=0,r=n.length;o0&&void 0!==arguments[0]?arguments[0]:[],t=arguments[1],n=this.list,o={},r=[];if("string"==typeof n[0]){for(var i=0,s=n.length;i1)throw new Error("Key weight has to be > 0 and <= 1");p=p.name}else a[p]={weight:1};this._analyze({key:p,value:this.options.getFn(u,p),record:u,index:l},{resultMap:o,results:r,tokenSearchers:e,fullSearcher:t})}return{weights:a,results:r}}},{key:"_analyze",value:function(e,t){var n=e.key,o=e.arrayIndex,r=void 0===o?-1:o,i=e.value,s=e.record,l=e.index,c=t.tokenSearchers,u=void 0===c?[]:c,h=t.fullSearcher,d=void 0===h?[]:h,p=t.resultMap,f=void 0===p?{}:p,v=t.results,m=void 0===v?[]:v;if(void 0!==i&&null!==i){var g=!1,y=-1,_=0;if("string"==typeof i){this._log("\nKey: "+(""===n?"-":n));var k=d.search(i);if(this._log('Full text: "'+i+'", score: '+k.score),this.options.tokenize){for(var b=i.split(this.options.tokenSeparator),x=[],S=0;S-1&&(E=(E+y)/2),this._log("Score average:",E);var T=!this.options.tokenize||!this.options.matchAllTokens||_>=u.length;if(this._log("\nCheck Matches: "+T),(g||k.isMatch)&&T){var j=f[l];j?j.output.push({key:n,arrayIndex:r,value:i,score:E,matchedIndices:k.matchedIndices}):(f[l]={item:s,output:[{key:n,arrayIndex:r,value:i,score:E,matchedIndices:k.matchedIndices}]},m.push(f[l]))}}else if(a(i))for(var P=0,R=i.length;P-1&&(s.arrayIndex=i.arrayIndex),t.matches.push(s)}}}),this.options.includeScore&&n.push(function(e,t){t.score=e.score});for(var o=0,r=e.length;o2;)A.push(arguments[s]);for(n&&null!=n.children&&(A.length||A.push(n.children),delete n.children);A.length;)if((r=A.pop())&&void 0!==r.pop)for(s=r.length;s--;)A.push(r[s]);else"boolean"==typeof r&&(r=null),(i="function"!=typeof t)&&(null==r?r="":"number"==typeof r?r=String(r):"string"!=typeof r&&(i=!1)),i&&o?a[a.length-1]+=r:a===O?a=[r]:a.push(r),o=i;var l=new e;return l.nodeName=t,l.children=a,l.attributes=null==n?void 0:n,l.key=null==n?void 0:n.key,void 0!==N.vnode&&N.vnode(l),l}function o(e,t){for(var n in t)e[n]=t[n];return e}function r(e){!e.__d&&(e.__d=!0)&&1==j.push(e)&&(N.debounceRendering||E)(i)}function i(){var e,t=j;for(j=[];e=t.pop();)e.__d&&L(e)}function s(e,t,n){return"string"==typeof t||"number"==typeof t?void 0!==e.splitText:"string"==typeof t.nodeName?!e._componentConstructor&&a(e,t.nodeName):n||e._componentConstructor===t.nodeName}function a(e,t){return e.__n===t||e.nodeName.toLowerCase()===t.toLowerCase()}function l(e){var t=o({},e.attributes);t.children=e.children;var n=e.nodeName.defaultProps;if(void 0!==n)for(var r in n)void 0===t[r]&&(t[r]=n[r]);return t}function c(e,t){var n=t?document.createElementNS("http://www.w3.org/2000/svg",e):document.createElement(e);return n.__n=e,n}function u(e){var t=e.parentNode;t&&t.removeChild(e)}function h(e,t,n,o,r){if("className"===t&&(t="class"),"key"===t);else if("ref"===t)n&&n(null),o&&o(e);else if("class"!==t||r)if("style"===t){if(o&&"string"!=typeof o&&"string"!=typeof n||(e.style.cssText=o||""),o&&"object"==typeof o){if("string"!=typeof n)for(var i in n)i in o||(e.style[i]="");for(var i in o)e.style[i]="number"==typeof o[i]&&!1===T.test(i)?o[i]+"px":o[i]}}else if("dangerouslySetInnerHTML"===t)o&&(e.innerHTML=o.__html||"");else if("o"==t[0]&&"n"==t[1]){var s=t!==(t=t.replace(/Capture$/,""));t=t.toLowerCase().substring(2),o?n||e.addEventListener(t,p,s):e.removeEventListener(t,p,s),(e.__l||(e.__l={}))[t]=o}else if("list"!==t&&"type"!==t&&!r&&t in e)d(e,t,null==o?"":o),null!=o&&!1!==o||e.removeAttribute(t);else{var a=r&&t!==(t=t.replace(/^xlink\:?/,""));null==o||!1===o?a?e.removeAttributeNS("http://www.w3.org/1999/xlink",t.toLowerCase()):e.removeAttribute(t):"function"!=typeof o&&(a?e.setAttributeNS("http://www.w3.org/1999/xlink",t.toLowerCase(),o):e.setAttribute(t,o))}else e.className=o||""}function d(e,t,n){try{e[t]=n}catch(e){}}function p(e){return this.__l[e.type](N.event&&N.event(e)||e)}function f(){for(var e;e=P.pop();)N.afterMount&&N.afterMount(e),e.componentDidMount&&e.componentDidMount()}function v(e,t,n,o,r,i){R++||(U=null!=r&&void 0!==r.ownerSVGElement,D=null!=e&&!("__preactattr_"in e));var s=m(e,t,n,o,i);return r&&s.parentNode!==r&&r.appendChild(s),--R||(D=!1,i||f()),s}function m(e,t,n,o,r){var i=e,s=U;if(null!=t&&"boolean"!=typeof t||(t=""),"string"==typeof t||"number"==typeof t)return e&&void 0!==e.splitText&&e.parentNode&&(!e._component||r)?e.nodeValue!=t&&(e.nodeValue=t):(i=document.createTextNode(t),e&&(e.parentNode&&e.parentNode.replaceChild(i,e),y(e,!0))),i.__preactattr_=!0,i;var l=t.nodeName;if("function"==typeof l)return C(e,t,n,o);if(U="svg"===l||"foreignObject"!==l&&U,l=String(l),(!e||!a(e,l))&&(i=c(l,U),e)){for(;e.firstChild;)i.appendChild(e.firstChild);e.parentNode&&e.parentNode.replaceChild(i,e),y(e,!0)}var u=i.firstChild,h=i.__preactattr_,d=t.children;if(null==h){h=i.__preactattr_={};for(var p=i.attributes,f=p.length;f--;)h[p[f].name]=p[f].value}return!D&&d&&1===d.length&&"string"==typeof d[0]&&null!=u&&void 0!==u.splitText&&null==u.nextSibling?u.nodeValue!=d[0]&&(u.nodeValue=d[0]):(d&&d.length||null!=u)&&g(i,d,n,o,D||null!=h.dangerouslySetInnerHTML),k(i,t.attributes,h),U=s,i}function g(e,t,n,o,r){var i,a,l,c,h,d=e.childNodes,p=[],f={},v=0,g=0,_=d.length,k=0,b=t?t.length:0;if(0!==_)for(L=0;L<_;L++){var x=d[L],S=x.__preactattr_;null!=(w=b&&S?x._component?x._component.__k:S.key:null)?(v++,f[w]=x):(S||(void 0!==x.splitText?!r||x.nodeValue.trim():r))&&(p[k++]=x)}if(0!==b)for(L=0;L2?[].slice.call(arguments,2):e.children)},Component:I,render:function(e,t,n){return v(n,e,{},!1,t,!1)},rerender:i,options:N};void 0!==t?t.exports=F:self.preact=F}()},{}]},{},[2]); +!function e(t,n,o){function r(s,a){if(!n[s]){if(!t[s]){var l="function"==typeof require&&require;if(!a&&l)return l(s,!0);if(i)return i(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var u=n[s]={exports:{}};t[s][0].call(u.exports,function(e){var n=t[s][1][e];return r(n||e)},u,u.exports,e,t,n,o)}return n[s].exports}for(var i="function"==typeof require&&require,s=0;s element with id '"+e+"'");return t}function r(e){for(var t=e.target,n=t.id,r=o(n),i=r.element.open,s=0,l=r.toggles;s0&&(d[n.id]={element:n,openByDefault:!!n.open,toggles:[]},n.addEventListener("toggle",r))}}function s(e){var t=o(e).element;t.open=!t.open}function a(){var e=Object.keys(p);document.cookie="toggled="+encodeURIComponent(e.join("+"))}function l(){var e=h.getCookie("toggled");if(e)for(var t=0,n=e.split("+");t=0&&e.followActiveLink()),"s"===t.key&&"input"!==t.target.tagName.toLowerCase()&&(t.preventDefault(),e.show())})},t.prototype.hide=function(){this.setState({isVisible:!1})},t.prototype.show=function(){this.state.isVisible||(this.focusPlease=!0,this.setState({isVisible:!0,activeLinkIndex:-1}))},t.prototype.toggleVisibility=function(){this.state.isVisible?this.hide():this.show()},t.prototype.navigateLinks=function(e){var t=Math.max(-1,Math.min(this.linkIndex-1,this.state.activeLinkIndex+e));this.navigatedByKeyboard=!0,this.setState({activeLinkIndex:t})},t.prototype.followActiveLink=function(){this.activeLinkAction&&this.activeLinkAction()},t.prototype.updateResults=function(){var e=this.input&&this.input.value||"",t={};this.state.fuse.search(e).forEach(function(e){var n=e.item.module;(t[n]||(t[n]=[])).push(e)});var n=[];for(var o in t)!function(e){var o=t[e],r=0;o.forEach(function(e){r+=1/e.score}),n.push({module:e,totalScore:1/r,items:o})}(o);n.sort(function(e,t){return e.totalScore-t.totalScore}),this.setState({searchString:e,isVisible:!0,moduleResults:n})},t.prototype.componentDidUpdate=function(){if(this.searchResults&&this.activeLink&&this.navigatedByKeyboard){var e=this.activeLink.getClientRects()[0],t=this.searchResults.getClientRects()[0].top;e.bottom>window.innerHeight?this.searchResults.scrollTop+=e.bottom-window.innerHeight+80:e.top=0}function s(e,t){var n=o(e.className||"");n.indexOf(" "+t+" ")<0&&(e.className=r(n+" "+t))}function a(e,t){var n=o(e.className||"");n=n.replace(" "+t+" "," "),e.className=r(n)}function l(e,t,n,o){return null==o&&(o=!i(e,t)),o?(a(e,n),s(e,t)):(a(e,t),s(e,n)),o}function c(e){var t=document.getElementById("page-menu");if(t&&t.firstChild){var n=t.firstChild.cloneNode(!1);n.innerHTML=e,t.appendChild(n)}}function u(){return Array.prototype.slice.call(document.getElementsByTagName("link")).filter(function(e){return-1!=e.rel.indexOf("style")&&e.title})}function h(){var e=u(),t="";e.forEach(function(e){t+="
  • "+e.title+"
  • "}),e.length>1&&c("")}function d(e){for(var t=u(),n=null,o=0;on)return i(e,this.pattern,o);var r=this.options,a=r.location,l=r.distance,c=r.threshold,u=r.findAllMatches,h=r.minMatchCharLength;return s(e,this.pattern,this.patternAlphabet,{location:a,distance:l,threshold:c,findAllMatches:u,minMatchCharLength:h})}}]),e}();e.exports=l},function(e,t,n){"use strict";var o=n(0),r=function e(t,n,r){if(n){var i=n.indexOf("."),s=n,a=null;-1!==i&&(s=n.slice(0,i),a=n.slice(i+1));var l=t[s];if(null!==l&&void 0!==l)if(a||"string"!=typeof l&&"number"!=typeof l)if(o(l))for(var c=0,u=l.length;c0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=[],o=-1,r=-1,i=0,s=e.length;i=t&&n.push([o,r]),o=-1)}return e[i-1]&&i-o>=t&&n.push([o,i-1]),n}},function(e,t,n){"use strict";e.exports=function(e){for(var t={},n=e.length,o=0;o2&&void 0!==arguments[2]?arguments[2]:/ +/g,r=new RegExp(t.replace(o,"\\$&").replace(n,"|")),i=e.match(r),s=!!i,a=[];if(s)for(var l=0,c=i.length;l=E;P-=1){var R=P-1,U=n[e.charAt(R)];if(U&&(b[R]=1),T[P]=(T[P+1]<<1|1)&U,0!==I&&(T[P]|=(L[P+1]|L[P])<<1|1|L[P+1]),T[P]&N&&(C=o(t,{errors:I,currentLocation:R,expectedLocation:g,distance:c}))<=y){if(y=C,(_=R)<=g)break;E=Math.max(1,2*g-_)}}if(o(t,{errors:I+1,currentLocation:g,expectedLocation:g,distance:c})>y)break;L=T}return{isMatch:_>=0,score:0===C?.001:C,matchedIndices:r(b,v)}}},function(e,t,n){"use strict";function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var r=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:"",t=[];if(this.options.tokenize)for(var n=e.split(this.options.tokenSeparator),o=0,r=n.length;o0&&void 0!==arguments[0]?arguments[0]:[],t=arguments[1],n=this.list,o={},r=[];if("string"==typeof n[0]){for(var i=0,s=n.length;i1)throw new Error("Key weight has to be > 0 and <= 1");p=p.name}else a[p]={weight:1};this._analyze({key:p,value:this.options.getFn(u,p),record:u,index:l},{resultMap:o,results:r,tokenSearchers:e,fullSearcher:t})}return{weights:a,results:r}}},{key:"_analyze",value:function(e,t){var n=e.key,o=e.arrayIndex,r=void 0===o?-1:o,i=e.value,s=e.record,l=e.index,c=t.tokenSearchers,u=void 0===c?[]:c,h=t.fullSearcher,d=void 0===h?[]:h,p=t.resultMap,f=void 0===p?{}:p,v=t.results,g=void 0===v?[]:v;if(void 0!==i&&null!==i){var m=!1,y=-1,_=0;if("string"==typeof i){this._log("\nKey: "+(""===n?"-":n));var k=d.search(i);if(this._log('Full text: "'+i+'", score: '+k.score),this.options.tokenize){for(var b=i.split(this.options.tokenSeparator),x=[],w=0;w-1&&(E=(E+y)/2),this._log("Score average:",E);var j=!this.options.tokenize||!this.options.matchAllTokens||_>=u.length;if(this._log("\nCheck Matches: "+j),(m||k.isMatch)&&j){var T=f[l];T?T.output.push({key:n,arrayIndex:r,value:i,score:E,matchedIndices:k.matchedIndices}):(f[l]={item:s,output:[{key:n,arrayIndex:r,value:i,score:E,matchedIndices:k.matchedIndices}]},g.push(f[l]))}}else if(a(i))for(var P=0,R=i.length;P-1&&(s.arrayIndex=i.arrayIndex),t.matches.push(s)}}}),this.options.includeScore&&n.push(function(e,t){t.score=e.score});for(var o=0,r=e.length;o2;)A.push(arguments[s]);for(n&&null!=n.children&&(A.length||A.push(n.children),delete n.children);A.length;)if((r=A.pop())&&void 0!==r.pop)for(s=r.length;s--;)A.push(r[s]);else"boolean"==typeof r&&(r=null),(i="function"!=typeof t)&&(null==r?r="":"number"==typeof r?r=String(r):"string"!=typeof r&&(i=!1)),i&&o?a[a.length-1]+=r:a===O?a=[r]:a.push(r),o=i;var l=new e;return l.nodeName=t,l.children=a,l.attributes=null==n?void 0:n,l.key=null==n?void 0:n.key,void 0!==I.vnode&&I.vnode(l),l}function o(e,t){for(var n in t)e[n]=t[n];return e}function r(e){!e.__d&&(e.__d=!0)&&1==T.push(e)&&(I.debounceRendering||E)(i)}function i(){var e,t=T;for(T=[];e=t.pop();)e.__d&&L(e)}function s(e,t,n){return"string"==typeof t||"number"==typeof t?void 0!==e.splitText:"string"==typeof t.nodeName?!e._componentConstructor&&a(e,t.nodeName):n||e._componentConstructor===t.nodeName}function a(e,t){return e.__n===t||e.nodeName.toLowerCase()===t.toLowerCase()}function l(e){var t=o({},e.attributes);t.children=e.children;var n=e.nodeName.defaultProps;if(void 0!==n)for(var r in n)void 0===t[r]&&(t[r]=n[r]);return t}function c(e,t){var n=t?document.createElementNS("http://www.w3.org/2000/svg",e):document.createElement(e);return n.__n=e,n}function u(e){var t=e.parentNode;t&&t.removeChild(e)}function h(e,t,n,o,r){if("className"===t&&(t="class"),"key"===t);else if("ref"===t)n&&n(null),o&&o(e);else if("class"!==t||r)if("style"===t){if(o&&"string"!=typeof o&&"string"!=typeof n||(e.style.cssText=o||""),o&&"object"==typeof o){if("string"!=typeof n)for(var i in n)i in o||(e.style[i]="");for(var i in o)e.style[i]="number"==typeof o[i]&&!1===j.test(i)?o[i]+"px":o[i]}}else if("dangerouslySetInnerHTML"===t)o&&(e.innerHTML=o.__html||"");else if("o"==t[0]&&"n"==t[1]){var s=t!==(t=t.replace(/Capture$/,""));t=t.toLowerCase().substring(2),o?n||e.addEventListener(t,p,s):e.removeEventListener(t,p,s),(e.__l||(e.__l={}))[t]=o}else if("list"!==t&&"type"!==t&&!r&&t in e)d(e,t,null==o?"":o),null!=o&&!1!==o||e.removeAttribute(t);else{var a=r&&t!==(t=t.replace(/^xlink\:?/,""));null==o||!1===o?a?e.removeAttributeNS("http://www.w3.org/1999/xlink",t.toLowerCase()):e.removeAttribute(t):"function"!=typeof o&&(a?e.setAttributeNS("http://www.w3.org/1999/xlink",t.toLowerCase(),o):e.setAttribute(t,o))}else e.className=o||""}function d(e,t,n){try{e[t]=n}catch(e){}}function p(e){return this.__l[e.type](I.event&&I.event(e)||e)}function f(){for(var e;e=P.pop();)I.afterMount&&I.afterMount(e),e.componentDidMount&&e.componentDidMount()}function v(e,t,n,o,r,i){R++||(U=null!=r&&void 0!==r.ownerSVGElement,D=null!=e&&!("__preactattr_"in e));var s=g(e,t,n,o,i);return r&&s.parentNode!==r&&r.appendChild(s),--R||(D=!1,i||f()),s}function g(e,t,n,o,r){var i=e,s=U;if(null!=t&&"boolean"!=typeof t||(t=""),"string"==typeof t||"number"==typeof t)return e&&void 0!==e.splitText&&e.parentNode&&(!e._component||r)?e.nodeValue!=t&&(e.nodeValue=t):(i=document.createTextNode(t),e&&(e.parentNode&&e.parentNode.replaceChild(i,e),y(e,!0))),i.__preactattr_=!0,i;var l=t.nodeName;if("function"==typeof l)return C(e,t,n,o);if(U="svg"===l||"foreignObject"!==l&&U,l=String(l),(!e||!a(e,l))&&(i=c(l,U),e)){for(;e.firstChild;)i.appendChild(e.firstChild);e.parentNode&&e.parentNode.replaceChild(i,e),y(e,!0)}var u=i.firstChild,h=i.__preactattr_,d=t.children;if(null==h){h=i.__preactattr_={};for(var p=i.attributes,f=p.length;f--;)h[p[f].name]=p[f].value}return!D&&d&&1===d.length&&"string"==typeof d[0]&&null!=u&&void 0!==u.splitText&&null==u.nextSibling?u.nodeValue!=d[0]&&(u.nodeValue=d[0]):(d&&d.length||null!=u)&&m(i,d,n,o,D||null!=h.dangerouslySetInnerHTML),k(i,t.attributes,h),U=s,i}function m(e,t,n,o,r){var i,a,l,c,h,d=e.childNodes,p=[],f={},v=0,m=0,_=d.length,k=0,b=t?t.length:0;if(0!==_)for(L=0;L<_;L++){var x=d[L],w=x.__preactattr_;null!=(S=b&&w?x._component?x._component.__k:w.key:null)?(v++,f[S]=x):(w||(void 0!==x.splitText?!r||x.nodeValue.trim():r))&&(p[k++]=x)}if(0!==b)for(L=0;L2?[].slice.call(arguments,2):e.children)},Component:N,render:function(e,t,n){return v(n,e,{},!1,t,!1)},rerender:i,options:I};void 0!==t?t.exports=B:self.preact=B}()},{}]},{},[3]); //# sourceMappingURL=haddock-bundle.min.js.map diff --git a/haddock-api/resources/html/js-src/cookies.ts b/haddock-api/resources/html/js-src/cookies.ts new file mode 100644 index 00000000..3b68d6d8 --- /dev/null +++ b/haddock-api/resources/html/js-src/cookies.ts @@ -0,0 +1,20 @@ +export function setCookie(name: string, value: string) { + document.cookie = name + "=" + encodeURIComponent(value) + ";path=/;"; +} + +export function clearCookie(name: string) { + document.cookie = name + "=;path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT;"; +} + +export function getCookie(name: string) { + const nameEQ = name + "="; + const ca = document.cookie.split(';'); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + while (c.charAt(0)==' ') c = c.substring(1,c.length); + if (c.indexOf(nameEQ) == 0) { + return decodeURIComponent(c.substring(nameEQ.length,c.length)); + } + } + return null; +} \ No newline at end of file diff --git a/haddock-api/resources/html/js-src/details-helper.ts b/haddock-api/resources/html/js-src/details-helper.ts new file mode 100644 index 00000000..f13ac905 --- /dev/null +++ b/haddock-api/resources/html/js-src/details-helper.ts @@ -0,0 +1,106 @@ +import {getCookie} from "./cookies"; + +interface HTMLDetailsElement extends HTMLElement { + open: boolean +} + +interface DetailsInfo { + element: HTMLDetailsElement + openByDefault: boolean + toggles: HTMLElement[] +} + +// Global state +const detailsRegistry: { [id: string]: DetailsInfo } = {}; +const toggled: { [id: string]: true } = {}; /* stores which
    are not in their default state */ + +function lookupDetailsRegistry(id: string): DetailsInfo { + const info = detailsRegistry[id]; + if (info == undefined) { throw new Error(`could not find
    element with id '${id}'`); } + return info; +} + +function onDetailsToggle(ev: Event) { + const element = ev.target as HTMLDetailsElement; + const id = element.id; + const info = lookupDetailsRegistry(id); + const isOpen = info.element.open; + for (const toggle of info.toggles) { + if (toggle.classList.contains('details-toggle-control')) { + toggle.classList.add(isOpen ? 'collapser' : 'expander'); + toggle.classList.remove(isOpen ? 'expander' : 'collapser'); + } + } + if (element.open == info.openByDefault) { + delete toggled[id]; + } else { + toggled[id] = true; + } + rememberToggled(); +} + +function gatherDetailsElements() { + const els: HTMLDetailsElement[] = Array.prototype.slice.call(document.getElementsByTagName('details')); + for (const el of els) { + if (typeof el.id == "string" && el.id.length > 0) { + detailsRegistry[el.id] = { + element: el, + openByDefault: !!el.open, + toggles: [] // added later + }; + el.addEventListener('toggle', onDetailsToggle); + } + } +} + +function toggleDetails(id: string) { + const {element} = lookupDetailsRegistry(id); + element.open = !element.open; +} + +function rememberToggled() { + const sections: string[] = Object.keys(toggled); + // cookie specific to this page; don't use setCookie which sets path=/ + document.cookie = "toggled=" + encodeURIComponent(sections.join('+')); +} + +function restoreToggled() { + const cookie = getCookie("toggled"); + if (!cookie) { return; } + const ids = cookie.split('+'); + for (const id of ids) { + const info = detailsRegistry[id]; + toggled[id] = true; + if (info) { + info.element.open = !info.element.open; + } + } +} + +function onToggleClick(ev: MouseEvent) { + ev.preventDefault(); + const toggle = ev.currentTarget as HTMLElement; + const id = toggle.getAttribute('data-details-id'); + if (!id) { throw new Error("element with class 'details-toggle' has no 'data-details-id' attribute!"); } + toggleDetails(id); +} + +function initCollapseToggles() { + const toggles: HTMLElement[] = Array.prototype.slice.call(document.getElementsByClassName('details-toggle')); + toggles.forEach(toggle => { + const id = toggle.getAttribute('data-details-id'); + if (!id) { throw new Error("element with class 'details-toggle' has no 'data-details-id' attribute!"); } + const info = lookupDetailsRegistry(id); + info.toggles.push(toggle); + toggle.addEventListener('click', onToggleClick); + if (toggle.classList.contains('details-toggle-control')) { + toggle.classList.add(info.element.open ? 'collapser' : 'expander'); + } + }); +} + +export function init() { + gatherDetailsElements(); + restoreToggled(); + initCollapseToggles(); +} \ No newline at end of file diff --git a/haddock-api/resources/html/js-src/haddock-util.ts b/haddock-api/resources/html/js-src/haddock-util.ts deleted file mode 100644 index 257ceb6a..00000000 --- a/haddock-api/resources/html/js-src/haddock-util.ts +++ /dev/null @@ -1,173 +0,0 @@ -// Haddock JavaScript utilities - -const rspace = /\s\s+/g, - rtrim = /^\s+|\s+$/g; - -function spaced(s: string) { return (" " + s + " ").replace(rspace, " "); } -function trim(s: string) { return s.replace(rtrim, ""); } - -function hasClass(elem: Element, value: string) { - const className = spaced(elem.className || ""); - return className.indexOf( " " + value + " " ) >= 0; -} - -function addClass(elem: Element, value: string) { - const className = spaced(elem.className || ""); - if ( className.indexOf( " " + value + " " ) < 0 ) { - elem.className = trim(className + " " + value); - } -} - -function removeClass(elem: Element, value: string) { - let className = spaced(elem.className || ""); - className = className.replace(" " + value + " ", " "); - elem.className = trim(className); -} - -function toggleClass(elem: Element, valueOn: string, valueOff: string, bool?: boolean): boolean { - if (bool == null) { bool = ! hasClass(elem, valueOn); } - if (bool) { - removeClass(elem, valueOff); - addClass(elem, valueOn); - } - else { - removeClass(elem, valueOn); - addClass(elem, valueOff); - } - return bool; -} - - -function makeClassToggle(valueOn: string, valueOff: string): (elem: Element, bool?: boolean) => boolean { - return function(elem, bool) { - return toggleClass(elem, valueOn, valueOff, bool); - } -} - -const toggleShow = makeClassToggle("show", "hide"); -const toggleCollapser = makeClassToggle("collapser", "expander"); - -function toggleSection(id: string): boolean { - const b = toggleShow(document.getElementById("section." + id) as Element); - toggleCollapser(document.getElementById("control." + id) as Element, b); - rememberCollapsed(id); - return b; -} - -// TODO: get rid of global variables -if (typeof window !== 'undefined') { - (window as any).toggleSection = toggleSection; -} - -const collapsed: { [id: string]: boolean } = {}; -function rememberCollapsed(id: string) { - if(collapsed[id]) - delete collapsed[id] - else - collapsed[id] = true; - - const sections: string[] = []; - for(let i in collapsed) { - if(collapsed.hasOwnProperty(i)) - sections.push(i); - } - // cookie specific to this page; don't use setCookie which sets path=/ - document.cookie = "collapsed=" + encodeURIComponent(sections.join('+')); -} - -export function restoreCollapsed() { - const cookie = getCookie("collapsed"); - if(!cookie) - return; - - const ids = cookie.split('+'); - for(const i in ids) - { - if(document.getElementById("section." + ids[i])) - toggleSection(ids[i]); - } -} - -function setCookie(name: string, value: string) { - document.cookie = name + "=" + encodeURIComponent(value) + ";path=/;"; -} - -function clearCookie(name: string) { - document.cookie = name + "=;path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT;"; -} - -function getCookie(name: string) { - const nameEQ = name + "="; - const ca = document.cookie.split(';'); - for (let i = 0; i < ca.length; i++) { - let c = ca[i]; - while (c.charAt(0)==' ') c = c.substring(1,c.length); - if (c.indexOf(nameEQ) == 0) { - return decodeURIComponent(c.substring(nameEQ.length,c.length)); - } - } - return null; -} - -function addMenuItem(html: string) { - const menu = document.getElementById("page-menu"); - if (menu && menu.firstChild) { - const btn = menu.firstChild.cloneNode(false) as Element; - btn.innerHTML = html; - menu.appendChild(btn); - } -} - -function styles(): HTMLLinkElement[] { - const es = Array.prototype.slice.call(document.getElementsByTagName("link")); - return es.filter((a: HTMLLinkElement) => a.rel.indexOf("style") != -1 && a.title); -} - -export function addStyleMenu() { - const as = styles(); - let btns = ""; - as.forEach((a) => { - btns += "
  • " - + a.title + "
  • " - }); - if (as.length > 1) { - const h = "
    " - + "Style ▾" - + "
      " + btns + "
    " - + "
    "; - addMenuItem(h); - } -} - -function setActiveStyleSheet(title: string) { - const as = styles(); - let found: null | HTMLLinkElement = null; - for(let i = 0; i < as.length; i++) { - const a = as[i]; - a.disabled = true; - // need to do this always, some browsers are edge triggered - if(a.title == title) { - found = a; - } - } - if (found) { - found.disabled = false; - setCookie("haddock-style", title); - } - else { - as[0].disabled = false; - clearCookie("haddock-style"); - } - styleMenu(false); -} - -export function resetStyle() { - const s = getCookie("haddock-style"); - if (s) setActiveStyleSheet(s); -} - -function styleMenu(show?: boolean) { - const m = document.getElementById('style-menu'); - if (m) toggleShow(m, show); -} \ No newline at end of file diff --git a/haddock-api/resources/html/js-src/init.ts b/haddock-api/resources/html/js-src/init.ts index 0619dfc3..877874ae 100644 --- a/haddock-api/resources/html/js-src/init.ts +++ b/haddock-api/resources/html/js-src/init.ts @@ -1,4 +1,5 @@ -import * as util from "./haddock-util"; +import * as styleMenu from "./style-menu"; +import * as detailsHelper from "./details-helper"; import * as quickJump from "./quick-jump"; function onDomReady(callback: () => void) { @@ -14,8 +15,8 @@ function onDomReady(callback: () => void) { } onDomReady(() => { - util.addStyleMenu(); - util.resetStyle(); - util.restoreCollapsed(); + document.body.classList.add('js-enabled'); + styleMenu.init(); + detailsHelper.init(); quickJump.init(); }); \ No newline at end of file diff --git a/haddock-api/resources/html/js-src/style-menu.ts b/haddock-api/resources/html/js-src/style-menu.ts new file mode 100644 index 00000000..3911655b --- /dev/null +++ b/haddock-api/resources/html/js-src/style-menu.ts @@ -0,0 +1,116 @@ +// Haddock JavaScript utilities + +import {getCookie, setCookie, clearCookie} from "./cookies"; + +const rspace = /\s\s+/g, + rtrim = /^\s+|\s+$/g; + +function spaced(s: string) { return (" " + s + " ").replace(rspace, " "); } +function trim(s: string) { return s.replace(rtrim, ""); } + +function hasClass(elem: Element, value: string) { + const className = spaced(elem.className || ""); + return className.indexOf( " " + value + " " ) >= 0; +} + +function addClass(elem: Element, value: string) { + const className = spaced(elem.className || ""); + if ( className.indexOf( " " + value + " " ) < 0 ) { + elem.className = trim(className + " " + value); + } +} + +function removeClass(elem: Element, value: string) { + let className = spaced(elem.className || ""); + className = className.replace(" " + value + " ", " "); + elem.className = trim(className); +} + +function toggleClass(elem: Element, valueOn: string, valueOff: string, bool?: boolean): boolean { + if (bool == null) { bool = ! hasClass(elem, valueOn); } + if (bool) { + removeClass(elem, valueOff); + addClass(elem, valueOn); + } + else { + removeClass(elem, valueOn); + addClass(elem, valueOff); + } + return bool; +} + +function makeClassToggle(valueOn: string, valueOff: string): (elem: Element, bool?: boolean) => boolean { + return function(elem, bool) { + return toggleClass(elem, valueOn, valueOff, bool); + } +} + +const toggleShow = makeClassToggle("show", "hide"); + +function addMenuItem(html: string) { + const menu = document.getElementById("page-menu"); + if (menu && menu.firstChild) { + const btn = menu.firstChild.cloneNode(false) as Element; + btn.innerHTML = html; + menu.appendChild(btn); + } +} + +function styles(): HTMLLinkElement[] { + const es = Array.prototype.slice.call(document.getElementsByTagName("link")); + return es.filter((a: HTMLLinkElement) => a.rel.indexOf("style") != -1 && a.title); +} + +function addStyleMenu() { + const as = styles(); + let btns = ""; + as.forEach((a) => { + btns += "
  • " + + a.title + "
  • " + }); + if (as.length > 1) { + const h = "
    " + + "Style ▾" + + "
      " + btns + "
    " + + "
    "; + addMenuItem(h); + } +} + +function setActiveStyleSheet(title: string) { + const as = styles(); + let found: null | HTMLLinkElement = null; + for(let i = 0; i < as.length; i++) { + const a = as[i]; + a.disabled = true; + // need to do this always, some browsers are edge triggered + if(a.title == title) { + found = a; + } + } + if (found) { + found.disabled = false; + setCookie("haddock-style", title); + } + else { + as[0].disabled = false; + clearCookie("haddock-style"); + } + styleMenu(false); +} + +function resetStyle() { + const s = getCookie("haddock-style"); + if (s) setActiveStyleSheet(s); +} + +function styleMenu(show?: boolean) { + const m = document.getElementById('style-menu'); + if (m) toggleShow(m, show); +} + +export function init() { + addStyleMenu(); + resetStyle(); +} \ No newline at end of file diff --git a/haddock-api/src/Haddock/Backends/Xhtml.hs b/haddock-api/src/Haddock/Backends/Xhtml.hs index e8148782..c76c0c88 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml.hs @@ -310,11 +310,11 @@ mkNode qual ss p (Node s leaf pkg srcPkg short ts) = htmlModule <+> shortDescr +++ htmlPkg +++ subtree where modAttrs = case (ts, leaf) of - (_:_, False) -> collapseControl p True "module" + (_:_, False) -> collapseControl p "module" (_, _ ) -> [theclass "module"] cBtn = case (ts, leaf) of - (_:_, True) -> thespan ! collapseControl p True "" << spaceHtml + (_:_, True) -> thespan ! collapseControl p "" << spaceHtml (_, _ ) -> noHtml -- We only need an explicit collapser button when the module name -- is also a leaf, and so is a link to a module page. Indeed, the @@ -332,7 +332,12 @@ mkNode qual ss p (Node s leaf pkg srcPkg short ts) = shortDescr = maybe noHtml (origDocToHtml qual) short htmlPkg = maybe noHtml (thespan ! [theclass "package"] <<) srcPkg - subtree = mkNodeList qual (s:ss) p ts ! collapseSection p True "" + subtree = + if null ts then noHtml else + collapseDetails p DetailsOpen ( + thesummary ! [ theclass "hide-when-js-enabled" ] << "Submodules" +++ + mkNodeList qual (s:ss) p ts + ) @@ -586,10 +591,12 @@ ifaceToHtml maybe_source_url maybe_wiki_url iface unicode qual | no_doc_at_all = noHtml | otherwise = divSynopsis $ - paragraph ! collapseControl "syn" False "caption" << "Synopsis" +++ - shortDeclList ( - mapMaybe (processExport True linksInfo unicode qual) exports - ) ! (collapseSection "syn" False "" ++ collapseToggle "syn") + collapseDetails "syn" DetailsClosed ( + thesummary << "Synopsis" +++ + shortDeclList ( + mapMaybe (processExport True linksInfo unicode qual) exports + ) ! collapseToggle "syn" "" + ) -- if the documentation doesn't begin with a section header, then -- add one ("Documentation"). diff --git a/haddock-api/src/Haddock/Backends/Xhtml/DocMarkup.hs b/haddock-api/src/Haddock/Backends/Xhtml/DocMarkup.hs index 18c8a0ff..e63667b0 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/DocMarkup.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/DocMarkup.hs @@ -165,9 +165,9 @@ hackMarkup fmt' h' = UntouchedDoc d -> (markup fmt $ _doc d, [_meta d]) CollapsingHeader (Header lvl titl) par n nm -> let id_ = makeAnchorId $ "ch:" ++ fromMaybe "noid:" nm ++ show n - expanded = False - col' = collapseControl id_ expanded "caption" - instTable = (thediv ! collapseSection id_ expanded [] <<) + col' = collapseControl id_ "caption" + summary = thesummary ! [ theclass "hide-when-js-enabled" ] << "Expand" + instTable contents = collapseDetails id_ DetailsClosed (summary +++ contents) lvs = zip [1 .. ] [h1, h2, h3, h4, h5, h6] getHeader = fromMaybe caption (lookup lvl lvs) subCaption = getHeader ! col' << markup fmt titl diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Layout.hs b/haddock-api/src/Haddock/Backends/Xhtml/Layout.hs index 6993c7f6..e020b909 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/Layout.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/Layout.hs @@ -199,10 +199,10 @@ subInstances :: Qualification -> [(SubDecl,Located DocName)] -> Html subInstances qual nm lnks splice = maybe noHtml wrap . instTable where - wrap = (subSection <<) . (subCaption +++) - instTable = fmap (thediv ! collapseSection id_ True [] <<) . subTableSrc qual lnks splice + wrap contents = subSection (collapseDetails id_ DetailsOpen (summary +++ contents)) + instTable = subTableSrc qual lnks splice subSection = thediv ! [theclass "subs instances"] - subCaption = paragraph ! collapseControl id_ True "caption" << "Instances" + summary = thesummary << "Instances" id_ = makeAnchorId $ "i:" ++ nm @@ -212,7 +212,7 @@ subOrphanInstances :: Qualification subOrphanInstances qual lnks splice = maybe noHtml wrap . instTable where wrap = ((h1 << "Orphan instances") +++) - instTable = fmap (thediv ! collapseSection id_ True [] <<) . subTableSrc qual lnks splice + instTable = fmap (thediv ! [ identifier ("section." ++ id_) ] <<) . subTableSrc qual lnks splice id_ = makeAnchorId $ "orphans" @@ -222,7 +222,7 @@ subInstHead :: String -- ^ Instance unique id (for anchor generation) subInstHead iid hdr = expander noHtml <+> hdr where - expander = thespan ! collapseControl (instAnchorId iid) False "instance" + expander = thespan ! collapseControl (instAnchorId iid) "instance" subInstDetails :: String -- ^ Instance unique id (for anchor generation) @@ -241,7 +241,9 @@ subFamInstDetails iid fi = subInstSection :: String -- ^ Instance unique id (for anchor generation) -> Html -> Html -subInstSection iid = thediv ! collapseSection (instAnchorId iid) False "inst-details" +subInstSection iid contents = collapseDetails (instAnchorId iid) DetailsClosed (summary +++ contents) + where + summary = thesummary ! [ theclass "hide-when-js-enabled" ] << "Instance details" instAnchorId :: String -> String instAnchorId iid = makeAnchorId $ "i:" ++ iid diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs b/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs index a8b4a4ec..a75c4b9a 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs @@ -25,7 +25,8 @@ module Haddock.Backends.Xhtml.Utils ( hsep, vcat, - collapseSection, collapseToggle, collapseControl, + DetailsState(..), collapseDetails, thesummary, + collapseToggle, collapseControl, ) where @@ -213,26 +214,22 @@ groupId g = makeAnchorId ("g:" ++ g) -- A section of HTML which is collapsible. -- --- | Attributes for an area that can be collapsed -collapseSection :: String -> Bool -> String -> [HtmlAttr] -collapseSection id_ state classes = [ identifier sid, theclass cs ] - where cs = unwords (words classes ++ [pick state "show" "hide"]) - sid = "section." ++ id_ +data DetailsState = DetailsOpen | DetailsClosed + +collapseDetails :: String -> DetailsState -> Html -> Html +collapseDetails id_ state = tag "details" ! (identifier id_ : openAttrs) + where openAttrs = case state of { DetailsOpen -> [emptyAttr "open"]; DetailsClosed -> [] } + +thesummary :: Html -> Html +thesummary = tag "summary" -- | Attributes for an area that toggles a collapsed area -collapseToggle :: String -> [HtmlAttr] -collapseToggle id_ = [ strAttr "onclick" js ] - where js = "toggleSection('" ++ id_ ++ "')"; +collapseToggle :: String -> String -> [HtmlAttr] +collapseToggle id_ classes = [ theclass cs, strAttr "data-details-id" id_ ] + where cs = unwords (words classes ++ ["details-toggle"]) -- | Attributes for an area that toggles a collapsed area, -- and displays a control. -collapseControl :: String -> Bool -> String -> [HtmlAttr] -collapseControl id_ state classes = - [ identifier cid, theclass cs ] ++ collapseToggle id_ - where cs = unwords (words classes ++ [pick state "collapser" "expander"]) - cid = "control." ++ id_ - - -pick :: Bool -> a -> a -> a -pick True t _ = t -pick False _ f = f +collapseControl :: String -> String -> [HtmlAttr] +collapseControl id_ classes = collapseToggle id_ cs + where cs = unwords (words classes ++ ["details-toggle-control"]) \ No newline at end of file diff --git a/html-test/ref/A.html b/html-test/ref/A.html index 094455f8..1fbfb371 100644 --- a/html-test/ref/A.html +++ b/html-test/ref/A.html @@ -39,44 +39,46 @@ >A

    Synopsis

    B

    Synopsis

    Bold

    Synopsis

    Synopsis

    Bug1

    Synopsis

    • data T = T
    Synopsis
    • data T = T

    Bug201

    Synopsis

    • f :: ()
    • Synopsis
      • g :: ()
      f :: ()
    • g :: ()

    Synopsis

    Synopsis

    Synopsis

    • f :: ()
    • g :: ()
    • Synopsis
      • class C a where
          f :: ()
        • g :: ()
        • class C a where

      Instances

      Instances
      C
      Instance details

      Methods

      #

      #

      Instances

      Instances
      data
      Instance details
      data A
      data
      Instance details
      data TP A
      #

      Instances

      Instances
      data
      Instance details
      data A
      Bug298

      Synopsis

      Bug3

      Synopsis

      Synopsis

      Bug308

      Synopsis

      Bug308CrossModule

      Synopsis

      Synopsis
      • h :: ()

      Bug310

      Synopsis

      Synopsis
      • type family (a :: Nat) + (b :: Nat) :: Nat where ...

      Synopsis

      Bug335

      Synopsis

      #

      ExF:

      Expand

      abc

      #

      ExG:

      Expand
      >>> Under ex

      foo

      Out of Ex

      Synopsis

      Bug4

      Synopsis

      Synopsis

      Synopsis

      Bug613

      Synopsis

      Instances

      Instances
      Functor
      Instance details

      Methods

      #

      Functor
      Instance details

      Methods

      #

      Instances

      Instances
      Functor
      Instance details

      Methods

      #

      Synopsis

      Instances

      Instances
      Bar
      Instance details
      The Bar class

      Instances

      Instances
      Bar
      Instance details
      BugDeprecated

      Synopsis

      Synopsis

      BundledPatterns

      Synopsis

      BundledPatterns2

      Synopsis

      DeprecatedClass

      Synopsis

      DeprecatedData

      Synopsis

      DeprecatedFunction

      Synopsis

      DeprecatedFunction2

      Synopsis

      Synopsis

      DeprecatedFunction3

      Synopsis

      Synopsis

      DeprecatedNewtype

      Synopsis

      Synopsis

      DeprecatedRecord

      Synopsis

      DeprecatedTypeFamily

      Synopsis

      DeprecatedTypeSynonym

      Synopsis

      Examples

      Synopsis

      Synopsis

      Extensions

      Synopsis

      Synopsis

      GADTRecords

      Synopsis

      Synopsis

      Instances

      Instances
      Hash
      Instance details

      Methods

      #

      Hash
      Instance details

      Methods

      #

      (Hash
      Instance details

      Methods

      #

      HiddenInstances

      Synopsis

      Should be visible

      Instances

      Instances
      VisibleClass
      Instance details
      VisibleClass
      Instance details
      Should be visible

      Instances

      Instances
      Num
      Instance details

      Methods

      #

      VisibleClass
      Instance details
      HiddenInstancesB

      Synopsis

      Should be visible

      Instances

      Instances
      Foo
      Instance details
      Should be visible

      Instances

      Instances
      Foo
      Instance details
      Hyperlinks

      Synopsis

      Synopsis

      IgnoreExports

      Synopsis

      Instances

      Instances
      Foo
      Instance details

      Methods

      #

      Instances

      Instances
      Foo
      Instance details

      Methods

      #

      Foo
      Instance details

      Methods

      #

      Foo
      Instance details

      Methods

      #

      (Eq
      Instance details

      Methods

      #

      Foo
      Instance details

      Methods

      #

      Foo
      Instance details

      Methods

      #

      Foo
      Instance details

      Methods

      #

      Foo
      Instance details

      Methods

      #

      Instances

      Instances
      Bar
      Instance details

      Methods

      #

      Bar
      Instance details

      Methods

      #

      Bar
      Instance details

      Methods

      #

      Foo
      Instance details

      Methods

      #

      Foo
      Instance details

      Methods

      #

      Bar
      Instance details

      Methods

      #

      Instances

      Instances
      Baz
      Instance details

      Methods

      #

      Baz
      Instance details

      Methods

      #

      Baz
      Instance details

      Methods

      #

      Baz
      Instance details

      Methods

      #

      Baz
      Instance details

      Methods

      #

      Instances

      Instances
      Foo
      Instance details

      Methods

      #

      Bar
      Instance details

      Methods

      #

      Baz
      Instance details

      Methods

      #

      data
      Instance details
      data

      Instances

      Instances
      Norf
      Instance details

      Associated Types

      #

      Norf
      Instance details

      Associated Types

      #

      Synopsis

      Synopsis

      NamedDoc

      Synopsis

        Synopsis

          Nesting

          Synopsis

          • d :: t
          • e :: t
          • f :: t
          • g :: t
          • Synopsis
            • h :: t
            • i :: t
            • j :: t
            • k :: t
            d :: t
          • e :: t
          • f :: t
          • g :: t
          • h :: t
          • i :: t
          • j :: t
          • k :: t

          NoLayout

          Synopsis

          Synopsis

          NonGreedy

          Synopsis

          • f :: a
          Synopsis
          • f :: a

          Synopsis

          Synopsis

            Synopsis

              Documentation

              Orphan instances

              AClass
              Instance details

              Methods

              #

              PR643

              Synopsis

              Synopsis

              PR643_1

              Synopsis

              Synopsis

              Synopsis

              Properties

              Synopsis

              Synopsis

              Instances

              Instances
              Show
              Instance details

              Methods

              #

              Instances

              Instances
              Show
              Instance details

              Methods

              #

              #

              Instances

              Instances
              Functor
              Instance details

              Methods

              #

              Applicative
              Instance details

              Methods

              #

              Synopsis

              Instances

              Instances
              D
              Instance details

              Methods

              #

              D
              Instance details

              Methods

              #

              Synopsis

              Synopsis

              Synopsis

              Synopsis

              Ticket112

              Synopsis

              • f :: a
              Synopsis
              • f :: a

              Ticket75

              Synopsis

              TitledPicture

              Synopsis

              Synopsis

              • data X
              • Synopsis
              • class Test a
              • type family Foo a :: k
              • data family Bat (a :: k) :: *
              • class Assoc a where
              • type family Bar b where ...
              • type family (a :: k) <> (b :: k) :: k
              • class (a :: k) >< (b :: k)

              Instances

              Instances
              (><)
              Instance details
              Assoc
              Instance details

              Associated Types

              #

              Test
              Instance details
              type
              Instance details
              type = Y
              type
              Instance details
              type = X
              data
              Instance details
              type
              Instance details
              type X
              data
              Instance details
              data }
              type
              Instance details
              type = Y
              type
              Instance details
              type a = X
              Doc for: data Y

              Instances

              Instances
              Assoc
              Instance details

              Associated Types

              #

              Test
              Instance details
              data
              Instance details
              data Y
              data
              Instance details
              type
              Instance details
              type Y
              data
              Instance details
              data Y
              type
              Instance details
              type = X
              type
              Instance details
              type Y a = a

              Instances

              Instances
              data
              Instance details
              data
              Doc for: class Test a

              Instances

              Instances
              Test
              Instance details
              Test
              Instance details
              Doc for: type family Foo a

              Instances

              Instances
              type
              Instance details
              type = X
              type
              Instance details
              type = Y
              Doc for: data family Bat a

              Instances

              Instances
              data
              Instance details
              data
              data
              Instance details
              data Y
              data
              Instance details
              data }

              Instances

              Instances
              Assoc
              Instance details

              Associated Types

              #

              Assoc
              Instance details

              Associated Types

              #

              #

              Instances

              Instances
              type
              Instance details
              type = X
              type
              Instance details
              type Y a = a
              type
              Instance details
              type a = X
              #

              Instances

              Instances
              (><)
              Instance details
              TypeFamilies2

              Synopsis

              • data W
              • type family Foo a
              • Synopsis
                • data family Bar a
                data W
              • type family Foo a
              • data family Bar a

              Exported type

              Instances

              Instances
              data
              Instance details
              data = BarX Z
              type
              Instance details
              type W
              Exported type family

              Instances

              Instances
              type
              Instance details
              type W
              type
              Instance details
              type = Y
              Exported data family

              Instances

              Instances
              data
              Instance details
              data = BarX Z
              data
              Instance details
              data Y
              Unicode

              Synopsis

              Synopsis