├── .gitignore ├── LICENSE ├── README.md ├── app ├── css │ ├── buffer.css │ ├── code.css │ ├── drawarea.css │ ├── footer.css │ ├── header.css │ ├── overlay.css │ └── style.css ├── index.php └── js │ ├── Bootstrap.js │ ├── Bootstrap.ts │ ├── Main.js │ ├── Main.ts │ ├── editor │ ├── AbstractOverlayElement.js │ ├── AbstractOverlayElement.ts │ ├── Editor.js │ ├── Editor.ts │ ├── Footer.js │ ├── Footer.ts │ ├── Header.js │ ├── Header.ts │ ├── Help.js │ ├── Help.ts │ ├── MenuConfig.js │ ├── MenuConfig.ts │ ├── ViewCode.js │ ├── ViewCode.ts │ ├── buffer │ │ ├── BufferList.js │ │ ├── BufferList.ts │ │ ├── VisualBuffer.js │ │ └── VisualBuffer.ts │ ├── code │ │ ├── CodeGenerator.js │ │ ├── CodeGenerator.ts │ │ ├── LiveCode.js │ │ └── LiveCode.ts │ ├── data │ │ └── interface │ │ │ ├── IPoint.js │ │ │ └── IPoint.ts │ ├── event │ │ ├── ConnectionsCanvasEvent.js │ │ ├── ConnectionsCanvasEvent.ts │ │ ├── FooterEvent.js │ │ ├── FooterEvent.ts │ │ ├── HeaderEvent.js │ │ ├── HeaderEvent.ts │ │ ├── VisualModuleEvent.js │ │ └── VisualModuleEvent.ts │ ├── net │ │ ├── Tracking.js │ │ └── Tracking.ts │ ├── patch │ │ ├── ConnectionsCanvas.js │ │ ├── ConnectionsCanvas.ts │ │ ├── ConnectionsSelectionGrid.js │ │ ├── ConnectionsSelectionGrid.ts │ │ ├── VisualModule.js │ │ └── VisualModule.ts │ ├── share.js │ ├── share.ts │ └── util │ │ ├── EditorUtils.js │ │ └── EditorUtils.ts │ ├── lib │ ├── jquery-1.11.2.js │ └── require.js │ └── patchwork │ ├── config │ ├── IAbstractModuleDefinitionAttribute.js │ ├── IAbstractModuleDefinitionAttribute.ts │ ├── IModuleDefinition.js │ ├── IModuleDefinition.ts │ ├── IModuleDefinitionFloatAttribute.js │ ├── IModuleDefinitionFloatAttribute.ts │ ├── IModuleDefinitionOptionListAttribute.js │ ├── IModuleDefinitionOptionListAttribute.ts │ ├── IModuleDefinitionReadOnlyAttribute.js │ ├── IModuleDefinitionReadOnlyAttribute.ts │ ├── ModuleDefinitions.js │ └── ModuleDefinitions.ts │ ├── core │ ├── AudioContextManager.js │ ├── AudioContextManager.ts │ ├── Buffer.js │ ├── Buffer.ts │ ├── BufferManager.js │ ├── BufferManager.ts │ ├── Connection.js │ ├── Connection.ts │ ├── EventDispatcher.js │ ├── EventDispatcher.ts │ ├── IConnectionObject.js │ ├── IConnectionObject.ts │ ├── IModuleObject.js │ ├── IModuleObject.ts │ ├── IPatchObject.js │ ├── IPatchObject.ts │ ├── Module.js │ ├── Module.ts │ ├── Patch.js │ └── Patch.ts │ ├── enum │ ├── AttributeTypes.js │ ├── AttributeTypes.ts │ ├── ModuleCategories.js │ ├── ModuleCategories.ts │ ├── ModuleTypes.js │ └── ModuleTypes.ts │ ├── event │ ├── AudioContextManagerEvent.js │ ├── AudioContextManagerEvent.ts │ ├── BufferEvent.js │ ├── BufferEvent.ts │ ├── BufferManagerEvent.js │ ├── BufferManagerEvent.ts │ ├── ModuleEvent.js │ ├── ModuleEvent.ts │ ├── PatchEvent.js │ └── PatchEvent.ts │ └── util │ ├── Utils.js │ └── Utils.ts ├── tools ├── Gruntfile.js ├── build.js └── package.json └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | tools/node_modules/ 2 | .idea/ 3 | build/ 4 | tools/.tscache/ 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Peter van der Noord 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web Audio Tool 2 | 3 | Web Audio Tool (www.webaudiotool.com) is a visual editor for the development of applications that make use of the Web Audio API. It helps with the graph creation/modification part of the Web Audio API, where you setup and connect the nodes that you need for your application. Doing this by code can be quite confusing when you end up with a huge amount of code that doesn't give any overview at all about the network that you're building. That's where the editor comes in: you can cleary see what you are creating and what's connected with what. 4 | 5 | Apart from that, I will release the core engine as a standalone Javascript library to make it easier to talk to the graph you created, since there are some things about the API that can make life difficult there. The library will allow you to: 6 | * get information about the current nodes and connections 7 | * easily remove single nodes or connections from the graph 8 | * inject (or remove) large subgraphs into the current one by a single command 9 | 10 | # tl;dr 11 | Web Audio Tool wants to make the creation of the audio network easy, after that you will still talk to the Web Audio API in the same way that you do now. 12 | -------------------------------------------------------------------------------- /app/css/buffer.css: -------------------------------------------------------------------------------- 1 | #bufferlist { 2 | position: fixed; 3 | z-index: 100; 4 | right: 0; 5 | top: 65px; 6 | background-color: rgba(0,0,0,0.7); 7 | width: 190px; 8 | height: calc(100% - 225px); 9 | color: white; 10 | padding: 10px; 11 | } 12 | 13 | #bufferlist .header { 14 | 15 | } 16 | 17 | #bufferlist .header a.new { 18 | position: relative; 19 | } 20 | 21 | #bufferlist .header a.new { 22 | color: white; 23 | float: right; 24 | font-size: 11px; 25 | position: absolute; 26 | right: 10px; 27 | top: 10px; 28 | } 29 | 30 | #bufferlist .header h2 { 31 | font-size: 16px; 32 | font-weight: normal; 33 | } 34 | 35 | #bufferlist .list .buffer { 36 | height: 50px; 37 | background-color: black; 38 | margin: 5px 0; 39 | padding: 5px; 40 | } 41 | 42 | #bufferlist .list .buffer h3 { 43 | font-size: 10px; 44 | font-weight: normal; 45 | } -------------------------------------------------------------------------------- /app/css/code.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petervdn/webaudiotool/574a682b13965c0f96d7e6fe28255e8fe5129bfa/app/css/code.css -------------------------------------------------------------------------------- /app/css/drawarea.css: -------------------------------------------------------------------------------- 1 | 2 | .draw-area { 3 | width: 100%; 4 | height: calc(100% - 140px); 5 | background-color: #EEE; 6 | overflow: hidden; 7 | } 8 | 9 | .draw-area .module { 10 | width: 190px; 11 | position: absolute; 12 | z-index: 10; 13 | border-radius: 3px; 14 | box-shadow: 1px 1px 5px rgba(0,0,0,0.2); 15 | } 16 | 17 | .draw-area .module .main { 18 | padding: 10px 35px 10px 35px; 19 | background-color: white; 20 | border-bottom-left-radius: 3px; 21 | border-bottom-right-radius: 3px; 22 | border: 1px solid #595241; 23 | border-top: none; 24 | position: relative; 25 | } 26 | 27 | .draw-area .module .inputs, 28 | .draw-area .module .outputs { 29 | height: 21px; 30 | xbackground-color: white; 31 | } 32 | 33 | .draw-area .module .input, 34 | .draw-area .module .output { 35 | width: 25px; 36 | height: 18px; 37 | background-color: #000; 38 | padding-top: 10px; 39 | color: white; 40 | font-size: 8px; 41 | text-align: center; 42 | position: absolute; 43 | xbox-shadow: 1px 1px 5px rgba(0,0,0,0.2); 44 | 45 | } 46 | 47 | 48 | .draw-area .module .input { 49 | border-top-right-radius: 3px; 50 | border-bottom-right-radius: 3px; 51 | } 52 | 53 | .draw-area .module .output { 54 | border-top-left-radius: 3px; 55 | border-bottom-left-radius: 3px; 56 | 57 | } 58 | 59 | .draw-area .module .input.audioparam, 60 | .draw-area .module .output.audioparam { 61 | 62 | background-color: #ACCFCC; 63 | } 64 | 65 | .draw-area .module .main .info 66 | { 67 | background-color: white; 68 | font-size: 9px; 69 | color: #ccc; 70 | margin-bottom: 6px; 71 | } 72 | 73 | .draw-area .module .main .attribute 74 | { 75 | border-top: 1px solid #eee; 76 | width: 100%; 77 | height: 25px; 78 | float: left; 79 | 80 | } 81 | 82 | .draw-area .module .main .attribute input, 83 | .draw-area .module .main .attribute select 84 | { 85 | margin-left: 10px; 86 | } 87 | 88 | .draw-area .module .main .attribute select 89 | { 90 | margin-top: 6px; 91 | } 92 | 93 | .draw-area .module .main .attribute input 94 | { 95 | margin-top: 4px; 96 | } 97 | 98 | .draw-area .module .main .attribute .value 99 | { 100 | width: 30px; 101 | height: 20px; 102 | padding-top: 5px; 103 | float: right; 104 | font-size: 10px; 105 | border: 1px solid red; 106 | } 107 | 108 | .draw-area .module .main .attribute .label 109 | { 110 | width: 24px; 111 | height: 20px; 112 | padding-top: 8px; 113 | float: left; 114 | font-size: 9px; 115 | text-align: right; 116 | border: 0px solid blue; 117 | } 118 | 119 | 120 | 121 | 122 | .draw-area .module .main .attribute input.float 123 | { 124 | width: 30px; 125 | } 126 | 127 | 128 | .draw-area .module .header { 129 | background-color: #595241; 130 | color: white; 131 | padding: 12px 12px 12px 12px; 132 | font-size: 12px; 133 | border-top-left-radius: 3px; 134 | border-top-right-radius: 3px; 135 | } 136 | 137 | .draw-area .module .header.proxy { 138 | background-color: #8a0917; 139 | } 140 | .draw-area .module .header span { 141 | 142 | } 143 | 144 | .draw-area .module .header a { 145 | width: 10px; 146 | float: right; 147 | color: white; 148 | text-decoration: none; 149 | } 150 | -------------------------------------------------------------------------------- /app/css/footer.css: -------------------------------------------------------------------------------- 1 | #footer { 2 | position: fixed; 3 | left: 0; 4 | bottom: 0; 5 | width: 100%; 6 | height: 140px; 7 | z-index: 100; 8 | background-color: #595241; 9 | color: white; 10 | font-size: 12px; 11 | } 12 | 13 | #footer .breadcrumb { 14 | 15 | padding: 10px; 16 | background-color: rgba(0,0,0,0.2); 17 | } 18 | 19 | #footer a { 20 | 21 | color: white; 22 | } 23 | 24 | #footer ul.options { 25 | position: fixed; 26 | right: 0; 27 | } 28 | 29 | #footer ul.options li { 30 | float: right; 31 | border: 0px solid red; 32 | padding: 10px; 33 | } 34 | 35 | 36 | #footer .livecode { 37 | padding: 10px; 38 | font-family: Courier; 39 | color: white; 40 | font-size: 10px; 41 | height: 80px; 42 | border: 0px solid white; 43 | overflow-y: auto; 44 | } 45 | -------------------------------------------------------------------------------- /app/css/header.css: -------------------------------------------------------------------------------- 1 | 2 | .siteheader { 3 | position: fixed; 4 | width: 100%; 5 | padding: 10px 10px 0px 10px; 6 | background: #8a0917; 7 | color: white; 8 | box-shadow: 3px 3px 12px rgba(0,0,0,0.2); 9 | z-index: 999; 10 | height: 55px; 11 | } 12 | 13 | .siteheader ul.menu { 14 | margin-top: 5px; 15 | } 16 | 17 | .siteheader ul.menu > li { 18 | position: relative; 19 | float: left; 20 | margin-right: 5px; 21 | padding: 10px 4px 4px 4px; 22 | } 23 | 24 | .siteheader ul.menu > li h2 { 25 | font-weight: normal; 26 | } 27 | 28 | .siteheader ul.menu ul.sub { 29 | position: absolute; 30 | left: 0; 31 | top: 25px; 32 | width: 120px; 33 | display: none; 34 | background-color: #610917; 35 | z-index: 10; 36 | } 37 | 38 | .siteheader ul.menu ul.sub li { 39 | padding: 10px 10px 5px 10px; 40 | } 41 | 42 | .siteheader ul.menu ul.sub li a { 43 | font-size: 12px; 44 | color: white; 45 | text-decoration: none; 46 | } 47 | 48 | .siteheader ul.menu ul.sub li a:hover { 49 | text-decoration: underline; 50 | } 51 | 52 | .siteheader .menu li h2 { 53 | font-size: 12px; 54 | 55 | } 56 | 57 | .siteheader h1 { 58 | font-size: 20px; 59 | } -------------------------------------------------------------------------------- /app/css/overlay.css: -------------------------------------------------------------------------------- 1 | #overlay { 2 | 3 | position: fixed; 4 | background-color: rgba(0,0,0,0.8); 5 | width: 100%; 6 | height: 100%; 7 | z-index: 999; 8 | top: 0; 9 | left: 0; 10 | display: none; 11 | } 12 | 13 | #overlay .container { 14 | position: relative; 15 | background-color: white; 16 | margin: 0 auto; 17 | border-radius: 5px; 18 | top: 50%; 19 | transform: translateY(-50%); 20 | padding: 20px; 21 | } 22 | 23 | #overlay .container h2 { 24 | color: #595241; 25 | font-size: 22px; 26 | } 27 | 28 | #overlay .container.code pre { 29 | font-size: 11px; 30 | font-family: Courier; 31 | } 32 | 33 | #overlay .container.help ul { 34 | margin: 20px; 35 | list-style: disc; 36 | font-size: 14px; 37 | } 38 | 39 | #overlay .container.share .content { 40 | text-align: center; 41 | padding: 70px 0 0 0; 42 | } 43 | 44 | #overlay .container.share .content button { 45 | padding: 10px; 46 | margin: 0 auto; 47 | width: 200px; 48 | } 49 | 50 | #overlay .container.share .content input { 51 | width: 250px; 52 | font-size: 18px; 53 | padding: 5px; 54 | text-align: center; 55 | } 56 | 57 | #overlay .container.share .content .error { 58 | color: red; 59 | font-size: 14px; 60 | padding: 5px; 61 | } -------------------------------------------------------------------------------- /app/css/style.css: -------------------------------------------------------------------------------- 1 | html, body, p, ul, li, h1, h2, h3, h4 { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | * { 7 | font-family: 'Helvetica', 'Arial', sans-serif; 8 | } 9 | 10 | ul { 11 | list-style-type: none; 12 | } 13 | 14 | html, body { 15 | width: 100%; 16 | height: 100%; 17 | overflow: hidden; 18 | } 19 | 20 | 21 | .noselect { 22 | -webkit-touch-callout: none; 23 | -webkit-user-select: none; 24 | -khtml-user-select: none; 25 | -moz-user-select: none; 26 | -ms-user-select: none; 27 | user-select: none; 28 | } 29 | 30 | .clear { 31 | clear: both; 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/index.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | Web Audio Tool 8 | 9 | \n"; 11 | echo '\n"; 12 | echo '\n"; 13 | echo '\n"; 14 | echo '\n"; 15 | echo '\n"; 16 | echo '\n"; 17 | ?> 18 | 19 | 28 | 29 | 30 | 34 |
35 | 36 |
37 |
38 | 48 |
49 |
50 |

