411 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			HTML
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			411 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			HTML
		
	
	
		
			Executable File
		
	
	
	
	
| 
 | ||
| <html>
 | ||
|     <head>
 | ||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | ||
|         <script src="N.js"></script>
 | ||
|         <script src="Pivot.js"></script>
 | ||
|     </head>
 | ||
|     <body>
 | ||
|         <div id="app"></div>
 | ||
|         
 | ||
|         <!-- rendering -->
 | ||
|         <script>
 | ||
|             var Render = function(){};
 | ||
|         </script>
 | ||
|         <script type="module">
 | ||
| 
 | ||
|     Pivot.Init(
 | ||
|         ["id", "type-a", "type-b", "count", "extra"],
 | ||
|         ["label", "label", "label", "sum", "sum"],
 | ||
|         [
 | ||
|         ["#1", "a", "long",  1, 4],
 | ||
|         ["#2", "b", "long",  2, 4],
 | ||
|         ["#3", "b", "short", 2, 4],
 | ||
|         ["#4", "a", "long",  3, 4],
 | ||
|         ["#5", "b", "short", 1, 4],
 | ||
|         ["#6", "a", "short", 0, 4],
 | ||
|         ["#7", "b", "short", 7, 4]
 | ||
|         ]
 | ||
|     );
 | ||
|     
 | ||
|     import { h, render, createContext, Fragment } from 'https://cdn.skypack.dev/preact';
 | ||
|     import { useReducer, useState } from 'https://cdn.skypack.dev/preact/hooks';
 | ||
|     import { css, cx } from 'https://cdn.skypack.dev/@emotion/css';
 | ||
|     import htm from 'https://unpkg.com/htm?module';
 | ||
|     const html = htm.bind(h);
 | ||
|     
 | ||
|     let PivotForm = props =>
 | ||
|     {
 | ||
|         let styles = css`
 | ||
|             position:realtive;
 | ||
|             box-sizing: border-box;
 | ||
|             padding: 10px;
 | ||
|             color:black;
 | ||
|             font-family:sans-serif;
 | ||
|     
 | ||
|             .Title
 | ||
|             {
 | ||
|                 font-size:24px;
 | ||
|                 font-weight:100;
 | ||
|             }
 | ||
|     
 | ||
|             .Section
 | ||
|             {
 | ||
|                 padding:10px 0 10px 0;
 | ||
|     
 | ||
|                 .Heading
 | ||
|                 {
 | ||
|                     display:inline-block;
 | ||
|                     color:#666;
 | ||
|                     font-family:sans-serif;
 | ||
|                     font-size:12px;
 | ||
|                     font-weight:900;
 | ||
|                     text-transform:uppercase;
 | ||
|                 }
 | ||
|                 .Group
 | ||
|                 {
 | ||
|                     display:inline-block;
 | ||
|                     padding:5px;
 | ||
|                     border-radius:5px;
 | ||
|                     margin:3px;
 | ||
|                     background:rgba(0, 0, 0, 0.3)
 | ||
|                 }
 | ||
|             }
 | ||
|         `;
 | ||
|     
 | ||
|     
 | ||
|         let pivotColumns = N.Step(Pivot.Schema, "label")||[];
 | ||
|         let pivotColumnsUsed = N.Step(Pivot.Proto, "used-pivot")||[];
 | ||
|     
 | ||
|         let sumColumns = N.Step(Pivot.Schema, "sum")||[];
 | ||
|         //let sumColumnsUsed = N.Step(Pivot.Proto, "used-sum")||[];
 | ||
|     
 | ||
|         let indiciesPivot = pivotColumnsUsed.map(node=>node.Meta.Index);
 | ||
|         let indiciesSum = sumColumns.map(node=>node.Meta.Index);
 | ||
|         //let indiciesSum = sumColumnsUsed.map(node=>node.Meta.Index);
 | ||
|         
 | ||
|         let displayPivotsAll = html`
 | ||
|         <div class="Section">
 | ||
|             <div class="Heading">Available Columns</div>
 | ||
|             <div class="Group">
 | ||
|             ${pivotColumns.map( columnPivot =>
 | ||
|             {
 | ||
|                 let attributes = {};
 | ||
|                 if(N.Step(columnPivot, "used-pivot", false))
 | ||
|                 {
 | ||
|                     attributes.disabled = true;
 | ||
|                 }
 | ||
|                 else
 | ||
|                 {
 | ||
|                     attributes.onClick = e=>
 | ||
|                     {
 | ||
|                         N.Connect(Pivot.Proto, columnPivot, "used-pivot");
 | ||
|                         Render();
 | ||
|                     }
 | ||
|                 }
 | ||
|                 return html`<button ...${attributes}>${columnPivot.Meta.Label}</button>`;
 | ||
|             })}
 | ||
|             </div>
 | ||
|         </div>
 | ||
|         `;
 | ||
|     
 | ||
|         let displayPivotsPending = null;
 | ||
|         if(pivotColumnsUsed.length)
 | ||
|         {
 | ||
|             displayPivotsPending  = html`
 | ||
|             <div class="Section">
 | ||
|                 <div class="Heading">Pending Pivot</div>
 | ||
|                 <div class="Group">
 | ||
|                     ${pivotColumnsUsed.map(columnPivot=>html`
 | ||
|                     <button onClick=${e=>{N.Disconnect(Pivot.Proto, columnPivot, "used-pivot");Render();}}>
 | ||
|                         ${columnPivot.Meta.Label}
 | ||
|                     </button>
 | ||
|                     `)}
 | ||
|                 </div>
 | ||
|     
 | ||
|                 <button onClick=${e=>{
 | ||
|                     N.Disconnect(Pivot.Proto, null, "used-pivot");
 | ||
|                     N.Disconnect(Pivot.Proto, null, "used-sum");
 | ||
|                     Pivot.Create(indiciesPivot, indiciesSum);
 | ||
|                     Render();
 | ||
|                 }}>Create</button>
 | ||
|             </div>
 | ||
|             `;
 | ||
|         }
 | ||
|     
 | ||
|         return html`
 | ||
|         <div class=${styles}>
 | ||
|             <div class="Title">Create New Pivot</div>
 | ||
|             ${displayPivotsAll}
 | ||
|             ${displayPivotsPending}
 | ||
|         </div>
 | ||
|         `;
 | ||
|     }
 | ||
