Breaking

Showing posts with label CSS. Show all posts
Showing posts with label CSS. Show all posts

Monday, February 6, 2017

February 06, 2017

Notifikasi Adblocker Adsense Ala Kompi Ajaib

Salam Blogger, kali ini Arlina Design akan berbagi tutorial cara memberikan notifikasi adblocker adsense saat pengguna mengakses blog dan mengaktifkan ekstensi adblock di browser.

Notifikasi Adblocker Adsense Ala Kompi Ajaib

Tutorial ini saya dapat dari blog Kompi Ajaib yang dikelola oleh admin +Adhy Suryadi yang senantiasa memberikan trik dan tips blogger yang bermanfaat dan beliau sangat menginspirasi saya untuk membangun blog menjadi lebih baik. Mengenai penjelasan kenapa sobat perlu Menambahkan Notifikasi Adblocker Adsense di dalam blog sobat bisa mengunjungi sumbernya di http://www.kompiajaib.com/2016/07/membuat-notifikasi-untuk-pengguna.html
Selengkapnya »

Saturday, January 28, 2017

January 28, 2017

Membuat Tombol Demo dan Download Material Design

Membuat Tombol Demo dan Download Material Design - Seperti yang kita ketahui, kini Material Design sudah menjadi tren sebagai antarmuka web atau UI (User Interface) baik itu pada perangkat mobile maupun desktop dalam sebuah halaman website. Antarmuka web ini pun disambut baik oleh pengguna maupun pengembang website karena memiliki segudang fitur yang bermanfaat serta tampilan yang lebih menarik.

Membuat Tombol Demo dan Download Material Design

Pada kesempatan ini Arlina Design akan memberikan contoh tombol demo dan download yang ditambahkan dengan efek animasi ripple (gelombang) pada saat kita menekan tombol tersebut yang merupakan salah satu fitur seperti efek animasi dari Material Design.
Selengkapnya »

Tuesday, January 17, 2017

January 17, 2017

Cara Memasang Artikel Terkait di Dalam Postingan

Cara Memasang Artikel Terkait di Dalam Postingan - Halo sobat blogger, tentunya sobat sudah mengetahui dengan fungsi sebuah widget artikel terkait di blog yang menampilkan sejumlah artikel terkait sesuai label di bawah artikel baik itu dalam bentuk link dan thumbnail ataupun link saja.

Cara Memasang Artikel Terkait di Dalam Postingan

Namun sedikit berbeda dari sebelumnya, di sini saya akan memberikan tutorial Cara Memasang Artikel Terkait di Dalam Postingan. Seperti yang saya singgung sebelumnya di artikel Cara Memasang Iklan Adsense di Tengah Postingan bahwa sobat juga bisa memasang kode atau widget lain di dalam kode tersebut, tutorial blogger kali ini pun masih menggunakan kode yang sama. Tutorial ini saya dapatkan dari blog http://www.bungfrangki.com/2015/12/membuat-related-pos-dalam-postingan.html dan telah saya modifikasi kembali disesuaikan dengan style saya.
Selengkapnya »

Tuesday, January 10, 2017

January 10, 2017

Cara Memasang Iklan Adsense di Tengah Postingan

Cara Memasang Iklan Adsense di Tengah Postingan - Masih membahas seputar Adsense, kali ini Arlina Design membahas tentang trik dan tips Cara Memasang Iklan Adsense di tengah postingan. Sebetulnya sudah banyak sekali artikel yang membahas tentang trik ini, namun kebetulan di blog ini belum ada jadi saya bagikan dan mungkin judulnya agak mainstream menurut saya tapi tidak apa-apa yang penting berbagi.

Cara Memasang Iklan Adsense di Tengah Postingan

Manfaat dari trik Memasang Iklan Adsense di tengah postingan ini yaitu sobat bisa lebih meningkatkan pendapatan Google Adsense blog sobat dengan jumlah rasio klik yang lebih tinggi dan biasanya akan lebih menarik minat pembaca dengan konten iklan yang ditampilkan karena posisi iklan yang strategis berada di tengah postingan. Singkat saja, berikut Cara Memasang Iklan Adsense di Tengah Postingan.
Selengkapnya »

Wednesday, November 23, 2016

November 23, 2016

Membuat Morphing Button Menggunakan CSS & Javascript



