├── .doingrc ├── .gitignore ├── CHANGELOG.md ├── README.md ├── _config.yml ├── checkmark-dark.png ├── checkmark.png ├── config.codekit3 ├── config.rb ├── dist ├── css │ └── niftymenu.css ├── images │ ├── background.jpg │ ├── background2.jpg │ ├── darkbackground.jpg │ └── locked.svg ├── js │ ├── handler.min.js │ ├── lib │ │ ├── fuzzysort.min.js │ │ ├── html2canvas.min.js │ │ ├── jquery.min.js │ │ ├── jquery.min.min.js │ │ └── mousetrap.min.js │ ├── modules.min.js │ ├── nifty.min.js │ └── search.min.js └── testMenu.html ├── docs ├── MultiMarkdown-Composer.html ├── Pages.html ├── README.md ├── css │ └── niftymenu.css ├── images │ ├── background.jpg │ ├── background2.jpg │ ├── darkbackground.jpg │ └── locked.svg ├── js │ ├── handler.min.js │ ├── lib │ │ ├── fuzzysort.min.js │ │ ├── html2canvas.min.js │ │ ├── jquery.min.js │ │ ├── jquery.min.min.js │ │ └── mousetrap.min.js │ ├── modules.min.js │ ├── nifty.min.js │ └── search.min.js ├── jsapi │ ├── NiftyAPI.html │ ├── api.js.html │ ├── callout.js.html │ ├── fonts │ │ ├── OpenSans-Bold-webfont.eot │ │ ├── OpenSans-Bold-webfont.svg │ │ ├── OpenSans-Bold-webfont.woff │ │ ├── OpenSans-BoldItalic-webfont.eot │ │ ├── OpenSans-BoldItalic-webfont.svg │ │ ├── OpenSans-BoldItalic-webfont.woff │ │ ├── OpenSans-Italic-webfont.eot │ │ ├── OpenSans-Italic-webfont.svg │ │ ├── OpenSans-Italic-webfont.woff │ │ ├── OpenSans-Light-webfont.eot │ │ ├── OpenSans-Light-webfont.svg │ │ ├── OpenSans-Light-webfont.woff │ │ ├── OpenSans-LightItalic-webfont.eot │ │ ├── OpenSans-LightItalic-webfont.svg │ │ ├── OpenSans-LightItalic-webfont.woff │ │ ├── OpenSans-Regular-webfont.eot │ │ ├── OpenSans-Regular-webfont.svg │ │ ├── OpenSans-Regular-webfont.woff │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ ├── handler.js.html │ ├── img │ │ ├── glyphicons-halflings-white.png │ │ └── glyphicons-halflings.png │ ├── index.html │ ├── namespaces.list.html │ ├── nifty.js.html │ ├── quicksearch.html │ ├── scripts │ │ ├── docstrap.lib.js │ │ ├── fulltext-search-ui.js │ │ ├── fulltext-search.js │ │ ├── linenumber.js │ │ ├── lunr.min.js │ │ ├── prettify │ │ │ ├── Apache-License-2.0.txt │ │ │ ├── jquery.min.js │ │ │ ├── lang-css.js │ │ │ └── prettify.js │ │ ├── sunlight.js │ │ └── toc.js │ ├── styles │ │ ├── darkstrap.css │ │ ├── jsdoc-default.css │ │ ├── prettify-jsdoc.css │ │ ├── prettify-tomorrow.css │ │ ├── site.cerulean.css │ │ ├── site.cosmo.css │ │ ├── site.cyborg.css │ │ ├── site.darkly.css │ │ ├── site.darkstrap.css │ │ ├── site.dibs-bootstrap.css │ │ ├── site.flatly.css │ │ ├── site.journal.css │ │ ├── site.lumen.css │ │ ├── site.paper.css │ │ ├── site.readable.css │ │ ├── site.sandstone.css │ │ ├── site.simplex.css │ │ ├── site.slate.css │ │ ├── site.spacelab.css │ │ ├── site.superhero.css │ │ ├── site.united.css │ │ ├── site.yeti.css │ │ ├── sunlight.dark.css │ │ └── sunlight.default.css │ └── util.js.html └── testMenu.html ├── javascript ├── .jshintrc ├── README.html ├── README.md ├── app.js ├── lib │ ├── fuzzysort.js │ ├── html2canvas.min.js │ ├── jquery.js │ └── mousetrap.js └── modules │ ├── api.js │ ├── callout.js │ ├── handler.js │ ├── modules.js │ ├── nifty.js │ ├── prefs.js │ ├── search.js │ └── util.js ├── niftymenu.rb ├── out ├── NiftyAPI.html ├── fonts │ ├── OpenSans-Bold-webfont.eot │ ├── OpenSans-Bold-webfont.svg │ ├── OpenSans-Bold-webfont.woff │ ├── OpenSans-BoldItalic-webfont.eot │ ├── OpenSans-BoldItalic-webfont.svg │ ├── OpenSans-BoldItalic-webfont.woff │ ├── OpenSans-Italic-webfont.eot │ ├── OpenSans-Italic-webfont.svg │ ├── OpenSans-Italic-webfont.woff │ ├── OpenSans-Light-webfont.eot │ ├── OpenSans-Light-webfont.svg │ ├── OpenSans-Light-webfont.woff │ ├── OpenSans-LightItalic-webfont.eot │ ├── OpenSans-LightItalic-webfont.svg │ ├── OpenSans-LightItalic-webfont.woff │ ├── OpenSans-Regular-webfont.eot │ ├── OpenSans-Regular-webfont.svg │ └── OpenSans-Regular-webfont.woff ├── index.html ├── lib_mousetrap.js.html ├── modules_api.js.html ├── modules_callout.js.html ├── modules_handler.js.html ├── modules_nifty.js.html ├── scripts │ ├── linenumber.js │ └── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── lang-css.js │ │ └── prettify.js └── styles │ ├── jsdoc-default.css │ ├── prettify-jsdoc.css │ └── prettify-tomorrow.css ├── package-lock.json ├── sass ├── custom │ ├── _custom.scss │ └── _variables.scss ├── include │ └── _colors.scss └── niftymenu.scss └── scripts ├── docjs └── jsdoc.conf.json /.doingrc: -------------------------------------------------------------------------------- 1 | --- 2 | default_tags: [niftymenu] 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /get nvUltra menus.applescript 2 | /osatest.applescript 3 | dist/*.html 4 | node_modules 5 | .doingrc 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 1.0.9 2 | 3 | 2023-05-03 12:05 4 | 5 | #### IMPROVED 6 | 7 | - Update submenu indicator for Ventura styling 8 | - Reduce font size for Ventura visible compatibility 9 | - Better font stack for macOS system font 10 | 11 | ### 1.0.8 12 | 13 | - Update submenu indicator 14 | 15 | ### 1.0.7 16 | 17 | - update docs 18 | 19 | ### 1.0.4 20 | 21 | - force wallpaper update when switching dark mode 22 | - reload page after expose to restore width 23 | - reorder submenu 24 | - menu transparency in dark mode 25 | 26 | ### 1.0.1 27 | 28 | - Refactored all JS code 29 | 30 | ### 1.0.0 31 | 32 | - Rewritten JavaScript API 33 | - Keyboard shortcuts in menu 34 | - Customizable desktop images 35 | 36 | ### 0.1.4 37 | 38 | - js api touchup 39 | - Adds keyboard shortcuts in menu 40 | 41 | 42 | ### 0.1.3 43 | 44 | - Click behavior, demo tutorial 45 | - Better callout handling 46 | - Onscreen tutorial for demo pages 47 | - Position arrow callout on left if item has submenu 48 | 49 | 50 | ### 0.1 51 | 52 | - Initial release 53 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /checkmark-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/checkmark-dark.png -------------------------------------------------------------------------------- /checkmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/checkmark.png -------------------------------------------------------------------------------- /config.rb: -------------------------------------------------------------------------------- 1 | # Require any additional compass plugins here. 2 | sass_options = { :cache_location => '/tmp/sass_cache' } 3 | # Set this to the root of your project when deployed: 4 | http_path = "dist" 5 | css_dir = "dist/css" 6 | sass_dir = "sass" 7 | images_dir = "dist/images" 8 | javascripts_dir = "dist/js" 9 | 10 | # You can select your preferred output style here (can be overridden via the command line): 11 | # output_style = :expanded or :nested or :compact or :compressed 12 | output_style = :compressed 13 | 14 | # To enable relative paths to assets via compass helper functions. Uncomment: 15 | # relative_assets = true 16 | 17 | # To disable debugging comments that display the original location of your selectors. Uncomment: 18 | line_comments = false 19 | 20 | # If you prefer the indented syntax, you might want to regenerate this 21 | # project again passing --syntax sass, or you can uncomment this: 22 | # preferred_syntax = :sass 23 | # and then run: 24 | # sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass 25 | 26 | -------------------------------------------------------------------------------- /dist/images/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/dist/images/background.jpg -------------------------------------------------------------------------------- /dist/images/background2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/dist/images/background2.jpg -------------------------------------------------------------------------------- /dist/images/darkbackground.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/dist/images/darkbackground.jpg -------------------------------------------------------------------------------- /dist/images/locked.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dist/js/handler.min.js: -------------------------------------------------------------------------------- 1 | import Util from"util.js";import Callout from"callout.js";import Prefs from"prefs.js";import Search from"search.js";const Handler=function(){const e=()=>{let e=prompt("Enter URL for background image");Prefs.set("wallpaper",e),Util.loadWallpaper()},l=()=>{let e=prompt("Enter optional keywords (comma separated words)"),l="https://source.unsplash.com/random/1900x1200?"+encodeURIComponent(e);Prefs.set("wallpaper",l),Util.loadWallpaper()};return{itemClick:e=>{e.preventDefault();let l,t=!1;if("SPAN"===e.target.tagName?(l=$(e.target).closest("li"),$(e.target).hasClass("shortcut")&&(t=!0)):l=$(e.target),e.metaKey||e.altKey)return e.metaKey?Callout.toggleCheckmark(l):e.altKey&&(t?Callout.toggleShortcut(l):Callout.toggleArrow(l)),!1;if($(".callout").removeClass("callout"),$(".persist").removeClass("persist"),"BODY"===e.target.tagName)$(".clicked").removeClass("clicked"),$(".last").removeClass("last"),Callout.setArrow(!1),Callout.setShortcut(!1);else{if(l.hasClass("clicked"))return l.find(".last").length?(Util.clearClicks(),l.parents("li").addClass("clicked"),l.addClass("clicked last")):($(".last").removeClass("last"),l.parents(".clicked").length?(l.removeClass("clicked"),l.siblings(".clicked").removeClass("clicked"),l.parents(".clicked").first().addClass("last")):$(".clicked").removeClass("clicked"),Callout.setArrow(!1),Callout.setShortcut(!1)),!1;Callout.setArrow(!1),Callout.setShortcut(!1),$("li.clicked").removeClass("clicked"),$(".last").removeClass("last"),l.parents("li").addClass("clicked"),e.altKey&&Callout.setArrow(!0,l),l.addClass("clicked last"),"dblclick"===e.type&&(l.addClass("callout"),e.shiftKey&&l.parents(".clicked").addClass("callout"))}return!1},controlsClick:t=>{switch(t.preventDefault(),t.target.id){case"darkModeToggle":Util.toggleDarkMode();break;case"exposeToggle":Util.toggleExpose();break;case"backgroundToggle":Util.toggleBG();break;case"chooseWallpaper":e();break;case"randomWallpaper":l();break;case"resetWallpaper":Util.setWallpaper(!1);break;case"arrowStyle":Callout.toggleArrowStyle();break;case"screenshot":Util.screenshot(t);break;case"commandshell":Util.terminal(t);break;default:throw"Element ID unrecognized"}return!1},liveSearch:e=>{let l=$(".helpsearch input"),t=l.val(),a=!1;if("Escape"===e.code)return e.preventDefault(),l.val("").blur(),Util.clearClicks(!0),!0;if("Enter"!==e.code&&"Return"!==e.code||(e.preventDefault(),$(".persist").removeClass("persist"),a=!0),t.length<2)return Util.clearClicks(!1),!0;let r=Search.find(t);return r?(Util.clearClicks(!1),r.parents("li")&&r.parents("li").addClass("clicked"),r.addClass("clicked last"),a&&(l.blur(),r.get(0).scrollIntoView({behavior:"smooth",block:"end",inline:"center"}))):Util.clearClicks(!1),!0},focusSearch:e=>{e.preventDefault(),$("li.callout").removeClass("callout"),$(".clicked").removeClass("clicked"),Util.clearClicks();let l=$(".helpsearch").first();return l.parents("li").addClass("clicked persist"),l.get(0).scrollIntoView({behavior:"smooth",block:"end",inline:"end"}),$("input",l).focus(),!1}}}();export default Handler; -------------------------------------------------------------------------------- /dist/js/lib/fuzzysort.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define([],r):"object"==typeof module&&module.exports?module.exports=r():e.fuzzysort=r()}(this,(function(){var e="undefined"!=typeof require&&"undefined"==typeof window,r=new Map,n=new Map,o=[];o.total=0;var t=[],i=[];function a(){r.clear(),n.clear(),t=[],i=[]}function l(e){for(var r=-9007199254740991,n=e.length-1;n>=0;--n){var o=e[n];if(null!==o){var t=o.score;t>r&&(r=t)}}return-9007199254740991===r?null:r}function f(e,r){var n=e[r];if(void 0!==n)return n;var o=r;Array.isArray(r)||(o=r.split("."));for(var t=o.length,i=-1;e&&++i>1]=e[n],t=1+(n<<1)}for(var a=n-1>>1;n>0&&o.score>1)e[n]=e[a];e[n]=o}return n.add=function(n){var o=r;e[r++]=n;for(var t=o-1>>1;o>0&&n.score>1)e[o]=e[t];e[o]=n},n.poll=function(){if(0!==r){var n=e[0];return e[0]=e[--r],o(),n}},n.peek=function(n){if(0!==r)return e[0]},n.replaceTop=function(r){e[0]=r,o()},n},p=s();return function d(c){var g={single:function(e,r,n){return e?(u(e)||(e=g.getPreparedSearch(e)),r?(u(r)||(r=g.getPrepared(r)),((n&&void 0!==n.allowTypo?n.allowTypo:!c||void 0===c.allowTypo||c.allowTypo)?g.algorithm:g.algorithmNoTypo)(e,r,e[0])):null):null},go:function(e,r,n){if(!e)return o;var t=(e=g.prepareSearch(e))[0],i=n&&n.threshold||c&&c.threshold||-9007199254740991,a=n&&n.limit||c&&c.limit||9007199254740991,s=(n&&void 0!==n.allowTypo?n.allowTypo:!c||void 0===c.allowTypo||c.allowTypo)?g.algorithm:g.algorithmNoTypo,d=0,v=0,h=r.length;if(n&&n.keys)for(var w=n.scoreFn||l,x=n.keys,y=x.length,m=h-1;m>=0;--m){for(var T=r[m],k=new Array(y),b=y-1;b>=0;--b){(_=f(T,B=x[b]))?(u(_)||(_=g.getPrepared(_)),k[b]=s(e,_,t)):k[b]=null}k.obj=T;var I=w(k);null!==I&&(Ip.peek().score&&p.replaceTop(k))))}else if(n&&n.key){var B=n.key;for(m=h-1;m>=0;--m){if(_=f(T=r[m],B))u(_)||(_=g.getPrepared(_)),null!==(C=s(e,_,t))&&(C.scorep.peek().score&&p.replaceTop(C))))}}else for(m=h-1;m>=0;--m){var _,C;if(_=r[m])u(_)||(_=g.getPrepared(_)),null!==(C=s(e,_,t))&&(C.scorep.peek().score&&p.replaceTop(C))))}if(0===d)return o;var A=new Array(d);for(m=d-1;m>=0;--m)A[m]=p.poll();return A.total=d+v,A},goAsync:function(r,n,t){var i=!1,a=new Promise((function(a,p){if(!r)return a(o);var d=(r=g.prepareSearch(r))[0],v=s(),h=n.length-1,w=t&&t.threshold||c&&c.threshold||-9007199254740991,x=t&&t.limit||c&&c.limit||9007199254740991,y=(t&&void 0!==t.allowTypo?t.allowTypo:!c||void 0===c.allowTypo||c.allowTypo)?g.algorithm:g.algorithmNoTypo,m=0,T=0;function k(){if(i)return p("canceled");var s=Date.now();if(t&&t.keys)for(var c=t.scoreFn||l,b=t.keys,I=b.length;h>=0;--h){for(var B=n[h],_=new Array(I),C=I-1;C>=0;--C){(P=f(B,L=b[C]))?(u(P)||(P=g.getPrepared(P)),_[C]=y(r,P,d)):_[C]=null}_.obj=B;var A=c(_);if(null!==A&&(!(Av.peek().score&&v.replaceTop(_)),h%1e3==0&&Date.now()-s>=10)))return void(e?setImmediate(k):setTimeout(k))}else if(t&&t.key)for(var L=t.key;h>=0;--h){if(P=f(B=n[h],L))if(u(P)||(P=g.getPrepared(P)),null!==(j=y(r,P,d))&&!(j.scorev.peek().score&&v.replaceTop(j)),h%1e3==0&&Date.now()-s>=10))return void(e?setImmediate(k):setTimeout(k))}else for(;h>=0;--h){var P,j;if(P=n[h])if(u(P)||(P=g.getPrepared(P)),null!==(j=y(r,P,d))&&!(j.scorev.peek().score&&v.replaceTop(j)),h%1e3==0&&Date.now()-s>=10))return void(e?setImmediate(k):setTimeout(k))}if(0===m)return a(o);for(var N=new Array(m),S=m-1;S>=0;--S)N[S]=v.poll();N.total=m+T,a(N)}e?setImmediate(k):k()}));return a.cancel=function(){i=!0},a},highlight:function(e,r,n){if(null===e)return null;void 0===r&&(r=""),void 0===n&&(n="");for(var o="",t=0,i=!1,a=e.target,l=a.length,f=e.indexes,u=0;u999)return g.prepare(e);var n=r.get(e);return void 0!==n?n:(n=g.prepare(e),r.set(e,n),n)},getPreparedSearch:function(e){if(e.length>999)return g.prepareSearch(e);var r=n.get(e);return void 0!==r?r:(r=g.prepareSearch(e),n.set(e,r),r)},algorithm:function(e,r,n){for(var o=r._targetLowerCodes,a=e.length,l=o.length,f=0,u=0,s=0,p=0;;){if(n===o[u]){if(t[p++]=u,++f===a)break;n=e[0===s?f:s===f?f+1:s===f-1?f-1:f]}if(++u>=l)for(;;){if(f<=1)return null;if(0===s){if(n===e[--f])continue;s=f}else{if(1===s)return null;if((n=e[(f=--s)+1])===e[f])continue}u=t[(p=f)-1]+1;break}}f=0;var d=0,c=!1,v=0,h=r._nextBeginningIndexes;null===h&&(h=r._nextBeginningIndexes=g.prepareNextBeginningIndexes(r.target));var w=u=0===t[0]?0:h[t[0]-1];if(u!==l)for(;;)if(u>=l){if(f<=0){if(++d>a-2)break;if(e[d]===e[d+1])continue;u=w;continue}--f,u=h[i[--v]]}else{if(e[0===d?f:d===f?f+1:d===f-1?f-1:f]===o[u]){if(i[v++]=u,++f===a){c=!0;break}++u}else u=h[u]}if(c)var x=i,y=v;else x=t,y=p;for(var m=0,T=-1,k=0;k=0;--k)r.indexes[k]=x[k];return r},algorithmNoTypo:function(e,r,n){for(var o=r._targetLowerCodes,a=e.length,l=o.length,f=0,u=0,s=0;;){if(n===o[u]){if(t[s++]=u,++f===a)break;n=e[f]}if(++u>=l)return null}f=0;var p=!1,d=0,c=r._nextBeginningIndexes;null===c&&(c=r._nextBeginningIndexes=g.prepareNextBeginningIndexes(r.target));u=0===t[0]?0:c[t[0]-1];if(u!==l)for(;;)if(u>=l){if(f<=0)break;--f,u=c[i[--d]]}else{if(e[f]===o[u]){if(i[d++]=u,++f===a){p=!0;break}++u}else u=c[u]}if(p)var v=i,h=d;else v=t,h=s;for(var w=0,x=-1,y=0;y=0;--y)r.indexes[y]=v[y];return r},prepareLowerCodes:function(e){for(var r=e.length,n=[],o=e.toLowerCase(),t=0;t=65&&l<=90,u=f||l>=97&&l<=122||l>=48&&l<=57,s=f&&!t||!i||!u;t=f,i=u,s&&(n[o++]=a)}return n},prepareNextBeginningIndexes:function(e){for(var r=e.length,n=g.prepareBeginningIndexes(e),o=[],t=n[0],i=0,a=0;aa?o[a]=t:(t=n[++i],o[a]=void 0===t?r:t);return o},cleanup:a,new:d};return g}()})); -------------------------------------------------------------------------------- /dist/js/lib/mousetrap.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t,n){if(e){for(var r,o={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},i={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},a={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},c={option:"alt",command:"meta",return:"enter",escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},s=1;s<20;++s)o[111+s]="f"+s;for(s=0;s<=9;++s)o[s+96]=s.toString();d.prototype.bind=function(e,t,n){return e=e instanceof Array?e:[e],this._bindMultiple.call(this,e,t,n),this},d.prototype.unbind=function(e,t){return this.bind.call(this,e,(function(){}),t)},d.prototype.trigger=function(e,t){return this._directMap[e+":"+t]&&this._directMap[e+":"+t]({},e),this},d.prototype.reset=function(){return this._callbacks={},this._directMap={},this},d.prototype.stopCallback=function(e,n){if((" "+n.className+" ").indexOf(" mousetrap ")>-1)return!1;if(function e(n,r){return null!==n&&n!==t&&(n===r||e(n.parentNode,r))}(n,this.target))return!1;if("composedPath"in e&&"function"==typeof e.composedPath){var r=e.composedPath()[0];r!==e.target&&(n=r)}return"INPUT"==n.tagName||"SELECT"==n.tagName||"TEXTAREA"==n.tagName||n.isContentEditable},d.prototype.handleKey=function(){var e=this;return e._handleKey.apply(e,arguments)},d.addKeycodes=function(e){for(var t in e)e.hasOwnProperty(t)&&(o[t]=e[t]);r=null},d.init=function(){var e=d(t);for(var n in e)"_"!==n.charAt(0)&&(d[n]=function(t){return function(){return e[t].apply(e,arguments)}}(n))},d.init(),e.Mousetrap=d,"undefined"!=typeof module&&module.exports&&(module.exports=d),"function"==typeof define&&define.amd&&define((function(){return d}))}function u(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent("on"+t,n)}function l(e){if("keypress"==e.type){var t=String.fromCharCode(e.which);return e.shiftKey||(t=t.toLowerCase()),t}return o[e.which]?o[e.which]:i[e.which]?i[e.which]:String.fromCharCode(e.which).toLowerCase()}function f(e){return"shift"==e||"ctrl"==e||"alt"==e||"meta"==e}function p(e,t,n){return n||(n=function(){if(!r)for(var e in r={},o)e>95&&e<112||o.hasOwnProperty(e)&&(r[o[e]]=e);return r}()[e]?"keydown":"keypress"),"keypress"==n&&t.length&&(n="keydown"),n}function h(e,t){var n,r,o,i=[];for(n=function(e){return"+"===e?["+"]:(e=e.replace(/\+{2}/g,"+plus")).split("+")}(e),o=0;o1?k(e,c,t,r):(a=h(e,r),n._callbacks[a.key]=n._callbacks[a.key]||[],p(a.key,a.modifiers,{type:a.action},o,e,i),n._callbacks[a.key][o?"unshift":"push"]({callback:t,modifiers:a.modifiers,action:a.action,seq:o,level:i,combo:e}))}n._handleKey=function(e,t,n){var r,o=p(e,t,n),i={},u=0,l=!1;for(r=0;r{if(t&&t.length>0)return t;let e=[];return $("li").each((function(t,n){let r=n.innerText.split(/\n/)[0].trim();$(n).parents("li").each((function(t,e){e.innerText.length&&(r=e.innerText.split(/\n/)[0].trim()+"/"+r)})),$(n).data("path",r),e.push(r)})),t=e};return{orderedMenuItemTitles:[],find:t=>{if(/^\s*$/.test(t))return null;t=t.replace(/>/g,"/");let n=e(),r=fuzzysort.go(t,n);return r.length?itemForPath(r[0].target):null}}}();export default Search; -------------------------------------------------------------------------------- /dist/testMenu.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
    11 |
  • 12 |
  • nvUltra Beta 13 | 14 |
      15 |
    • About nvUltra
    • 16 |
    • Check For Updates
    • 17 |
    • 18 |
    • Preferences…
    • 19 |
    • 20 |
    • Services [removed]
    • 21 |
    • 22 |
    • Hide nvUltra
    • 23 |
    • Hide Others
    • 24 |
    • Show All
    • 25 |
    • 26 |
    • Quit nvUltra
    • 27 |
    • Quit and Close All Windows
    • 28 |
  • 29 |
  • File 30 | 31 |
      32 |
    • New Folder
    • 33 |
    • Open Folder…
    • 34 |
    • Move Selected File(s) to Trash
    • 35 |
    • Search/Create
    • 36 |
    • Open Recent 37 | 38 |
        39 |
      • content
      • 40 |
      • nvALT2.2
      • 41 |
      • 42 |
      • Clear Menu
      • 43 |
    • 44 |
    • 45 |
    • Edit File(s) in MultiMarkdown Composer
    • 46 |
    • Preview File(s) in Marked
    • 47 |
    • 48 |
    • Close
    • 49 |
    • Close All
    • 50 |
    • 51 |
    • Page Setup…
    • 52 |
    • Print…
    • 53 |
    • Print Preview Using Browser…
    • 54 |
  • 55 |
  • Edit 56 | 57 |
      58 |
    • Undo
    • 59 |
    • Redo
    • 60 |
    • 61 |
    • Cut
    • 62 |
    • Copy
    • 63 |
    • Copy As 64 | 65 |
        66 |
      • Copy As HTML
      • 67 |
      • Copy As LaTeX
      • 68 |
    • 69 |
    • Paste
    • 70 |
    • Paste As 71 | 72 |
        73 |
      • Paste As Blockquote
      • 74 |
      • Paste As Bulleted List
      • 75 |
      • Paste As Enumerated List
      • 76 |
      • Paste As Table
      • 77 |
      • Paste As Table Rows
      • 78 |
    • 79 |
    • Paste and Match Style
    • 80 |
    • Adjust Selected Line(s) 81 | 82 |
        83 |
      • Decrease ATX Header Level
      • 84 |
      • Increase ATX Header Level
      • 85 |
    • 86 |
    • Selection 87 | 88 |
        89 |
      • Select All
      • 90 |
      • Increase Selection
      • 91 |
      • Decrease Selection
      • 92 |
      • 93 |
      • Move to Next Paragraph
      • 94 |
      • Move to Previous Paragraph
      • 95 |
    • 96 |
    • Move Selected Text 97 | 98 |
        99 |
      • Shift Left
      • 100 |
      • Shift Right
      • 101 |
      • Shift Up
      • 102 |
      • Shift Down
      • 103 |
    • 104 |
    • Delete
    • 105 |
    • Select All
    • 106 |
    • 107 |
    • Find 108 | 109 |
        110 |
      • Find…
      • 111 |
      • Find and Replace…
      • 112 |
      • Find Next
      • 113 |
      • Find Previous
      • 114 |
      • Use Selection for Find
      • 115 |
      • Jump to Selection
      • 116 |
    • 117 |
    • Spelling and Grammar 118 | 119 |
        120 |
      • Show Spelling and Grammar
      • 121 |
      • Check Document Now
      • 122 |
      • 123 |
      • Check Spelling While Typing
      • 124 |
      • Check Grammar With Spelling
      • 125 |
      • Correct Spelling Automatically
      • 126 |
    • 127 |
    • Substitutions 128 | 129 |
        130 |
      • Show Substitutions
      • 131 |
      • 132 |
      • Smart Copy/Paste
      • 133 |
      • Smart Quotes
      • 134 |
      • Smart Dashes
      • 135 |
      • Smart Links
      • 136 |
      • Data Detectors
      • 137 |
      • Text Replacement
      • 138 |
    • 139 |
    • Transformations 140 | 141 |
        142 |
      • Make Upper Case
      • 143 |
      • Make Lower Case
      • 144 |
      • Capitalize
      • 145 |
    • 146 |
    • Speech 147 | 148 |
        149 |
      • Start Speaking
      • 150 |
      • Stop Speaking
      • 151 |
    • 152 |
    • 153 |
    • Start Dictation…
    • 154 |
    • Emoji & Symbols
    • 155 |
  • 156 |
  • Format 157 | 158 |
      159 |
    • Bold
    • 160 |
    • Italic
    • 161 |
    • Cleanup 162 | 163 |
        164 |
      • Selected HTML Entities
      • 165 |
      • Selected List(s)
      • 166 |
      • Selected Metadata
      • 167 |
      • Selected Paragraph(s)
      • 168 |
      • Selected “Smart Typography”
      • 169 |
      • Selected Table(s)
      • 170 |
      • 171 |
      • Full Cleanup
      • 172 |
    • 173 |
    • 174 |
    • Highlight Selection for CriticMarkup
    • 175 |
    • Insert CriticMarkup Comment
    • 176 |
    • 177 |
    • Apply Lower Case to Selection
    • 178 |
    • Apply Sentence Case to Selection
    • 179 |
    • Apply Title Case to Selection
    • 180 |
    • Apply Upper Case to Selection
    • 181 |
    • 182 |
    • Convert Selection To 183 | 184 |
        185 |
      • Convert to ATX Header
      • 186 |
      • Convert to Blockquote
      • 187 |
      • Convert to Bulleted List
      • 188 |
      • Convert to Enumerated List
      • 189 |
      • Convert to Fenced Code Block
      • 190 |
      • Convert to Regular Text
      • 191 |
    • 192 |
    • Toggle List Type
    • 193 |
    • Toggle List Indent to Space
    • 194 |
    • Toggle List Indent to Tab
    • 195 |
    • 196 |
    • CriticMarkup 197 | 198 |
        199 |
      • Accept Selected Change(s)
      • 200 |
      • Reject Selected Change(s)
      • 201 |
      • 202 |
      • Move Selection to Previous Change
      • 203 |
      • Move Selection to Next Change
      • 204 |
    • 205 |
  • 206 |
  • View 207 | 208 |
      209 |
    • Show Tab Bar
    • 210 |
    • Show All Tabs
    • 211 |
    • 212 |
    • Typewriter mode
    • 213 |
    • Auto Zoom
    • 214 |
    • Zoom 215 | 216 |
        217 |
      • Zoom Editor In
      • 218 |
      • Zoom Editor Out
      • 219 |
    • 220 |
    • 221 |
    • Show Line Numbers
    • 222 |
    • Show Paragraph Numbers
    • 223 |
    • 224 |
    • Theme 225 | 226 |
        227 |
      • Default
      • 228 |
      • Default-Dark
      • 229 |
      • Default-Dark-FTP
      • 230 |
      • Default-FTP
      • 231 |
      • Empty
      • 232 |
      • Modern Red
      • 233 |
      • Pretentious
      • 234 |
      • Printing
      • 235 |
      • Solarized
      • 236 |
      • Solarized-Dark
      • 237 |
    • 238 |
    • 239 |
    • Show Invisible Characters
    • 240 |
    • Show Linebreaks
    • 241 |
    • 242 |
    • Track Changes
    • 243 |
    • Enter Full Screen
    • 244 |
  • 245 |
  • Window 246 | 247 |
      248 |
    • Minimize
    • 249 |
    • Minimize All
    • 250 |
    • Zoom
    • 251 |
    • Zoom All
    • 252 |
    • 253 |
    • Show Previous Tab
    • 254 |
    • Show Next Tab
    • 255 |
    • Move Tab to New Window
    • 256 |
    • Merge All Windows
    • 257 |
    • 258 |
    • Toggle File List
    • 259 |
    • Toggle Info
    • 260 |
    • Toggle Preview
    • 261 |
    • Refresh Preview
    • 262 |
    • 263 |
    • Bring All to Front
    • 264 |
    • Arrange in Front
    • 265 |
    • 266 |
    • content
    • 267 |
    • nvALT2.2
    • 268 |
  • 269 |
  • Help 270 | 271 |
      272 |
    • 273 |
    • nvUltra Help
    • 274 |
    • Beta Feedback
    • 275 |
    • MultiMarkdown Syntax Guide
    • 276 |
    • nvUltra Welcome
    • 277 |
  • 278 |
279 |
280 |

Tutorial

281 |
    282 |
  • Hover to reveal menus
  • 283 |
  • Click to lock in place
  • 284 |
  • Double click to highlight
  • 285 |
  • Hold shift and double click to highlight hierarchy
  • 286 |
  • Option-click to add arrow
  • 287 |
  • Use the help menu to (fuzzy) search menu items
  • 288 |
  • See the settings menu (lower right)
  • 289 |
290 | 291 |
292 | 296 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | -------------------------------------------------------------------------------- /docs/images/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/images/background.jpg -------------------------------------------------------------------------------- /docs/images/background2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/images/background2.jpg -------------------------------------------------------------------------------- /docs/images/darkbackground.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/images/darkbackground.jpg -------------------------------------------------------------------------------- /docs/images/locked.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/js/handler.min.js: -------------------------------------------------------------------------------- 1 | import Util from"util.js";import Callout from"callout.js";import Prefs from"prefs.js";import Search from"search.js";const Handler=function(){const e=()=>{let e=prompt("Enter URL for background image");Prefs.set("wallpaper",e),Util.loadWallpaper()},l=()=>{let e=prompt("Enter optional keywords (comma separated words)"),l="https://source.unsplash.com/random/1900x1200?"+encodeURIComponent(e);Prefs.set("wallpaper",l),Util.loadWallpaper()};return{itemClick:e=>{e.preventDefault();let l,t=!1;if("SPAN"===e.target.tagName?(l=$(e.target).closest("li"),$(e.target).hasClass("shortcut")&&(t=!0)):l=$(e.target),e.metaKey||e.altKey)return e.metaKey?Callout.toggleCheckmark(l):e.altKey&&(t?Callout.toggleShortcut(l):Callout.toggleArrow(l)),!1;if($(".callout").removeClass("callout"),$(".persist").removeClass("persist"),"BODY"===e.target.tagName)$(".clicked").removeClass("clicked"),$(".last").removeClass("last"),Callout.setArrow(!1),Callout.setShortcut(!1);else{if(l.hasClass("clicked"))return l.find(".last").length?(Util.clearClicks(),l.parents("li").addClass("clicked"),l.addClass("clicked last")):($(".last").removeClass("last"),l.parents(".clicked").length?(l.removeClass("clicked"),l.siblings(".clicked").removeClass("clicked"),l.parents(".clicked").first().addClass("last")):$(".clicked").removeClass("clicked"),Callout.setArrow(!1),Callout.setShortcut(!1)),!1;Callout.setArrow(!1),Callout.setShortcut(!1),$("li.clicked").removeClass("clicked"),$(".last").removeClass("last"),l.parents("li").addClass("clicked"),e.altKey&&Callout.setArrow(!0,l),l.addClass("clicked last"),"dblclick"===e.type&&(l.addClass("callout"),e.shiftKey&&l.parents(".clicked").addClass("callout"))}return!1},controlsClick:t=>{switch(t.preventDefault(),t.target.id){case"darkModeToggle":Util.toggleDarkMode();break;case"exposeToggle":Util.toggleExpose();break;case"backgroundToggle":Util.toggleBG();break;case"chooseWallpaper":e();break;case"randomWallpaper":l();break;case"resetWallpaper":Util.setWallpaper(!1);break;case"arrowStyle":Callout.toggleArrowStyle();break;case"screenshot":Util.screenshot(t);break;case"commandshell":Util.terminal(t);break;default:throw"Element ID unrecognized"}return!1},liveSearch:e=>{let l=$(".helpsearch input"),t=l.val(),a=!1;if("Escape"===e.code)return e.preventDefault(),l.val("").blur(),Util.clearClicks(!0),!0;if("Enter"!==e.code&&"Return"!==e.code||(e.preventDefault(),$(".persist").removeClass("persist"),a=!0),t.length<2)return Util.clearClicks(!1),!0;let r=Search.find(t);return r?(Util.clearClicks(!1),r.parents("li")&&r.parents("li").addClass("clicked"),r.addClass("clicked last"),a&&(l.blur(),r.get(0).scrollIntoView({behavior:"smooth",block:"end",inline:"center"}))):Util.clearClicks(!1),!0},focusSearch:e=>{e.preventDefault(),$("li.callout").removeClass("callout"),$(".clicked").removeClass("clicked"),Util.clearClicks();let l=$(".helpsearch").first();return l.parents("li").addClass("clicked persist"),l.get(0).scrollIntoView({behavior:"smooth",block:"end",inline:"end"}),$("input",l).focus(),!1}}}();export default Handler; -------------------------------------------------------------------------------- /docs/js/lib/fuzzysort.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define([],r):"object"==typeof module&&module.exports?module.exports=r():e.fuzzysort=r()}(this,(function(){var e="undefined"!=typeof require&&"undefined"==typeof window,r=new Map,n=new Map,o=[];o.total=0;var t=[],i=[];function a(){r.clear(),n.clear(),t=[],i=[]}function l(e){for(var r=-9007199254740991,n=e.length-1;n>=0;--n){var o=e[n];if(null!==o){var t=o.score;t>r&&(r=t)}}return-9007199254740991===r?null:r}function f(e,r){var n=e[r];if(void 0!==n)return n;var o=r;Array.isArray(r)||(o=r.split("."));for(var t=o.length,i=-1;e&&++i>1]=e[n],t=1+(n<<1)}for(var a=n-1>>1;n>0&&o.score>1)e[n]=e[a];e[n]=o}return n.add=function(n){var o=r;e[r++]=n;for(var t=o-1>>1;o>0&&n.score>1)e[o]=e[t];e[o]=n},n.poll=function(){if(0!==r){var n=e[0];return e[0]=e[--r],o(),n}},n.peek=function(n){if(0!==r)return e[0]},n.replaceTop=function(r){e[0]=r,o()},n},p=s();return function d(c){var g={single:function(e,r,n){return e?(u(e)||(e=g.getPreparedSearch(e)),r?(u(r)||(r=g.getPrepared(r)),((n&&void 0!==n.allowTypo?n.allowTypo:!c||void 0===c.allowTypo||c.allowTypo)?g.algorithm:g.algorithmNoTypo)(e,r,e[0])):null):null},go:function(e,r,n){if(!e)return o;var t=(e=g.prepareSearch(e))[0],i=n&&n.threshold||c&&c.threshold||-9007199254740991,a=n&&n.limit||c&&c.limit||9007199254740991,s=(n&&void 0!==n.allowTypo?n.allowTypo:!c||void 0===c.allowTypo||c.allowTypo)?g.algorithm:g.algorithmNoTypo,d=0,v=0,h=r.length;if(n&&n.keys)for(var w=n.scoreFn||l,x=n.keys,y=x.length,m=h-1;m>=0;--m){for(var T=r[m],k=new Array(y),b=y-1;b>=0;--b){(_=f(T,B=x[b]))?(u(_)||(_=g.getPrepared(_)),k[b]=s(e,_,t)):k[b]=null}k.obj=T;var I=w(k);null!==I&&(Ip.peek().score&&p.replaceTop(k))))}else if(n&&n.key){var B=n.key;for(m=h-1;m>=0;--m){if(_=f(T=r[m],B))u(_)||(_=g.getPrepared(_)),null!==(C=s(e,_,t))&&(C.scorep.peek().score&&p.replaceTop(C))))}}else for(m=h-1;m>=0;--m){var _,C;if(_=r[m])u(_)||(_=g.getPrepared(_)),null!==(C=s(e,_,t))&&(C.scorep.peek().score&&p.replaceTop(C))))}if(0===d)return o;var A=new Array(d);for(m=d-1;m>=0;--m)A[m]=p.poll();return A.total=d+v,A},goAsync:function(r,n,t){var i=!1,a=new Promise((function(a,p){if(!r)return a(o);var d=(r=g.prepareSearch(r))[0],v=s(),h=n.length-1,w=t&&t.threshold||c&&c.threshold||-9007199254740991,x=t&&t.limit||c&&c.limit||9007199254740991,y=(t&&void 0!==t.allowTypo?t.allowTypo:!c||void 0===c.allowTypo||c.allowTypo)?g.algorithm:g.algorithmNoTypo,m=0,T=0;function k(){if(i)return p("canceled");var s=Date.now();if(t&&t.keys)for(var c=t.scoreFn||l,b=t.keys,I=b.length;h>=0;--h){for(var B=n[h],_=new Array(I),C=I-1;C>=0;--C){(P=f(B,L=b[C]))?(u(P)||(P=g.getPrepared(P)),_[C]=y(r,P,d)):_[C]=null}_.obj=B;var A=c(_);if(null!==A&&(!(Av.peek().score&&v.replaceTop(_)),h%1e3==0&&Date.now()-s>=10)))return void(e?setImmediate(k):setTimeout(k))}else if(t&&t.key)for(var L=t.key;h>=0;--h){if(P=f(B=n[h],L))if(u(P)||(P=g.getPrepared(P)),null!==(j=y(r,P,d))&&!(j.scorev.peek().score&&v.replaceTop(j)),h%1e3==0&&Date.now()-s>=10))return void(e?setImmediate(k):setTimeout(k))}else for(;h>=0;--h){var P,j;if(P=n[h])if(u(P)||(P=g.getPrepared(P)),null!==(j=y(r,P,d))&&!(j.scorev.peek().score&&v.replaceTop(j)),h%1e3==0&&Date.now()-s>=10))return void(e?setImmediate(k):setTimeout(k))}if(0===m)return a(o);for(var N=new Array(m),S=m-1;S>=0;--S)N[S]=v.poll();N.total=m+T,a(N)}e?setImmediate(k):k()}));return a.cancel=function(){i=!0},a},highlight:function(e,r,n){if(null===e)return null;void 0===r&&(r=""),void 0===n&&(n="");for(var o="",t=0,i=!1,a=e.target,l=a.length,f=e.indexes,u=0;u999)return g.prepare(e);var n=r.get(e);return void 0!==n?n:(n=g.prepare(e),r.set(e,n),n)},getPreparedSearch:function(e){if(e.length>999)return g.prepareSearch(e);var r=n.get(e);return void 0!==r?r:(r=g.prepareSearch(e),n.set(e,r),r)},algorithm:function(e,r,n){for(var o=r._targetLowerCodes,a=e.length,l=o.length,f=0,u=0,s=0,p=0;;){if(n===o[u]){if(t[p++]=u,++f===a)break;n=e[0===s?f:s===f?f+1:s===f-1?f-1:f]}if(++u>=l)for(;;){if(f<=1)return null;if(0===s){if(n===e[--f])continue;s=f}else{if(1===s)return null;if((n=e[(f=--s)+1])===e[f])continue}u=t[(p=f)-1]+1;break}}f=0;var d=0,c=!1,v=0,h=r._nextBeginningIndexes;null===h&&(h=r._nextBeginningIndexes=g.prepareNextBeginningIndexes(r.target));var w=u=0===t[0]?0:h[t[0]-1];if(u!==l)for(;;)if(u>=l){if(f<=0){if(++d>a-2)break;if(e[d]===e[d+1])continue;u=w;continue}--f,u=h[i[--v]]}else{if(e[0===d?f:d===f?f+1:d===f-1?f-1:f]===o[u]){if(i[v++]=u,++f===a){c=!0;break}++u}else u=h[u]}if(c)var x=i,y=v;else x=t,y=p;for(var m=0,T=-1,k=0;k=0;--k)r.indexes[k]=x[k];return r},algorithmNoTypo:function(e,r,n){for(var o=r._targetLowerCodes,a=e.length,l=o.length,f=0,u=0,s=0;;){if(n===o[u]){if(t[s++]=u,++f===a)break;n=e[f]}if(++u>=l)return null}f=0;var p=!1,d=0,c=r._nextBeginningIndexes;null===c&&(c=r._nextBeginningIndexes=g.prepareNextBeginningIndexes(r.target));u=0===t[0]?0:c[t[0]-1];if(u!==l)for(;;)if(u>=l){if(f<=0)break;--f,u=c[i[--d]]}else{if(e[f]===o[u]){if(i[d++]=u,++f===a){p=!0;break}++u}else u=c[u]}if(p)var v=i,h=d;else v=t,h=s;for(var w=0,x=-1,y=0;y=0;--y)r.indexes[y]=v[y];return r},prepareLowerCodes:function(e){for(var r=e.length,n=[],o=e.toLowerCase(),t=0;t=65&&l<=90,u=f||l>=97&&l<=122||l>=48&&l<=57,s=f&&!t||!i||!u;t=f,i=u,s&&(n[o++]=a)}return n},prepareNextBeginningIndexes:function(e){for(var r=e.length,n=g.prepareBeginningIndexes(e),o=[],t=n[0],i=0,a=0;aa?o[a]=t:(t=n[++i],o[a]=void 0===t?r:t);return o},cleanup:a,new:d};return g}()})); -------------------------------------------------------------------------------- /docs/js/lib/mousetrap.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t,n){if(e){for(var r,o={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},i={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},a={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},c={option:"alt",command:"meta",return:"enter",escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},s=1;s<20;++s)o[111+s]="f"+s;for(s=0;s<=9;++s)o[s+96]=s.toString();d.prototype.bind=function(e,t,n){return e=e instanceof Array?e:[e],this._bindMultiple.call(this,e,t,n),this},d.prototype.unbind=function(e,t){return this.bind.call(this,e,(function(){}),t)},d.prototype.trigger=function(e,t){return this._directMap[e+":"+t]&&this._directMap[e+":"+t]({},e),this},d.prototype.reset=function(){return this._callbacks={},this._directMap={},this},d.prototype.stopCallback=function(e,n){if((" "+n.className+" ").indexOf(" mousetrap ")>-1)return!1;if(function e(n,r){return null!==n&&n!==t&&(n===r||e(n.parentNode,r))}(n,this.target))return!1;if("composedPath"in e&&"function"==typeof e.composedPath){var r=e.composedPath()[0];r!==e.target&&(n=r)}return"INPUT"==n.tagName||"SELECT"==n.tagName||"TEXTAREA"==n.tagName||n.isContentEditable},d.prototype.handleKey=function(){var e=this;return e._handleKey.apply(e,arguments)},d.addKeycodes=function(e){for(var t in e)e.hasOwnProperty(t)&&(o[t]=e[t]);r=null},d.init=function(){var e=d(t);for(var n in e)"_"!==n.charAt(0)&&(d[n]=function(t){return function(){return e[t].apply(e,arguments)}}(n))},d.init(),e.Mousetrap=d,"undefined"!=typeof module&&module.exports&&(module.exports=d),"function"==typeof define&&define.amd&&define((function(){return d}))}function u(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent("on"+t,n)}function l(e){if("keypress"==e.type){var t=String.fromCharCode(e.which);return e.shiftKey||(t=t.toLowerCase()),t}return o[e.which]?o[e.which]:i[e.which]?i[e.which]:String.fromCharCode(e.which).toLowerCase()}function f(e){return"shift"==e||"ctrl"==e||"alt"==e||"meta"==e}function p(e,t,n){return n||(n=function(){if(!r)for(var e in r={},o)e>95&&e<112||o.hasOwnProperty(e)&&(r[o[e]]=e);return r}()[e]?"keydown":"keypress"),"keypress"==n&&t.length&&(n="keydown"),n}function h(e,t){var n,r,o,i=[];for(n=function(e){return"+"===e?["+"]:(e=e.replace(/\+{2}/g,"+plus")).split("+")}(e),o=0;o1?k(e,c,t,r):(a=h(e,r),n._callbacks[a.key]=n._callbacks[a.key]||[],p(a.key,a.modifiers,{type:a.action},o,e,i),n._callbacks[a.key][o?"unshift":"push"]({callback:t,modifiers:a.modifiers,action:a.action,seq:o,level:i,combo:e}))}n._handleKey=function(e,t,n){var r,o=p(e,t,n),i={},u=0,l=!1;for(r=0;r{if(t&&t.length>0)return t;let e=[];return $("li").each((function(t,n){let r=n.innerText.split(/\n/)[0].trim();$(n).parents("li").each((function(t,e){e.innerText.length&&(r=e.innerText.split(/\n/)[0].trim()+"/"+r)})),$(n).data("path",r),e.push(r)})),t=e};return{orderedMenuItemTitles:[],find:t=>{if(/^\s*$/.test(t))return null;t=t.replace(/>/g,"/");let n=e(),r=fuzzysort.go(t,n);return r.length?itemForPath(r[0].target):null}}}();export default Search; -------------------------------------------------------------------------------- /docs/jsapi/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /docs/jsapi/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /docs/jsapi/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /docs/jsapi/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/jsapi/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /docs/jsapi/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /docs/jsapi/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /docs/jsapi/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /docs/jsapi/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /docs/jsapi/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /docs/jsapi/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /docs/jsapi/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /docs/jsapi/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /docs/jsapi/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /docs/jsapi/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /docs/jsapi/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /docs/jsapi/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /docs/jsapi/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/docs/jsapi/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /docs/jsapi/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | NiftyMenu Index 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 57 | 58 | 59 |
60 |
61 | 62 | 63 |
64 | 65 |
66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
89 |

The NiftyMenu API

The primary namespace is NiftyAPI, which is a chainable set of functions covering searching, clicking, and callouts.

90 |

Configuration functions

Methods that adjust the display do not require an element to be passed, but can still be chained in with other functions. The primary display command is config(), which accepts an object containing keys for any/all of the display options. Example:

91 |
NiftyAPI.config({
 92 |   'arrowStyle': 'arrow',
 93 |   'bgImage': true,
 94 |   'expose': false,
 95 |   'darkMode': false,
 96 |   'wallpaper': 'default'
 97 | });

There are shorcuts for Dark Mode (NiftyAPI.darkMode()) and Exposé (NiftyAPI.expose()).

98 |

Chainable functions

All chainable functions should start with find (or a variable containing the result of a find). The found element can then have one or more callout functions applied:

99 |
    100 |
  • lock() (equivalent to a click)
  • 101 |
  • callout() (equivalent to a double click)
  • 102 |
  • arrow() (equivalent to an Option-click)
  • 103 |
  • shortcut() (equivalent to Option-clicking a keyboard shortcut)
  • 104 |
105 |

Example:

106 |
// Find the File->Save menu item and apply a callout ring to it 
107 | // and all parent elements up the chain
108 | NiftyAPI.find('file/save').callout(true, true);

All callout functions can be passed a boolean parameter to enable/disable the callout. Running NiftyAPI.clear() will disable all callouts and clicks.

109 |

In the case of callout() a second boolean parameter determines whether parent items of the selected menu item will also receive callouts. This defaults to false.

110 |

Screenshots

html2canvas is built in, but the screenshot capability currently only works properly in Chrome. In Chrome you can use .shoot() to take a screenshot and immediately download it with a name based on the menu items path. If an argument is passed with shoot it will be used as the filename. See notes.

111 |
NiftyAPI.find('view/next tab').lock().shoot();
112 |
113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 |
121 |
122 | 123 |
124 | 125 | 126 |
127 | 128 |
129 | 130 | 131 |
132 |
133 | 134 | 135 | 149 | 150 | 151 |
152 | 153 | 154 | 155 | NiftyMenu © Brett Terpstra 2020, MIT License 156 | 157 | 158 | 159 | Documentation generated by JSDoc 3.5.5 160 | 161 | on 2020-05-17T12:03:05-05:00 162 | 163 | using the DocStrap template. 164 | 165 |
166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 249 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /docs/jsapi/namespaces.list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | NiftyMenu Namespaces 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 57 | 58 | 59 |
60 |
61 | 62 | 63 |
64 | 65 |
66 | 67 | 68 |

Namespaces

69 |
70 | 71 |
72 | 73 |

74 | 75 |

76 | 77 | 78 |
79 | 80 | 81 |
82 |
83 | 84 | 85 | 86 | 87 |
88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 |
124 | 125 | 126 | 127 | 128 |
129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 |

Namespaces

140 | 141 |
142 |
NiftyAPI
143 |
144 |
145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 |
155 | 156 |
157 | 158 | 159 | 160 | 161 |
162 |
163 | 164 |
165 | 166 | 167 |
168 | 169 |
170 | 171 | 172 |
173 |
174 | 175 | 176 | 190 | 191 | 192 |
193 | 194 | 195 | 196 | NiftyMenu © Brett Terpstra 2020, MIT License 197 | 198 | 199 | 200 | Documentation generated by JSDoc 3.5.5 201 | 202 | on 2020-05-17T12:03:05-05:00 203 | 204 | using the DocStrap template. 205 | 206 |
207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 290 | 291 | 292 | 293 | -------------------------------------------------------------------------------- /docs/jsapi/quicksearch.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/jsapi/scripts/fulltext-search-ui.js: -------------------------------------------------------------------------------- 1 | window.SearcherDisplay = (function($) { 2 | /** 3 | * This class provides support for displaying quick search text results to users. 4 | */ 5 | function SearcherDisplay() { } 6 | 7 | SearcherDisplay.prototype.init = function() { 8 | this._displayQuickSearch(); 9 | }; 10 | 11 | /** 12 | * This method creates the quick text search entry in navigation menu and wires all required events. 13 | */ 14 | SearcherDisplay.prototype._displayQuickSearch = function() { 15 | var quickSearch = $(document.createElement("iframe")), 16 | body = $("body"), 17 | self = this; 18 | 19 | quickSearch.attr("src", "quicksearch.html"); 20 | quickSearch.css("width", "0px"); 21 | quickSearch.css("height", "0px"); 22 | 23 | body.append(quickSearch); 24 | 25 | $(window).on("message", function(msg) { 26 | var msgData = msg.originalEvent.data; 27 | 28 | if (msgData.msgid != "docstrap.quicksearch.done") { 29 | return; 30 | } 31 | 32 | var results = msgData.results || []; 33 | 34 | self._displaySearchResults(results); 35 | }); 36 | 37 | function startSearch() { 38 | var searchTerms = $('#search-input').prop("value"); 39 | if (searchTerms) { 40 | quickSearch[0].contentWindow.postMessage({ 41 | "searchTerms": searchTerms, 42 | "msgid": "docstrap.quicksearch.start" 43 | }, "*"); 44 | } 45 | } 46 | 47 | $('#search-input').on('keyup', function(evt) { 48 | if (evt.keyCode != 13) { 49 | return; 50 | } 51 | startSearch(); 52 | return false; 53 | }); 54 | $('#search-submit').on('click', function() { 55 | startSearch(); 56 | return false; 57 | }); 58 | }; 59 | 60 | /** 61 | * This method displays the quick text search results in a modal dialog. 62 | */ 63 | SearcherDisplay.prototype._displaySearchResults = function(results) { 64 | var resultsHolder = $($("#searchResults").find(".modal-body")), 65 | fragment = document.createDocumentFragment(), 66 | resultsList = document.createElement("ul"); 67 | 68 | resultsHolder.empty(); 69 | 70 | for (var idx = 0; idx < results.length; idx++) { 71 | var result = results[idx], 72 | item = document.createElement("li"), 73 | link = document.createElement("a"); 74 | 75 | link.href = result.id; 76 | link.innerHTML = result.title; 77 | 78 | item.appendChild(link) 79 | resultsList.appendChild(item); 80 | } 81 | 82 | fragment.appendChild(resultsList); 83 | resultsHolder.append(fragment); 84 | 85 | $("#searchResults").modal({"show": true}); 86 | }; 87 | 88 | return new SearcherDisplay(); 89 | })($); 90 | -------------------------------------------------------------------------------- /docs/jsapi/scripts/fulltext-search.js: -------------------------------------------------------------------------------- 1 | window.Searcher = (function() { 2 | function Searcher() { 3 | this._index = lunr(function () { 4 | this.field('title', {boost: 10}) 5 | this.field('body') 6 | this.ref('id') 7 | }) ; 8 | 9 | this._indexContent = undefined; 10 | } 11 | 12 | Searcher.prototype.init = function() { 13 | var self = this; 14 | 15 | $("script[type='text/x-docstrap-searchdb']").each(function(idx, item) { 16 | self._indexContent = JSON.parse(item.innerHTML); 17 | 18 | for (var entryId in self._indexContent) { 19 | self._index.add(self._indexContent[entryId]); 20 | } 21 | }); 22 | }; 23 | 24 | Searcher.prototype.search = function(searchTerm) { 25 | var results = [], 26 | searchResults = this._index.search(searchTerm); 27 | 28 | for (var idx = 0; idx < searchResults.length; idx++) { 29 | results.push(this._indexContent[searchResults[idx].ref]) 30 | } 31 | 32 | return results; 33 | }; 34 | 35 | return new Searcher(); 36 | })(); -------------------------------------------------------------------------------- /docs/jsapi/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/jsapi/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([ 2 | ["pln", /^[\t\n\f\r ]+/, null, " \t\r\n "] 3 | ], [ 4 | ["str", /^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/, null], 5 | ["str", /^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/, null], 6 | ["lang-css-str", /^url\(([^"')]*)\)/i], 7 | ["kwd", /^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i, null], 8 | ["lang-css-kw", /^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i], 9 | ["com", /^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//], 10 | ["com", /^(?:<\!--|--\>)/], 11 | ["lit", /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i], 12 | ["lit", /^#[\da-f]{3,6}/i], 13 | ["pln", /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i], 14 | ["pun", /^[^\s\w"']+/] 15 | ]), ["css"]); 16 | PR.registerLangHandler(PR.createSimpleLexer([], [ 17 | ["kwd", /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i] 18 | ]), ["css-kw"]); 19 | PR.registerLangHandler(PR.createSimpleLexer([], [ 20 | ["str", /^[^"')]+/] 21 | ]), ["css-str"]); -------------------------------------------------------------------------------- /docs/jsapi/scripts/toc.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | var navbarHeight; 3 | var initialised = false; 4 | var navbarOffset; 5 | 6 | function elOffset($el) { 7 | return $el.offset().top - (navbarHeight + navbarOffset); 8 | } 9 | 10 | function scrollToHash(duringPageLoad) { 11 | var elScrollToId = location.hash.replace(/^#/, ''); 12 | var $el; 13 | 14 | function doScroll() { 15 | var offsetTop = elOffset($el); 16 | window.scrollTo(window.pageXOffset || window.scrollX, offsetTop); 17 | } 18 | 19 | if (elScrollToId) { 20 | $el = $(document.getElementById(elScrollToId)); 21 | 22 | if (!$el.length) { 23 | $el = $(document.getElementsByName(elScrollToId)); 24 | } 25 | 26 | if ($el.length) { 27 | if (duringPageLoad) { 28 | $(window).one('scroll', function() { 29 | setTimeout(doScroll, 100); 30 | }); 31 | } else { 32 | setTimeout(doScroll, 0); 33 | } 34 | } 35 | } 36 | } 37 | 38 | function init(opts) { 39 | if (initialised) { 40 | return; 41 | } 42 | initialised = true; 43 | navbarHeight = $('.navbar').height(); 44 | navbarOffset = opts.navbarOffset; 45 | 46 | // some browsers move the offset after changing location. 47 | // also catch external links coming in 48 | $(window).on("hashchange", scrollToHash.bind(null, false)); 49 | $(scrollToHash.bind(null, true)); 50 | } 51 | 52 | $.catchAnchorLinks = function(options) { 53 | var opts = $.extend({}, jQuery.fn.toc.defaults, options); 54 | init(opts); 55 | }; 56 | 57 | $.fn.toc = function(options) { 58 | var self = this; 59 | var opts = $.extend({}, jQuery.fn.toc.defaults, options); 60 | 61 | var container = $(opts.container); 62 | var tocs = []; 63 | var headings = $(opts.selectors, container); 64 | var headingOffsets = []; 65 | var activeClassName = 'active'; 66 | var ANCHOR_PREFIX = "__anchor"; 67 | var maxScrollTo; 68 | var visibleHeight; 69 | var headerHeight = 10; // so if the header is readable, its counted as shown 70 | init(); 71 | 72 | var scrollTo = function(e) { 73 | e.preventDefault(); 74 | var target = $(e.target); 75 | if (target.prop('tagName').toLowerCase() !== "a") { 76 | target = target.parent(); 77 | } 78 | var elScrollToId = target.attr('href').replace(/^#/, '') + ANCHOR_PREFIX; 79 | var $el = $(document.getElementById(elScrollToId)); 80 | 81 | var offsetTop = Math.min(maxScrollTo, elOffset($el)); 82 | 83 | $('body,html').animate({ scrollTop: offsetTop }, 400, 'swing', function() { 84 | location.hash = '#' + elScrollToId; 85 | }); 86 | 87 | $('a', self).removeClass(activeClassName); 88 | target.addClass(activeClassName); 89 | }; 90 | 91 | var calcHadingOffsets = function() { 92 | maxScrollTo = $("body").height() - $(window).height(); 93 | visibleHeight = $(window).height() - navbarHeight; 94 | headingOffsets = []; 95 | headings.each(function(i, heading) { 96 | var anchorSpan = $(heading).prev("span"); 97 | var top = 0; 98 | if (anchorSpan.length) { 99 | top = elOffset(anchorSpan); 100 | } 101 | headingOffsets.push(top > 0 ? top : 0); 102 | }); 103 | } 104 | 105 | //highlight on scroll 106 | var timeout; 107 | var highlightOnScroll = function(e) { 108 | if (!tocs.length) { 109 | return; 110 | } 111 | if (timeout) { 112 | clearTimeout(timeout); 113 | } 114 | timeout = setTimeout(function() { 115 | var top = $(window).scrollTop(), 116 | highlighted; 117 | for (var i = headingOffsets.length - 1; i >= 0; i--) { 118 | var isActive = tocs[i].hasClass(activeClassName); 119 | // at the end of the page, allow any shown header 120 | if (isActive && headingOffsets[i] >= maxScrollTo && top >= maxScrollTo) { 121 | return; 122 | } 123 | // if we have got to the first heading or the heading is the first one visible 124 | if (i === 0 || (headingOffsets[i] + headerHeight >= top && (headingOffsets[i - 1] + headerHeight <= top))) { 125 | // in the case that a heading takes up more than the visible height e.g. we are showing 126 | // only the one above, highlight the one above 127 | if (i > 0 && headingOffsets[i] - visibleHeight >= top) { 128 | i--; 129 | } 130 | $('a', self).removeClass(activeClassName); 131 | if (i >= 0) { 132 | highlighted = tocs[i].addClass(activeClassName); 133 | opts.onHighlight(highlighted); 134 | } 135 | break; 136 | } 137 | } 138 | }, 50); 139 | }; 140 | if (opts.highlightOnScroll) { 141 | $(window).bind('scroll', highlightOnScroll); 142 | $(window).bind('load resize', function() { 143 | calcHadingOffsets(); 144 | highlightOnScroll(); 145 | }); 146 | } 147 | 148 | return this.each(function() { 149 | //build TOC 150 | var el = $(this); 151 | var ul = $('
'); 152 | 153 | headings.each(function(i, heading) { 154 | var $h = $(heading); 155 | 156 | var anchor = $('').attr('id', opts.anchorName(i, heading, opts.prefix) + ANCHOR_PREFIX).insertBefore($h); 157 | 158 | var span = $('') 159 | .text(opts.headerText(i, heading, $h)); 160 | 161 | //build TOC item 162 | var a = $('') 163 | .append(span) 164 | .attr('href', '#' + opts.anchorName(i, heading, opts.prefix)) 165 | .bind('click', function(e) { 166 | scrollTo(e); 167 | el.trigger('selected', $(this).attr('href')); 168 | }); 169 | 170 | span.addClass(opts.itemClass(i, heading, $h, opts.prefix)); 171 | 172 | tocs.push(a); 173 | 174 | ul.append(a); 175 | }); 176 | el.html(ul); 177 | 178 | calcHadingOffsets(); 179 | }); 180 | }; 181 | 182 | 183 | jQuery.fn.toc.defaults = { 184 | container: 'body', 185 | selectors: 'h1,h2,h3', 186 | smoothScrolling: true, 187 | prefix: 'toc', 188 | onHighlight: function() {}, 189 | highlightOnScroll: true, 190 | navbarOffset: 0, 191 | anchorName: function(i, heading, prefix) { 192 | return prefix+i; 193 | }, 194 | headerText: function(i, heading, $heading) { 195 | return $heading.text(); 196 | }, 197 | itemClass: function(i, heading, $heading, prefix) { 198 | return prefix + '-' + $heading[0].tagName.toLowerCase(); 199 | } 200 | 201 | }; 202 | 203 | })(jQuery); 204 | -------------------------------------------------------------------------------- /docs/jsapi/styles/jsdoc-default.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Open Sans'; 3 | font-weight: normal; 4 | font-style: normal; 5 | src: url('../fonts/OpenSans-Regular-webfont.eot'); 6 | src: 7 | local('Open Sans'), 8 | local('OpenSans'), 9 | url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), 10 | url('../fonts/OpenSans-Regular-webfont.woff') format('woff'), 11 | url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg'); 12 | } 13 | 14 | @font-face { 15 | font-family: 'Open Sans Light'; 16 | font-weight: normal; 17 | font-style: normal; 18 | src: url('../fonts/OpenSans-Light-webfont.eot'); 19 | src: 20 | local('Open Sans Light'), 21 | local('OpenSans Light'), 22 | url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), 23 | url('../fonts/OpenSans-Light-webfont.woff') format('woff'), 24 | url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg'); 25 | } 26 | 27 | html 28 | { 29 | overflow: auto; 30 | background-color: #fff; 31 | font-size: 14px; 32 | } 33 | 34 | body 35 | { 36 | font-family: 'Open Sans', sans-serif; 37 | line-height: 1.5; 38 | color: #4d4e53; 39 | background-color: white; 40 | } 41 | 42 | a, a:visited, a:active { 43 | color: #0095dd; 44 | text-decoration: none; 45 | } 46 | 47 | a:hover { 48 | text-decoration: underline; 49 | } 50 | 51 | header 52 | { 53 | display: block; 54 | padding: 0px 4px; 55 | } 56 | 57 | tt, code, kbd, samp { 58 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 59 | } 60 | 61 | .class-description { 62 | font-size: 130%; 63 | line-height: 140%; 64 | margin-bottom: 1em; 65 | margin-top: 1em; 66 | } 67 | 68 | .class-description:empty { 69 | margin: 0; 70 | } 71 | 72 | #main { 73 | float: left; 74 | width: 70%; 75 | } 76 | 77 | article dl { 78 | margin-bottom: 40px; 79 | } 80 | 81 | article img { 82 | max-width: 100%; 83 | } 84 | 85 | section 86 | { 87 | display: block; 88 | background-color: #fff; 89 | padding: 12px 24px; 90 | border-bottom: 1px solid #ccc; 91 | margin-right: 30px; 92 | } 93 | 94 | .variation { 95 | display: none; 96 | } 97 | 98 | .signature-attributes { 99 | font-size: 60%; 100 | color: #aaa; 101 | font-style: italic; 102 | font-weight: lighter; 103 | } 104 | 105 | nav 106 | { 107 | display: block; 108 | float: right; 109 | margin-top: 28px; 110 | width: 30%; 111 | box-sizing: border-box; 112 | border-left: 1px solid #ccc; 113 | padding-left: 16px; 114 | } 115 | 116 | nav ul { 117 | font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; 118 | font-size: 100%; 119 | line-height: 17px; 120 | padding: 0; 121 | margin: 0; 122 | list-style-type: none; 123 | } 124 | 125 | nav ul a, nav ul a:visited, nav ul a:active { 126 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 127 | line-height: 18px; 128 | color: #4D4E53; 129 | } 130 | 131 | nav h3 { 132 | margin-top: 12px; 133 | } 134 | 135 | nav li { 136 | margin-top: 6px; 137 | } 138 | 139 | footer { 140 | display: block; 141 | padding: 6px; 142 | margin-top: 12px; 143 | font-style: italic; 144 | font-size: 90%; 145 | } 146 | 147 | h1, h2, h3, h4 { 148 | font-weight: 200; 149 | margin: 0; 150 | } 151 | 152 | h1 153 | { 154 | font-family: 'Open Sans Light', sans-serif; 155 | font-size: 48px; 156 | letter-spacing: -2px; 157 | margin: 12px 24px 20px; 158 | } 159 | 160 | h2, h3.subsection-title 161 | { 162 | font-size: 30px; 163 | font-weight: 700; 164 | letter-spacing: -1px; 165 | margin-bottom: 12px; 166 | } 167 | 168 | h3 169 | { 170 | font-size: 24px; 171 | letter-spacing: -0.5px; 172 | margin-bottom: 12px; 173 | } 174 | 175 | h4 176 | { 177 | font-size: 18px; 178 | letter-spacing: -0.33px; 179 | margin-bottom: 12px; 180 | color: #4d4e53; 181 | } 182 | 183 | h5, .container-overview .subsection-title 184 | { 185 | font-size: 120%; 186 | font-weight: bold; 187 | letter-spacing: -0.01em; 188 | margin: 8px 0 3px 0; 189 | } 190 | 191 | h6 192 | { 193 | font-size: 100%; 194 | letter-spacing: -0.01em; 195 | margin: 6px 0 3px 0; 196 | font-style: italic; 197 | } 198 | 199 | table 200 | { 201 | border-spacing: 0; 202 | border: 0; 203 | border-collapse: collapse; 204 | } 205 | 206 | td, th 207 | { 208 | border: 1px solid #ddd; 209 | margin: 0px; 210 | text-align: left; 211 | vertical-align: top; 212 | padding: 4px 6px; 213 | display: table-cell; 214 | } 215 | 216 | thead tr 217 | { 218 | background-color: #ddd; 219 | font-weight: bold; 220 | } 221 | 222 | th { border-right: 1px solid #aaa; } 223 | tr > th:last-child { border-right: 1px solid #ddd; } 224 | 225 | .ancestors, .attribs { color: #999; } 226 | .ancestors a, .attribs a 227 | { 228 | color: #999 !important; 229 | text-decoration: none; 230 | } 231 | 232 | .clear 233 | { 234 | clear: both; 235 | } 236 | 237 | .important 238 | { 239 | font-weight: bold; 240 | color: #950B02; 241 | } 242 | 243 | .yes-def { 244 | text-indent: -1000px; 245 | } 246 | 247 | .type-signature { 248 | color: #aaa; 249 | } 250 | 251 | .name, .signature { 252 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 253 | } 254 | 255 | .details { margin-top: 14px; border-left: 2px solid #DDD; } 256 | .details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } 257 | .details dd { margin-left: 70px; } 258 | .details ul { margin: 0; } 259 | .details ul { list-style-type: none; } 260 | .details li { margin-left: 30px; padding-top: 6px; } 261 | .details pre.prettyprint { margin: 0 } 262 | .details .object-value { padding-top: 0; } 263 | 264 | .description { 265 | margin-bottom: 1em; 266 | margin-top: 1em; 267 | } 268 | 269 | .code-caption 270 | { 271 | font-style: italic; 272 | font-size: 107%; 273 | margin: 0; 274 | } 275 | 276 | .prettyprint 277 | { 278 | border: 1px solid #ddd; 279 | width: 80%; 280 | overflow: auto; 281 | } 282 | 283 | .prettyprint.source { 284 | width: inherit; 285 | } 286 | 287 | .prettyprint code 288 | { 289 | font-size: 100%; 290 | line-height: 18px; 291 | display: block; 292 | padding: 4px 12px; 293 | margin: 0; 294 | background-color: #fff; 295 | color: #4D4E53; 296 | } 297 | 298 | .prettyprint code span.line 299 | { 300 | display: inline-block; 301 | } 302 | 303 | .prettyprint.linenums 304 | { 305 | padding-left: 70px; 306 | -webkit-user-select: none; 307 | -moz-user-select: none; 308 | -ms-user-select: none; 309 | user-select: none; 310 | } 311 | 312 | .prettyprint.linenums ol 313 | { 314 | padding-left: 0; 315 | } 316 | 317 | .prettyprint.linenums li 318 | { 319 | border-left: 3px #ddd solid; 320 | } 321 | 322 | .prettyprint.linenums li.selected, 323 | .prettyprint.linenums li.selected * 324 | { 325 | background-color: lightyellow; 326 | } 327 | 328 | .prettyprint.linenums li * 329 | { 330 | -webkit-user-select: text; 331 | -moz-user-select: text; 332 | -ms-user-select: text; 333 | user-select: text; 334 | } 335 | 336 | .params .name, .props .name, .name code { 337 | color: #4D4E53; 338 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 339 | font-size: 100%; 340 | } 341 | 342 | .params td.description > p:first-child, 343 | .props td.description > p:first-child 344 | { 345 | margin-top: 0; 346 | padding-top: 0; 347 | } 348 | 349 | .params td.description > p:last-child, 350 | .props td.description > p:last-child 351 | { 352 | margin-bottom: 0; 353 | padding-bottom: 0; 354 | } 355 | 356 | .disabled { 357 | color: #454545; 358 | } 359 | -------------------------------------------------------------------------------- /docs/jsapi/styles/prettify-jsdoc.css: -------------------------------------------------------------------------------- 1 | /* JSDoc prettify.js theme */ 2 | 3 | /* plain text */ 4 | .pln { 5 | color: #000000; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | /* string content */ 11 | .str { 12 | color: #006400; 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | /* a keyword */ 18 | .kwd { 19 | color: #000000; 20 | font-weight: bold; 21 | font-style: normal; 22 | } 23 | 24 | /* a comment */ 25 | .com { 26 | font-weight: normal; 27 | font-style: italic; 28 | } 29 | 30 | /* a type name */ 31 | .typ { 32 | color: #000000; 33 | font-weight: normal; 34 | font-style: normal; 35 | } 36 | 37 | /* a literal value */ 38 | .lit { 39 | color: #006400; 40 | font-weight: normal; 41 | font-style: normal; 42 | } 43 | 44 | /* punctuation */ 45 | .pun { 46 | color: #000000; 47 | font-weight: bold; 48 | font-style: normal; 49 | } 50 | 51 | /* lisp open bracket */ 52 | .opn { 53 | color: #000000; 54 | font-weight: bold; 55 | font-style: normal; 56 | } 57 | 58 | /* lisp close bracket */ 59 | .clo { 60 | color: #000000; 61 | font-weight: bold; 62 | font-style: normal; 63 | } 64 | 65 | /* a markup tag name */ 66 | .tag { 67 | color: #006400; 68 | font-weight: normal; 69 | font-style: normal; 70 | } 71 | 72 | /* a markup attribute name */ 73 | .atn { 74 | color: #006400; 75 | font-weight: normal; 76 | font-style: normal; 77 | } 78 | 79 | /* a markup attribute value */ 80 | .atv { 81 | color: #006400; 82 | font-weight: normal; 83 | font-style: normal; 84 | } 85 | 86 | /* a declaration */ 87 | .dec { 88 | color: #000000; 89 | font-weight: bold; 90 | font-style: normal; 91 | } 92 | 93 | /* a variable name */ 94 | .var { 95 | color: #000000; 96 | font-weight: normal; 97 | font-style: normal; 98 | } 99 | 100 | /* a function name */ 101 | .fun { 102 | color: #000000; 103 | font-weight: bold; 104 | font-style: normal; 105 | } 106 | 107 | /* Specify class=linenums on a pre to get line numbering */ 108 | ol.linenums { 109 | margin-top: 0; 110 | margin-bottom: 0; 111 | } 112 | -------------------------------------------------------------------------------- /docs/jsapi/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #718c00; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #8959a8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #8e908c; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #4271ae; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #f5871f; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #4d4d4c; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #4d4d4c; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #4d4d4c; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Menlo, Monaco, Consolas, monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /docs/jsapi/styles/sunlight.default.css: -------------------------------------------------------------------------------- 1 | /* global styles */ 2 | .sunlight-container { 3 | clear: both !important; 4 | position: relative !important; 5 | margin: 10px 0 !important; 6 | } 7 | .sunlight-code-container { 8 | clear: both !important; 9 | position: relative !important; 10 | border: none; 11 | border-color: #969696 !important; 12 | background-color: #FFFFFF !important; 13 | } 14 | .sunlight-highlighted, .sunlight-container, .sunlight-container textarea { 15 | font-family: Consolas, Inconsolata, Monaco, "Courier New" !important; 16 | font-size: 12px !important; 17 | line-height: 15px !important; 18 | } 19 | .sunlight-highlighted, .sunlight-container textarea { 20 | color: #000000 !important; 21 | margin: 0 !important; 22 | } 23 | .sunlight-container textarea { 24 | padding-left: 0 !important; 25 | margin-left: 0 !important; 26 | margin-right: 0 !important; 27 | padding-right: 0 !important; 28 | } 29 | .sunlight-code-container > .sunlight-highlighted { 30 | white-space: pre; 31 | overflow-x: auto; 32 | overflow-y: hidden; /* ie requires this wtf? */ 33 | } 34 | .sunlight-highlighted { 35 | z-index: 1; 36 | position: relative; 37 | } 38 | .sunlight-highlighted * { 39 | background: transparent; 40 | } 41 | .sunlight-line-number-margin { 42 | float: left !important; 43 | margin-right: 5px !important; 44 | margin-top: 0 !important; 45 | margin-bottom: 0 !important; 46 | padding: 0 !important; 47 | padding-right: 4px !important; 48 | padding-left: 4px !important; 49 | border-right: 1px solid #CCCCCC !important; 50 | background-color: #EEEEEE !important; 51 | color: #848484 !important; 52 | text-align: right !important; 53 | position: relative; 54 | z-index: 3; 55 | } 56 | .sunlight-highlighted a, .sunlight-line-number-margin a { 57 | border: none !important; 58 | text-decoration: none !important; 59 | font-weight: normal !important; 60 | font-style: normal !important; 61 | padding: 0 !important; 62 | } 63 | .sunlight-line-number-margin a { 64 | color: inherit !important; 65 | } 66 | .sunlight-line-highlight-overlay { 67 | position: absolute; 68 | top: 0; 69 | left: 0; 70 | width: 100%; 71 | z-index: 0; 72 | } 73 | .sunlight-line-highlight-overlay div { 74 | height: 15px; 75 | width: 100%; 76 | } 77 | .sunlight-line-highlight-overlay .sunlight-line-highlight-active { 78 | background-color: #E7FCFA; 79 | } 80 | 81 | /* menu */ 82 | .sunlight-menu { 83 | background-color: #FFFFCC; 84 | color: #000000; 85 | } 86 | .sunlight-menu ul { 87 | margin: 0 !important; 88 | padding: 0 !important; 89 | list-style-type: none !important; 90 | } 91 | .sunlight-menu li { 92 | float: right !important; 93 | margin-left: 5px !important; 94 | } 95 | .sunlight-menu a, .sunlight-menu img { 96 | color: #000099 !important; 97 | text-decoration: none !important; 98 | border: none !important; 99 | } 100 | 101 | 102 | 103 | 104 | .sunlight-string, 105 | .sunlight-char, 106 | .sunlight-heredoc, 107 | .sunlight-heredocDeclaration, 108 | .sunlight-nowdoc, 109 | .sunlight-longString, 110 | .sunlight-rawString, 111 | .sunlight-binaryString, 112 | .sunlight-rawLongString, 113 | .sunlight-binaryLongString, 114 | .sunlight-verbatimString, 115 | .sunlight-diff .sunlight-removed { 116 | color: #990000 !important; 117 | } 118 | 119 | .sunlight-ident, 120 | .sunlight-operator, 121 | .sunlight-punctuation, 122 | .sunlight-delimiter, 123 | .sunlight-diff .sunlight-unchanged { 124 | color: #000000 !important; 125 | } 126 | 127 | .sunlight-comment, 128 | .sunlight-xmlDocCommentContent, 129 | .sunlight-nginx .sunlight-ssiCommand, 130 | .sunlight-sln .sunlight-formatDeclaration, 131 | .sunlight-diff .sunlight-added { 132 | color: #009900 !important; 133 | } 134 | .sunlight-number, 135 | .sunlight-guid, 136 | .sunlight-cdata { 137 | color: #CC6600 !important; 138 | } 139 | 140 | .sunlight-named-ident, 141 | .sunlight-constant, 142 | .sunlight-javascript .sunlight-globalVariable, 143 | .sunlight-globalObject, 144 | .sunlight-python .sunlight-attribute, 145 | .sunlight-nginx .sunlight-context, 146 | .sunlight-httpd .sunlight-context, 147 | .sunlight-haskell .sunlight-class, 148 | .sunlight-haskell .sunlight-type, 149 | .sunlight-lisp .sunlight-declarationSpecifier, 150 | .sunlight-erlang .sunlight-userDefinedFunction, 151 | .sunlight-diff .sunlight-header { 152 | color: #2B91AF !important; 153 | } 154 | .sunlight-keyword, 155 | .sunlight-languageConstruct, 156 | .sunlight-css 157 | .sunlight-element, 158 | .sunlight-bash .sunlight-command, 159 | .sunlight-specialOperator, 160 | .sunlight-erlang .sunlight-moduleAttribute, 161 | .sunlight-xml .sunlight-tagName, 162 | .sunlight-xml .sunlight-operator, 163 | .sunlight-diff .sunlight-modified { 164 | color: #0000FF !important; 165 | } 166 | .sunlight-shortOpenTag, 167 | .sunlight-openTag, 168 | .sunlight-closeTag, 169 | .sunlight-xmlOpenTag, 170 | .sunlight-xmlCloseTag, 171 | .sunlight-aspOpenTag, 172 | .sunlight-aspCloseTag, 173 | .sunlight-label, 174 | .sunlight-css .sunlight-importantFlag { 175 | background-color: #FFFF99 !important; 176 | color: #000000 !important; 177 | } 178 | .sunlight-function, 179 | .sunlight-globalFunction, 180 | .sunlight-ruby .sunlight-specialFunction, 181 | .sunlight-objective-c .sunlight-messageDestination, 182 | .sunlight-6502asm .sunlight-illegalOpcode, 183 | .sunlight-powershell .sunlight-switch, 184 | .sunlight-lisp .sunlight-macro, 185 | .sunlight-lisp .sunlight-specialForm, 186 | .sunlight-lisp .sunlight-type, 187 | .sunlight-sln .sunlight-sectionName, 188 | .sunlight-diff .sunlight-rangeInfo { 189 | color: #B069AF !important; 190 | } 191 | 192 | .sunlight-variable, 193 | .sunlight-specialVariable, 194 | .sunlight-environmentVariable, 195 | .sunlight-objective-c .sunlight-messageArgumentName, 196 | .sunlight-lisp .sunlight-globalVariable, 197 | .sunlight-ruby .sunlight-globalVariable, 198 | .sunlight-ruby .sunlight-instanceVariable, 199 | .sunlight-sln .sunlight-operator { 200 | color: #325484 !important; 201 | } 202 | .sunlight-regexLiteral, 203 | .sunlight-lisp .sunlight-operator, 204 | .sunlight-6502asm .sunlight-pseudoOp, 205 | .sunlight-erlang .sunlight-macro { 206 | color: #FF00B2 !important; 207 | } 208 | .sunlight-specialVariable { 209 | font-style: italic !important; 210 | font-weight: bold !important; 211 | } 212 | .sunlight-csharp .sunlight-pragma, 213 | .sunlight-preprocessorDirective, 214 | .sunlight-vb .sunlight-compilerDirective, 215 | .sunlight-diff .sunlight-mergeHeader, 216 | .sunlight-diff .sunlight-noNewLine { 217 | color: #999999 !important; 218 | font-style: italic !important; 219 | } 220 | .sunlight-xmlDocCommentMeta, 221 | .sunlight-java .sunlight-annotation, 222 | .sunlight-scala .sunlight-annotation, 223 | .sunlight-docComment { 224 | color: #808080 !important; 225 | } 226 | .sunlight-quotedIdent, 227 | .sunlight-ruby .sunlight-subshellCommand, 228 | .sunlight-lisp .sunlight-keywordArgument, 229 | .sunlight-haskell .sunlight-infixOperator, 230 | .sunlight-erlang .sunlight-quotedAtom { 231 | color: #999900 !important; 232 | } 233 | 234 | 235 | 236 | /* xml */ 237 | .sunlight-xml .sunlight-string { 238 | color: #990099 !important; 239 | } 240 | .sunlight-xml .sunlight-attribute { 241 | color: #FF0000 !important; 242 | } 243 | .sunlight-xml .sunlight-entity { 244 | background-color: #EEEEEE !important; 245 | color: #000000 !important; 246 | border: 1px solid #000000 !important; 247 | } 248 | .sunlight-xml .sunlight-doctype { 249 | color: #2B91AF !important; 250 | } 251 | 252 | /* javascript */ 253 | .sunlight-javascript .sunlight-reservedWord { 254 | font-style: italic !important; 255 | } 256 | 257 | /* css */ 258 | .sunlight-css .sunlight-microsoftFilterPrefix { 259 | color: #FF00FF !important; 260 | } 261 | .sunlight-css .sunlight-rule { 262 | color: #0099FF !important; 263 | } 264 | .sunlight-css .sunlight-keyword { 265 | color: #4E65B8 !important; 266 | } 267 | .sunlight-css .sunlight-class { 268 | color: #FF0000 !important; 269 | } 270 | .sunlight-css .sunlight-id { 271 | color: #8A8E13 !important; 272 | } 273 | .sunlight-css .sunlight-pseudoClass, 274 | .sunlight-css .sunlight-pseudoElement { 275 | color: #368B87 !important; 276 | } 277 | 278 | /* bash */ 279 | .sunlight-bash .sunlight-hashBang { 280 | color: #3D97F5 !important; 281 | } 282 | .sunlight-bash .sunlight-verbatimCommand { 283 | color: #999900 !important; 284 | } 285 | .sunlight-bash .sunlight-variable, 286 | .sunlight-bash .sunlight-specialVariable { 287 | color: #FF0000 !important; 288 | } 289 | 290 | /* python */ 291 | .sunlight-python .sunlight-specialMethod { 292 | font-weight: bold !important; 293 | color: #A07DD3; 294 | } 295 | 296 | /* ruby */ 297 | .sunlight-ruby .sunlight-symbol { 298 | font-weight: bold !important; 299 | color: #ED7272 !important; 300 | } 301 | 302 | /* brainfuck */ 303 | .sunlight-brainfuck { 304 | font-weight: bold !important; 305 | color: #000000 !important; 306 | } 307 | .sunlight-brainfuck .sunlight-increment { 308 | background-color: #FF9900 !important; 309 | } 310 | .sunlight-brainfuck .sunlight-decrement { 311 | background-color: #FF99FF !important; 312 | } 313 | .sunlight-brainfuck .sunlight-incrementPointer { 314 | background-color: #FFFF99 !important; 315 | } 316 | .sunlight-brainfuck .sunlight-decrementPointer { 317 | background-color: #66CCFF !important; 318 | } 319 | .sunlight-brainfuck .sunlight-read { 320 | background-color: #FFFFFF !important; 321 | } 322 | .sunlight-brainfuck .sunlight-write { 323 | background-color: #99FF99 !important; 324 | } 325 | .sunlight-brainfuck .sunlight-openLoop, .sunlight-brainfuck .sunlight-closeLoop { 326 | background-color: #FFFFFF !important; 327 | } 328 | 329 | /* 6502 asm */ 330 | .sunlight-6502asm .sunlight-label { 331 | font-weight: bold !important; 332 | color: #000000 !important; 333 | background: none !important; 334 | } 335 | 336 | /* lisp */ 337 | .sunlight-lisp .sunlight-macro { 338 | font-style: italic !important; 339 | } 340 | 341 | /* erlang */ 342 | .sunlight-erlang .sunlight-atom { 343 | font-weight: bold !important; 344 | } -------------------------------------------------------------------------------- /docs/testMenu.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
    11 |
  • 12 |
  • nvUltra Beta 13 | 14 |
      15 |
    • About nvUltra
    • 16 |
    • Check For Updates
    • 17 |
    • 18 |
    • Preferences…
    • 19 |
    • 20 |
    • Services [removed]
    • 21 |
    • 22 |
    • Hide nvUltra
    • 23 |
    • Hide Others
    • 24 |
    • Show All
    • 25 |
    • 26 |
    • Quit nvUltra
    • 27 |
    • Quit and Close All Windows
    • 28 |
  • 29 |
  • File 30 | 31 |
      32 |
    • New Folder
    • 33 |
    • Open Folder…
    • 34 |
    • Move Selected File(s) to Trash
    • 35 |
    • Search/Create
    • 36 |
    • Open Recent 37 | 38 |
        39 |
      • content
      • 40 |
      • nvALT2.2
      • 41 |
      • 42 |
      • Clear Menu
      • 43 |
    • 44 |
    • 45 |
    • Edit File(s) in MultiMarkdown Composer
    • 46 |
    • Preview File(s) in Marked
    • 47 |
    • 48 |
    • Close
    • 49 |
    • Close All
    • 50 |
    • 51 |
    • Page Setup…
    • 52 |
    • Print…
    • 53 |
    • Print Preview Using Browser…
    • 54 |
  • 55 |
  • Edit 56 | 57 |
      58 |
    • Undo
    • 59 |
    • Redo
    • 60 |
    • 61 |
    • Cut
    • 62 |
    • Copy
    • 63 |
    • Copy As 64 | 65 |
        66 |
      • Copy As HTML
      • 67 |
      • Copy As LaTeX
      • 68 |
    • 69 |
    • Paste
    • 70 |
    • Paste As 71 | 72 |
        73 |
      • Paste As Blockquote
      • 74 |
      • Paste As Bulleted List
      • 75 |
      • Paste As Enumerated List
      • 76 |
      • Paste As Table
      • 77 |
      • Paste As Table Rows
      • 78 |
    • 79 |
    • Paste and Match Style
    • 80 |
    • Adjust Selected Line(s) 81 | 82 |
        83 |
      • Decrease ATX Header Level
      • 84 |
      • Increase ATX Header Level
      • 85 |
    • 86 |
    • Selection 87 | 88 |
        89 |
      • Select All
      • 90 |
      • Increase Selection
      • 91 |
      • Decrease Selection
      • 92 |
      • 93 |
      • Move to Next Paragraph
      • 94 |
      • Move to Previous Paragraph
      • 95 |
    • 96 |
    • Move Selected Text 97 | 98 |
        99 |
      • Shift Left
      • 100 |
      • Shift Right
      • 101 |
      • Shift Up
      • 102 |
      • Shift Down
      • 103 |
    • 104 |
    • Delete
    • 105 |
    • Select All
    • 106 |
    • 107 |
    • Find 108 | 109 |
        110 |
      • Find…
      • 111 |
      • Find and Replace…
      • 112 |
      • Find Next
      • 113 |
      • Find Previous
      • 114 |
      • Use Selection for Find
      • 115 |
      • Jump to Selection
      • 116 |
    • 117 |
    • Spelling and Grammar 118 | 119 |
        120 |
      • Show Spelling and Grammar
      • 121 |
      • Check Document Now
      • 122 |
      • 123 |
      • Check Spelling While Typing
      • 124 |
      • Check Grammar With Spelling
      • 125 |
      • Correct Spelling Automatically
      • 126 |
    • 127 |
    • Substitutions 128 | 129 |
        130 |
      • Show Substitutions
      • 131 |
      • 132 |
      • Smart Copy/Paste
      • 133 |
      • Smart Quotes
      • 134 |
      • Smart Dashes
      • 135 |
      • Smart Links
      • 136 |
      • Data Detectors
      • 137 |
      • Text Replacement
      • 138 |
    • 139 |
    • Transformations 140 | 141 |
        142 |
      • Make Upper Case
      • 143 |
      • Make Lower Case
      • 144 |
      • Capitalize
      • 145 |
    • 146 |
    • Speech 147 | 148 |
        149 |
      • Start Speaking
      • 150 |
      • Stop Speaking
      • 151 |
    • 152 |
    • 153 |
    • Start Dictation…
    • 154 |
    • Emoji & Symbols
    • 155 |
  • 156 |
  • Format 157 | 158 |
      159 |
    • Bold
    • 160 |
    • Italic
    • 161 |
    • Cleanup 162 | 163 |
        164 |
      • Selected HTML Entities
      • 165 |
      • Selected List(s)
      • 166 |
      • Selected Metadata
      • 167 |
      • Selected Paragraph(s)
      • 168 |
      • Selected “Smart Typography”
      • 169 |
      • Selected Table(s)
      • 170 |
      • 171 |
      • Full Cleanup
      • 172 |
    • 173 |
    • 174 |
    • Highlight Selection for CriticMarkup
    • 175 |
    • Insert CriticMarkup Comment
    • 176 |
    • 177 |
    • Apply Lower Case to Selection
    • 178 |
    • Apply Sentence Case to Selection
    • 179 |
    • Apply Title Case to Selection
    • 180 |
    • Apply Upper Case to Selection
    • 181 |
    • 182 |
    • Convert Selection To 183 | 184 |
        185 |
      • Convert to ATX Header
      • 186 |
      • Convert to Blockquote
      • 187 |
      • Convert to Bulleted List
      • 188 |
      • Convert to Enumerated List
      • 189 |
      • Convert to Fenced Code Block
      • 190 |
      • Convert to Regular Text
      • 191 |
    • 192 |
    • Toggle List Type
    • 193 |
    • Toggle List Indent to Space
    • 194 |
    • Toggle List Indent to Tab
    • 195 |
    • 196 |
    • CriticMarkup 197 | 198 |
        199 |
      • Accept Selected Change(s)
      • 200 |
      • Reject Selected Change(s)
      • 201 |
      • 202 |
      • Move Selection to Previous Change
      • 203 |
      • Move Selection to Next Change
      • 204 |
    • 205 |
  • 206 |
  • View 207 | 208 |
      209 |
    • Show Tab Bar
    • 210 |
    • Show All Tabs
    • 211 |
    • 212 |
    • Typewriter mode
    • 213 |
    • Auto Zoom
    • 214 |
    • Zoom 215 | 216 |
        217 |
      • Zoom Editor In
      • 218 |
      • Zoom Editor Out
      • 219 |
    • 220 |
    • 221 |
    • Show Line Numbers
    • 222 |
    • Show Paragraph Numbers
    • 223 |
    • 224 |
    • Theme 225 | 226 |
        227 |
      • Default
      • 228 |
      • Default-Dark
      • 229 |
      • Default-Dark-FTP
      • 230 |
      • Default-FTP
      • 231 |
      • Empty
      • 232 |
      • Modern Red
      • 233 |
      • Pretentious
      • 234 |
      • Printing
      • 235 |
      • Solarized
      • 236 |
      • Solarized-Dark
      • 237 |
    • 238 |
    • 239 |
    • Show Invisible Characters
    • 240 |
    • Show Linebreaks
    • 241 |
    • 242 |
    • Track Changes
    • 243 |
    • Enter Full Screen
    • 244 |
  • 245 |
  • Window 246 | 247 |
      248 |
    • Minimize
    • 249 |
    • Minimize All
    • 250 |
    • Zoom
    • 251 |
    • Zoom All
    • 252 |
    • 253 |
    • Show Previous Tab
    • 254 |
    • Show Next Tab
    • 255 |
    • Move Tab to New Window
    • 256 |
    • Merge All Windows
    • 257 |
    • 258 |
    • Toggle File List
    • 259 |
    • Toggle Info
    • 260 |
    • Toggle Preview
    • 261 |
    • Refresh Preview
    • 262 |
    • 263 |
    • Bring All to Front
    • 264 |
    • Arrange in Front
    • 265 |
    • 266 |
    • content
    • 267 |
    • nvALT2.2
    • 268 |
  • 269 |
  • Help 270 | 271 |
      272 |
    • 273 |
    • nvUltra Help
    • 274 |
    • Beta Feedback
    • 275 |
    • MultiMarkdown Syntax Guide
    • 276 |
    • nvUltra Welcome
    • 277 |
  • 278 |
279 |
280 |

Tutorial

281 |
    282 |
  • Hover to reveal menus
  • 283 |
  • Click to lock in place
  • 284 |
  • Double click to highlight
  • 285 |
  • Hold shift and double click to highlight hierarchy
  • 286 |
  • Option-click to add arrow
  • 287 |
  • Use the help menu to (fuzzy) search menu items
  • 288 |
  • See the settings menu (lower right)
  • 289 |
290 | 291 |
292 | 296 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | -------------------------------------------------------------------------------- /javascript/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "$": false 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /javascript/README.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

The NiftyMenu API

9 | 10 |

The primary namespace is NiftyAPI, which is a chainable set of functions covering searching, clicking, and callouts.

11 | 12 |

Configuration functions

13 | 14 |

Methods that adjust the display do not require an element to be passed, but can still be chained in with other functions. The primary display command is config(), which accepts an object containing keys for any/all of the display options. Example:

15 | 16 |
NiftyAPI.config({
17 |   'arrowStyle': 'arrow',
18 |   'bgImage': true,
19 |   'expose': false,
20 |   'darkMode': false,
21 |   'wallpaper': 'default'
22 | });
23 | 
24 | 25 |

There are shorcuts for Dark Mode (NiftyAPI.darkMode()) and Exposé (NiftyAPI.expose()).

26 | 27 |

Chainable functions

28 | 29 |

All chainable functions should start with find (or a variable containing the result of a find). The found element can then have one or more callout functions applied:

30 | 31 |
    32 |
  • lock() (equivalent to a click)
  • 33 |
  • callout() (equivalent to a double click)
  • 34 |
  • arrow() (equivalent to an Option-click)
  • 35 |
  • shortcut() (equivalent to Option-clicking a keyboard shortcut)
  • 36 |
37 | 38 |

Example:

39 | 40 |
// Find the File->Save menu item and apply a callout ring to it 
41 | // and all parent elements up the chain
42 | NiftyAPI.find('file/save').callout(true, true);
43 | 
44 | 45 |

All callout functions can be passed a boolean parameter to enable/disable the callout. Running NiftyAPI.clear() will disable all callouts and clicks.

46 | 47 |

In the case of callout() a second boolean parameter determines whether parent items of the selected menu item will also receive callouts. This defaults to false.

48 | 49 |

Screenshots

50 | 51 |

html2canvas is built in, but the screenshot capability currently only works properly in Chrome. In Chrome you can use .shoot() to take a screenshot and immediately download it with a name based on the menu items path. See notes.

52 | 53 |
NiftyAPI.find('view/next tab').lock().shoot();
54 | 
55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /javascript/README.md: -------------------------------------------------------------------------------- 1 | ### The NiftyMenu API 2 | 3 | The primary namespace is `NiftyAPI`, which is a chainable set of functions covering searching, clicking, and callouts. 4 | 5 | ### Configuration functions 6 | 7 | Methods that adjust the display do not require an element to be passed, but can still be chained in with other functions. The primary display command is `config()`, which accepts an object containing keys for any/all of the display options. Example: 8 | 9 | NiftyAPI.config({ 10 | 'arrowStyle': 'arrow', 11 | 'bgImage': true, 12 | 'expose': false, 13 | 'darkMode': false, 14 | 'wallpaper': 'default' 15 | }); 16 | 17 | There are shorcuts for Dark Mode (`NiftyAPI.darkMode()`) and Exposé (`NiftyAPI.expose()`). 18 | 19 | ### Chainable functions 20 | 21 | All chainable functions should start with `find` (or a variable containing the result of a `find`). The found element can then have one or more callout functions applied: 22 | 23 | - `lock()` (equivalent to a click) 24 | - `callout()` (equivalent to a double click) 25 | - `arrow()` (equivalent to an Option-click) 26 | - `shortcut()` (equivalent to Option-clicking a keyboard shortcut) 27 | 28 | Example: 29 | 30 | // Find the File->Save menu item and apply a callout ring to it 31 | // and all parent elements up the chain 32 | NiftyAPI.find('file/save').callout(true, true); 33 | 34 | All callout functions can be passed a boolean parameter to enable/disable the callout. Running `NiftyAPI.clear()` will disable all callouts and clicks. 35 | 36 | In the case of `callout()` a second boolean parameter determines whether parent items of the selected menu item will also receive callouts. This defaults to `false`. 37 | 38 | # Screenshots 39 | 40 | `html2canvas` is built in, but the screenshot capability currently ***only works properly in Chrome***. In Chrome you can use `.shoot()` to take a screenshot and immediately download it with a name based on the menu items path. If an argument is passed with `shoot` it will be used as the filename. [See notes.](https://ttscoff.github.io/niftymenu/jsapi/NiftyAPI.html#.shoot__anchor) 41 | 42 | NiftyAPI.find('view/next tab').lock().shoot(); 43 | 44 | 45 | -------------------------------------------------------------------------------- /javascript/app.js: -------------------------------------------------------------------------------- 1 | import Nifty from './modules/nifty.js'; 2 | import NiftyAPI from './modules/api.js'; 3 | 4 | $(function() { 5 | Nifty.init(); 6 | window.NiftyAPI = NiftyAPI; 7 | }); 8 | 9 | 10 | -------------------------------------------------------------------------------- /javascript/modules/api.js: -------------------------------------------------------------------------------- 1 | import { Callout, Prefs, Search, Util } from 'modules.js'; 2 | 3 | /** 4 | * @namespace NiftyAPI 5 | * @description Chainable automation API. All chains that affect a menu item 6 | * should start with a .find('search string') call. 7 | * 8 | * @example NiftyAPI.find('file/save').arrow(); // locate File->Save menu item and add an arrow callout 9 | */ 10 | const NiftyAPI = { 11 | targetEl: null, 12 | 13 | /** 14 | * Show current configuration options 15 | * 16 | * @return {object} The configuration. 17 | */ 18 | getConfig: function() { 19 | return Prefs.get(); 20 | }, 21 | 22 | /** 23 | * Set multiple display options via a configuration object 24 | * 25 | * @param {Object} options object containing settings 26 | * @example 27 | * NiftyAPI.config({ 28 | * 'arrowStyle': 'arrow', 29 | * 'bgImage': true, 30 | * 'darkMode': false, 31 | * 'wallpaper': 'default' 32 | * }); 33 | */ 34 | config: function(options={}) { 35 | let defaults = Prefs.config; 36 | 37 | let config = $.extend({}, defaults, options); 38 | 39 | Util.setDarkMode(Prefs.truthy(config.darkMode)); 40 | Util.setBG(Prefs.truthy(config.bgImage)); 41 | Util.setWallpaper(config.wallpaper); 42 | Callout.setArrowStyle(config.arrowStyle); 43 | return this; 44 | }, 45 | 46 | /** 47 | * Case insensitive string match for menu item search. Use / to separate 48 | * heirarchical menu search items. This function can be chained for use with 49 | * other functions. 50 | * @example 51 | * NiftyAPI.find('insert/toc/section'); 52 | * NiftyAPI.find('insert/toc/section').arrow(); 53 | * 54 | * @param {string} str The string to search for 55 | * @return {jQuery} single jQuery element or null 56 | */ 57 | find: function(str) { 58 | this.targetEl = Search.find(str); 59 | return this; 60 | }, 61 | 62 | /** 63 | * Clear all clicks, callouts, and arrows 64 | * @example 65 | * NiftyAPI.clear(); 66 | */ 67 | clear: function() { 68 | Util.clearClicks(true); 69 | return this; 70 | }, 71 | 72 | /** 73 | * Lock menu item. Removes any existing locks. Equivalent to clicking a menu 74 | * item. 75 | * @example 76 | * NiftyAPI.find('file/save').lock(); 77 | */ 78 | lock: function() { 79 | Util.clearClicks(true); 80 | this.targetEl.click(); 81 | this.targetEl.get(0).scrollIntoView({behavior: "auto", block: "end", inline: "center"}); 82 | return this; 83 | }, 84 | 85 | /** 86 | * Add callout to menu item. Equivalent to double clicking a menu item. 87 | * 88 | * @param {boolean} [bool=true] Callout on or off (default: true) 89 | * @param {boolean} [recurse=false] Call out parent items (default: 90 | * false) 91 | * @example 92 | * NiftyAPI.find('file/open').callout(); 93 | *NiftyAPI.find('file/open').callout(true, true); // add callout to item and parents 94 | *NiftyAPI.find('file/open').callout(false); // remove callout 95 | */ 96 | callout: function(bool, recurse=false) { 97 | if (bool === undefined) { 98 | bool = true; 99 | } 100 | 101 | Util.clearClicks(true); 102 | 103 | if (bool) { 104 | this.targetEl.dblclick(); 105 | this.targetEl.get(0).scrollIntoView({behavior: "auto", block: "end", inline: "center"}); 106 | 107 | if (recurse) { 108 | this.targetEl.parents('.clicked').addClass('callout'); 109 | } 110 | } 111 | 112 | return this; 113 | }, 114 | 115 | /** 116 | * Set callout arrow for menu item. Equivalent to option-clicking a menu item. 117 | * 118 | * @param {boolean} [bool=true] Arrow on or off 119 | * @example 120 | * NiftyAPI.find('view/merge').arrow(); 121 | *NiftyAPI.find('view/merge').arrow(false); // remove arrow 122 | */ 123 | arrow: function(bool) { 124 | if (bool === undefined) { 125 | bool = true; 126 | } 127 | Callout.setArrow(bool, this.targetEl); 128 | return this; 129 | }, 130 | 131 | /** 132 | * Set shortcut callout for menu item. Equivalent to option-clicking a 133 | * shortcut on a menu item. 134 | * 135 | * @param {boolean} [bool=true] Shortcut callout on or off 136 | * @example 137 | * NiftyAPI.find('file/save').shortcut(); 138 | *NiftyAPI.find('file/save').shortcut(false); // remove arrow 139 | */ 140 | shortcut: function(bool) { 141 | if (bool === undefined) { 142 | bool = true; 143 | } 144 | Callout.setShortcut(bool, this.targetEl); 145 | return this; 146 | }, 147 | 148 | /** 149 | * Turn Dark Mode on or off 150 | * 151 | * @param {boolean} [bool=true] Dark Mode on or off 152 | * @example 153 | * NiftyAPI.darkMode(); // turn dark mode on 154 | *NiftyAPI.darkMode(false); // turn dark mode off 155 | */ 156 | darkMode: function(bool) { 157 | if (bool === undefined) { 158 | bool = true; 159 | } 160 | Util.setDarkMode(bool); 161 | return this; 162 | }, 163 | 164 | /** 165 | * Turn Expose on or off 166 | * 167 | * @param {boolean} [bool=true] Expose on or off 168 | * @example 169 | * NiftyAPI.expose(); // turn expose on 170 | *NiftyAPI.expose(false); // turn expose off 171 | */ 172 | expose: function(bool) { 173 | if (bool === undefined) { 174 | bool = true; 175 | } 176 | Util.setExpose(bool); 177 | return this; 178 | }, 179 | 180 | /** 181 | * Take a screenshot of selected menu item. Currently experimental, **only 182 | * works in Chrome**. 183 | * 184 | * Background images work if they're remote (hosted, with proper CORS 185 | * headers). Local images seem to taint the canvas, making it impossible to 186 | * save with Chrome's security restrictions. Thus, background images are 187 | * disabled during screenshot if using a file: protocol. 188 | * 189 | * @param {string} [title=null] The title for downloaded image, no extension 190 | * 191 | * @example 192 | * NiftyAPI.find('edit/paste as').arrow().shoot('filename'); 193 | * 194 | */ 195 | shoot: function(title=null) { 196 | Util.screenshot(false, title); 197 | return this; 198 | } 199 | }; 200 | 201 | export default NiftyAPI; 202 | -------------------------------------------------------------------------------- /javascript/modules/callout.js: -------------------------------------------------------------------------------- 1 | import Prefs from 'prefs.js' 2 | 3 | /** 4 | * @namespace Callout 5 | * @private 6 | * @memberof Nifty 7 | * @description Methods for adding callouts to items 8 | */ 9 | const Callout = (function() { 10 | /** 11 | * Sets the arrow callout 12 | * @memberof Callout 13 | * 14 | * @param {boolean} bool Add or remove arrow 15 | * @param {element} el DOM element or jQuery object, applies to all .arrow if empty 16 | * @return {boolean} Result 17 | */ 18 | const setArrow = (bool, el) => { 19 | if (!el && !bool) { 20 | $('.arrow').each(function(i,n) { 21 | setArrow(false,$(n)); 22 | }); 23 | return; 24 | } 25 | 26 | if (!(el instanceof jQuery)) { 27 | el = $(el); 28 | } 29 | 30 | if (el.get(0).tagName !== 'LI') { 31 | el = el.parents('li').first(); 32 | } 33 | 34 | if (bool) { 35 | setArrow(false); 36 | setShortcut(false); 37 | const style = Prefs.get('arrowStyle') || 'arrow'; 38 | const direction = el.find('ul').length ? 'left' : 'right'; 39 | $('.clicked').removeClass('clicked'); 40 | el.addClass('arrow arrow-'+style+' clicked '+direction).append(''); 41 | el.parents('li').addClass('clicked'); 42 | } else { 43 | el.removeClass('arrow arrow-arrow arrow-circle').find('b').remove(); 44 | } 45 | }; 46 | 47 | /** 48 | * Toggles the arrow callout 49 | * @memberof Callout 50 | * 51 | * @param {jquery} el jQuery object, all .arrow if empty 52 | * @return {boolean} Result 53 | */ 54 | const toggleArrow = (el) => { 55 | if (!el) { 56 | setArrow(false); 57 | return; 58 | } 59 | 60 | if (!(el instanceof jQuery)) { 61 | el = $(el); 62 | } 63 | 64 | if (el.hasClass('arrow')) { 65 | setArrow(false, el); 66 | } else { 67 | setArrow(false); 68 | setShortcut(false); 69 | setArrow(true, el); 70 | } 71 | }; 72 | 73 | /** 74 | * Sets the shortcut callout 75 | * @memberof Callout 76 | * 77 | * @param {boolean} bool Add or remove shortcut callout 78 | * @param {element} el DOM element or jQuery object containing shortcut, 79 | * applies to all .shortcut-callout if empty 80 | * @return {boolean} Result 81 | */ 82 | const setShortcut = (bool, el) => { 83 | if (!el && !bool) { 84 | $('.shortcut-callout').each(function(i,n) { 85 | setShortcut(false,$(n)); 86 | }); 87 | return; 88 | } 89 | 90 | if (!(el instanceof jQuery)) { 91 | el = $(el); 92 | } 93 | 94 | if (el.get(0).tagName !== 'LI') { 95 | el = el.parents('li').first(); 96 | } 97 | 98 | if (bool) { 99 | setShortcut(false); 100 | setArrow(false); 101 | $('.clicked').removeClass('clicked'); 102 | el.addClass('clicked').find('.shortcut').addClass('shortcut-callout'); 103 | el.parents('li').addClass('clicked'); 104 | } else { 105 | el.find('.shortcut').removeClass('shortcut-callout'); 106 | } 107 | }; 108 | 109 | /** 110 | * Toggles the shortcut callout 111 | * @memberof Callout 112 | * 113 | * @param {jquery} el jQuery object, all .arrow if empty 114 | * @return {boolean} Result 115 | */ 116 | const toggleShortcut = (el) => { 117 | if (!el) { 118 | setShortcut(false); 119 | return; 120 | } 121 | 122 | if (!(el instanceof jQuery)) { 123 | el = $(el); 124 | } 125 | 126 | if (el.has('.shortcut-callout').length) { 127 | setShortcut(false, el); 128 | } else { 129 | setShortcut(false); 130 | setShortcut(true, el); 131 | } 132 | }; 133 | 134 | /** 135 | * Toggles a checkmark on the clicked menu item. 136 | * @memberof Callout 137 | * @param {jquery} el jQuery object, all .arrow if empty. 138 | * @return {boolean} Result 139 | */ 140 | const toggleCheckmark = (el) => { 141 | if (!(el instanceof jQuery)) { 142 | el = $(el); 143 | } 144 | 145 | if (el.hasClass('checked')) { 146 | el.removeClass('checked'); 147 | } else { 148 | el.addClass('checked'); 149 | } 150 | return true; 151 | }; 152 | 153 | /** 154 | * Sets the style of the callout arrow 155 | * @memberof Callout 156 | * @param {string} style 'circle' or 'arrow' 157 | */ 158 | const setArrowStyle = (style) => { 159 | let newStyle = 'arrow'; 160 | if (style && style === 'circle') { 161 | newStyle = 'circle'; 162 | $('.arrow-arrow').removeClass('arrow-arrow').addClass('arrow-circle'); 163 | } else { 164 | $('.arrow-circle').removeClass('arrow-circle').addClass('arrow-arrow'); 165 | } 166 | Prefs.set('arrowStyle', newStyle); 167 | }; 168 | 169 | /** 170 | * Toggles arrow style between circle and arrow. 171 | * @memberof Callout 172 | */ 173 | const toggleArrowStyle = () => { 174 | let newStyle; 175 | const current = Prefs.get('arrowStyle'); 176 | if (current === 'circle') { 177 | newStyle = 'arrow'; 178 | $('#arrowStyle','.controls').text('Arrow style: Arrow'); 179 | } else { 180 | newStyle = 'circle'; 181 | $('#arrowStyle','.controls').text('Arrow style: Circle'); 182 | } 183 | setArrowStyle(newStyle); 184 | }; 185 | 186 | return { 187 | setArrow, 188 | setArrowStyle, 189 | toggleArrowStyle, 190 | toggleArrow, 191 | toggleCheckmark, 192 | setShortcut, 193 | toggleShortcut 194 | } 195 | })(); 196 | 197 | export default Callout; 198 | -------------------------------------------------------------------------------- /javascript/modules/handler.js: -------------------------------------------------------------------------------- 1 | import Util from 'util.js' 2 | import Callout from 'callout.js'; 3 | import Prefs from 'prefs.js'; 4 | import Search from 'search.js'; 5 | 6 | /** 7 | * @namespace Nifty.handlers 8 | * @private 9 | * @memberof Nifty 10 | * @description Event handlers 11 | */ 12 | 13 | const Handler = (function() { 14 | /** 15 | * live search for the help menu, function ~ macOS 16 | * @private 17 | * @memberof Nifty.handlers 18 | * 19 | * @param {event} e Event 20 | */ 21 | const liveSearch = (e) => { 22 | 23 | let $field = $('.helpsearch input'), 24 | string = $field.val(), 25 | shouldScroll = false; 26 | 27 | if (e.code === 'Escape') { 28 | e.preventDefault(); 29 | $field.val('').blur(); 30 | Util.clearClicks(true); 31 | return true; 32 | } 33 | 34 | if (e.code === 'Enter' || e.code === 'Return') { 35 | e.preventDefault(); 36 | $('.persist').removeClass('persist'); 37 | shouldScroll = true; 38 | // return true; 39 | } 40 | 41 | if (string.length < 2) { 42 | Util.clearClicks(false); 43 | return true; 44 | } 45 | 46 | let $item = Search.find(string); 47 | 48 | if ($item) { 49 | Util.clearClicks(false); 50 | if ($item.parents('li')) { 51 | $item.parents('li').addClass('clicked'); 52 | } 53 | $item.addClass('clicked last'); 54 | 55 | if (shouldScroll) { 56 | $field.blur(); 57 | $item.get(0).scrollIntoView({behavior: "smooth", block: "end", inline: "center"}); 58 | } 59 | } else { 60 | Util.clearClicks(false); 61 | } 62 | 63 | return true; 64 | }; 65 | 66 | /** 67 | * click handler for menu items 68 | * @private 69 | * @memberof Nifty.handlers 70 | * @param {event} e Event 71 | * @return {boolean} continue handling event 72 | */ 73 | const itemClick = (e) => { 74 | e.preventDefault(); 75 | 76 | let $this, 77 | shortcutClicked = false; 78 | 79 | if (e.target.tagName === 'SPAN') { 80 | $this = $(e.target).closest('li'); 81 | if ($(e.target).hasClass('shortcut')) { 82 | shortcutClicked = true; 83 | } 84 | } else { 85 | $this = $(e.target); 86 | } 87 | 88 | if (e.metaKey || e.altKey) { 89 | if (e.metaKey) { 90 | Callout.toggleCheckmark($this); 91 | } else if (e.altKey) { 92 | if (shortcutClicked) { 93 | Callout.toggleShortcut($this); 94 | } else { 95 | Callout.toggleArrow($this); 96 | } 97 | } 98 | return false; 99 | } 100 | 101 | 102 | $('.callout').removeClass('callout'); 103 | $('.persist').removeClass('persist'); 104 | 105 | if (e.target.tagName === 'BODY') { 106 | $('.clicked').removeClass('clicked'); 107 | $('.last').removeClass('last'); 108 | Callout.setArrow(false); 109 | Callout.setShortcut(false); 110 | } else { 111 | if ($this.hasClass('clicked')) { 112 | if ($this.find('.last').length) { 113 | Util.clearClicks(); 114 | $this.parents('li').addClass('clicked'); 115 | $this.addClass('clicked last'); 116 | } else { 117 | $('.last').removeClass('last'); 118 | if ($this.parents('.clicked').length) { 119 | $this.removeClass('clicked'); 120 | $this.siblings('.clicked').removeClass('clicked'); 121 | $this.parents('.clicked').first().addClass('last'); 122 | } else { 123 | $('.clicked').removeClass('clicked'); 124 | } 125 | 126 | Callout.setArrow(false); 127 | Callout.setShortcut(false); 128 | } 129 | return false; 130 | } else { 131 | Callout.setArrow(false); 132 | Callout.setShortcut(false); 133 | $('li.clicked').removeClass('clicked'); 134 | $('.last').removeClass('last'); 135 | $this.parents('li').addClass('clicked'); 136 | if (e.altKey) { 137 | Callout.setArrow(true, $this); 138 | } 139 | $this.addClass('clicked last'); 140 | } 141 | 142 | if (e.type === 'dblclick') { 143 | $this.addClass('callout'); 144 | if (e.shiftKey) { 145 | $this.parents('.clicked').addClass('callout'); 146 | } 147 | } 148 | } 149 | return false; 150 | }; 151 | /** 152 | * handler for all clicks within the .controls element 153 | * @private 154 | * @memberof Nifty.handlers 155 | * @param {event} e Event 156 | * @return {boolean} continue handling event 157 | */ 158 | const controlsClick = (e) => { 159 | e.preventDefault(); 160 | let $this = e.target; 161 | 162 | switch($this.id) { 163 | case 'darkModeToggle': 164 | Util.toggleDarkMode(); 165 | break; 166 | case 'exposeToggle': 167 | Util.toggleExpose(); 168 | break; 169 | case 'backgroundToggle': 170 | Util.toggleBG(); 171 | break; 172 | case 'chooseWallpaper': 173 | chooseWallpaper(); 174 | break; 175 | case 'randomWallpaper': 176 | randomWallpaper(); 177 | break; 178 | case 'resetWallpaper': 179 | Util.setWallpaper(false); 180 | break; 181 | case 'arrowStyle': 182 | Callout.toggleArrowStyle(); 183 | break; 184 | case 'screenshot': 185 | Util.screenshot(e); 186 | break; 187 | case 'commandshell': 188 | Util.terminal(e); 189 | break; 190 | default: 191 | throw('Element ID unrecognized'); 192 | } 193 | 194 | return false; 195 | }; 196 | 197 | /** 198 | * Allow entry of a url to load as wallpaper 199 | * @memberof Handlers 200 | * @private 201 | */ 202 | const chooseWallpaper = () => { 203 | let url = prompt("Enter URL for background image"); 204 | Prefs.set('wallpaper', url); 205 | Util.loadWallpaper(); 206 | }; 207 | 208 | /** 209 | * Choose random unsplash wallpaper 210 | * @memberof Handlers 211 | * @private 212 | */ 213 | const randomWallpaper = () => { 214 | let keywords = prompt("Enter optional keywords (comma separated words)"), 215 | url = 'https://source.unsplash.com/random/1900x1200?' + encodeURIComponent(keywords); 216 | 217 | Prefs.set('wallpaper', url); 218 | Util.loadWallpaper(); 219 | }; 220 | 221 | 222 | 223 | /** 224 | * reveal and focus the help search field 225 | * @memberof Nifty.handlers 226 | * 227 | * @param {event} e Event 228 | * @return {boolean} continue handling event 229 | */ 230 | const focusSearch = (e) => { 231 | e.preventDefault(); 232 | $('li.callout').removeClass('callout'); 233 | $('.clicked').removeClass('clicked'); 234 | Util.clearClicks(); 235 | let $search = $('.helpsearch').first(); 236 | $search.parents('li').addClass('clicked persist'); 237 | $search.get(0).scrollIntoView({behavior: "smooth", block: "end", inline: "end"}); 238 | $('input',$search).focus(); 239 | return false; 240 | }; 241 | 242 | return { 243 | itemClick, 244 | controlsClick, 245 | liveSearch, 246 | focusSearch 247 | } 248 | }()); 249 | 250 | export default Handler; 251 | -------------------------------------------------------------------------------- /javascript/modules/modules.js: -------------------------------------------------------------------------------- 1 | import Callout from 'callout.js'; 2 | import Handler from 'handler.js' 3 | import Prefs from 'prefs.js'; 4 | import Search from 'search.js'; 5 | import Util from 'util.js'; 6 | 7 | export { Callout, Handler, Prefs, Search, Util }; 8 | -------------------------------------------------------------------------------- /javascript/modules/nifty.js: -------------------------------------------------------------------------------- 1 | import { Util, Prefs, Callout, Handler, Search } from 'modules.js'; 2 | 3 | /** 4 | * @namespace Nifty 5 | * @private 6 | * @description Automation API and event handlers 7 | */ 8 | const Nifty = (function() { 9 | 'use strict'; 10 | 11 | /** 12 | * Setup function, cache menu items and init preferences 13 | * @memberof Nifty 14 | */ 15 | const init = () => { 16 | Search.getOrderedMenuItemTitles(); 17 | if (Prefs.getBool('darkMode')) { 18 | Util.setDarkMode(true); 19 | } 20 | if (Prefs.getBool('expose')) { 21 | Util.setExpose(true); 22 | } 23 | Util.loadWallpaper(); 24 | if (Prefs.getBool('bgImage')) { 25 | Util.setBG(true); 26 | } 27 | Callout.setArrowStyle(Prefs.get('arrowStyle')); 28 | 29 | // set up handlers 30 | 31 | 32 | $('body,li').on('click dblclick', Handler.itemClick); 33 | 34 | $('span','.controls').on('click', Handler.controlsClick); 35 | 36 | $('.helpsearch input').on('keyup', Handler.liveSearch); 37 | 38 | $('.helpsearch').on('click', Handler.focusSearch); 39 | 40 | $('.helpsearch').on('blur', () => { 41 | $('.persist').removeClass('persist'); 42 | }); 43 | 44 | // $('body').on('click', () => { 45 | // $('#screenshotHolder').empty(); 46 | // }); 47 | 48 | // Load demo overlay if viewed on GitHub 49 | if (window.location.host === 'ttscoff.github.io') { $('body').addClass('demo'); } 50 | 51 | // bind some keys 52 | 53 | Mousetrap.bind('shift+/', Handler.focusSearch); 54 | Mousetrap.bind('shift+d', Util.toggleDarkMode); 55 | Mousetrap.bind('shift+e', Util.toggleExpose); 56 | Mousetrap.bind('shift+s', Util.screenshot); 57 | Mousetrap.bind('$', Util.terminal); 58 | }; 59 | 60 | /** 61 | * search for a menu item by string and click 62 | * @memberof Nifty 63 | * 64 | * @param {string} str The string to search and click 65 | * @param {boolean} force If false/undefined, clicking a focused item 66 | * will hide it. Pass true to always open the 67 | * item. 68 | * @return {null} Nothing 69 | */ 70 | const click = (str, force=false) => { 71 | if (force) { 72 | Util.clearClicks(true); 73 | } 74 | 75 | if (!str || /^\s*$/.test(str)) { 76 | Util.clearClicks(true); 77 | return; 78 | } 79 | let match = Search.find(str); 80 | if (match) { 81 | match.click(); 82 | match.get(0).scrollIntoView({behavior: "auto", block: "end", inline: "center"}); 83 | } 84 | }; 85 | 86 | /** 87 | * search for a menu item by string and double-click 88 | * @memberof Nifty 89 | * 90 | * @param {string} str The string to search and double click 91 | * @param {boolean} force If false/undefined, clicking a focused item 92 | * will hide it. Pass true to always open the 93 | * item. 94 | * @return {null} Nothing 95 | */ 96 | const dblClick = (str, force=false) => { 97 | 98 | if (force) { 99 | Util.clearClicks(true); 100 | } 101 | 102 | if (!str || /^\s*$/.test(str)) { 103 | Util.clearClicks(true); 104 | return; 105 | } 106 | let match = Search.find(str); 107 | if (match) { 108 | match.dblclick(); 109 | match.get(0).scrollIntoView({behavior: "auto", block: "end", inline: "center"}); 110 | } 111 | }; 112 | 113 | return { 114 | orderedMenuItemTitles: [], 115 | init, 116 | click, 117 | dblClick 118 | } 119 | })(); 120 | 121 | export default Nifty; 122 | -------------------------------------------------------------------------------- /javascript/modules/prefs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace Prefs 3 | * @private 4 | * @description Utility methods for storing/retrieving preferences 5 | */ 6 | const Prefs = (function() { 7 | 'use strict'; 8 | 9 | const CONFIG_KEY = 'niftyPrefs'; 10 | 11 | const defaults = { 12 | 'arrowStyle' : 'arrow', 13 | 'bgImage' : 1, 14 | 'expose' : 0, 15 | 'darkMode' : 0, 16 | 'wallpaper' : 'default' 17 | }; 18 | 19 | let config = null; 20 | 21 | const getConfig = () => { 22 | if (!config) { 23 | let storedConfig = JSON.parse(localStorage.getItem(CONFIG_KEY)); 24 | 25 | if (storedConfig) { 26 | config = $.extend({}, defaults, storedConfig); 27 | } else { 28 | config = defaults; 29 | } 30 | 31 | localStorage.setItem(CONFIG_KEY, JSON.stringify(config)); 32 | } 33 | 34 | return config; 35 | }; 36 | 37 | /** 38 | * Retrieve preference key as a boolean value 39 | * 40 | * @param {string} key The key 41 | * @return {boolean} True for positive integer or truthy string 42 | */ 43 | const getBool = (key) => { 44 | let value = get(key); 45 | return truthy(value); 46 | }; 47 | 48 | 49 | /** 50 | * Determine truthiness of value 51 | * 52 | * @param {any} value The value: boolean, integer, or string 53 | * @return {boolean} determined value 54 | */ 55 | const truthy = (value) => { 56 | if (typeof value === 'boolean') { 57 | return value; 58 | } 59 | if (Number(value)) { 60 | return Boolean(Number(value)); 61 | } else { 62 | if (/(y(es)?|true)/i.test(value)) { 63 | return true; 64 | } 65 | return false; 66 | } 67 | }; 68 | 69 | /** 70 | * Set a preference value 71 | * 72 | * @param {string} key The config item's key 73 | * @param {string} value Value to set for key 74 | */ 75 | const set = (key, value) => { 76 | config = get(); 77 | config[key] = value; 78 | localStorage.setItem(CONFIG_KEY, JSON.stringify(config)); 79 | }; 80 | 81 | /** 82 | * Retrive the raw preference for a key 83 | * 84 | * @param {string} key The config item's key 85 | * @return {string} raw string from preferences, not decoded or JSONified 86 | */ 87 | const get = (key) => { 88 | 89 | let _config = getConfig(); 90 | 91 | if (_config && key) { 92 | if (_config.hasOwnProperty(key)) { 93 | return config[key]; 94 | } else { 95 | return null; 96 | } 97 | } else { 98 | return _config; 99 | } 100 | 101 | }; 102 | 103 | const Prefs = { 104 | config, 105 | set, 106 | get, 107 | getBool, 108 | truthy 109 | }; 110 | 111 | return Prefs; 112 | })(); 113 | 114 | export default Prefs; 115 | -------------------------------------------------------------------------------- /javascript/modules/search.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace Search 3 | * @private 4 | * @description Automation API and event handlers 5 | */ 6 | const Search = (function() { 7 | 'use strict'; 8 | let orderedMenuItemTitles; 9 | 10 | const itemForPath = (path) => { 11 | return $('li').filter(function(i,n) { 12 | if ($(n).data('path') === path) { 13 | return true; 14 | } 15 | return false; 16 | }).first(); 17 | }; 18 | 19 | /** 20 | * Case insensitive string match for menu item search. Use / to separate 21 | * heirarchical menu search items 22 | * @example Search.find('insert/toc/section') 23 | * 24 | * @param {string} query The string to search for 25 | * @return {jQuery} single jQuery element or null 26 | */ 27 | const find = (query) => { 28 | if (/^\s*$/.test(query)) { 29 | return null; 30 | } 31 | 32 | query = query.replace(/>/g,"/"); 33 | 34 | let titles = getOrderedMenuItemTitles(); 35 | let results = fuzzysort.go(query, titles); 36 | if (results.length) { 37 | return itemForPath(results[0].target); 38 | } else { 39 | return null; 40 | } 41 | }; 42 | 43 | /** 44 | * Get an array of all item tiles with hierarchy 45 | * @private 46 | * 47 | * @return {array} The menu item titles. 48 | */ 49 | const getOrderedMenuItemTitles = () => { 50 | if (orderedMenuItemTitles && orderedMenuItemTitles.length > 0) { 51 | return orderedMenuItemTitles; 52 | } 53 | let titles = []; 54 | 55 | $('li').each(function(i,n) { 56 | let thisTitle = n.innerText.split(/\n/)[0].trim(); 57 | $(n).parents('li').each(function(i,n) { 58 | if (n.innerText.length) { 59 | thisTitle = n.innerText.split(/\n/)[0].trim() + "/" + thisTitle; 60 | } 61 | }); 62 | $(n).data('path',thisTitle); 63 | titles.push(thisTitle); 64 | }); 65 | orderedMenuItemTitles = titles; 66 | return orderedMenuItemTitles; 67 | }; 68 | 69 | return { 70 | orderedMenuItemTitles: [], 71 | getOrderedMenuItemTitles, 72 | find 73 | } 74 | })(); 75 | 76 | export default Search; 77 | -------------------------------------------------------------------------------- /javascript/modules/util.js: -------------------------------------------------------------------------------- 1 | import Prefs from 'prefs.js'; 2 | import Callout from 'callout.js'; 3 | 4 | /** 5 | * @namespace Util 6 | * @private 7 | * @description DOM/interface utilities 8 | */ 9 | const Util = (function() { 10 | /** 11 | * Clear all active clicks (menu items held in place) 12 | * 13 | * @param {boolean} persist The help menu gets a special class to keep 14 | * it open while other menus are active, even 15 | * when it's not hovered. Setting this to true 16 | * removes that class as well. 17 | */ 18 | const clearClicks = (persist) => { 19 | $('li.callout').removeClass('callout'); 20 | $('.clicked').removeClass('clicked'); 21 | $('.last').removeClass('last'); 22 | Callout.setArrow(false); 23 | Callout.setShortcut(false); 24 | if (persist) { 25 | $('.persist').removeClass('persist'); 26 | } 27 | }; 28 | 29 | /** 30 | * Sets the wallpaper image to use when bgImage is enabled 31 | * @param {string} url URL for background image 32 | */ 33 | const setWallpaper = (url) => { 34 | Prefs.set('wallpaper', url); 35 | loadWallpaper(); 36 | }; 37 | 38 | /** 39 | * Add a style rule for the defined wallpaper 40 | * @private 41 | * @param {string} url URL for background image 42 | */ 43 | const loadWallpaper = () => { 44 | let url = Prefs.get('wallpaper'); 45 | if (!url || url === 'default') { 46 | if (Prefs.getBool('darkMode')) { 47 | url = 'images/darkbackground.jpg'; 48 | } else { 49 | url = 'images/background.jpg'; 50 | } 51 | } 52 | addStyleRule('body.bgimage, body.dark.bgimage {background-image: url('+url+')}'); 53 | }; 54 | 55 | /** 56 | * Add a style rule to main stylesheet 57 | * @private 58 | */ 59 | const addStyleRule = (rule) => { 60 | var sheet = (function() { 61 | var style = document.createElement("style"); 62 | style.appendChild(document.createTextNode("")); 63 | document.head.appendChild(style); 64 | return style.sheet; 65 | })(); 66 | sheet.insertRule(rule); 67 | }; 68 | 69 | /** 70 | * Sets the background image on or off. Use the boolean paramater to 71 | * determine which. 72 | * @param {boolean} bool true turns background image on, 73 | * false for off 74 | */ 75 | const setBG = (bool) => { 76 | let $body = $('body'); 77 | if (bool) { 78 | $body.addClass('bgimage'); 79 | Prefs.set('bgImage',1); 80 | loadWallpaper(); 81 | } else { 82 | $body.removeClass('bgimage'); 83 | Prefs.set('bgImage',0); 84 | } 85 | }; 86 | 87 | /** 88 | * Toggle background image 89 | */ 90 | const toggleBG = () => { 91 | let $body = $('body'); 92 | if ($body.hasClass('bgimage')) { 93 | setBG(false); 94 | } else { 95 | setBG(true); 96 | } 97 | }; 98 | 99 | /** 100 | * Toggle Dark Mode 101 | */ 102 | const toggleDarkMode = () => { 103 | let test = $('body').hasClass('dark'); 104 | 105 | if (test) { 106 | setDarkMode(false); 107 | } else { 108 | setDarkMode(true); 109 | } 110 | }; 111 | 112 | /** 113 | * Set Dark Mode 114 | * @param {boolean} [bool=true] Dark Mode on or off 115 | */ 116 | const setDarkMode = (bool=true) => { 117 | let $body = $('body'); 118 | if (!bool) { 119 | $body.removeClass('dark'); 120 | Prefs.set('darkMode',0); 121 | } else { 122 | $body.addClass('dark'); 123 | Prefs.set('darkMode',1); 124 | } 125 | loadWallpaper(); 126 | }; 127 | 128 | /** 129 | * Force Expose on or off. Use the boolean paramater to determine which. 130 | * @param {boolean} [bool=true] true turns Expose on, false for off 131 | */ 132 | const setExpose = (bool) => { 133 | let $body = $('body'); 134 | if (bool) { 135 | $body.addClass('expose'); 136 | $('html,body').width($('body>ul').width()); 137 | Prefs.set('expose',1); 138 | } else { 139 | Prefs.set('expose',0); 140 | window.location.reload(); 141 | } 142 | }; 143 | 144 | /** 145 | * Toggle Expose 146 | */ 147 | const toggleExpose = () => { 148 | let $body = $('body'); 149 | if ($body.hasClass('expose')) { 150 | setExpose(false); 151 | } else { 152 | setExpose(true); 153 | } 154 | }; 155 | 156 | /** 157 | * Take a screenshot of selected menu item. Experimental, currently only works 158 | * in Chrome. If called via NiftyAPI.shoot(), downloads immediately to 159 | * Downloads folder, names file based on menu path. 160 | * 161 | * Background images work if they're remote. Local images seem to taint the 162 | * canvas, making it impossible to save with Chrome's security restrictions. 163 | * 164 | * @param {event} e If e is undefined, download immediately 165 | */ 166 | const screenshot = (e, filename) => { 167 | $('body').addClass('screenshot'); 168 | let clicks = $('li.clicked'); 169 | if (!clicks.length) { 170 | throw("No menu items selected"); 171 | } 172 | 173 | let title; 174 | 175 | if (filename) { 176 | title = filename; 177 | } else { 178 | title = []; 179 | clicks.each((i,n) => { 180 | title.push($(n).find('>strong').text()); 181 | }); 182 | 183 | let last = clicks.last(); 184 | if (last.children('.shortcut').length > 0) { 185 | title.push(last.find('.menuitem').text()); 186 | } else { 187 | title.push(last.text()); 188 | } 189 | 190 | title = title.join('-').replace(/-+/g,'-').replace(/ +/g,'_'); 191 | } 192 | 193 | let menus = clicks.parents('ul').not('body>ul'), 194 | left = Math.floor(clicks.first().offset().left - 70), 195 | width = 150, 196 | height = 0; 197 | 198 | menus.each((i,n) => { 199 | width += $(n).width(); 200 | let ulTop = $(n).offset().top; 201 | let ulHeight = $(n).height(); 202 | if (ulTop + ulHeight > height) { 203 | height = ulTop + ulHeight; 204 | } 205 | }); 206 | 207 | // if the last item clicked has an open submenu, 208 | // include it in screenshot 209 | if (clicks.last().find('ul').length) { 210 | width += clicks.last().find('ul').width(); 211 | } 212 | 213 | let useCors = false; 214 | let hadBG = Prefs.getBool('bgImage'); 215 | 216 | if ((/url\("http/).test($('body').css('background-image'))) { 217 | useCors = true; 218 | } else if ((/url\("file/).test($('body').css('background-image'))) { 219 | setBG(false); 220 | } 221 | 222 | html2canvas(document.querySelector("body"), { 223 | x: left, 224 | y: 0, 225 | width: width, 226 | height: height + 50, 227 | useCORS: useCors, 228 | imageTimeout: 60000 229 | }).then(canvas => { 230 | $('#screenshotHolder').empty(); 231 | $('#screenshotHolder').append(canvas); 232 | clearClicks(true); 233 | $('body').removeClass('screenshot'); 234 | setBG(hadBG); 235 | 236 | // if called from a handler, display screenshot for download 237 | if (e) { 238 | let $controls = $('
'); 239 | $('') 240 | .addClass('screenshot-close') 241 | .on('click', () => { 242 | $('#screenshotHolder').empty(); 243 | }) 244 | .appendTo($controls); 245 | $('') 246 | .addClass('screenshot-dl') 247 | .data('title', title) 248 | .on('click', () => { 249 | downloadScreenshot(title); 250 | }) 251 | .appendTo($controls); 252 | $controls.appendTo('#screenshotHolder'); 253 | // if called from API, download immediately 254 | } else { 255 | downloadScreenshot(title); 256 | } 257 | 258 | }); 259 | } 260 | 261 | /** 262 | * Download a screenshot (handler) 263 | * 264 | * @param {string} title Filename to use 265 | */ 266 | const downloadScreenshot = (title) => { 267 | if (!title) 268 | title = 'NiftyMenu_Screenshot'; 269 | 270 | let canvas = document.querySelector('#screenshotHolder canvas'), 271 | link = document.createElement('a'); 272 | 273 | link.download = `${title}.png`; 274 | link.href = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream"); 275 | link.click(); 276 | $('#screenshotHolder').empty(); 277 | } 278 | 279 | /** 280 | * Launch a shell for running automations 281 | */ 282 | const terminal = (e) => { 283 | e.preventDefault(); 284 | if ($('#terminal').length > 0) { 285 | $('#terminal').toggle(); 286 | if ($('#terminal').is(':visible')) { 287 | $('#terminal>textarea').focus(); 288 | } 289 | } else { 290 | $('
').appendTo('body'); 291 | $('#terminal>input').on('click', (e) => { 292 | e.preventDefault(); 293 | let code = $('#terminal textarea').val(); 294 | $('#terminal').hide(); 295 | code.trim().split(/;/).forEach((line) => { 296 | let exec = line.trim(); 297 | if (exec.length > 0) { 298 | return Function(`"use strict";return (${exec})`)(); 299 | } 300 | }); 301 | }); 302 | $('#terminal>textarea').focus(); 303 | } 304 | return false; 305 | } 306 | 307 | return { 308 | setDarkMode, 309 | toggleDarkMode, 310 | setExpose, 311 | toggleExpose, 312 | setBG, 313 | setWallpaper, 314 | loadWallpaper, 315 | toggleBG, 316 | clearClicks, 317 | screenshot, 318 | downloadScreenshot, 319 | terminal 320 | } 321 | })(); 322 | 323 | export default Util; 324 | -------------------------------------------------------------------------------- /out/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/out/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /out/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/out/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /out/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/out/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /out/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/out/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /out/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/out/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /out/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/out/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /out/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/out/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /out/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/out/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /out/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/out/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /out/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/out/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /out/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/out/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /out/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/out/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /out/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Home 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Home

21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |

30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 | 52 | 55 | 56 |
57 | 58 |
59 | Documentation generated by JSDoc 3.6.11 on Thu May 04 2023 08:37:34 GMT-0500 (Central Daylight Time) 60 |
61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /out/modules_api.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: modules/api.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: modules/api.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
import { Callout, Prefs, Search, Util } from 'modules.js';
 30 | 
 31 | /**
 32 |  * @namespace NiftyAPI
 33 |  * @description Chainable automation API. All chains that affect a menu item
 34 |  * should start with a .find('search string') call.
 35 |  *
 36 |  * @example NiftyAPI.find('file/save').arrow(); // locate File->Save menu item and add an arrow callout
 37 |  */
 38 | const NiftyAPI = {
 39 |   targetEl: null,
 40 | 
 41 |   /**
 42 |    * Show current configuration options
 43 |    *
 44 |    * @return     {object}  The configuration.
 45 |    */
 46 |   getConfig: function() {
 47 |     return Prefs.get();
 48 |   },
 49 | 
 50 |   /**
 51 |    * Set multiple display options via a configuration object
 52 |    *
 53 |    * @param      {Object}  options  object containing settings
 54 |    * @example
 55 |    *  NiftyAPI.config({
 56 |    *   'arrowStyle': 'arrow',
 57 |    *   'bgImage': true,
 58 |    *   'darkMode': false,
 59 |    *   'wallpaper': 'default'
 60 |    * });
 61 |    */
 62 |   config: function(options={}) {
 63 |     let defaults = Prefs.config;
 64 | 
 65 |     let config = $.extend({}, defaults, options);
 66 | 
 67 |     Util.setDarkMode(Prefs.truthy(config.darkMode));
 68 |     Util.setBG(Prefs.truthy(config.bgImage));
 69 |     Util.setWallpaper(config.wallpaper);
 70 |     Callout.setArrowStyle(config.arrowStyle);
 71 |     return this;
 72 |   },
 73 | 
 74 |   /**
 75 |    * Case insensitive string match for menu item search. Use / to separate
 76 |    * heirarchical menu search items. This function can be chained for use with
 77 |    * other functions.
 78 |    * @example
 79 |    *   NiftyAPI.find('insert/toc/section');
 80 |    * NiftyAPI.find('insert/toc/section').arrow();
 81 |    *
 82 |    * @param      {string}  str     The string to search for
 83 |    * @return     {jQuery}  single jQuery element or null
 84 |    */
 85 |   find: function(str) {
 86 |     this.targetEl = Search.find(str);
 87 |     return this;
 88 |   },
 89 | 
 90 |   /**
 91 |    * Clear all clicks, callouts, and arrows
 92 |    * @example
 93 |    *  NiftyAPI.clear();
 94 |    */
 95 |   clear: function() {
 96 |     Util.clearClicks(true);
 97 |     return this;
 98 |   },
 99 | 
100 |   /**
101 |    * Lock menu item. Removes any existing locks. Equivalent to clicking a menu
102 |    * item.
103 |    * @example
104 |    *  NiftyAPI.find('file/save').lock();
105 |    */
106 |   lock: function() {
107 |     Util.clearClicks(true);
108 |     this.targetEl.click();
109 |     this.targetEl.get(0).scrollIntoView({behavior: "auto", block: "end", inline: "center"});
110 |     return this;
111 |   },
112 | 
113 |   /**
114 |    * Add callout to menu item. Equivalent to double clicking a menu item.
115 |    *
116 |    * @param      {boolean}  [bool=true]      Callout on or off (default: true)
117 |    * @param      {boolean}  [recurse=false]  Call out parent items (default:
118 |    *                                         false)
119 |    * @example
120 |    *  NiftyAPI.find('file/open').callout();
121 |    *NiftyAPI.find('file/open').callout(true, true); // add callout to item and parents
122 |    *NiftyAPI.find('file/open').callout(false); // remove callout
123 |    */
124 |   callout: function(bool, recurse=false) {
125 |     if (bool === undefined) {
126 |       bool = true;
127 |     }
128 | 
129 |     Util.clearClicks(true);
130 | 
131 |     if (bool) {
132 |       this.targetEl.dblclick();
133 |       this.targetEl.get(0).scrollIntoView({behavior: "auto", block: "end", inline: "center"});
134 | 
135 |       if (recurse) {
136 |         this.targetEl.parents('.clicked').addClass('callout');
137 |       }
138 |     }
139 | 
140 |     return this;
141 |   },
142 | 
143 |   /**
144 |    * Set callout arrow for menu item. Equivalent to option-clicking a menu item.
145 |    *
146 |    * @param      {boolean}  [bool=true]  Arrow on or off
147 |    * @example
148 |    *  NiftyAPI.find('view/merge').arrow();
149 |    *NiftyAPI.find('view/merge').arrow(false); // remove arrow
150 |    */
151 |   arrow: function(bool) {
152 |     if (bool === undefined) {
153 |       bool = true;
154 |     }
155 |     Callout.setArrow(bool, this.targetEl);
156 |     return this;
157 |   },
158 | 
159 |   /**
160 |    * Set shortcut callout for menu item. Equivalent to option-clicking a
161 |    * shortcut on a menu item.
162 |    *
163 |    * @param      {boolean}  [bool=true]  Shortcut callout on or off
164 |    * @example
165 |    *  NiftyAPI.find('file/save').shortcut();
166 |    *NiftyAPI.find('file/save').shortcut(false); // remove arrow
167 |    */
168 |   shortcut: function(bool) {
169 |     if (bool === undefined) {
170 |       bool = true;
171 |     }
172 |     Callout.setShortcut(bool, this.targetEl);
173 |     return this;
174 |   },
175 | 
176 |   /**
177 |    * Turn Dark Mode on or off
178 |    *
179 |    * @param      {boolean}  [bool=true]  Dark Mode on or off
180 |    * @example
181 |    *  NiftyAPI.darkMode(); // turn dark mode on
182 |    *NiftyAPI.darkMode(false); // turn dark mode off
183 |    */
184 |   darkMode: function(bool) {
185 |     if (bool === undefined) {
186 |       bool = true;
187 |     }
188 |     Util.setDarkMode(bool);
189 |     return this;
190 |   },
191 | 
192 |   /**
193 |    * Turn Expose on or off
194 |    *
195 |    * @param      {boolean}  [bool=true]  Expose on or off
196 |    * @example
197 |    *  NiftyAPI.expose(); // turn expose on
198 |    *NiftyAPI.expose(false); // turn expose off
199 |    */
200 |   expose: function(bool) {
201 |     if (bool === undefined) {
202 |       bool = true;
203 |     }
204 |     Util.setExpose(bool);
205 |     return this;
206 |   },
207 | 
208 |   /**
209 |    * Take a screenshot of selected menu item. Currently experimental, **only
210 |    * works in Chrome**.
211 |    *
212 |    * Background images work if they're remote (hosted, with proper CORS
213 |    * headers). Local images seem to taint the canvas, making it impossible to
214 |    * save with Chrome's security restrictions. Thus, background images are
215 |    * disabled during screenshot if using a file: protocol.
216 |    *
217 |    * @param      {string}  [title=null]  The title for downloaded image, no extension
218 |    *
219 |    * @example
220 |    *  NiftyAPI.find('edit/paste as').arrow().shoot('filename');
221 |    *
222 |    */
223 |   shoot: function(title=null) {
224 |     Util.screenshot(false, title);
225 |     return this;
226 |   }
227 | };
228 | 
229 | export default NiftyAPI;
230 | 
231 |
232 |
233 | 234 | 235 | 236 | 237 |
238 | 239 | 242 | 243 |
244 | 245 |
246 | Documentation generated by JSDoc 3.6.11 on Thu May 04 2023 08:37:34 GMT-0500 (Central Daylight Time) 247 |
248 | 249 | 250 | 251 | 252 | 253 | -------------------------------------------------------------------------------- /out/modules_callout.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: modules/callout.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: modules/callout.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
import Prefs from 'prefs.js'
 30 | 
 31 | /**
 32 |  * @namespace Callout
 33 |  * @private
 34 |  * @memberof  Nifty
 35 |  * @description Methods for adding callouts to items
 36 |  */
 37 | const Callout = (function() {
 38 |   /**
 39 |    * Sets the arrow callout
 40 |    * @memberof   Callout
 41 |    *
 42 |    * @param      {boolean}  bool    Add or remove arrow
 43 |    * @param      {element}   el     DOM element or jQuery object, applies to all .arrow if empty
 44 |    * @return     {boolean}  Result
 45 |    */
 46 |   const setArrow = (bool, el) => {
 47 |     if (!el && !bool) {
 48 |       $('.arrow').each(function(i,n) {
 49 |         setArrow(false,$(n));
 50 |       });
 51 |       return;
 52 |     }
 53 | 
 54 |     if (!(el instanceof jQuery)) {
 55 |       el = $(el);
 56 |     }
 57 | 
 58 |     if (el.get(0).tagName !== 'LI') {
 59 |       el = el.parents('li').first();
 60 |     }
 61 | 
 62 |     if (bool) {
 63 |       setArrow(false);
 64 |       setShortcut(false);
 65 |       const style = Prefs.get('arrowStyle') || 'arrow';
 66 |       const direction = el.find('ul').length ? 'left' : 'right';
 67 |       $('.clicked').removeClass('clicked');
 68 |       el.addClass('arrow arrow-'+style+' clicked '+direction).append('<b><i></i></b>');
 69 |       el.parents('li').addClass('clicked');
 70 |     } else {
 71 |       el.removeClass('arrow arrow-arrow arrow-circle').find('b').remove();
 72 |     }
 73 |   };
 74 | 
 75 |   /**
 76 |    * Toggles the arrow callout
 77 |    * @memberof   Callout
 78 |    *
 79 |    * @param      {jquery}   el      jQuery object, all .arrow if empty
 80 |    * @return     {boolean}  Result
 81 |    */
 82 |   const toggleArrow = (el) => {
 83 |     if (!el) {
 84 |       setArrow(false);
 85 |       return;
 86 |     }
 87 | 
 88 |     if (!(el instanceof jQuery)) {
 89 |       el = $(el);
 90 |     }
 91 | 
 92 |     if (el.hasClass('arrow')) {
 93 |       setArrow(false, el);
 94 |     } else {
 95 |       setArrow(false);
 96 |       setShortcut(false);
 97 |       setArrow(true, el);
 98 |     }
 99 |   };
100 | 
101 |   /**
102 |    * Sets the shortcut callout
103 |    * @memberof   Callout
104 |    *
105 |    * @param      {boolean}  bool    Add or remove shortcut callout
106 |    * @param      {element}   el     DOM element or jQuery object containing shortcut,
107 |    *                                applies to all .shortcut-callout if empty
108 |    * @return     {boolean}  Result
109 |    */
110 |   const setShortcut = (bool, el) => {
111 |     if (!el && !bool) {
112 |       $('.shortcut-callout').each(function(i,n) {
113 |         setShortcut(false,$(n));
114 |       });
115 |       return;
116 |     }
117 | 
118 |     if (!(el instanceof jQuery)) {
119 |       el = $(el);
120 |     }
121 | 
122 |     if (el.get(0).tagName !== 'LI') {
123 |       el = el.parents('li').first();
124 |     }
125 | 
126 |     if (bool) {
127 |       setShortcut(false);
128 |       setArrow(false);
129 |       $('.clicked').removeClass('clicked');
130 |       el.addClass('clicked').find('.shortcut').addClass('shortcut-callout');
131 |       el.parents('li').addClass('clicked');
132 |     } else {
133 |       el.find('.shortcut').removeClass('shortcut-callout');
134 |     }
135 |   };
136 | 
137 |   /**
138 |    * Toggles the shortcut callout
139 |    * @memberof   Callout
140 |    *
141 |    * @param      {jquery}   el      jQuery object, all .arrow if empty
142 |    * @return     {boolean}  Result
143 |    */
144 |   const toggleShortcut = (el) => {
145 |     if (!el) {
146 |       setShortcut(false);
147 |       return;
148 |     }
149 | 
150 |     if (!(el instanceof jQuery)) {
151 |       el = $(el);
152 |     }
153 | 
154 |     if (el.has('.shortcut-callout').length) {
155 |       setShortcut(false, el);
156 |     } else {
157 |       setShortcut(false);
158 |       setShortcut(true, el);
159 |     }
160 |   };
161 | 
162 |   /**
163 |    * Toggles a checkmark on the clicked menu item.
164 |    * @memberof   Callout
165 |    * @param      {jquery}   el      jQuery object, all .arrow if empty.
166 |    * @return     {boolean}  Result
167 |    */
168 |   const toggleCheckmark = (el) => {
169 |     if (!(el instanceof jQuery)) {
170 |       el = $(el);
171 |     }
172 | 
173 |     if (el.hasClass('checked')) {
174 |       el.removeClass('checked');
175 |     } else {
176 |       el.addClass('checked');
177 |     }
178 |     return true;
179 |   };
180 | 
181 |   /**
182 |   * Sets the style of the callout arrow
183 |   * @memberof   Callout
184 |   * @param      {string}  style    'circle' or 'arrow'
185 |   */
186 |   const setArrowStyle = (style) => {
187 |     let newStyle = 'arrow';
188 |     if (style && style === 'circle') {
189 |       newStyle = 'circle';
190 |       $('.arrow-arrow').removeClass('arrow-arrow').addClass('arrow-circle');
191 |     } else {
192 |       $('.arrow-circle').removeClass('arrow-circle').addClass('arrow-arrow');
193 |     }
194 |     Prefs.set('arrowStyle', newStyle);
195 |   };
196 | 
197 |   /**
198 |    * Toggles arrow style between circle and arrow.
199 |    * @memberof   Callout
200 |    */
201 |   const toggleArrowStyle = () => {
202 |     let newStyle;
203 |     const current = Prefs.get('arrowStyle');
204 |     if (current === 'circle') {
205 |       newStyle = 'arrow';
206 |       $('#arrowStyle','.controls').text('Arrow style: Arrow');
207 |     } else {
208 |       newStyle = 'circle';
209 |       $('#arrowStyle','.controls').text('Arrow style: Circle');
210 |     }
211 |     setArrowStyle(newStyle);
212 |   };
213 | 
214 |   return {
215 |     setArrow,
216 |     setArrowStyle,
217 |     toggleArrowStyle,
218 |     toggleArrow,
219 |     toggleCheckmark,
220 |     setShortcut,
221 |     toggleShortcut
222 |   }
223 | })();
224 | 
225 | export default Callout;
226 | 
227 |
228 |
229 | 230 | 231 | 232 | 233 |
234 | 235 | 238 | 239 |
240 | 241 |
242 | Documentation generated by JSDoc 3.6.11 on Thu May 04 2023 08:37:34 GMT-0500 (Central Daylight Time) 243 |
244 | 245 | 246 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /out/modules_handler.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: modules/handler.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: modules/handler.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
import Util from 'util.js'
 30 | import Callout from 'callout.js';
 31 | import Prefs from 'prefs.js';
 32 | import Search from 'search.js';
 33 | 
 34 | /**
 35 |  * @namespace Nifty.handlers
 36 |  * @private
 37 |  * @memberof  Nifty
 38 |  * @description Event handlers
 39 |  */
 40 | 
 41 | const Handler = (function() {
 42 |   /**
 43 |    * live search for the help menu, function ~ macOS
 44 |    * @private
 45 |    * @memberof   Nifty.handlers
 46 |    *
 47 |    * @param      {event}    e       Event
 48 |    */
 49 |   const liveSearch = (e) => {
 50 | 
 51 |     let $field = $('.helpsearch input'),
 52 |         string = $field.val(),
 53 |         shouldScroll = false;
 54 | 
 55 |     if (e.code === 'Escape') {
 56 |       e.preventDefault();
 57 |       $field.val('').blur();
 58 |       Util.clearClicks(true);
 59 |       return true;
 60 |     }
 61 | 
 62 |     if (e.code === 'Enter' || e.code === 'Return') {
 63 |       e.preventDefault();
 64 |       $('.persist').removeClass('persist');
 65 |       shouldScroll = true;
 66 |       // return true;
 67 |     }
 68 | 
 69 |     if (string.length < 2) {
 70 |       Util.clearClicks(false);
 71 |       return true;
 72 |     }
 73 | 
 74 |     let $item = Search.find(string);
 75 | 
 76 |     if ($item) {
 77 |       Util.clearClicks(false);
 78 |       if ($item.parents('li')) {
 79 |         $item.parents('li').addClass('clicked');
 80 |       }
 81 |       $item.addClass('clicked last');
 82 | 
 83 |       if (shouldScroll) {
 84 |         $field.blur();
 85 |         $item.get(0).scrollIntoView({behavior: "smooth", block: "end", inline: "center"});
 86 |       }
 87 |     } else {
 88 |       Util.clearClicks(false);
 89 |     }
 90 | 
 91 |     return true;
 92 |   };
 93 | 
 94 |   /**
 95 |    * click handler for menu items
 96 |    * @private
 97 |    * @memberof   Nifty.handlers
 98 |    * @param      {event}   e       Event
 99 |    * @return     {boolean}  continue handling event
100 |    */
101 |   const itemClick = (e) => {
102 |     e.preventDefault();
103 | 
104 |     let $this,
105 |         shortcutClicked = false;
106 | 
107 |     if (e.target.tagName === 'SPAN') {
108 |       $this = $(e.target).closest('li');
109 |       if ($(e.target).hasClass('shortcut')) {
110 |         shortcutClicked = true;
111 |       }
112 |     } else {
113 |       $this = $(e.target);
114 |     }
115 | 
116 |     if (e.metaKey || e.altKey) {
117 |       if (e.metaKey) {
118 |         Callout.toggleCheckmark($this);
119 |       } else if (e.altKey) {
120 |         if (shortcutClicked) {
121 |           Callout.toggleShortcut($this);
122 |         } else {
123 |           Callout.toggleArrow($this);
124 |         }
125 |       }
126 |       return false;
127 |     }
128 | 
129 | 
130 |     $('.callout').removeClass('callout');
131 |     $('.persist').removeClass('persist');
132 | 
133 |     if (e.target.tagName === 'BODY') {
134 |       $('.clicked').removeClass('clicked');
135 |       $('.last').removeClass('last');
136 |       Callout.setArrow(false);
137 |       Callout.setShortcut(false);
138 |     } else {
139 |       if ($this.hasClass('clicked')) {
140 |         if ($this.find('.last').length) {
141 |           Util.clearClicks();
142 |           $this.parents('li').addClass('clicked');
143 |           $this.addClass('clicked last');
144 |         } else {
145 |           $('.last').removeClass('last');
146 |           if ($this.parents('.clicked').length) {
147 |             $this.removeClass('clicked');
148 |             $this.siblings('.clicked').removeClass('clicked');
149 |             $this.parents('.clicked').first().addClass('last');
150 |           } else {
151 |             $('.clicked').removeClass('clicked');
152 |           }
153 | 
154 |           Callout.setArrow(false);
155 |           Callout.setShortcut(false);
156 |         }
157 |         return false;
158 |       } else {
159 |         Callout.setArrow(false);
160 |         Callout.setShortcut(false);
161 |         $('li.clicked').removeClass('clicked');
162 |         $('.last').removeClass('last');
163 |         $this.parents('li').addClass('clicked');
164 |         if (e.altKey) {
165 |           Callout.setArrow(true, $this);
166 |         }
167 |         $this.addClass('clicked last');
168 |       }
169 | 
170 |       if (e.type === 'dblclick') {
171 |         $this.addClass('callout');
172 |         if (e.shiftKey) {
173 |           $this.parents('.clicked').addClass('callout');
174 |         }
175 |       }
176 |     }
177 |     return false;
178 |   };
179 |   /**
180 |    * handler for all clicks within the .controls element
181 |    * @private
182 |    * @memberof   Nifty.handlers
183 |    * @param      {event}   e       Event
184 |    * @return     {boolean}  continue handling event
185 |    */
186 |   const controlsClick = (e) => {
187 |     e.preventDefault();
188 |     let $this = e.target;
189 | 
190 |     switch($this.id) {
191 |       case 'darkModeToggle':
192 |         Util.toggleDarkMode();
193 |         break;
194 |       case 'exposeToggle':
195 |         Util.toggleExpose();
196 |         break;
197 |       case 'backgroundToggle':
198 |         Util.toggleBG();
199 |         break;
200 |       case 'chooseWallpaper':
201 |         chooseWallpaper();
202 |         break;
203 |       case 'randomWallpaper':
204 |         randomWallpaper();
205 |         break;
206 |       case 'resetWallpaper':
207 |         Util.setWallpaper(false);
208 |         break;
209 |       case 'arrowStyle':
210 |         Callout.toggleArrowStyle();
211 |         break;
212 |       case 'screenshot':
213 |         Util.screenshot(e);
214 |         break;
215 |       case 'commandshell':
216 |         Util.terminal(e);
217 |         break;
218 |       default:
219 |         throw('Element ID unrecognized');
220 |     }
221 | 
222 |     return false;
223 |   };
224 | 
225 |   /**
226 |    * Allow entry of a url to load as wallpaper
227 |    * @memberof Handlers
228 |    * @private
229 |    */
230 |   const chooseWallpaper = () => {
231 |     let url = prompt("Enter URL for background image");
232 |     Prefs.set('wallpaper', url);
233 |     Util.loadWallpaper();
234 |   };
235 | 
236 |   /**
237 |    * Choose random unsplash wallpaper
238 |    * @memberof Handlers
239 |    * @private
240 |    */
241 |   const randomWallpaper = () => {
242 |     let keywords = prompt("Enter optional keywords (comma separated words)"),
243 |         url = 'https://source.unsplash.com/random/1900x1200?' + encodeURIComponent(keywords);
244 | 
245 |     Prefs.set('wallpaper', url);
246 |     Util.loadWallpaper();
247 |   };
248 | 
249 | 
250 | 
251 |   /**
252 |    * reveal and focus the help search field
253 |    * @memberof   Nifty.handlers
254 |    *
255 |    * @param      {event}    e       Event
256 |    * @return     {boolean}  continue handling event
257 |    */
258 |   const focusSearch = (e) => {
259 |     e.preventDefault();
260 |     $('li.callout').removeClass('callout');
261 |     $('.clicked').removeClass('clicked');
262 |     Util.clearClicks();
263 |     let $search = $('.helpsearch').first();
264 |     $search.parents('li').addClass('clicked persist');
265 |     $search.get(0).scrollIntoView({behavior: "smooth", block: "end", inline: "end"});
266 |     $('input',$search).focus();
267 |     return false;
268 |   };
269 | 
270 |   return {
271 |     itemClick,
272 |     controlsClick,
273 |     liveSearch,
274 |     focusSearch
275 |   }
276 | }());
277 | 
278 | export default Handler;
279 | 
280 |
281 |
282 | 283 | 284 | 285 | 286 |
287 | 288 | 291 | 292 |
293 | 294 |
295 | Documentation generated by JSDoc 3.6.11 on Thu May 04 2023 08:37:34 GMT-0500 (Central Daylight Time) 296 |
297 | 298 | 299 | 300 | 301 | 302 | -------------------------------------------------------------------------------- /out/modules_nifty.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: modules/nifty.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: modules/nifty.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
import { Util, Prefs, Callout, Handler, Search } from 'modules.js';
 30 | 
 31 | /**
 32 |  * @namespace Nifty
 33 |  * @private
 34 |  * @description Automation API and event handlers
 35 |  */
 36 | const Nifty = (function() {
 37 |   'use strict';
 38 | 
 39 |   /**
 40 |    * Setup function, cache menu items and init preferences
 41 |    * @memberof   Nifty
 42 |    */
 43 |   const init = () => {
 44 |     Search.getOrderedMenuItemTitles();
 45 |     if (Prefs.getBool('darkMode')) {
 46 |       Util.setDarkMode(true);
 47 |     }
 48 |     if (Prefs.getBool('expose')) {
 49 |       Util.setExpose(true);
 50 |     }
 51 |     Util.loadWallpaper();
 52 |     if (Prefs.getBool('bgImage')) {
 53 |       Util.setBG(true);
 54 |     }
 55 |     Callout.setArrowStyle(Prefs.get('arrowStyle'));
 56 | 
 57 |     // set up handlers
 58 | 
 59 | 
 60 |     $('body,li').on('click dblclick', Handler.itemClick);
 61 | 
 62 |     $('span','.controls').on('click', Handler.controlsClick);
 63 | 
 64 |     $('.helpsearch input').on('keyup', Handler.liveSearch);
 65 | 
 66 |     $('.helpsearch').on('click', Handler.focusSearch);
 67 | 
 68 |     $('.helpsearch').on('blur', () => {
 69 |       $('.persist').removeClass('persist');
 70 |     });
 71 | 
 72 |     // $('body').on('click', () => {
 73 |     //   $('#screenshotHolder').empty();
 74 |     // });
 75 | 
 76 |     // Load demo overlay if viewed on GitHub
 77 |     if (window.location.host === 'ttscoff.github.io') { $('body').addClass('demo'); }
 78 | 
 79 |     // bind some keys
 80 | 
 81 |     Mousetrap.bind('shift+/', Handler.focusSearch);
 82 |     Mousetrap.bind('shift+d', Util.toggleDarkMode);
 83 |     Mousetrap.bind('shift+e', Util.toggleExpose);
 84 |     Mousetrap.bind('shift+s', Util.screenshot);
 85 |     Mousetrap.bind('$', Util.terminal);
 86 |   };
 87 | 
 88 |   /**
 89 |    * search for a menu item by string and click
 90 |    * @memberof   Nifty
 91 |    *
 92 |    * @param      {string}   str     The string to search and click
 93 |    * @param      {boolean}  force   If false/undefined, clicking a focused item
 94 |    *                                will hide it. Pass true to always open the
 95 |    *                                item.
 96 |    * @return     {null}     Nothing
 97 |    */
 98 |   const click = (str, force=false) => {
 99 |     if (force) {
100 |       Util.clearClicks(true);
101 |     }
102 | 
103 |     if (!str || /^\s*$/.test(str)) {
104 |       Util.clearClicks(true);
105 |       return;
106 |     }
107 |     let match = Search.find(str);
108 |     if (match) {
109 |       match.click();
110 |       match.get(0).scrollIntoView({behavior: "auto", block: "end", inline: "center"});
111 |     }
112 |   };
113 | 
114 |   /**
115 |    * search for a menu item by string and double-click
116 |    * @memberof   Nifty
117 |    *
118 |    * @param      {string}   str     The string to search and double click
119 |    * @param      {boolean}  force   If false/undefined, clicking a focused item
120 |    *                                will hide it. Pass true to always open the
121 |    *                                item.
122 |    * @return     {null}     Nothing
123 |    */
124 |   const dblClick = (str, force=false) => {
125 | 
126 |     if (force) {
127 |       Util.clearClicks(true);
128 |     }
129 | 
130 |     if (!str || /^\s*$/.test(str)) {
131 |       Util.clearClicks(true);
132 |       return;
133 |     }
134 |     let match = Search.find(str);
135 |     if (match) {
136 |       match.dblclick();
137 |       match.get(0).scrollIntoView({behavior: "auto", block: "end", inline: "center"});
138 |     }
139 |   };
140 | 
141 |   return {
142 |     orderedMenuItemTitles: [],
143 |     init,
144 |     click,
145 |     dblClick
146 |   }
147 | })();
148 | 
149 | export default Nifty;
150 | 
151 |
152 |
153 | 154 | 155 | 156 | 157 |
158 | 159 | 162 | 163 |
164 | 165 |
166 | Documentation generated by JSDoc 3.6.11 on Thu May 04 2023 08:37:34 GMT-0500 (Central Daylight Time) 167 |
168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /out/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (() => { 3 | const source = document.getElementsByClassName('prettyprint source linenums'); 4 | let i = 0; 5 | let lineNumber = 0; 6 | let lineId; 7 | let lines; 8 | let totalLines; 9 | let anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = `line${lineNumber}`; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /out/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /out/styles/jsdoc-default.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Open Sans'; 3 | font-weight: normal; 4 | font-style: normal; 5 | src: url('../fonts/OpenSans-Regular-webfont.eot'); 6 | src: 7 | local('Open Sans'), 8 | local('OpenSans'), 9 | url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), 10 | url('../fonts/OpenSans-Regular-webfont.woff') format('woff'), 11 | url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg'); 12 | } 13 | 14 | @font-face { 15 | font-family: 'Open Sans Light'; 16 | font-weight: normal; 17 | font-style: normal; 18 | src: url('../fonts/OpenSans-Light-webfont.eot'); 19 | src: 20 | local('Open Sans Light'), 21 | local('OpenSans Light'), 22 | url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), 23 | url('../fonts/OpenSans-Light-webfont.woff') format('woff'), 24 | url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg'); 25 | } 26 | 27 | html 28 | { 29 | overflow: auto; 30 | background-color: #fff; 31 | font-size: 14px; 32 | } 33 | 34 | body 35 | { 36 | font-family: 'Open Sans', sans-serif; 37 | line-height: 1.5; 38 | color: #4d4e53; 39 | background-color: white; 40 | } 41 | 42 | a, a:visited, a:active { 43 | color: #0095dd; 44 | text-decoration: none; 45 | } 46 | 47 | a:hover { 48 | text-decoration: underline; 49 | } 50 | 51 | header 52 | { 53 | display: block; 54 | padding: 0px 4px; 55 | } 56 | 57 | tt, code, kbd, samp { 58 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 59 | } 60 | 61 | .class-description { 62 | font-size: 130%; 63 | line-height: 140%; 64 | margin-bottom: 1em; 65 | margin-top: 1em; 66 | } 67 | 68 | .class-description:empty { 69 | margin: 0; 70 | } 71 | 72 | #main { 73 | float: left; 74 | width: 70%; 75 | } 76 | 77 | article dl { 78 | margin-bottom: 40px; 79 | } 80 | 81 | article img { 82 | max-width: 100%; 83 | } 84 | 85 | section 86 | { 87 | display: block; 88 | background-color: #fff; 89 | padding: 12px 24px; 90 | border-bottom: 1px solid #ccc; 91 | margin-right: 30px; 92 | } 93 | 94 | .variation { 95 | display: none; 96 | } 97 | 98 | .signature-attributes { 99 | font-size: 60%; 100 | color: #aaa; 101 | font-style: italic; 102 | font-weight: lighter; 103 | } 104 | 105 | nav 106 | { 107 | display: block; 108 | float: right; 109 | margin-top: 28px; 110 | width: 30%; 111 | box-sizing: border-box; 112 | border-left: 1px solid #ccc; 113 | padding-left: 16px; 114 | } 115 | 116 | nav ul { 117 | font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; 118 | font-size: 100%; 119 | line-height: 17px; 120 | padding: 0; 121 | margin: 0; 122 | list-style-type: none; 123 | } 124 | 125 | nav ul a, nav ul a:visited, nav ul a:active { 126 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 127 | line-height: 18px; 128 | color: #4D4E53; 129 | } 130 | 131 | nav h3 { 132 | margin-top: 12px; 133 | } 134 | 135 | nav li { 136 | margin-top: 6px; 137 | } 138 | 139 | footer { 140 | display: block; 141 | padding: 6px; 142 | margin-top: 12px; 143 | font-style: italic; 144 | font-size: 90%; 145 | } 146 | 147 | h1, h2, h3, h4 { 148 | font-weight: 200; 149 | margin: 0; 150 | } 151 | 152 | h1 153 | { 154 | font-family: 'Open Sans Light', sans-serif; 155 | font-size: 48px; 156 | letter-spacing: -2px; 157 | margin: 12px 24px 20px; 158 | } 159 | 160 | h2, h3.subsection-title 161 | { 162 | font-size: 30px; 163 | font-weight: 700; 164 | letter-spacing: -1px; 165 | margin-bottom: 12px; 166 | } 167 | 168 | h3 169 | { 170 | font-size: 24px; 171 | letter-spacing: -0.5px; 172 | margin-bottom: 12px; 173 | } 174 | 175 | h4 176 | { 177 | font-size: 18px; 178 | letter-spacing: -0.33px; 179 | margin-bottom: 12px; 180 | color: #4d4e53; 181 | } 182 | 183 | h5, .container-overview .subsection-title 184 | { 185 | font-size: 120%; 186 | font-weight: bold; 187 | letter-spacing: -0.01em; 188 | margin: 8px 0 3px 0; 189 | } 190 | 191 | h6 192 | { 193 | font-size: 100%; 194 | letter-spacing: -0.01em; 195 | margin: 6px 0 3px 0; 196 | font-style: italic; 197 | } 198 | 199 | table 200 | { 201 | border-spacing: 0; 202 | border: 0; 203 | border-collapse: collapse; 204 | } 205 | 206 | td, th 207 | { 208 | border: 1px solid #ddd; 209 | margin: 0px; 210 | text-align: left; 211 | vertical-align: top; 212 | padding: 4px 6px; 213 | display: table-cell; 214 | } 215 | 216 | thead tr 217 | { 218 | background-color: #ddd; 219 | font-weight: bold; 220 | } 221 | 222 | th { border-right: 1px solid #aaa; } 223 | tr > th:last-child { border-right: 1px solid #ddd; } 224 | 225 | .ancestors, .attribs { color: #999; } 226 | .ancestors a, .attribs a 227 | { 228 | color: #999 !important; 229 | text-decoration: none; 230 | } 231 | 232 | .clear 233 | { 234 | clear: both; 235 | } 236 | 237 | .important 238 | { 239 | font-weight: bold; 240 | color: #950B02; 241 | } 242 | 243 | .yes-def { 244 | text-indent: -1000px; 245 | } 246 | 247 | .type-signature { 248 | color: #aaa; 249 | } 250 | 251 | .name, .signature { 252 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 253 | } 254 | 255 | .details { margin-top: 14px; border-left: 2px solid #DDD; } 256 | .details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } 257 | .details dd { margin-left: 70px; } 258 | .details ul { margin: 0; } 259 | .details ul { list-style-type: none; } 260 | .details li { margin-left: 30px; padding-top: 6px; } 261 | .details pre.prettyprint { margin: 0 } 262 | .details .object-value { padding-top: 0; } 263 | 264 | .description { 265 | margin-bottom: 1em; 266 | margin-top: 1em; 267 | } 268 | 269 | .code-caption 270 | { 271 | font-style: italic; 272 | font-size: 107%; 273 | margin: 0; 274 | } 275 | 276 | .source 277 | { 278 | border: 1px solid #ddd; 279 | width: 80%; 280 | overflow: auto; 281 | } 282 | 283 | .prettyprint.source { 284 | width: inherit; 285 | } 286 | 287 | .source code 288 | { 289 | font-size: 100%; 290 | line-height: 18px; 291 | display: block; 292 | padding: 4px 12px; 293 | margin: 0; 294 | background-color: #fff; 295 | color: #4D4E53; 296 | } 297 | 298 | .prettyprint code span.line 299 | { 300 | display: inline-block; 301 | } 302 | 303 | .prettyprint.linenums 304 | { 305 | padding-left: 70px; 306 | -webkit-user-select: none; 307 | -moz-user-select: none; 308 | -ms-user-select: none; 309 | user-select: none; 310 | } 311 | 312 | .prettyprint.linenums ol 313 | { 314 | padding-left: 0; 315 | } 316 | 317 | .prettyprint.linenums li 318 | { 319 | border-left: 3px #ddd solid; 320 | } 321 | 322 | .prettyprint.linenums li.selected, 323 | .prettyprint.linenums li.selected * 324 | { 325 | background-color: lightyellow; 326 | } 327 | 328 | .prettyprint.linenums li * 329 | { 330 | -webkit-user-select: text; 331 | -moz-user-select: text; 332 | -ms-user-select: text; 333 | user-select: text; 334 | } 335 | 336 | .params .name, .props .name, .name code { 337 | color: #4D4E53; 338 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 339 | font-size: 100%; 340 | } 341 | 342 | .params td.description > p:first-child, 343 | .props td.description > p:first-child 344 | { 345 | margin-top: 0; 346 | padding-top: 0; 347 | } 348 | 349 | .params td.description > p:last-child, 350 | .props td.description > p:last-child 351 | { 352 | margin-bottom: 0; 353 | padding-bottom: 0; 354 | } 355 | 356 | .disabled { 357 | color: #454545; 358 | } 359 | -------------------------------------------------------------------------------- /out/styles/prettify-jsdoc.css: -------------------------------------------------------------------------------- 1 | /* JSDoc prettify.js theme */ 2 | 3 | /* plain text */ 4 | .pln { 5 | color: #000000; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | /* string content */ 11 | .str { 12 | color: #006400; 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | /* a keyword */ 18 | .kwd { 19 | color: #000000; 20 | font-weight: bold; 21 | font-style: normal; 22 | } 23 | 24 | /* a comment */ 25 | .com { 26 | font-weight: normal; 27 | font-style: italic; 28 | } 29 | 30 | /* a type name */ 31 | .typ { 32 | color: #000000; 33 | font-weight: normal; 34 | font-style: normal; 35 | } 36 | 37 | /* a literal value */ 38 | .lit { 39 | color: #006400; 40 | font-weight: normal; 41 | font-style: normal; 42 | } 43 | 44 | /* punctuation */ 45 | .pun { 46 | color: #000000; 47 | font-weight: bold; 48 | font-style: normal; 49 | } 50 | 51 | /* lisp open bracket */ 52 | .opn { 53 | color: #000000; 54 | font-weight: bold; 55 | font-style: normal; 56 | } 57 | 58 | /* lisp close bracket */ 59 | .clo { 60 | color: #000000; 61 | font-weight: bold; 62 | font-style: normal; 63 | } 64 | 65 | /* a markup tag name */ 66 | .tag { 67 | color: #006400; 68 | font-weight: normal; 69 | font-style: normal; 70 | } 71 | 72 | /* a markup attribute name */ 73 | .atn { 74 | color: #006400; 75 | font-weight: normal; 76 | font-style: normal; 77 | } 78 | 79 | /* a markup attribute value */ 80 | .atv { 81 | color: #006400; 82 | font-weight: normal; 83 | font-style: normal; 84 | } 85 | 86 | /* a declaration */ 87 | .dec { 88 | color: #000000; 89 | font-weight: bold; 90 | font-style: normal; 91 | } 92 | 93 | /* a variable name */ 94 | .var { 95 | color: #000000; 96 | font-weight: normal; 97 | font-style: normal; 98 | } 99 | 100 | /* a function name */ 101 | .fun { 102 | color: #000000; 103 | font-weight: bold; 104 | font-style: normal; 105 | } 106 | 107 | /* Specify class=linenums on a pre to get line numbering */ 108 | ol.linenums { 109 | margin-top: 0; 110 | margin-bottom: 0; 111 | } 112 | -------------------------------------------------------------------------------- /out/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #718c00; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #8959a8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #8e908c; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #4271ae; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #f5871f; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #4d4d4c; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #4d4d4c; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #4d4d4c; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "ansi-styles": { 6 | "version": "3.2.1", 7 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 8 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 9 | "requires": { 10 | "color-convert": "^1.9.0" 11 | } 12 | }, 13 | "chalk": { 14 | "version": "2.4.2", 15 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 16 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 17 | "requires": { 18 | "ansi-styles": "^3.2.1", 19 | "escape-string-regexp": "^1.0.5", 20 | "supports-color": "^5.3.0" 21 | } 22 | }, 23 | "color-convert": { 24 | "version": "1.9.3", 25 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 26 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 27 | "requires": { 28 | "color-name": "1.1.3" 29 | } 30 | }, 31 | "color-name": { 32 | "version": "1.1.3", 33 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 34 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 35 | }, 36 | "dom-serializer": { 37 | "version": "0.2.2", 38 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", 39 | "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", 40 | "requires": { 41 | "domelementtype": "^2.0.1", 42 | "entities": "^2.0.0" 43 | } 44 | }, 45 | "domelementtype": { 46 | "version": "2.0.1", 47 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", 48 | "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==" 49 | }, 50 | "domhandler": { 51 | "version": "3.0.0", 52 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.0.0.tgz", 53 | "integrity": "sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw==", 54 | "requires": { 55 | "domelementtype": "^2.0.1" 56 | } 57 | }, 58 | "domutils": { 59 | "version": "2.0.0", 60 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.0.0.tgz", 61 | "integrity": "sha512-n5SelJ1axbO636c2yUtOGia/IcJtVtlhQbFiVDBZHKV5ReJO1ViX7sFEemtuyoAnBxk5meNSYgA8V4s0271efg==", 62 | "requires": { 63 | "dom-serializer": "^0.2.1", 64 | "domelementtype": "^2.0.1", 65 | "domhandler": "^3.0.0" 66 | } 67 | }, 68 | "entities": { 69 | "version": "2.0.0", 70 | "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", 71 | "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==" 72 | }, 73 | "escape-string-regexp": { 74 | "version": "1.0.5", 75 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 76 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 77 | }, 78 | "has-flag": { 79 | "version": "3.0.0", 80 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 81 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" 82 | }, 83 | "htmlparser2": { 84 | "version": "4.1.0", 85 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", 86 | "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", 87 | "requires": { 88 | "domelementtype": "^2.0.1", 89 | "domhandler": "^3.0.0", 90 | "domutils": "^2.0.0", 91 | "entities": "^2.0.0" 92 | } 93 | }, 94 | "ink-docstrap": { 95 | "version": "1.3.2", 96 | "resolved": "https://registry.npmjs.org/ink-docstrap/-/ink-docstrap-1.3.2.tgz", 97 | "integrity": "sha512-STx5orGQU1gfrkoI/fMU7lX6CSP7LBGO10gXNgOZhwKhUqbtNjCkYSewJtNnLmWP1tAGN6oyEpG1HFPw5vpa5Q==", 98 | "requires": { 99 | "moment": "^2.14.1", 100 | "sanitize-html": "^1.13.0" 101 | } 102 | }, 103 | "lodash.clonedeep": { 104 | "version": "4.5.0", 105 | "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", 106 | "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" 107 | }, 108 | "lodash.escaperegexp": { 109 | "version": "4.1.2", 110 | "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", 111 | "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=" 112 | }, 113 | "lodash.isplainobject": { 114 | "version": "4.0.6", 115 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 116 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" 117 | }, 118 | "lodash.isstring": { 119 | "version": "4.0.1", 120 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", 121 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" 122 | }, 123 | "lodash.mergewith": { 124 | "version": "4.6.2", 125 | "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", 126 | "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" 127 | }, 128 | "moment": { 129 | "version": "2.24.0", 130 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", 131 | "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" 132 | }, 133 | "postcss": { 134 | "version": "7.0.27", 135 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", 136 | "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", 137 | "requires": { 138 | "chalk": "^2.4.2", 139 | "source-map": "^0.6.1", 140 | "supports-color": "^6.1.0" 141 | }, 142 | "dependencies": { 143 | "supports-color": { 144 | "version": "6.1.0", 145 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", 146 | "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", 147 | "requires": { 148 | "has-flag": "^3.0.0" 149 | } 150 | } 151 | } 152 | }, 153 | "sanitize-html": { 154 | "version": "1.22.0", 155 | "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-1.22.0.tgz", 156 | "integrity": "sha512-3RPo65mbTKpOAdAYWU496MSty1YbB3Y5bjwL5OclgaSSMtv65xvM7RW/EHRumzaZ1UddEJowCbSdK0xl5sAu0A==", 157 | "requires": { 158 | "chalk": "^2.4.1", 159 | "htmlparser2": "^4.1.0", 160 | "lodash.clonedeep": "^4.5.0", 161 | "lodash.escaperegexp": "^4.1.2", 162 | "lodash.isplainobject": "^4.0.6", 163 | "lodash.isstring": "^4.0.1", 164 | "lodash.mergewith": "^4.6.1", 165 | "postcss": "^7.0.27", 166 | "srcset": "^2.0.1", 167 | "xtend": "^4.0.1" 168 | } 169 | }, 170 | "source-map": { 171 | "version": "0.6.1", 172 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 173 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 174 | }, 175 | "srcset": { 176 | "version": "2.0.1", 177 | "resolved": "https://registry.npmjs.org/srcset/-/srcset-2.0.1.tgz", 178 | "integrity": "sha512-00kZI87TdRKwt+P8jj8UZxbfp7mK2ufxcIMWvhAOZNJTRROimpHeruWrGvCZneiuVDLqdyHefVp748ECTnyUBQ==" 179 | }, 180 | "supports-color": { 181 | "version": "5.5.0", 182 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 183 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 184 | "requires": { 185 | "has-flag": "^3.0.0" 186 | } 187 | }, 188 | "xtend": { 189 | "version": "4.0.2", 190 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 191 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /sass/custom/_custom.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/niftymenu/030b545ad6ae3082228d5fa75b31b38202b6d71f/sass/custom/_custom.scss -------------------------------------------------------------------------------- /sass/custom/_variables.scss: -------------------------------------------------------------------------------- 1 | // Modify all of the colors used in both dark and light layouts here 2 | 3 | ////// Light Mode ////// 4 | 5 | // background gradient and default image 6 | $color-desktop-gradient-1: #00c2da; 7 | $color-desktop-gradient-2: #00618d; 8 | $desktop-image: '../images/background.jpg'; 9 | 10 | // base colors 11 | $color-foreground: #000; 12 | $color-foreground-inverted: #fff; 13 | $color-drop-shadow: rgba(0, 0, 0, .25); 14 | // system accent color (menu item hover state) Can be any of 15 | // $accent-blue, $accent-purple, $accent-pink, $accent-red, 16 | // $accent-orange, $accent-yellow, $accent-green, $accent-grey 17 | $color-accent: #1d7bf0; 18 | // Top level toolbar background 19 | $color-background-toolbar: #ededed; 20 | // Slightly different color for submenu backgrounds 21 | $color-background-submenu: rgb(220, 224, 224) !default; 22 | // Color for menu dividers 23 | $color-divider: rgb(198, 198, 198) !default; 24 | // Color used for menu borders 25 | $color-border: rgb(168, 168, 168) !default; 26 | // glow around item when double clicking to color-accent 27 | $color-callout: #aeff00; 28 | 29 | // for the help menu item search field 30 | $color-background-help: rgb(189, 189, 190); 31 | $color-background-help-search: rgb(168, 170, 171); 32 | 33 | ////// Dark Mode ////// 34 | 35 | // Same as above but with "dark-" prefix 36 | $dark-color-desktop-gradient-1: darken(adjust_hue($color-desktop-gradient-1,90deg),15); 37 | $dark-color-desktop-gradient-2: #333; 38 | $dark-desktop-image: '../images/darkbackground.jpg'; 39 | 40 | $dark-color-foreground: #fff; 41 | $dark-color-foreground-inverted: #000; 42 | $dark-color-accent: $accent-purple; 43 | $dark-color-background-toolbar: rgba(29, 28, 28, .85); 44 | $dark-color-background-submenu: rgba(104, 106, 107, .7); 45 | $dark-color-divider: rgba(38, 39, 37, 1); 46 | $dark-color-border: rgba(38, 39, 37, 1) !default; 47 | $dark-color-callout: lighten(adjust_hue($color-callout, 85deg),10); 48 | 49 | $dark-color-background-help: rgba(74, 75, 74, .95); 50 | $dark-color-background-help-search: rgba(87, 89, 89, .95); 51 | 52 | $color-shortcut-callout: $color-accent; 53 | $color-shortcut-callout-border: $color-foreground-inverted; 54 | 55 | $dark-color-shortcut-callout: $dark-color-accent; 56 | $dark-color-shortcut-callout-border: $dark-color-foreground; 57 | -------------------------------------------------------------------------------- /sass/include/_colors.scss: -------------------------------------------------------------------------------- 1 | // System accent colors 2 | 3 | $accent-blue: rgb(0, 122, 255); 4 | $accent-purple: rgb(178, 68, 165); 5 | $accent-pink: rgb(247, 79, 158); 6 | $accent-red: rgb(224, 56, 62); 7 | $accent-orange: rgb(247, 130, 27); 8 | $accent-yellow: rgb(252, 184, 39); 9 | $accent-green: rgb(98, 186, 70); 10 | $accent-grey: rgb(147, 147, 147); 11 | 12 | $active: rgb(41, 182, 220); 13 | $inactive: rgb(188, 216, 224); 14 | $disabled: rgba(150, 150, 150, .5); 15 | 16 | // A bunch of variables that control *all* the colors 17 | 18 | ////// Light Mode ////// 19 | 20 | // background gradient and default image 21 | $color-desktop-gradient-1: rgb(86, 118, 127) !default; 22 | $color-desktop-gradient-2: rgb(120, 156, 165) !default; 23 | $desktop-image: '../images/background.jpg' !default; 24 | 25 | // base colors 26 | $color-foreground: #000 !default; 27 | $color-foreground-inverted: #fff !default; 28 | $color-drop-shadow: rgba(0, 0, 0, .25) !default; 29 | // system accent color (menu item hover state) Can be any of 30 | // $accent-blue, $accent-purple, $accent-pink, $accent-red, 31 | // $accent-orange, $accent-yellow, $accent-green, $accent-grey 32 | $color-accent: #1d7bf0 !default; 33 | // Top level toolbar background 34 | $color-background-toolbar: #ededed !default; 35 | // Slightly different color for submenu backgrounds 36 | $color-background-submenu: rgb(220, 224, 224) !default; 37 | // Color for menu dividers 38 | $color-divider: rgb(198, 198, 198) !default; 39 | // Color used for menu borders 40 | $color-border: rgb(168, 168, 168) !default; 41 | // glow around item when double clicking to color-accent 42 | $color-callout: rgb(98, 186, 70) !default; 43 | 44 | // for the help menu item search field 45 | $color-background-help: rgb(189, 189, 190) !default; 46 | $color-background-help-search: rgb(168, 170, 171) !default; 47 | 48 | ////// Dark Mode ////// 49 | 50 | // Same as above but with "dark-" prefix 51 | $dark-color-desktop-gradient-1: darken(adjust-hue($color-desktop-gradient-1, 90deg), 15) !default; 52 | $dark-color-desktop-gradient-2: #333 !default; 53 | $dark-desktop-image: '../images/darkbackground.jpg' !default; 54 | 55 | $dark-color-foreground: #fff !default; 56 | $dark-color-foreground-inverted: #000 !default; 57 | $dark-color-accent: $accent-purple !default; 58 | $dark-color-background-toolbar: rgba(29, 28, 28, .85) !default; 59 | $dark-color-background-submenu: rgba(104, 106, 107, .7) !default; 60 | $dark-color-divider: rgba(38, 39, 37, 1) !default; 61 | $dark-color-border: rgba(38, 39, 37, 1) !default; 62 | $dark-color-callout: lighten(adjust-hue($color-callout, 85deg), 10) !default; 63 | 64 | $dark-color-background-help: rgba(74, 75, 74, .95) !default; 65 | $dark-color-background-help-search: rgba(87, 89, 89, .95) !default; 66 | 67 | $color-status: rgba(255, 255, 255, .5); 68 | $color-status-background: rgba(0, 0, 0, .2); 69 | 70 | $color-shortcut-callout: $color-accent !default; 71 | $color-shortcut-callout-border: $color-foreground-inverted !default; 72 | 73 | $dark-color-shortcut-callout: $dark-color-accent !default; 74 | $dark-color-shortcut-callout-border: $dark-color-foreground !default; 75 | -------------------------------------------------------------------------------- /scripts/docjs: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | jsdoc -c scripts/jsdoc.conf.json -t ./node_modules/ink-docstrap/template -R javascript/README.md -d docs/jsapi/ -r javascript/modules/*.js 4 | -------------------------------------------------------------------------------- /scripts/jsdoc.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "plugins/markdown" 4 | ], 5 | "recurseDepth": 10, 6 | "source": { 7 | "includePattern": ".+\\.js(doc|x)?$", 8 | "excludePattern": "(^|\\/|\\\\)_" 9 | }, 10 | "sourceType": "module", 11 | "tags": { 12 | "allowUnknownTags": true, 13 | "dictionaries": ["jsdoc","closure"] 14 | }, 15 | "templates": { 16 | "cleverLinks": false, 17 | "monospaceLinks": false, 18 | "default": {"outputSourceFiles": false}, 19 | "methodHeadingReturns": false, 20 | "systemName" : "NiftyMenu", 21 | "copyright" : "NiftyMenu © Brett Terpstra 2020, MIT License", 22 | "navType" : "inline", 23 | "theme" : "journal", 24 | "linenums" : false, 25 | "collapseSymbols" : false, 26 | "inverseNav" : true, 27 | "outputSourceFiles" : false, 28 | "outputSourcePath" : false, 29 | "syntaxTheme" : "default", 30 | "search" : true 31 | } 32 | } 33 | --------------------------------------------------------------------------------