|     
 | ||
|     let Section = props =>
 | ||
|     {
 | ||
|         let styles = css`
 | ||
|             .Heading
 | ||
|             {
 | ||
|                 padding:6px 0 6px 0;
 | ||
|                 color:#666;
 | ||
|                 font-weight:900;
 | ||
|                 font-size:12px;
 | ||
|                 text-transform:uppercase;
 | ||
|                 cursor:pointer;
 | ||
|     
 | ||
|                 span
 | ||
|                 {
 | ||
|                     display:inline-block;
 | ||
|                     width:20px;
 | ||
|                     height:20px;
 | ||
|                     margin-right:10px;
 | ||
|                     border-radius:20px;
 | ||
|                     background:black;
 | ||
|                     color:white;
 | ||
|                     text-align:center;
 | ||
|                 }
 | ||
|             }
 | ||
|             .Heading:hover
 | ||
|             {
 | ||
|                 color:black;
 | ||
|             }
 | ||
|             .Body
 | ||
|             {
 | ||
|                 position:relative;
 | ||
|                 padding:10px 0 20px 30px;
 | ||
|                 &::before
 | ||
|                 {
 | ||
|                     content: " ";
 | ||
|                     display:block;
 | ||
|                     position:absolute;
 | ||
|                     top:-8px;
 | ||
|                     left:8px;
 | ||
|                     width:3px;
 | ||
|                     height:100%;
 | ||
|                     background:black;
 | ||
|                 }
 | ||
|             }
 | ||
|         `;
 | ||
|     
 | ||
|         let [openGet, openSet] = useState(false);
 | ||
|         return html`
 | ||
|             <div class=${styles}>
 | ||
|                 <div class="Heading" onClick=${e=>openSet(!openGet)}>
 | ||
|                     <span>${openGet ? `−` : `+`}</span>
 | ||
|                     ${props.label}
 | ||
|                 </div>
 | ||
|                 ${ openGet ? html`<div class="Body">${props.children}</div>` : null }
 | ||
|             </div>
 | ||
|         `;
 | ||
|     }
 | ||
|     
 | ||
|     let ModificationsIcon = ({node}) =>
 | ||