Dalam postingan ini kita akan mencoba untuk Membuat Morphing Button Menggunakan CSS Dan Javascript, nantinya yang kita buat akan terlihat seperti musiXmatch Musik Recognizer tapi bukannya menunjukkan hasil di layar penuh, di sini saya akan menunjukkan kartu dengan inforrmasi artis dan judul lagu. Tutorial ini saya kutip langsung dari blog saya karena lagi tidak ada bahan, buat yang mengerti bahasa inggris bisa mampir ke http://muhammadsayuti.com :D.

Pertama buatlah file html baru dan beri nama index.html dan kemudian salin template di bawah ini.
<!DOCTYPE html>
<html>
<head>
<meta name="author" content="Muhammad Sayuti">
<meta name="msapplication-tap-highlight" content="no">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">

<link rel="stylesheet" type="text/css" href="css/style.css">
<link rel="stylesheet" type="text/css" href="css/normalize.css">
<link rel="stylesheet" type="text/css" href="css/icons.css">
<title>Morphing Button</title>
</head>
<body>
<div class="content">
<div class="morpher">
<a class="circle-button" href="#"><span class="icon icon--microphone"></span></a>
</div>
<div class="player">
<img class="player__cover" src="img/Montevallo.jpeg" alt="Take Your Time by Sam Hunt" />
<div class="player__meta">
<h4 class="player__track">Take Your Time</h3>
<h4 class="player__artist">Sam Hunt</h3n>
<h4 class="player__album-name">Montevallo</h3>
</div>
<a href="#" class="button--close"><span class="icon icon--cross"></span></a>
</div><!-- /player -->
</div>
<script type="text/javascript" src="index.js"></script>
</body>
</html>

Selanjutnya buatlah file css baru dan beri nama style.css dan copy css di bawah ini.
html,body{
padding:0px;
margin:0px;
font-family:san-serif;
background-color: #eee;
}
*{
box-sizing:border-box;
}

.content{
display: -ms-flexbox;
display: -webkit-flex;
display: flex;

-ms-flex-align: center;
-webkit-align-items: center;
-webkit-box-align: center;

align-items: center;
-webkit-box-pack: center;
align-items: center;
justify-content: center;
flex-direction: column;
flex-flow: column wrap;
height:100vh;
}
/* Buttton container Style */
.morpher{
color: #2196F3;
align-items: center;
background-color: #FFF;
display: flex;
-webkit-box-flex: 0;
justify-content: center;
flex: none;
min-height: 48px;
min-width: 48px;
overflow: visible;
border-radius: 25px;
transform: scale3d(1,1,1);
-webkit-transform: scale3d(1,1,1);
}
.card {
transform: scale3d(7,10,1);
-webkit-transform: scale3d(7,10,1);
border-radius: 1px;
box-shadow: 0 3px 4px rgba(0,0,0,0.3);
}
/* Buttton Style */
.btn{
color: #2196F3;
background-color: #FFF;
text-decoration: none;
display: flex;
text-align: center;
border-radius: 25px;
padding: 1em 5em;
overflow: visible;
border: none;
}
.circle-button{
width: 50px;
height:50px;
padding: 1em !important;
border-radius: 50%;
}
.listening{
position: relative;
}
.listening::before,
.listening::after {
content: '';
position: absolute;
top: calc(50% - 24px);
left: calc(50% - 24px);
height: 48px;
width: 48px;
pointer-events: none;
opacity: 1;
border: 1px solid rgba(255, 255, 255, 0.7);
border-radius: 50%;
}

.listening::before,
.listening::after {
-webkit-animation: anim-ripple 1.2s ease-out infinite forwards;
animation: anim-ripple 1.2s ease-out infinite forwards;
}
.listening::after {
-webkit-animation-delay: 0.6s;
animation-delay: 0.6s;
}

/* Player Style */
.cover{
display: none;
margin-top: -1px;
width:300px;
height:200px;
flex: none;
border-radius: 5px 5px 0 0;
}

.button--close {
position: absolute;
z-index: 10;
top: 0px;
right: 0px;
left: auto;
width: 40px;
height: 40px;
padding: 10px;
color: #eee;
pointer-events: all;
text-decoration: none;
}

.button--close:hover,
.button--close:focus {
color: #ddd;
}
.player {
position: absolute;
width:calc(50px * 7);
height:calc(50px * 10);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
pointer-events: none;
opacity: 0;
}
.player::after {
content: '';
position: absolute;
pointer-events: none;
border-radius: 5px 5px 0 0;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), transparent);
}
.player--visible {
pointer-events: none;
-webkit-transition: opacity 0.5s linear 0.2s;
transition: opacity 0.5s linear 0.2s;
opacity: 1;
}
.player__cover {
margin-top: -1px;
width:100%;
max-height: 300px;
overflow: hidden;
border-radius: 5px 5px 0 0;
}