Audio buffers

add new 51 |
52 | 53 |
54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /app/js/Bootstrap.js: -------------------------------------------------------------------------------- 1 | requirejs.config({ 2 | baseUrl: 'js', 3 | waitSeconds: 15, 4 | paths: {}, 5 | map: {}, 6 | shim: {} 7 | }); 8 | requirejs(['Main']); 9 | -------------------------------------------------------------------------------- /app/js/Bootstrap.ts: -------------------------------------------------------------------------------- 1 | declare var requirejs:any; 2 | 3 | requirejs.config({ 4 | baseUrl: 'js', 5 | waitSeconds: 15, 6 | paths: { 7 | }, 8 | map: { 9 | }, 10 | shim: { 11 | } 12 | }); 13 | 14 | requirejs(['Main']); -------------------------------------------------------------------------------- /app/js/Main.js: -------------------------------------------------------------------------------- 1 | define(["require", "exports", "./editor/Editor"], function (require, exports, Editor_1) { 2 | "use strict"; 3 | new Editor_1.default(new AudioContext()); 4 | }); 5 | -------------------------------------------------------------------------------- /app/js/Main.ts: -------------------------------------------------------------------------------- 1 | import Editor from "./editor/Editor"; 2 | 3 | new Editor(new AudioContext()); -------------------------------------------------------------------------------- /app/js/editor/AbstractOverlayElement.js: -------------------------------------------------------------------------------- 1 | define(["require", "exports"], function (require, exports) { 2 | "use strict"; 3 | class AbstractOverlayElement { 4 | constructor(width, height, containerId) { 5 | this.$overlay = $('#overlay'); 6 | this.containerId = containerId; 7 | this.$overlay.click(function (event) { 8 | if (event.target === this.$overlay[0]) 9 | this.hide(); 10 | }.bind(this)); 11 | this.$container = $('
', { class: 'container ' + containerId }); 12 | this.$container.css({ width: width, height: height, display: 'none' }); 13 | this.$overlay.append(this.$container); 14 | } 15 | show() { 16 | this.$overlay.show(); 17 | this.$overlay.find('.' + this.containerId).show(); 18 | $('body').removeClass('noselect'); 19 | } 20 | hide() { 21 | $('body').addClass('noselect'); 22 | this.$overlay.find('.' + this.containerId).hide(); 23 | this.$overlay.hide(); 24 | } 25 | } 26 | Object.defineProperty(exports, "__esModule", { value: true }); 27 | exports.default = AbstractOverlayElement; 28 | }); 29 | -------------------------------------------------------------------------------- /app/js/editor/AbstractOverlayElement.ts: -------------------------------------------------------------------------------- 1 | declare var $:any; 2 | 3 | class AbstractOverlayElement 4 | { 5 | public $overlay:any; 6 | public $container:any; 7 | public containerId:string; 8 | 9 | constructor(width:number, height:number, containerId:string) 10 | { 11 | this.$overlay = $('#overlay'); 12 | this.containerId = containerId; 13 | 14 | this.$overlay.click(function(event) 15 | { 16 | if(event.target === this.$overlay[0]) this.hide(); 17 | }.bind(this)); 18 | 19 | this.$container = $('
', {class: 'container ' + containerId}); 20 | this.$container.css({width: width, height: height, display: 'none'}); 21 | 22 | this.$overlay.append(this.$container); 23 | } 24 | 25 | public show():void 26 | { 27 | this.$overlay.show(); 28 | 29 | this.$overlay.find('.' + this.containerId).show(); 30 | 31 | $('body').removeClass('noselect'); 32 | 33 | } 34 | 35 | public hide():void 36 | { 37 | $('body').addClass('noselect'); 38 | 39 | this.$overlay.find('.' + this.containerId).hide(); 40 | 41 | this.$overlay.hide(); 42 | } 43 | } 44 | 45 | export default AbstractOverlayElement; -------------------------------------------------------------------------------- /app/js/editor/Footer.js: -------------------------------------------------------------------------------- 1 | define(["require", "exports", "./event/FooterEvent", "./net/Tracking", "../patchwork/core/EventDispatcher"], function (require, exports, FooterEvent_1, Tracking_1, EventDispatcher_1) { 2 | "use strict"; 3 | class Footer extends EventDispatcher_1.default { 4 | constructor() { 5 | super(); 6 | this.$element = $('#footer'); 7 | // init footer 8 | this.$breadcrumb = this.$element.find('.breadcrumb'); 9 | this.$breadcrumb.on('click', function (event) { 10 | if ($(event.target).is('a')) { 11 | // user clicked a link in breadcrumb 12 | var id = $(event.target).attr('data-id'); 13 | this.dispatchEvent(FooterEvent_1.default.BREADCRUMB_CLICK, { id: id }); 14 | } 15 | }.bind(this)); 16 | // init some buttons 17 | this.$element.find('a.to_code').click(function () { 18 | this.dispatchEvent(FooterEvent_1.default.GENERATE_CODE); 19 | }.bind(this)); 20 | this.$element.find('a.help').click(function () { 21 | this.dispatchEvent(FooterEvent_1.default.HELP); 22 | }.bind(this)); 23 | this.$element.find('a.share').click(function () { 24 | this.dispatchEvent(FooterEvent_1.default.SHARE); 25 | }.bind(this)); 26 | this.$element.find('a.twitter').click(function () { 27 | Tracking_1.default.trackEvent('click_out', 'twitter'); 28 | }.bind(this)); 29 | } 30 | setBreadcrumb(patch) { 31 | var list = patch.createParentList(); 32 | var links = ['root']; 33 | var usedIds = []; 34 | for (var i = 0; i < list.length; i++) { 35 | var subPatchId = list[i]; 36 | usedIds.push(subPatchId); 37 | links.push('' + subPatchId + ''); 38 | } 39 | this.$breadcrumb.html('Now viewing: ' + links.join(' → ')); 40 | } 41 | } 42 | Object.defineProperty(exports, "__esModule", { value: true }); 43 | exports.default = Footer; 44 | }); 45 | -------------------------------------------------------------------------------- /app/js/editor/Footer.ts: -------------------------------------------------------------------------------- 1 | import FooterEvent from "./event/FooterEvent"; 2 | import Tracking from "./net/Tracking"; 3 | import EventDispatcher from "../patchwork/core/EventDispatcher"; 4 | 5 | declare var $:any; // todo 6 | 7 | class Footer extends EventDispatcher 8 | { 9 | public $element:any; 10 | public $breadcrumb:any; 11 | 12 | constructor() 13 | { 14 | super(); 15 | 16 | this.$element = $('#footer'); 17 | 18 | // init footer 19 | this.$breadcrumb = this.$element.find('.breadcrumb'); 20 | 21 | this.$breadcrumb.on('click', function(event){ // todo arrow functions 22 | 23 | if($(event.target).is('a')) 24 | { 25 | // user clicked a link in breadcrumb 26 | var id = $(event.target).attr('data-id'); 27 | 28 | this.dispatchEvent(FooterEvent.BREADCRUMB_CLICK, {id: id}); 29 | } 30 | }.bind(this)); 31 | 32 | // init some buttons 33 | this.$element.find('a.to_code').click(function() 34 | { 35 | this.dispatchEvent(FooterEvent.GENERATE_CODE); 36 | }.bind(this)); 37 | 38 | this.$element.find('a.help').click(function() 39 | { 40 | this.dispatchEvent(FooterEvent.HELP); 41 | }.bind(this)); 42 | 43 | this.$element.find('a.share').click(function() 44 | { 45 | this.dispatchEvent(FooterEvent.SHARE); 46 | }.bind(this)); 47 | 48 | this.$element.find('a.twitter').click(function() 49 | { 50 | Tracking.trackEvent('click_out', 'twitter'); 51 | }.bind(this)); 52 | } 53 | 54 | public setBreadcrumb(patch):void 55 | { 56 | var list = patch.createParentList(); 57 | 58 | var links = ['root']; 59 | var usedIds = []; 60 | for(var i = 0; i < list.length; i++) 61 | { 62 | var subPatchId = list[i]; 63 | usedIds.push(subPatchId); 64 | links.push('' + subPatchId + '') 65 | } 66 | 67 | this.$breadcrumb.html('Now viewing: ' + links.join(' → ')); 68 | } 69 | } 70 | 71 | export default Footer; -------------------------------------------------------------------------------- /app/js/editor/Header.js: -------------------------------------------------------------------------------- 1 | define(["require", "exports", "../patchwork/core/EventDispatcher", "./net/Tracking", "../patchwork/enum/ModuleCategories", "../patchwork/config/ModuleDefinitions", "./event/HeaderEvent", "./MenuConfig"], function (require, exports, EventDispatcher_1, Tracking_1, ModuleCategories_1, ModuleDefinitions_1, HeaderEvent_1, MenuConfig_1) { 2 | "use strict"; 3 | class Header extends EventDispatcher_1.default { 4 | constructor() { 5 | super(); 6 | this.$header = $('.siteheader'); 7 | this.$menu = this.$header.find('.menu'); 8 | // inject the modules into the config 9 | this.insertModulesIntoConfig(ModuleCategories_1.default.NATIVE, MenuConfig_1.default.items[1]); 10 | this.insertModulesIntoConfig('destination', MenuConfig_1.default.items[1]); 11 | this.insertModulesIntoConfig(ModuleCategories_1.default.PROXY, MenuConfig_1.default.items[2]); 12 | this.createMenu(); 13 | } 14 | insertModulesIntoConfig(moduleCategory, menuItem) { 15 | var modules = ModuleDefinitions_1.default.findByCategory(moduleCategory); 16 | for (var i = 0; i < modules.length; i++) { 17 | menuItem.items.push({ 18 | name: modules[i].label, 19 | id: 'module.' + modules[i].type 20 | }); 21 | } 22 | } 23 | handleMenuItemClick(event) { 24 | // TODO close all submenus 25 | //$menus.css('display: none'); 26 | var id = $(event.target).attr('data-id'); 27 | var type = id.split('.')[0]; 28 | var data = id.split('.')[1]; 29 | Tracking_1.default.trackEvent('menu_select', id); 30 | switch (type) { 31 | case 'patch': 32 | { 33 | this.dispatchEvent(HeaderEvent_1.default.MENU_ITEM_SELECTED, { type: type, data: data }); 34 | break; 35 | } 36 | case 'module': 37 | { 38 | var moduleType = data; 39 | var definition = ModuleDefinitions_1.default.findByType(moduleType); 40 | var args = []; 41 | if (definition.args) { 42 | // node needs constructor arguments 43 | for (var i = 0; i < definition.args.length; i++) { 44 | args.push(prompt(definition.args[i].label)); 45 | } 46 | } 47 | this.patch.addModuleByType(moduleType, args); 48 | break; 49 | } 50 | default: 51 | { 52 | console.log('Unhandled menu selection: ' + id); 53 | break; 54 | } 55 | } 56 | } 57 | createMenu() { 58 | for (var i = 0; i < MenuConfig_1.default.items.length; i++) { 59 | var item = MenuConfig_1.default.items[i]; 60 | var $item = $('
  • ').html('

    ' + item.name + '

    '); 61 | this.$menu.append($item); 62 | // sub items 63 | let $subItems = $('