|     {
 | ||
|         let modsUp   = N.Step(node, "ModifyUp",   false)||[];
 | ||
|         let modsDown = N.Step(node, "ModifyDown", false)||[];
 | ||
|         let modsAt   = N.Step(node, "ModifyAt",   false)||[];
 | ||
|         let modsOut  = N.Step(node, "ModifyOut",  false)||[];
 | ||
|     
 | ||
|     
 | ||
|         let padding = 7;
 | ||
|         let icon = 0;
 | ||
|         let styles = css`
 | ||
|             position:relative;
 | ||
|             display:inline-block;
 | ||
|             vertical-align:middle;
 | ||
|             width:${padding*2 + icon}px;
 | ||
|             height:${padding*2 + icon}px;
 | ||
|             margin:${padding};
 | ||
|             .Icon
 | ||
|             {
 | ||
|                 position:absolute;
 | ||
|                 display:inline-block;
 | ||
|                 width:${padding*2 + icon}px;
 | ||
|                 height:${padding*2 + icon}px;
 | ||
|                 text-align:center;
 | ||
|                 font-size:9px;
 | ||
|                 font-family:sans-serif;
 | ||
|                 font-weight:900;
 | ||
|                 line-height:${padding*2 + icon}px;
 | ||
|     
 | ||
|                 &::after
 | ||
|                 {
 | ||
|                     content:" ";
 | ||
|                     display:block;
 | ||
|                     position:absolute;
 | ||
|                     width:${icon}px;
 | ||
|                     height:${icon}px;
 | ||
|                     border:${padding}px solid transparent;
 | ||
|                 }
 | ||
|     
 | ||
|                 &.Down
 | ||
|                 {
 | ||
|                     left:0;
 | ||
|                     bottom:100%;
 | ||
|                     &::after
 | ||
|                     {
 | ||
|                         top:100%;
 | ||
|                         border-top-color:green;
 | ||
|                         border-bottom:0px solid transparent;
 | ||
|                     }
 | ||
|                 }
 | ||
|                 &.At
 | ||
|                 {
 | ||
|                     top:0;
 | ||
|                     left:100%;
 | ||
|                     &::after
 | ||
|                     {
 | ||
|                         top:0;
 | ||
|                         right:100%;
 | ||
|                         border-right-color:red;
 | ||
|                         border-left:0px solid transparent;
 | ||
|                     }
 | ||
|                 }
 | ||
|                 &.Up
 | ||
|                 {
 | ||
|                     left:0;
 | ||
|                     top:100%;
 | ||
|                     &::after
 | ||
|                     {
 | ||
|                         bottom:100%;
 | ||
|                         border-bottom-color:orange;
 | ||
|                         border-top:0px solid transparent;
 | ||
|                     }
 | ||
|                 }
 | ||
|     
 | ||
|                 &.Out
 | ||
|                 {
 | ||
|                     top:0;
 | ||
|                     right:100%;
 | ||
|                     &::after
 | ||
|                     {
 | ||
|                         top:0;
 | ||
|                         left:100%;
 | ||
|                         border-left-color:grey;
 | ||
|                         border-right:0px solid transparent;
 | ||
|                     }
 | ||
|                 }
 | ||
|             }
 | ||
|     
 | ||
|         `;
 | ||
|     
 | ||
|         return html`
 | ||
|         <div class=${styles}>
 | ||
|             ${modsDown.length ? html`<div class="Icon Down">${modsDown.length}</div>` : null}
 | ||
|             ${modsAt.length ? html`<span class="Icon At">${modsAt.length}</span>` : null}
 | ||
|             ${modsUp.length ? html`<span class="Icon Up">${modsUp.length}</span>` : null}
 | ||
|             ${modsOut.length ? html`<span class="Icon Out">${modsOut.length}</span>` : null}
 | ||
|         </div>
 | ||
|         `;
 | ||
|     
 | ||
|     };
 | ||
|     
 | ||
|     let PivotBranch = props =>
 | ||