.player__meta {
position: absolute;
width: 100%;
bottom:20px;
padding: 0 1em 1em;
text-align: center;
}

.player__track {
font-size: 1.15em;
margin: 1.25em 0 0.05em 0;
color: #55656c;
}

.player__album {
font-size: 12px;
margin: 0;
color: #bbc1c3;
}

.player__album-name,
.player__artist {
color: #adb5b8;
}

/* Keyframes Animation */
@-webkit-keyframes anim-ripple {
0% {
opacity: 0;
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
50% {
opacity: 1;
}
100% {
opacity: 0;
-webkit-transform: scale3d(3, 3, 1);
transform: scale3d(3, 3, 1);

}
}

@keyframes anim-ripple {
0% {
opacity: 0;
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
50% {
opacity: 1;
}
100% {
opacity: 0;
-webkit-transform: scale3d(3, 3, 1);
transform: scale3d(3, 3, 1);

}
}

Bagian berikutnya adalah file javascript, saya akan mulai menjelaskan semua proses animasi dari file ini sehingga mudah untuk memahami seluruh proses. Sekarang buatlah file javascript baru dan beri nama index.js. Buatlah kelas baru dan tambahkan konstruktor untuk menginisialisasikan semua variabel.

'use strict';
class MorphingButton{
constructor(){
//initilize all variables
this.btn = document.querySelector('.morpher a');
this.meta = document.querySelector('.player');
this.btnClose = document.querySelector('.button--close');

this.onClick = this.onClick.bind(this);
this.onCardClose = this.onCardClose.bind(this);
//add all even listener needed
this.addEventListeners();
}
}
window.addEventListener('load',() => new MorphingButton());

Sekarang tambahkan 3 fungsi baru onClick, onCardClose dan addEventListeners di kelas sebelumnya. addEventListeners digunakan untuk menambahkan semua listener yang akan kita gunakan, onClick akan digunakan untuk mendengarkan event klik pada tombol dan onCardClose akan digunakan untuk mendengarkan klik event pada tombol tanda silang di dalam kartu padainformasi lagu.

addEventListeners(){
this.btn.addEventListener('click',this.onClick);
this.btnClose.addEventListener('click',this.onCardClose);
}
onCardClose(e){
e.preventDefault();
this.hideCard();
}
onClick(e){
e.preventDefault();
let self = this;
// start listening state
this.listening();

//simulate listening for song in 5000 miliseconds
setTimeout(function(){
// stop listening state
self.stopListening();
// show card with song information
self.showCard();
// clear current Timeout
clearTimeout(this);
},5000);
}

Pada kode di atas dalam fungsi onClick kita perlu menyimpan innstance kelas pada variabel self karena setTimeout berjalan di thread berbeda, sehingga kita tidak mungkin dapat mengakses fungsi yang ada pada kelas saat ini didalam fungsi setTimeout.

Sekarang mari kita membuat bagian animasi dan membuat 4 fungsi baru yaitu listening, stopListening, Showcard dan hideCard. Pertama mari kita mulai dengan fungsi listening dimana fungsi ini kita menambahkan kelas listening pada elemen btn, jika Anda melihat kelas listening dengan pseudo class(kelas semu) ::after dan ::before di css, saya membuat border di mana border-radius diatur ke 50% sehingga akan membuat semacam cincin di tengah layar dan menganimasikannya dengan keyframes anim-ripple di mana animasi akan selalu berjalan karena saya mengatur animation-iteration-count menjadi infinit. Pada pseudo class ::after saya mengatur penundaan selama 0,6 detik sehingga ini akan membiarkan animasi di pseudo class ::before untuk berjalan terlebih dahulu selama 0,6 detik sebelum animasi di pseudo class ::after dieksekusi.

listening(){
// add class listening to circle-button
this.btn.className += ' listening';
}

Sekarang untuk fungsi stopListening kita hanya perlu menghapus kelas listening dari tombol untuk menghentikan animasi sehingga hanya kelas circle-button yang ada dalam elemen btn.

stopListening(){
// remove the listening class from button
this.btn.className = 'circle-button';
}

Berikutnya mari kita pindah ke fungsi showCard, dalam fungsi ini saya mengubah elemen induk dari btn menjadi kartu dengan menambahkan kelas card, ada beberapa urutan transisi untuk elemen ini dan urutannya berbeda saat kartu tampil dan saat kartu disembunyikan. Pada Showcard urutan transisi pertama adalah transform kemudian diikuti dengan border-radius. Jadi border-radius akan menunggu transform untuk menyelesaikannya terlebih dahulu sebelum dieksekusi. Dalam fungsi ini kita akan menyembunyikan btn dan mengatur opacity ke 0 serta menampilkan informasi lagu dengan menambahkan kelas player–visible pada elemen meta.

showCard(){
// add transition to morpher with 100ms delay on border-radius
this.btn.parentNode.style.transition = 'border-radius 100ms linear 100ms,transform 100ms linear';
//add transtion on opacity with duration 50ms
this.btn.style.transition = 'opacity 50ms linear';
//change button opacity to 0 and hide the button
this.btn.style.opacity = 0;
// add card class to morpher to transform it from circle button to card
this.btn.parentNode.className += ' card';
// add player--visible class to show track information
this.meta.className += ' player--visible';
}

Yang terakhir adalah fungsi hideCard. Dalam fungsi ini kita akan melakukan kebalikan dari fungsi Showcard dimana kita akan mengubah kembali elemen induk dari btn ke menjadi lingkaran yang memiliki bentuk yang sama dengan elemen btn. Urutan transisinya kebalikan dari fungsi Showcard, sehingga urutan transisinya adalah border-radius pertama dan kemudian diikuti dengan transform. Setelah itu kita akan menampilkan kembali elemen btn dan menyembunyikan informasi lagu.

hideCard(){
// remove player--visible to hide the song information
this.meta.className = 'player';
// add transition to morpher with 100ms delay on transform
this.btn.parentNode.style.transition = 'border-radius 100ms linear,transform 100ms linear 100ms';
// remove card class from morpher
this.btn.parentNode.className = 'morpher';
//add transtion on opacity with duration 200ms and delay 200ms
this.btn.style.transition = 'opacity 200ms linear 200ms';
//change button opacity to 1 and show the button
this.btn.style.opacity = 1;
}

Mungkin itu saja yang dapat saya share pada postingan kali ini, untuk sourcecode dapat di download melalui Github.

Saturday, October 22, 2016

October 22, 2016

Membuat SlidingUpPanel Dengan HTML,CSS Dan Javascript Bagian 4





Setelah sebelumnya di postingan Membuat SlidingUpPanel Dengan HTML, CSS Dan Javascript Bagian 3 kita telah membuat pemutar musiknya, maka pada postingan terahir di dalam topik ini kita akan memperbaiki beberapa element serta sedikit memberi efek untuk mempercantik tampilan antarmuka.

Pertama-tama kita akan mengedit pada bagian panel header dimana content dari panel header akan kita bagi menjadi 2, yaitu panel header saat posisi SlidingUpPanel terbuka dan panel header saat posisi SlidingUpPanel tertutup atau berada dibagian dibawah layar.
Ubah bagian sliding-up-panel-header menjadi seperti berikut




SlidingUpPanel Music Player























Sekarang tambahkan css berikut kedalam file sliding-up-panel.css.
#sliding-up-panel-header.expanded .panel-header-content__expanded{
transition:opacity 300ms;
opacity:1;
}
#sliding-up-panel-header .panel-header-content__expanded{
position: absolute;
transition: opacity 300ms;
opacity:0;
text-align: left;
padding:20px;
pointer-events: none;
}
#sliding-up-panel-header .panel-header-content__collapsed{
pointer-events: none;
}
#sliding-up-panel-header.expanded .panel-header-content__collapsed{
display: none;
}

