Editor Side Panel Example
This example searches the Pixabay web site for images.
(function (imageSearch) { imageSearch.dragStart = function (event) { const imageData = JSON.parse(event.currentTarget.getAttribute('data-hit')); const dataUrl = this.getDataUrlFromImage(event.currentTarget, imageData.webformatWidth, imageData.webformatHeight); const jsonData = JSON.stringify({ files: [ { dataUrl: dataUrl, name: imageData.tags.replace(/, /g, '-') + '-' + imageData.id, mimeType: 'image/jpeg' } ] }); event.dataTransfer.setData('application/x-web-component-data', jsonData); }; imageSearch.getDataUrlFromImage = function (image, width, height) { let canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; const context = canvas.getContext('2d'); context.drawImage(image, 0, 0); return canvas.toDataURL('image/jpeg'); }; })(window.imageSearch || (window.imageSearch = {})); class ImageSearch extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = ` <style> :host { margin: 0; padding: 0; width: 100%; height: 100%; display: flex; } .content-wrapper { flex-grow: 1; flex-direction: column; margin: 0 10px 0 10px; height: calc(100vh - 60px); } #wrapper { flex-grow: 1; flex-direction: column; position: relative; overflow: auto; height: calc(100% - 60px); margin-top: 28px; } .search { position: relative; } #images { overflow-y: auto; overflow-x: hidden; position: absolute; top: 10px; bottom: 10px; left: 0; right: 0; scrollbar-face-color: #000000; scrollbar-track-color: transparent; } #images::-webkit-scrollbar { width: 9px; height: 9px; } #images::-webkit-scrollbar-thumb { background: #333333; border-left: 2px solid #444444; } #images::-webkit-scrollbar-track { background: transparent; } #images img { display: block; max-height: 250px; max-width: 80%; padding: 2px; margin: 0 auto 10px auto; cursor: pointer; border: 2px solid #9c9c9c; opacity: 0.8; transition: all 250ms ease-in-out; } #images img:hover { border: 2px solid #ffffff; opacity: 1; } #search-term { position: absolute; z-index: 1; width: 100%; height: 28px; border: 2px solid #000000; background: #333333; font-family: "Hind", Helvetica Neue, Helvetica, Arial, Sans-serif; color: #ffffff; font-weight: 300; font-size: 14px; padding-left: 10px; padding-right: 28px; box-sizing: border-box; } #search-term:focus, .searchButton:focus { outline: none; } .searchButton { position: absolute; z-index: 2; top: 2px; right: 2px; width: 24px; height: 24px; border: 0; cursor: pointer; background: transparent; color: #9c9c9c; } .searchButton:before { font: 16px 'cf'; font-style: normal; font-weight: normal; padding: 2px 0 0 4px; line-height: 24px; content: '\\e878'; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .searchButton:hover{ color: #ffffff; } h1 { display: block; width: 100%; height: 44px; margin: 0; padding: 0; background: url("webcomponents/image-search/pixabay_logo.png") no-repeat center 10px; } </style> <div class="content-wrapper"> <h1></h1> <div class="search"> <input id="search-term" type="textbox" value="" placeholder="Search in Pixabay free images"> <div id="search" class="searchButton"></div> </div> <div id="wrapper"> <div id="images"></div> </div> </div> `; } connectedCallback() { if (this.cueInterface.editor && this.cueInterface.editor.getTags) { const tags = this.cueInterface.editor.getTags(); if (tags && tags.length > 0) { this.shadowRoot.querySelector('#search-term').value = tags[0].value; } } this.search(); $(this.shadowRoot.querySelector('#search-term')).keypress(event => { if (event.which === 13 /* ENTER */) { this.search(); } }); $(this.shadowRoot.querySelector('#search')).click(this.search.bind(this)); } ImageSearchProto.search = function() { var searchTerm = panelShadowRoot.querySelector('#search-term').value; searchTerm = searchTerm.replace(' ', '+'); this.loadImages(searchTerm); }; loadImages(searchTerm) { const xhr = new XMLHttpRequest(); xhr.open('GET', 'https://pixabay.com/api/?key=<YOUR_API_KEY>&q=' + searchTerm + '&image_type=photo&safesearch=true', true); xhr.onload = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { this.showImages(xhr.responseText); } else { console.error(xhr.statusText); } } }.bind(this); xhr.onerror = function () { console.error(xhr.statusText); }; xhr.send(null); }; ImageSearchProto.showImages = function(responseData) { var responseJson = JSON.parse(responseData); var images = ''; responseJson.hits.forEach(function (hit) { images += "<img src='" + hit.webformatURL + "' data-hit='" + JSON.stringify(hit) + "' crossorigin='anonymous' ondragstart='imageSearch.dragStart(event);'>"; }); images += '<a href="https://pixabay.com/" target="_blank"><img src="https://pixabay.com/static/img/public/medium_rectangle_a.png" alt="Pixabay"></a>'; panelShadowRoot.querySelector('#images').innerHTML = images; } ; customElements.define('image-search', ImageSearch); class ImageSearchIcon extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = ` <style> :host { margin: 0; padding: 6px; display: block; } img { max-width: 80%; position: relative; top: 3px; left: 3px; } </style> <img class="icon"> `; ImageSearchIconProto.createdCallback = function () { var template = thisDoc.querySelector('template#icon').content; iconShadowRoot = this.attachShadow({ mode: 'open' }); iconShadowRoot.appendChild(template.cloneNode(true)); }; ImageSearchIconProto.attachedCallback = function() { if (this.cueInterface.homeScreen) { this.activeStateChanged(this.cueInterface.isActive()); this.cueInterface.addActiveWatcher(function (active) { this.activeStateChanged(active); }.bind(this)); } else { var img = iconShadowRoot.querySelector('img.icon'); img.src = this.getAbsolutePath(this.editorIconPath); } }; ImageSearchIconProto.activeStateChanged = function(active) { var img = iconShadowRoot.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('image-search-icon', ImageSearchIcon);