|     {
 | ||
|         let row = props.node.Meta.Row;
 | ||
|         let displayCells = row.map(column=>h("td", null, column));
 | ||
|         let displayCellsModify = row.map(column=>false);
 | ||
|         props.node.Meta.IndexSum.forEach(i=>
 | ||
|         {
 | ||
|             displayCellsModify[i] = html`<td><input type="number" value=${row[i]}/></td>`;
 | ||
|         });
 | ||
|         displayCellsModify.forEach((cell, i)=>
 | ||
|         {
 | ||
|             if(!cell)
 | ||
|             {
 | ||
|                 displayCellsModify[i] = html`<td>${row[i]}</td>`
 | ||
|             }
 | ||
|         });
 | ||
|     
 | ||
|         let modifier = N.Step(props.node, "ModifyAt", false);
 | ||
|         let modifierDisplay = false;
 | ||
|         if(modifier)
 | ||
|         {
 | ||
|             modifierDisplay = html`<button onClick=${e=>{Pivot.Unmodify(modifier[0]); Render();}}>-</button>`;
 | ||
|         } 
 | ||
|         else
 | ||
|         {
 | ||
|             modifierDisplay = html`<button onClick=${e=>{Pivot.Modify(props.node); Render();}}>+</button>`;
 | ||
|         }
 | ||
|     
 | ||
|         return html`
 | ||
|         <tbody>
 | ||
|             <tr>
 | ||
|                 <td>
 | ||
|                     <${ModificationsIcon} node=${props.node}><//>
 | ||
|                     <strong class=${css`margin-left:${props.node.Meta.Depth*10}px;`}>${props.node.Meta.Label}</strong>
 | ||
|                     ${modifierDisplay}
 | ||
|                 </td>
 | ||
|                 ${displayCells}
 | ||
|             </tr>
 | ||
|         
 | ||
|         </tbody>
 | ||
|         `;
 | ||
|     };
 | ||
|     
 | ||
|     let PivotRoot = ({pivot}) =>
 | ||
|     {
 | ||
|     
 | ||
|         let stylesRoot = css`
 | ||
|             display:block;
 | ||
|             box-sizing:border-box;
 | ||
|             padding:15px;
 | ||
|             font-family:sans-serif;
 | ||
|         `;
 | ||
|         let stylesHeading = css`
 | ||
|             margin: 0 0 15px 0;
 | ||
|             font-weight:0;
 | ||
|             font-size:24px;
 | ||
|         `;
 | ||
|     
 | ||
|         let modifiers = N.Step(pivot, "ModifyUp", false) || [];
 | ||
|         let handleDelete = ()=>
 | ||
|         {
 | ||
|             Pivot.Delete(pivot);
 | ||
|             Render();
 | ||
|         };
 | ||
|     
 | ||
|         let rows = [];
 | ||
|         N.ID.Walk++;
 | ||
|         N.Walk(n=>rows.push(h(PivotBranch, {node:n}, null)), pivot, "Hierarchy");
 | ||
|     
 | ||
|         return html`
 | ||
|         <div class=${stylesRoot}>
 | ||
|             <div key="heading" class=${stylesHeading}>${pivot.Meta.Label}</div>
 | ||
|             <${Section} key="settings" label=${`Settings`}>
 | ||
|                 <button onClick=${handleDelete}>Destroy Pivot</button>
 | ||
|             <//>
 | ||
|             <${Section} key="tree" label=${"Tree"}>
 | ||
|                 <table>
 | ||
|                 ${rows}
 | ||
|                 </table>
 | ||
|             <//>
 | ||
|         </div>
 | ||
|         `;
 | ||
|     };
 | ||
|     
 | ||
|     let ElRoot = props =>
 | ||
|     {
 | ||
|         let pivots = N.Step(Pivot.Root, "Pivot")||[];
 | ||
|         return h("div", null, [
 | ||
|             h(PivotForm),
 | ||
|             pivots.map(pivot=>h(PivotRoot, {key:pivot.Meta.Label, pivot}))
 | ||
|         ])
 | ||
|     };
 | ||
|     Render = () => render(h(ElRoot), document.querySelector("#app"));
 | ||
|     Render();
 | ||
|         </script>
 | ||
| 
 | ||
| <script>
 | ||
| Pivot.Create([1, 2], [3, 4]);
 | ||
| let pivot = N.Path([0], Pivot.Root, "Pivot");
 | ||
| let node = N.Path([0, 1], pivot, "Hierarchy");
 | ||
| Pivot.Modify(node);
 | ||
| Pivot.Create([2, 1], [3, 4]);
 | ||
| Render();
 | ||
| </script>
 | ||
|     </body>
 | ||
| 
 | ||
| </html>
 |