Sekarang kita akan memperbaiki beberapa bug yang mungkin telah Anda lihat saat kita mendrag panel header lebih dari tinggi layar maka panel header akan overflow dan tidak nampak dilayar, untuk mengatasinya kita perlu menambahkan statement if saat user mendrag header dengan mengecek apakah posisi sumbu y saat ini kurang dari ukuran saat SlidingUpPanel pada posisi terbuka dan apakah posisi sumbu y saat ini lebih dari 0. Tambahkan 2 baris statement if berikut pada fungsi update di file sliding-up-panel.js tepat sebelum this.slidingPanel.style.transform = `translateY(${to}px)`;

//prevent the header to overflow the screen height when dragging
if(to < this.expandedY) to = this.expandedY;
if(to > 0) to = 0;

Selanjutnya masih di file yang sama, ubah fungsi animateSlidingPanelIntoPosition menjadi seperti berikut.
animateSlidePanelIntoPosition (target) {
if(!target){
return;
}
// create new function variable to excecute when the transition has ended
const onAnimationComplete = evt => {
const panel = evt.target;
panel.removeEventListener('transitionend', onAnimationComplete);
panel.style.transition = '';
};
// create and set panel to current slidingPanel
const panel = target;
//check if current state is expanded
if(this.isExpanded){
//add event listener when the transition has ended.
panel.addEventListener('transitionend', onAnimationComplete);
//set the panel transition to transform with duration 200 miliseconds
panel.style.transition = `transform 200ms`;
//set the panel transform to position when it's in expanded state
panel.style.transform = `translateY(${this.expandedY}px)`;
//add class expanded to panel header
this.panelHeader.setAttribute('class','expanded');
}else{
//add event listener when the transition has ended.
panel.addEventListener('transitionend', onAnimationComplete);
//set the panel transition to transform with duration 200 miliseconds
panel.style.transition = `transform 200ms`;
//set the panel transform to position when it's not in expanded state
panel.style.transform = `translateY(0px)`;
//remove class attribute from panel header
this.panelHeader.removeAttribute('class')
}
// user has finish dragging the header, set target to null
if(!this.draggingHeader)
this.target = null;
}

