TheRogerLAB Codes

Window web component

  June, 2021

Introduction

This component consists in a floating window in which several children elements can be placed. Let's start by creating the structure of our web component. Create a file windowLab.js:

class windowLab extends HTMLElement {

  //Here will be all the functionality.

}
window.customElements.define('window-lab', windowLab);

Step 1: Add a constructor

class windowLab extends HTMLElement {
  constructor () {
    super();
  }
}
window.customElements.define('window-lab', windowLab);

Step 2: Add the observed attributes

class windowLab extends HTMLElement {
  //Step 1

  static get observedAttributes() {
    return ['nodrag','closable'];
  }
}
window.customElements.define('window-lab', windowLab);

In this case we create two attributes: nodrag and closable. When you include them in the observedAttributes function you are saying that they will be observed in case to change at some point.

Step 3: Add the getters for the observable attributes

class windowLab extends HTMLElement {
  //Step 1

  //Step 2

  get nodrag() {
    return this.hasAttribute('nodrag');
  }

  get closable() {
    return this.hasAttribute('closable');
  }
}
window.customElements.define('window-lab', windowLab);

Step 4: Add a function for drag the component

class windowLab extends HTMLElement {
  //Step 1

  //Step 2

  //Step 3

  dragElement(elmnt,shadowRoot,status) {

    //Here wil be functions and codes for dragging

  }
}
window.customElements.define('window-lab', windowLab);

Note that the dragElement function has three params:

Filling the dragElement function:

class windowLab extends HTMLElement {
  //Step 1

  //Step 2

  //Step 3

  dragElement(elmnt,shadowRoot,status) {
    var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
    if(status == true){
      if(shadowRoot.querySelector('#mydivheader'))
        shadowRoot.querySelector('#mydivheader').onmousedown = dragMouseDown;
      else
        elmnt.onmousedown = dragMouseDown;
    } else {
      if(shadowRoot.querySelector('#mydivheader'))
        shadowRoot.querySelector('#mydivheader').onmousedown = '';
      else
        elmnt.onmousedown = '';
    }
    function dragMouseDown(e) {
      e = e || window.event;
      e.preventDefault();
      pos3 = e.clientX;
      pos4 = e.clientY;
      document.onmouseup = closeDragElement;
      document.onmousemove = elementDrag;
    }
    function elementDrag(e) {
      e = e || window.event;
      e.preventDefault();
      pos1 = pos3 - e.clientX;
      pos2 = pos4 - e.clientY;
      pos3 = e.clientX;
      pos4 = e.clientY;
      elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
      elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
    }
    function closeDragElement() {
      document.onmouseup = null;
      document.onmousemove = null;
    }
  }
}
window.customElements.define('window-lab', windowLab);

Step 5: Add a function to change the component's height

class windowLab extends HTMLElement {
  //Step 1

  //Step 2

  //Step 3

  //Step 4

  setHeight(e){
    this.shadowRoot.querySelector('#container').style.height = e;
  }
}
window.customElements.define('window-lab', windowLab);

Note that the setHeight function has one params:

Step 6: Add a function to close the component

class windowLab extends HTMLElement {
  //Step 1

  //Step 2

  //Step 3

  //Step 4

  //Step 5

  close(){
    this.style.display = 'none';
  }
}
window.customElements.define('window-lab', windowLab);

Step 7: Add a function to remove the component

class windowLab extends HTMLElement {
  //Step 1

  //Step 2

  //Step 3

  //Step 4

  //Step 5

  //Step 6

  remove(){
    this.parentNode.removeChild(this);
  }
}
window.customElements.define('window-lab', windowLab);

Step 8: Add a attributeChangedCallback function

This will be fired when a observable attribute change. In this case nodrag and closable

class windowLab extends HTMLElement {
  //Step 1

  //Step 2

  //Step 3

  //Step 4

  //Step 5

  //Step 6

  //Step 7

  attributeChangedCallback(name, oldValue, newValue) {
    if(this.shadowRoot){
      if (this.nodrag) { 
        this.dragElement(this,this.shadowRoot,false);
        this.shadowRoot.querySelector('#mydivheader').style.cursor='initial';
      } else {
        this.dragElement(this,this.shadowRoot,true);
        this.shadowRoot.querySelector('#mydivheader').style.cursor='move';
      }

      if (this.closable) {
        this.shadowRoot.querySelector('#closeBtn').style.display='block';
      } else {
        this.shadowRoot.querySelector('#closeBtn').style.display='none';
      }
    }
  }
}
window.customElements.define('window-lab', windowLab);

Step 9: Add a function connectedCallback

It fires when the component is created

class windowLab extends HTMLElement {
  //Step 1

  //Step 2

  //Step 3

  //Step 4

  //Step 5

  //Step 6

  //Step 7

  //Step 8

  connectedCallback () {

    //Here will be the functionality.

  }
}
window.customElements.define('window-lab', windowLab);

Inside connectedCallback function we will create two things:

Filling the connectedCallback function:

class windowLab extends HTMLElement {
  //Step 1

  //Step 2

  //Step 3

  //Step 4

  //Step 5

  //Step 6

  //Step 7

  //Step 8

  connectedCallback () {
    let shadowRoot = this.attachShadow({mode: 'open'});
    shadowRoot.innerHTML = `
      <style>
        #mydivheader {
          padding: 10px;
          cursor: move;
          z-index: 10;
          background-color: #2196F3;
          color: #fff;
        }
        .btn, .button {
          border: none;
          display: inline-block;
          padding: 8px 16px;
          vertical-align: middle;
          overflow: hidden;
          text-decoration: none;
          color: inherit;
          background-color: inherit;
          text-align: center;
          cursor: pointer;
          white-space: nowrap;
          font-family: "Verdana",sans-serif;
        }
        .btn, .button {
          -webkit-touch-callout: none;
          -webkit-user-select: none;
          -khtml-user-select: none;
          -moz-user-select: none;
          -ms-user-select: none;
          user-select: none;
        }
        .display-topright {
          position: absolute;
          right: 0;
          top: 0;
        }
      </style>
      <div id="mydivheader">
        <slot name="title">
          <div>Default title</div>
        </slot>
        <span id='closeBtn' class="button display-topright" style='display:none;color:white;font-size:18px;float:right;padding: 7px 16px'>×</span>
      </div>
      <div id="container" style='background-color:white;'>
        <slot name='body'>
          <div></div>
        </slot>
      </div>`;

    this.style.position = 'absolute';
    this.style.boxShadow = '0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12)';

    //if it does not has a nodrag attribute defined
    if(!this.nodrag){
      this.dragElement(this,shadowRoot,true);
    }else{
      shadowRoot.querySelector('#mydivheader').style.cursor='initial';
    }

    //if it has a nodrag closable defined
    if(this.closable){ 
      shadowRoot.querySelector('#closeBtn').style.display='block';
    }

    //attaching a event listener to the close button.
    shadowRoot.querySelector('#closeBtn').addEventListener('click', e => {
      this.style.display = 'none';
    });
  }
}
window.customElements.define('window-lab', windowLab);

Check a working demo for this code:

SEE DEMO RATE THIS ARTICLE
4.5
27
TheRogerLAB Codes
Powered by TheRogerLAB Sandbox

info@therogerlab.com