Dialog Example
The following example web component creates a metadata panel
section containing a series of forms that you can use to display
demo dialogs. It has no practical function, it is simply a
demonstration of how the various dialog methods work, and what
kind of dialogs they display. The web component is created using
the
cue.core.webcomponents.StorylineEditorMetadataPanel
class and is configured as follows:
customComponents: - name: "simple-dialog" tagName: "simple-dialog" modulePath: "webcomponents/simple-dialog/simple-dialog.js" attributes: title: "Simple Dialog" icon: "simple-dialog-icon"
Here is the web component code:
class SimpleDialog extends cue.core.webcomponents.StorylineEditorMetadataPanel { constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = ` <style> :host { margin:0; padding: 0; width: 100%; display:block; } h1, h2, h3, h4 { color: #9c9c9c; } /* Panel specific inputs */ .text-field { height: 32px; vertical-align: middle; font-family: 'Hind', Helvetica Neue, Helvetica, Arial, Sans-serif; font-weight: lighter; font-size: 18px; line-height: 1.3; color: #444444; cursor: pointer; border-radius: 3px; width: 100%; } .text-area { height: 128px; font-family: 'Hind', Helvetica Neue, Helvetica, Arial, Sans-serif; font-weight: lighter; font-size: 18px; color: #444444; cursor: pointer; border-radius: 3px; width: 100%; } button, input[type=submit], input[type=cancel], input[type=button] { height: 32px; border: none; background: #d3d3d3; vertical-align: middle; font-family: 'Hind', Helvetica Neue, Helvetica, Arial, Sans-serif; font-weight: lighter; font-size: 18px; line-height: 1.3; color: #444444; padding: 2px 10px 0 10px; cursor: pointer; border-radius: 3px; width: 100%; } button:hover { background: #e5e5e5; } .group { padding: 20px; } .spacer { padding:10px } p { margin: 0; } </style> <div> <h1>Simple Dialog API</h1> <h2>A Web Component</h2> </div> <hr> <div class="group"> <h3>Simple Customizable Dialogs</h3> <p></p> <div class="spacer"></div> <p>Title</p> <input class ="text-field" type="text" id="simple-title" value="Simple Dialog"> <p>Message</p> <textarea class="text-area" id="simple-message" rows="5" >description</textarea> <p>Button Label</p> <input class ="text-field" type="text" id="simple-button-label" value="Ok"> <div class="spacer"></div> <button id="simple-button">Show One Button Dialog</button> </div> <hr> <div class="group"> <h3>Customizable Reactive Dialogs</h3> <p>The dialog API exposes customizable dialogs with positve and negative options. The answer is a Promise that is resolved or rejected.</p> <div class="spacer"></div> <p>Title</p> <input class ="text-field" type="text" id="two-button-title" value="OK or Cancel dialog"> <p>Message</p> <textarea class="text-area" id="two-button-message" rows="5" >Using this dialog one can promt the user for a positive or negative answer. The answer can be used for further action.</textarea> <p>Cancel label</p> <input class ="text-field" type="text" id="two-button-cancel-label" value="Cancel"> <p>Ok Label</p> <input class ="text-field" type="text" id="two-button-ok-label" value="Ok"> <label for="two-button-use-default-buttons"> Use default buttons</label> <input type="checkbox" id="two-button-use-default-buttons" checked> <div class="spacer"></div> <div class="spacer"></div> <button id="two-button-button">Show Two Button Dialog</button> <div class="spacer"></div> <p>output:</p> <input disabled class ="text-field" type="text" id="two-button-output" value=""> </div> <hr> <div class="group"> <h3>Input validation using Dialogs</h3> <p>The Dialos API can be used to validate input from the user.</p> <div class="spacer"></div> <p>Which City was the European Capital of Culture 2017?</p> <input class ="text-field" type="text" id="answer" value=""> <div class="spacer"></div> <button id="quiz-button">Answer question</button> <div class="spacer"></div> <p>Insert a number between 5 and 10</p> <input class ="text-field" type="number" id="numberField" value=""> <div class="spacer"></div> <button type="submit"id="numValidation">Submit</button> <div class="spacer"></div> </div> <hr> <div class="group"> <h3>Alert Dialogs</h3> <p>The dialog API exposes two levels of alert dialogs; Warning and Error. A description of the problem can be passed to the dialog.</p> <div class="spacer"></div> <p>Type alert message:</p> <textarea class="text-area" id="error-msg" rows="5" >A error dialog can be used to notify the user, who is about to do something is not permitted</textarea> <div class="spacer"></div> <button id="openWarningDialog" class="buttons">Warning Dialog</button> <div class="spacer"></div> <button id="openErrorDialog" class="buttons">Error Dialog</button> <div class="spacer"></div> </div> <hr> <h2>Advanced Dialog API</h2> <p>The advanced API is based on VDF models.</p> <div class="group"> <h3>A dialog editor</h3> <p>Values can be passed to the dialog</p> <p>Top</p> <input class="text-field" type="text" id="editor-top" value="top"> <p>Titel</p> <input class="text-field" type="text" id="editor-title" value="title"> <p>Cancel label</p> <input class ="text-field" type="text" id="editor-cancel-label" value="Cancel"> <p>Ok Label</p> <input class ="text-field" type="text" id="editor-ok-label" value="Ok"> <label for="editor-use-default-buttons"> Use default buttons</label> <input type="checkbox" id="editor-use-default-buttons" checked> <div class="spacer"></div> <button id="editor">Editor Dialog</button> <div class="spacer"></div> <p>body output:</p> <span class="text-field" type="text" id="editor-output"></span> </div> `; } connectedCallback() { this.shadowRoot .getElementById('simple-button') .addEventListener('click', () => { // Get the dialog configurations const top = this.shadowRoot.querySelector('#simple-title').value; const description = this.shadowRoot.querySelector('#simple-message') .value; const buttonLabel = this.shadowRoot.querySelector( '#simple-button-label' ).value ? this.shadowRoot.querySelector('#simple-button-label').value : undefined; // Call the dialog api this.dialog.showOneButton(description, top, buttonLabel); }); this.shadowRoot .getElementById('two-button-button') .addEventListener('click', () => { // Get the dialog configurations const top = this.shadowRoot.querySelector('#two-button-title').value; const description = this.shadowRoot.querySelector('#two-button-message') .value; const okButtonLabel = this.shadowRoot.querySelector( 'input[id="two-button-ok-label"]' ).value ? this.shadowRoot.querySelector('input[id="two-button-ok-label"]') .value : undefined; const cancelButtonLabel = this.shadowRoot.querySelector( 'input[id="two-button-cancel-label"]' ).value ? this.shadowRoot.querySelector('input[id="two-button-cancel-label"]') .value : undefined; const useDefaultButtons = this.shadowRoot.querySelector( '#two-button-use-default-buttons' ).checked; // Call the dialog api this.dialog .showTwoButton( description, top, okButtonLabel, cancelButtonLabel, useDefaultButtons ) .then( // if promise is resolved () => { this.shadowRoot.querySelector( 'input[id="two-button-output"]' ).value = okButtonLabel ? okButtonLabel : 'OK'; }, //if promise is rejected () => { this.shadowRoot.querySelector( 'input[id="two-button-output"]' ).value = cancelButtonLabel ? cancelButtonLabel : 'Cancel'; } ); }); this.shadowRoot .getElementById('quiz-button') .addEventListener('click', () => { const answer = this.shadowRoot.querySelector('input[id="answer"]') .value; try { const possibleAnswers = ['aarhus', 'århus']; let correct = false; possibleAnswers.forEach(ans => { if (answer.toLowerCase().localeCompare(ans) === 0) correct = true; }); if (!correct) { throw Error( 'No "' + answer + '"' + ' was not the European Capital of Culture 2017' ); } this.dialog.showOneButton( 'Yes, it is correct that the European Capital of Culture 2017 is "Århus"', 'Correct', 'Yaay', true ); } catch (error) { this.dialog.showOneButton(error.message, 'Incorrect', 'Oops', true); } }); this.shadowRoot .getElementById('numValidation') .addEventListener('click', () => { let x = this.shadowRoot.querySelector('input[id="numberField"]').value; try { if (x == '') throw new Error('field is empty'); if (isNaN(x)) throw new Error('input is not a number'); x = Number(x); if (x < 5) throw new Error('input is too low'); if (x > 10) throw new Error('input is too high'); this.dialog.showOneButton( 'Yes, number is between 5 an 10', 'Good Job', 'Thanks', true ); } catch (error) { this.dialog.showOneButton( error.message, 'Invalid Input', "I'll try again", 'Please try again' ); } }); this.shadowRoot .getElementById('openWarningDialog') .addEventListener('click', () => { const description = this.shadowRoot.querySelector('#error-msg').value; this.dialog.showWarning(description); }); this.shadowRoot .getElementById('openErrorDialog') .addEventListener('click', () => { const description = this.shadowRoot.querySelector('#error-msg').value; this.dialog.showError(description); }); this.shadowRoot.getElementById('editor').addEventListener('click', () => { const top = this.shadowRoot.querySelector('#editor-top').value; const title = this.shadowRoot.querySelector('#editor-title').value; const okButtonLabel = this.shadowRoot.querySelector( 'input[id="editor-ok-label"]' ).value ? this.shadowRoot.querySelector('input[id="editor-ok-label"]').value : undefined; const cancelButtonLabel = this.shadowRoot.querySelector( 'input[id="editor-cancel-label"]' ).value ? this.shadowRoot.querySelector('input[id="editor-cancel-label"]').value : undefined; const useDefaultButtons = this.shadowRoot.querySelector( '#editor-use-default-buttons' ).checked; // Call the dialog api this.dialog .showVdf( ` <vdf:payload xmlns:vdf="http://www.vizrt.com/types" model="webcomponents/simple-dialog/vdfEditorModel.xml"> <vdf:field name="title"> <vdf:value>` + title + `</vdf:value> </vdf:field> <vdf:field name="body"> <vdf:value> <div xmlns="http://www.w3.org/1999/xhtml"> <p>this is body</p> </div> </vdf:value> </vdf:field> </vdf:payload>`, top, okButtonLabel, cancelButtonLabel, useDefaultButtons ) .then( // if promise is resolved res => { this.shadowRoot.querySelector('#editor-output').innerHTML = res.values.body; }, //if promise is rejected res => { console.log(res); } ); }); } } customElements.define('simple-dialog', SimpleDialog); class SimpleDialogIcon extends cue.core.webcomponents .StorylineEditorMetadataPanel { constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = ` <style> :host { margin: 0 0px 0 0px; width: 26px; display: inline; float: left; margin-right: 18px; } img { width: 20px; position: relative; } </style> <img class="icon"> `; this.activeIconPath = 'simple-dialog-icon.png'; this.inactiveIconPath = 'simple-dialog-icon.png'; } connectedCallback() { this.activeStateChanged(this.active); this.addActiveWatcher(active => { this.activeStateChanged(active); }); } activeStateChanged(active) { let img = this.shadowRoot.querySelector('img.icon'); if (active) { img.src = this.getAbsolutePath(this.activeIconPath); } else { img.src = this.getAbsolutePath(this.inactiveIconPath); } } getAbsolutePath(path) { const baseURI = import.meta.url; return baseURI.substring(0, baseURI.lastIndexOf('/') + 1) + path; } } customElements.define('simple-dialog-icon', SimpleDialogIcon);