Selanjutnya kita akan menampilkan preloader saat playlist masih kosong dan menyembunyikannya saat playlist telah terisi. Disini kita juga akan memberikan sedikit efek fade in dan slide.
Tambahkan tag div dengan nama class preloader tepat setelah tag audio.


Sekarang ubah css .playlist ul li serta tambahkan .playlist.loading ul li dan .preloader dalam file player.css menjadi seperti berikut.
.preloader{
position: absolute;
width:46px;
height:46px;
top:calc(50% - 23px);
left:calc(50% - 23px);
background-image: url(../assets/img/ajax-loader.gif);
}
.playlist ul li{
display: block;
border-bottom: 1px solid black;
transform: translate3d(0,0,0);
opacity:1;
}
.playlist.loading ul li{
transform: translate3d(100%,0,0);
opacity:0;
}
Selanjutnya buat variabel baru pada fungsi construct untuk menyimpan element preloader dan ubah fungsi loadPlaylistMetadata dan getPlaylist pada file player.js menjadi seperti berikut.
this.preloader = document.querySelector('.preloader');
getPlaylist(){
var self = this;
var xhr = new XMLHttpRequest();
xhr.onload = function(e){
e.preventDefault();
if(xhr.status == 200 || xhr.status == 409){
var data = JSON.parse(xhr.response.match(/\[.*\]/ig, "")[0]);
data.forEach(function(item,index){
self.loadPlaylistMetadata(item,index,data.length);
});
self.songs = Array.from(document.querySelectorAll('.song a'))
}else{
console.log('cant get playlist, error with status code ' + xhr.status);
}
}
xhr.open('get', '\songlist', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send();
}
loadPlaylistMetadata(path,index,length){
var self = this;
// create new li element for the playlist item and set the attribute
var li = document.createElement('li');
li.setAttribute('class','song');
li.setAttribute('data-index',index);

// create new link element and set the href attribute to the file path
var a = document.createElement('a');
a.setAttribute('href',path);

// create new image element
var img = document.createElement('img');
img.className = 'cover';
img.style.cssFloat = 'left';

//create new container for title and artist metadata
var meta = document.createElement('div');
meta.className = 'metatag playlist';

//create new span element to set title from the file metadata
var title = document.createElement('span');
title.className = 'title';
title.style.whiteSpace = 'nowrap';

//create new span element to set artist name from the file metadata
var artist = document.createElement('span');
artist.className = 'artist';
//insert link/anchor element to li element
li.appendChild(a);
//insert img element to link/anchor element
a.appendChild(img);
//insert meta container to the link/anchor element
a.appendChild(meta);
/* create new p element and insert title and artist to it then append it to meta container,
* this element is necessary if we want the title or artist to
* be marqueed if the width is more than container width.*/
var p = document.createElement('p').appendChild(title);
meta.appendChild(p);
p = document.createElement('p').appendChild(artist);
meta.appendChild(p);
// listen to link click event
a.onclick = function(e){
e.preventDefault();
self.player.setAttribute('src',path);
self.songChanged(self.currentSong,li.getAttribute('data-index'));
self.currentSong = parseInt(li.getAttribute('data-index'));
self.playPauseBtn[0].children[0].click();
};
//append li element to playlist
this.playlist.children[0].appendChild(li);
// read meta data from the file using jsmediatags
jsmediatags.read(path, {
onSuccess: function(tag) {
var url = path;
var filename = url.split('/');
filename = filename[filename.length-1];
if(tag.tags.picture != undefined){
var base64String = "";
for (var i = 0; i < tag.tags.picture.data.length; i++) {
base64String += String.fromCharCode(tag.tags.picture.data[i]);
}
img.setAttribute('src',"data:"+ tag.tags.picture.format +";base64," + window.btoa(base64String));
}else{
img.setAttribute('src',"assets/img/albumart_mp_unknown.png");
}
// if the artist name in metadata is undefined or null, set it to unknown.
artist.innerHTML = tag.tags.artist || 'unknown';
// if the title in metadata is undefined or null, use filename instead.
title.innerHTML = tag.tags.title || filename;

// setup marquee animation
self.setupMarqueeAnimation(titles[i],artists[i]);

if(index == length - 1){
//hide the preloader
self.preloader.style.display = 'none';
//get all li element in playlist
let list = self.playlist.querySelectorAll('li');
list.forEach(function(item,index){
//add transition with diffrent delay for each item in list depend on item index/position in the list
item.style.transition = `transform 300ms ease-in ${index*0.2}s, opacity 300ms ease-in ${index*0.2}s`;
});
//change playlist class name, this will remove loading class
self.playlist.setAttribute('class','playlist');
}
},
onError: function(error) {
console.log(error);
}
});
}
Terakhir tambahkan class loading pada playlist di dalam file index.html menjadi seperti berikut.



    Untuk file preloader Anda dapat menggunakan gambar berikut dan menyimpannya di folder assets > img.



    Mungkin sampai disini saja pada postingan terakhir dalam topik Membuat SlidingUpPanel Dengan HTML,CSS Dan Javscript ini, jika terdapat pertanyaan dapat menggunakan kotak komentar dibawah.

    Tuesday, October 11, 2016

    October 11, 2016

    Membuat SlidingUpPanel Dengan HTML,CSS Dan Javascript Bagian 3


    Pada postingan sebelumnya tentang Membuat SlidingUpPanel Dengan HTML, CSS Dan Javascript Bagian 2 kita telah selesai SlidingUpPanel, di postingan kali ini kita akan membuat javascript untuk memainkan lagu dari yang disimpan dalam folder songs.

    Buatlah file javascript baru di dalam folder proyek Anda beri nama player.js. Seperti sebelumnya ssaat membuat sliding-up-panel.js buatlah class MusicPlayer pada file tersebut kemudian tambahkan constructor pada kelas MusicPlayer dan inisialisasikan variable yang akan digunakan.
    'use strict';
    class MusicPlayer{
    constructor(){
    this.player = document.querySelector('audio');
    this.playlist = document.querySelector('.playlist');
    this.playPauseBtn = Array.from(document.querySelectorAll('.play-btn'));
    this.nextBtn = document.querySelector('.next-btn');
    this.prevBtn = document.querySelector('.prev-btn');

    this.songs = Array.from(document.querySelectorAll('.song a'));
    this.currentSong = 0;

    this.onPlayPause = this.onPlayPause.bind(this);
    this.onNextClick = this.onNextClick.bind(this);
    this.onPreviousClick = this.onPreviousClick.bind(this);
    this.onProgress = this.onProgress.bind(this);
    this.onMetadataLoaded = this.onMetadataLoaded.bind(this);
    this.onSongEnded = this.onSongEnded.bind(this);
    this.songChanged = this.songChanged;
    this.setupMarqueeAnimation = this.setupMarqueeAnimation.bind(this);
    this.addEventListeners();
    this.initPlaylist();

    }
    }
    window.addEventListener('load',() => new MusicPlayer());

    Sekarang buat fungsi untuk menginisialisasikan daftar putar dengan melakukan XMLHttpRequest ke sisi server dan menerima semua nama file yang ada dalam folder songs.
    initPlaylist(){
    this.getPlaylist();
    }
    getPlaylist(){
    var self = this;
    return new Promise(function(resolve,reject){
    var xhr = new XMLHttpRequest();
    xhr.onload = function(e){
    e.preventDefault();
    if(xhr.status == 200 || xhr.status == 409){
    //parse the response to JSON Array
    var data = JSON.parse(xhr.response.match(/\[.*\]/ig, "")[0]);
    // loopping through all item in array, where each item contain link to the file.
    data.forEach(function(item,index){
    // load metadata from the file
    self.loadPlaylistMetadata(item,index);
    });
    resolve(data);
    }else{
    reject('cant get paylist');
    }
    }
    // open XMLHttpRequest with GET method
    xhr.open('get', '\songlist', true);
    // set header Content-Type to JSON
    xhr.setRequestHeader('Content-Type', 'application/json');
    // send the request to server
    xhr.send();
    });
    }
    loadPlaylistMetadata(path,index){
    self =this;
    // create new li element for the playlist item and set the attribute
    var li = document.createElement('li');
    li.setAttribute('class','song');
    li.setAttribute('data-index',index);

    // create new link element and set the href attribute to the file path
    var a = document.createElement('a');
    a.setAttribute('href',path);

    // create new image element
    var img = document.createElement('img');
    img.className = 'cover';
    img.style.cssFloat = 'left';

    //create new container for title and artist metadata
    var meta = document.createElement('div');
    meta.className = 'metatag playlist';

    //create new span element to set title from the file metadata
    var title = document.createElement('span');
    title.className = 'title';
    title.style.whiteSpace = 'nowrap';

    //create new span element to set artist name from the file metadata
    var artist = document.createElement('span');
    artist.className = 'artist';
    //insert link/anchor element to li element
    li.appendChild(a);
    //insert img element to link/anchor element
    a.appendChild(img);
    //insert meta container to the link/anchor element
    a.appendChild(meta);
    /* create new p element and insert title and artist to it then append it to meta container,
    * this element is necessary if we want the title or artist to
    * be marqueed if the width is more than container width.*/
    var p = document.createElement('p').appendChild(title);
    meta.appendChild(p);
    p = document.createElement('p').appendChild(artist);
    meta.appendChild(p);
    // listen to link click event
    a.onclick = function(e){
    e.preventDefault();
    self.player.setAttribute('src',link);
    self.songChanged(self.currentSong,li.getAttribute('data-index'));
    self.currentSong = parseInt(li.getAttribute('data-index'));
    self.playPauseBtn[0].children[0].click();
    };
    //append li element to playlist
    this.playlist.children[0].appendChild(li);
    // read meta data from the file using jsmediatags
    jsmediatags.read(path, {
    onSuccess: function(tag) {
    var url = path;
    var filename = url.split('/');
    filename = filename[filename.length-1];
    if(tag.tags.picture != undefined){
    var base64String = "";
    for (var i = 0; i < tag.tags.picture.data.length; i++) {
    base64String += String.fromCharCode(tag.tags.picture.data[i]);
    }
    img.setAttribute('src',"data:"+ tag.tags.picture.format +";base64," + window.btoa(base64String));
    }else{
    img.setAttribute('src',"assets/img/albumart_mp_unknown.png");
    }
    // if the artist name in metadata is undefined or null, set it to unknown.
    artist.innerHTML = tag.tags.artist || 'unknown';
    // if the title in metadata is undefined or null, use filename instead.
    title.innerHTML = tag.tags.title || filename;

    // setup marquee animation
    self.setupMarqueeAnimation(titles[i],artists[i]);

    },
    onError: function(error) {
    console.log(error);
    }
    });
    }
    Buatlah fungsi baru untuk menambahkan animasi marquee pada title/artist jik lebarnya melebihi container/parent.
    setupMarqueeAnimation(title,artist){
    if(title.offsetWidth > parseInt(title.parentNode.style.width.replace('px',''))){
    title.className += ' marquee-title';
    }else{
    title.style.willChange = 'initial';
    title.className = 'title';
    }
    if(artist.offsetWidth > parseInt(artist.parentNode.style.width.replace('px',''))){
    artist.className += ' marquee-artist';
    }else{
    artist.className = 'artist';
    }
    }
    Setelah itu buat fungsi untuk menambahkan event listener yang dibutuhkan.
    addEventListeners(){
    this.player.ontimeupdate = this.onProgress;
    this.player.onended = this.onSongEnded;
    this.player.onloadedmetadata = this.onMetadataLoaded;
    for(var i in this.playPauseBtn){
    this.playPauseBtn[i].addEventListener('click',this.onPlayPause);
    }
    this.nextBtn.addEventListener('click',this.onNextClick);
    this.prevBtn.addEventListener('click',this.onPreviousClick);
    }
    Sekarang buat fungsi-fungsi yang digunakan di event listener diatas.
    onSongEnded(e){
    this.moveToNext();
    }
    onNextClick(e){
    this.moveToNext();
    e.preventDefault();
    }
    onPreviousClick(e){
    this.moveToPrevious();
    e.preventDefault();
    }
    onPlayPause(e){
    if(this.player.getAttribute('src') == ''){
    this.player.setAttribute('src',this.songs[0].getAttribute('href'));
    this.currentSong = 0;
    this.songChanged(null,0);
    }
    if(this.player.paused){
    this.player.play().then().catch(function(error){
    console.log(error);
    });
    for(var i in this.playPauseBtn){
    this.playPauseBtn[i].children[0].setAttribute('src','assets/icons/pause-btn.svg');
    this.playPauseBtn[i].setAttribute('state','play');
    }
    }else{
    try{
    this.player.pause();
    for(var i in this.playPauseBtn){
    this.playPauseBtn[i].children[0].setAttribute('src','assets/icons/play-btn.svg');
    this.playPauseBtn[i].setAttribute('state','play');
    }
    }catch(error){
    console.log(error);
    }
    }
    e.preventDefault();
    }
    onMetadataLoaded(e){
    var self = this;
    var artists = document.querySelectorAll('.meta .artist');
    var titles = document.querySelectorAll('.meta .title');
    var covers = Array.from(document.querySelectorAll('img.coverart'));
    jsmediatags.read(e.target.src, {
    onSuccess: function(tag) {
    var url = e.target.src;
    var filename = url.split('/');
    filename = filename[filename.length-1]
    if(tag.tags.picture != undefined){
    for(var j in covers){
    var base64String = "";
    for (var i = 0; i < tag.tags.picture.data.length; i++) {
    base64String += String.fromCharCode(tag.tags.picture.data[i]);
    }
    covers[j].setAttribute('src',"data:"+ tag.tags.picture.format +";base64," + window.btoa(base64String));
    }
    }else{
    for(var j in covers){
    covers[j].setAttribute('src',"assets/img/albumart_mp_unknown.png");
    }
    }
    for(var i = 0; i < artists.length;i++){
    titles[i].parentNode.style.width = 200;
    artists[i].parentNode.style.width = 200;
    artists[i].innerHTML = tag.tags.artist;
    titles[i].innerHTML = tag.tags.title;

    // if the artist name in metadata is undefined or null, set it to unknown.
    artist.innerHTML = tag.tags.artist || 'unknown';
    // if the title in metadata is undefined or null, use filename instead.
    title.innerHTML = tag.tags.title || filename;

    // setup marquee animation
    self.setupMarqueeAnimation(titles[i],artists[i]);
    }

    },
    onError: function(error) {
    console.log(error);
    }
    });
    }

    moveToNext(){
    var next = this.currentSong + 1,link;
    if(next < this.songs.length){
    link = this.songs[next].getAttribute('href');
    this.songChanged(this.currentSong,next);
    this.currentSong = next;
    this.player.setAttribute('src',link);

    }else{
    link = this.songs[0].getAttribute('href');
    this.songChanged(this.currentSong,0);
    this.currentSong = 0;
    this.player.setAttribute('src',link);
    }
    this.player.load();
    this.player.play();
    }
    moveToPrevious(){
    var prev = this.currentSong - 1,link;
    if(prev >= 0){
    link = this.songs[prev].getAttribute('href');
    this.songChanged(this.currentSong,prev);
    this.currentSong = prev;
    this.player.setAttribute('src',link);

    }else{
    prev = this.songs.length - 1;
    var link = this.songs[prev].getAttribute('href');
    this.songChanged(this.currentSong,prev);
    this.currentSong = prev;
    this.player.setAttribute('src',link);
    }
    this.player.play();
    }
    Kemudian buat fungsi baru lagi untuk mengubah warna background dari item yang saat ini sedang dimainkan.
    songChanged(before,current){
    //if the song before the current one is not null, remove active class from that element
    if(before != null){
    this.songs[before].removeAttribute('class');
    }
    // set the current song item class in playlist to active
    this.songs[current].setAttribute('class','active');
    }
    Sampai disini pembuatan pemutar musiknya telah selesai, sekarang buka cmd/terminal kemudiang ketikkan perintah supervisor index.js kemudian buka browser dan ubah url menjadi http:/localhost:3000 untuk melihat hasilnya. Kurang lebih hasilnya menjadi akan seperti berikut.



    untuk postingan selanjutnya kita akan memperbaiki beberapa tampilan termasuk panel header yang akan kita buat berganti tampilan saat kita membuka panel. :)