Breaking

Showing posts with label HTML. Show all posts
Showing posts with label HTML. Show all posts

Saturday, May 5, 2018

May 05, 2018

Cara Menyortir Komentar Blogger dari yang Terbaru

Seperti yang kita tahu, komentar blogger pada umumnya menyortir komentar dari komentar lama yang posisinya di atas dan komentar baru yang posisinya paling bawah. Nah bagaimana jika posisi komentar terbaru itu dibalik? Tumpah? 😅 nggak lah... Posisi komentar diurutkan dari yang terbaru, jadi posisi komentar terbaru akan berada di atas komentar lama.

Cara Menyortir Komentar Blogger dari yang Terbaru


Bagaimana caranya? Caranya sangat mudah, silakan lakukan langkah mudah di bawah ini.
Selengkapnya »

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 »

Wednesday, January 25, 2017

January 25, 2017

Meta Tag Seo Friendly dan Valid HTML5

Meta Tag Seo Friendly dan Valid HTML5 - Kali ini saya akan menjawab pertanyaan yang pernah ditanyakan sobat blogger yaitu tentang cara mengisi kode xxxxx yang saya tambahkan pada template-template yang saya bagikan.

Meta Tag Seo Friendly dan Valid HTML5

Mungkin diantara sobat blogger masih ada yang belum faham dengan meta tag ini, baiklah di sini saya akan menjelaskan sedikit tentang meta tag pada template blogger.
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 »

Thursday, December 15, 2016

December 15, 2016

Cara Menyembunyikan atau Menampilkan Widget di Mobile Device

Seperti yang kita tahu sesuai dengan perkembangan zaman kini perangkat mobile sudah menjadi kebutuhan pokok setiap orang sebagai alat komunikasi yang memberikan banyak manfaat bagi kita semua.

Cara Menyembunyikan atau Menampilkan Widget di Mobile Device

Masih berhubungan dengan hal ini, setelah Algoritma Google Mobile Friendly diperbarui pada tanggal 21 April 2015 lalu. Banyak webmaster membuat situs yang Mobile Friendly dan juga responsive agar dapat diakses lebih cepat dan nyaman melalui perangkat mobile. Tentunya hal ini merupakan langkah positif dan sebagai pondasi awal dalam membangun sebuah website, untuk langkah selanjutnya tinggal bagaimana kita mengelola situs tersebut.
Selengkapnya »

Thursday, November 10, 2016

November 10, 2016

Membuat Custom Element Di HTML Menggunakan Javascript



Pada kesempatan kali ini saya akan membahas tentang bagaimana cara Membuat Custom Element HTML Menggunakan javascript. Biasanya banyak developer yang masih kurang puas akan fitur-fitur dari element yang ada di HTML, sehingga kebanyakan dari mereka lebih senang untuk membuat custom elementnya sendiri. Pada postingan kali ini saya akan mencoba membuat conditional element dimanan nantinya element akan menampilkan child element pada kondisi tertentu.

Sebelum memulai buatlah file baru dan beri nama index.html kemudian copy template berikut.
<html>
<head>
<meta name="author" content="Muhammad Sayuti">
<title>Custom Elements</title>
</head>
<body>
<input type="checkbox" id="checkbox">
<dev-if if="checkbox is checked">
Checkbox is checked
</dev-if>
<script src="index.js"></script>
</body>
</html>

Sekarang buat file javascript baru dan beri nama index.js. Untuk membuat custom element kita akan menggunakan fungsi customElements untuk memberitahu browser tentang adanya tag baru yang kita buat. pada file ini buatlah class baru kemudian extends class tersebut dengan class DOM level 2 yaitu HTMLElement.
class DevIf extends HTMLElement{
constructor(){
// If you define a ctor, always call super() first!
// This is specific to CE and required by the spec.
super();
}
}

Jika Anda membuat suatu class dengan melakukan extends pada class yang ada pada DOM seperti HTMLElement, HTMLSelectElement dan sebagainya, sangat disarankan untuk memanggil super() pada bagian constructor() terlebih dahulu. Pada DOM level 2 kita dapat menggunakan beberapa callback sesuai keperluan yang akan kita gunakan pada custom element yang kita buat. Berikut adalah beberapa callback yang dapat Anda gunakan.

  • createdCallback() (Mozilla) : Biasanya callback ini akan dipanggil/dieksekusi saat element Anda teregister/terdaftar di DOM.
  • attachedCallback (Mozilla) atau connectedCallback() (Chrome) :
    Biasanya callback ini akan dipanggil /dieksekusi saat element Anda dimasukkan ke dalam DOM.
  • detachedCallback() (Mozilla) atau disconnectedCallback() (Chrome):
    Biasanya callback ini akan dipanggil /dieksekusi saat element Anda dihapus dari DOM.
  • attributeChangedCallback() (Mozilla & Chrome) :
    Biasanya callback ini akan dipanggil /dieksekusi saat ada perubahan pada attribute dari element yang Anda buat.
Di kasus ini saya menggunakan Chrome browser jadi kita akan fokus ke callback yang ada di Chrome browser.
Sekarang tambahkan 2 callback yaitu connectedCallback() dan attributeChangedCallback().
class DevIf extends HTMLElement{
constructor(){
// If you define a constructor, always call super() first!
// This is specific to CE and required by the specification.
super();
}
connectedCallback(){
//get value from if attribute and define new if variable on the current class
this.if = this.getAttribute('if');
}
attributeChangedCallback(name, oldValue, newValue){
if (name !== 'if') {
return;
}

this.if = newValue;
}
}

Pada script diatas saya memberikan value pada variable if dengan mengambil attribute if pada element dan mengubah value if jika terdapat perubahan pada attribute if di fungsi attributeChangedCallback(). Sekarang kita akan membuat getter and setter untuk variabel if, tambahkan script berikut kedalam class.
get if(){
return this.if;
}
set if(_condition){
if(!_condition){
return;
}

}
Selanjutnya kita akan membuat fungsi baru untuk melakukan parsing dan mengecek kondisi yang diberikan pada attribut if, buatlah fungsi baru checkCondition()
checkCondition(condition){
let parsed = condition.split(' ');
switch(parsed[1]){
case 'is':
//get element by id provided in first parameter
let el = document.querySelector(`#${parsed[0]}`);
//if element not found, warn the user and stop execution.
if(el == null){
console.warn('cannot find element with id',parsed[0]);
return;
}
// get the element type
let type = this.getElementType(el);
// check default state in our element for current condition
this.checkDefault(el);
// add listener to listen change on our element
this.addListener(el,type);
break;
}
}
Karena disini hanya demo jadi saya hanya akan memberikan 1 kondisi, jika Anda ingin mengembangkannya dan menambahkan kondisi lain Anda dapat mendapatkan source codenya melalui github. Pada script diatas saya melakukan split pada value yang diberikan di attribut if. variabel parsed akan menjadi array dan pada index 0 akan kita gunakan sebagai acuan untuk mencari element berdasarkan id, kemudian pada index 1 merupakan kondisinya, disini hanya ada kondisi "is", kemudian pada index 2 adalah kondisi apa yang akan digunakan. Pada contoh ini saya menggunakan element checkbox sebagai parameter pertama, is untuk parameter kedua dan checked pada parameter ketiga. Disini saya tidak melakukan pengecekan pada parameter ketiga karena jika kita menggunakan checkbox maka yang dicek sudah pasti apakah checkbox tersebut di check atau tidak.
Sekarang buat fungsi baru untuk mendapatkan tipe element yang diberikan pada parameter pertama jika element ditemukan.
getElementType(target){
if(target.nodeName === 'input'){
return target.getAttribute('type');
}else{
return target.nodeName.toLowerCase();
}
}
Setelah itu buat fungsi baru untuk menentukan apa yang terjadi pada element berdasarkan kondisi saat ini.
checkDefault(target,type){
if(type === 'checkbox'){
if(target.checked || target.hasAttribute('checked')){
this.style.display = 'initial';
}else{
this.style.display = 'none';
}
}
}
Sekarang buat fungsi baru lagi untuk menambahkan listener saat ada perubahan yang terjadi pada element dan memanggil fungsi checkDefault().
addListener(target,type){
let self = this;
target.addEventListener('change',function(){
let t = self.getElementType(this);
self.checkDefault(this,t);
});
}
Untuk langkah terakhir kita hanya perlu mendefinisikan element yang akan kita buat dengan menggunakan fungsi customElements() yang ada di window. parameter pertama merupakan nama tag yang kita berikan sedangkan yang kedua adalah class yang baru saja kita buat. Letakkan script berikut di baris paling akhir dalam file javascript Anda.
cusomElements.define('dev-if',DevIf);

Sekarang cek hasilnya pada Chrome browser Anda, element yang ada di dalam custom element yang kita buat hanya akan tampil saat checkbox di check. berikut hasil akhirnya.
See the Pen conditional-element by Muhammad Sayuti (@ekoputrapratama) on CodePen.


Mungkin itu saja yang dapat saya jelaskan pada postingan kali ini tentang bagaimana cara Membuat Custom Element HTML Menggunakan Javascript.
Semoga bermanfaat...!!

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. :)

    Friday, October 7, 2016

    October 07, 2016

    Membuat SlidingUpPanel Dengan HTML,CSS Dan Javascript Bagian 2


    Pada postingan sebelumnya tentang Membuat SlidingUpPanel Dengan HTML, CSS Dan Javascript Bagian 1 kita telah selesai membuat desain awal aplikasi, di postingan kali ini kita akan bermain dengan javascript untuk membuat SlidingUpPanel yang kita buat sebelumnya dapat bekerja sesuai apa yang kita inginkan.

    Pertama buatlah file javascript baru beri nama sliding-up-panel.js kemudian tuliskan "use strict";. Mode use strict ini berguna untuk menempatkan program atau fungsi dalam operasi konteks yang strict (ketat). konteks yang ketat ini mencegah tindakan-tindakan tertentu dan melempar lebih banyak exception/pengecualian.

    Disini kita akan membuat kelas baru dengan nama SlidingUpPanel dan memuat kelas pada event window onload.
    "use strict";
    class SlidingUpPanel{
    constructor(){

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

    Untuk mengetes apakah kelas yang kita buat bekerja kita akan menulis ke console, menjadi seperti berikut.
    "use strict";
    class SlidingUpPanel{
    constructor(){
    console.log('Hello World!')
    }
    }
    window.addEventListener('load',() => new SlidingUpPanel());


    Sekarang buka cmd/terminal di dalam folder proyek Anda kemudian ketikan perintah berikut dan buka browser ketikkan url http://locahost:3000.
    supervisor index.js
    Kemudian tekan CTRL + SHIFT + I untuk membuka panel alat pengembang dan melihat hasilnya di bagian console.


    Jika Anda melihat tulisan "Hello World!" di console seperti yang terlihat pada gambar diatas, artinya kelas SlidingUpPanel yang kita buat bekerja. Sekarang kita perlu menginisialisasikan variabel yang dibutuhkan didalam fungsi constructor() dan mengganti console.log yang kita buat sebelumnya.
    class SlidingUpPanel{
    constructor(){
    this.slidingPanel = document.querySelector('#sliding-up-panel');
    this.panelHeader = document.querySelector('#sliding-up-panel-header');
    this.panelBody = document.querySelector('#sliding-up-panel-body');
    this.mainContent = document.body.children[0];
    this.mainContent.style.marginBottom = `${this.panelHeader.offsetHeight}px`;
    this.slidingPanel.style.height = window.innerHeight;
    this.slidingPanel.style.top = window.innerHeight - this.panelHeader.offsetHeight;

    this.target = null;
    this.targetBCR = null;
    this.panelBCR = this.slidingPanel.getBoundingClientRect();

    this.startY = 0;
    this.currentY = 0;
    this.screenY = 0;
    this.targetY = 0;
    this.collapsedY = this.panelBCR.height - this.panelHeader.offsetHeight;
    this.expandedY = -this.panelBCR.height + this.panelHeader.offsetHeight;

    this.draggingHeader = false;
    this.isExpanded = false;
    }
    }

    Sekarang kita akan membuat beberapa fungsi baru untuk mendengarkan event yang kita butuhkan diantaranya adalah :
    • Event mousedown
    • Event mousemove
    • Event mouseup
    • Event touchstart
    • Event touchmove
    • Event touchend
    • Event Window Resize
    Event touch digunakan agar nantinya support untuk perangkat layar sentuh. Namun pada dasarnya isi dari fungsi touch dan mouse sama, sedangkan event Window resize digunakan untuk mengubah posisi top pada SlidingUpPanel saat jendela browser berubah ukuran.
    Sekarang buatlah fungsi baru seperti berikut di dalam class SlidingUpPanel.
    addEventListeners(){
    document.addEventListener('touchstart', this.onStart);
    document.addEventListener('touchmove', this.onMove);
    document.addEventListener('touchend', this.onEnd);

    const self = this;
    window.addEventListener('resize',function(e){
    self.slidingPanel.style.top = window.innerHeight - self.panelHeader.offsetHeight;
    self.expandedY = -window.innerHeight + self.panelHeader.offsetHeight;
    self.animateSlidePanelIntoPosition(self.slidingPanel);
    e.preventDefault();
    });

    document.addEventListener('mousedown', this.onStart);
    document.addEventListener('mousemove', this.onMove);
    document.addEventListener('mouseup', this.onEnd);
    }
    Sekarang kita buat 3 fungsi yang akan digunakaan yaitu onStart, onMove dan onEnd.
    onStart (evt) {
    if (this.target)
    return;

    //if current target id is not sliding-up-panel-header, don't execute the next code.
    if (evt.target.id != 'sliding-up-panel-header')
    return;
    //set target to current touched/clicked target
    this.target = evt.target;
    //set targetBCR to current touched/clicked target Bounding Client Rectangle
    this.targetBCR = this.target.getBoundingClientRect();
    //set startY to current touched/clicked Y position on page
    this.startY = evt.pageY || evt.touches[0].pageY;
    //set currentY equal to startY
    this.currentY = this.startY;

    //set draggingHeader to true
    this.draggingHeader = true;
    /* because we will change the panel position based on Y axis using translateY
    * set property will-change to transform */
    this.slidingPanel.style.willChange = 'transform';

    evt.preventDefault();
    }
    onMove(evt){
    if (!this.target)
    return;
    //set currentY to current touched/clicked Y position on page when we drag the header
    this.currentY = evt.pageY || evt.touches[0].pageY;
    }
    onEnd(evt){
    if (!this.target)
    return;

    this.targetY = 0;
    //create new variable screenY and set current header panel position to it.
    let screenY = this.currentY - this.startY;
    /* threshold variable is used to check if user has drag more then 1/4 of panel height size
    * you can change this to half or whatever you want the slider to be expanded or not
    * when user drag more then threshold */
    const threshold = this.panelBCR.height * 0.25;
    if (Math.abs(screenY) > threshold) {
    /* set targetY to panel bounding client rectangle height subtract by panel header height if screenY is
    * positive value and set to negative value of panel bounding client rectangle height add by
    * panel header height */
    this.targetY = (screenY > 0) ?
    (this.panelBCR.height - this.panelHeader.offsetHeight) :
    (-this.panelBCR.height + this.panelHeader.offsetHeight);
    }
    //set draggingHeader to false
    this.draggingHeader = false;
    }
    Setelah semua fungsi telah dibuat sekarang kita akan melakukan bind pada fungsi yang kita buat tadi ke variabel dalam konteks kelas SlidingUpPanel. Tambahkan script berikut ke dalam fungsi constructor.
    this.onStart = this.onStart.bind(this);
    this.onMove = this.onMove.bind(this);
    this.onEnd = this.onEnd.bind(this);
    this.addEventListeners();
    Sekarang kita akan masuk ke bagian animasi dimana kita menggerakan sliding panel berdasarkan sumbu y saat kita melakukan drag pada panel header.
    Untuk menganimasikan panel disini saya menggunakan requestAnimationFrame agar browser dapat megoptimasikan animasi sehingga animasi menjadi lebih halus saat objek bergerak. buatlah fungsi baru seperti berikut.
    update () {
    requestAnimationFrame(this.update);

    if (!this.target)
    return;

    if (this.draggingHeader) {
    this.screenY = this.currentY - this.startY;
    } else {
    this.screenY += (this.targetY - this.screenY) / 4;
    }
    /* create new variable to and set the value to where we want the sliding panel to move based on Y axis.
    * if current panel state is expanded then we move it to expandedY add by screenY
    * if not then use screenY instead */
    let to = (this.isExpanded) ? (this.expandedY + this.screenY) : this.screenY;
    this.slidingPanel.style.transform = `translateY(${to}px)`;

    // Check if user still dragging the header or not, if true don't execute the next code.
    if (this.draggingHeader)
    return;
    const panel = this.target.parentNode;
    const isNearlyAtStart = (!this.isExpanded)?(Math.abs(this.screenY) < Math.abs(panel.offsetHeight/4)):(Math.abs(this.screenY) > Math.abs(panel.offsetHeight/4));
    const isNearlyExpanded = (!this.isExpanded)?(Math.abs(this.screenY) > Math.abs(panel.offsetHeight/4)):(Math.abs(this.screenY) < Math.abs(panel.offsetHeight/4));
    // If the panel is nearly expanded and current state is not expanded.
    if (isNearlyExpanded && !this.isExpanded) {
    // Bail if there's no target or it's not attached to a parent anymore.
    if (!this.target || !this.target.parentNode)
    return;
    // set isExpanded to true
    this.isExpanded = true;
    } else if (isNearlyAtStart) {
    // set isExpanded to false
    this.isExpanded = false;
    }
    // animate the panel to the position where we want it based on its state expanded or not.
    this.animateSlidePanelIntoPosition(this.target.parentNode);
    }
    Selanjutnya tambahkan script berikut ke dalam fungsi construct.
    this.update = this.update.bind(this);
    requestAnimationFrame(this.update);
    Sekarang kita akan membuat fungsi baru untuk menggerakkan panel pada posisinya berdasarkan keadaan panel yang disimpan dalam variabel isExpanded.
    animateSlidePanelIntoPosition (target) {
    if(!target){
    return;
    }
    // create new function variable to excecute when the transition has ended
    const onAnimationComplete = evt => {
    const panel = evt.target;
    //remove current listener from the panel
    panel.removeEventListener('transitionend', onAnimationComplete);
    panel.style.transition = '';

    };
    // create and set panel to current slidingPanel
    const panel = this.slidingPanel;
    //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)`;
    }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)`;
    }
    // animation has ended, set target to null
    this.target = null;
    }
    Sekarang buka kembali browser Anda kemudian lihat hasilnya di http://localhost:3000, kurang lebih hasilnya akan seperti berikut. Sampai disini Anda telah berhasil membuat SlidingUpPanel Layout, untuk posting selanjutnya kita akan mulai membuat javascript untuk pemutar musiknya. So stay Tuned ;)!! Untuk gambar-gambar yang digunakan dalam tutorial ini dapat di download disini.

    Tuesday, October 4, 2016

    October 04, 2016

    Membuat SlidingUpPanel Dengan HTML,CSS Dan Javascript Bagian 1


    Pada kesempatan kali ini saya akan membahas tentang bagaimana Membuat SlidingUpPanel Dengan HTML, CSS dan javascript. Biasanya SlidingUpPanel ini banyak digunakan di aplikasi-aplikasi pemutar musik di Android. Namun disini kita akan mencoba membuatnya menggunakan HTML, CSS dan javascript. Kita akan membuat pemutar musik sederhana dengan SlidingUpPanel yang hampir mirip dengan Google Play Music.

    Sebelum memulai ada baiknya Anda menginstall Nodejs terlebih dahulu jika di Komputer/Laptop Anda belum terinstall Nodejs. Nodejs merupakan teknologi javascript sisi server. Anda dapat mendownload Nodejs di https://nodejs.org.
    Setelah mengistall nodejs Anda perlu menginisialisasikan folder proyek Anda terlebih dahulu, dan mengisi rincian tentang proyek Anda. Pada folder proyek Anda buka terminal/cmd kemudian ketikkan perintah berikut.
    npm init
    Setelah itu isi semua rincian yang ditanyakan.

    Selanjutnya Anda peru menginstall beberapa modul yang akan kita gunakan diantaranya adalah:
    1. express
    2. jsmediatags
    3. fs
    4. path
    5. supervisor
    Untuk menginstall modul-modul diatas Anda dapat menggunakan cmd/terminal dengan mengetikkan perintah sebagai berikut :


    Mac/Linux :

    sudo npm install -g [nama-module]


    Windows :
    npm install -g [nama-module]

    Ubah [nama-modul] menjadi nama modul yang ingin diinstall, contoh saya ingin menginstall modul express pada laptop yang memiliki sistem operasi Windows maka saya mengetikan perintah berikut :
    npm install -g express.

    Sebelum membuat file-file untuk sisi klien kita perlu membuat minimal 1 file javascript untuk digunakan di sisi server. Buatlah file baru dan beri nama index.js, kemudian tuliskan script berikut.
    'use strict';
    var fs = require('fs'),
    express = require('express'),
    app = express(),
    path = require('path');

    var data = [];
    readFiles('songs/', function(filename, content) {
    data.push('http://localhost:3000/songs/' +filename);
    }, function(err) {
    throw err;
    });

    function readFiles(dirname, onFileContent, onError) {
    fs.readdir(dirname, function(err, filenames) {
    if (err) {
    onError(err);
    return;
    }
    filenames.forEach(function(filename) {
    fs.readFile(dirname + filename, 'utf-8', function(err, content) {
    if (err) {
    onError(err);
    return;
    }
    onFileContent(filename, content);
    });
    });
    });
    }
    app.use(function (req, res, next) {
    var filename = req.url || "index.html";
    var ext = path.extname(filename);
    var localPath = __dirname;
    var validExtensions = {
    ".html" : "text/html",
    ".js": "application/javascript",
    ".json": "application/json",
    ".css": "text/css",
    ".txt": "text/plain",
    ".jpg": "image/jpeg",
    ".gif": "image/gif",
    ".png": "image/png",
    ".ico": "image/png",
    ".svg": "image/svg+xml",
    ".webm": "audio/webm",
    ".aac": "audio/aac",
    ".ogg": "audio/ogg",
    ".wav": "audio/wav",
    ".mp3": "audio/mpeg",
    ".mp4": "audio/mp4",
    ".m4a": "audio/mp4"
    };
    var isValidExt = validExtensions[ext];

    if (isValidExt) {
    localPath += filename;

    fs.exists(localPath, function(exists) {
    if(exists) {
    console.log("Serving file: " + localPath);
    getFile(localPath, res, validExtensions[ext]);
    } else {
    console.log("File not found: " + localPath);

    if(ext === 'text/html'){
    getFile(__dirname + '/404.html', res, validExtensions[ext]);
    }
    }
    });

    } else if(req.url == "/songlist"){
    res.setHeader("Content-Type", 'application/json');
    res.statusCode = 200;
    res.end(JSON.stringify(data));
    }else {
    console.log("Invalid file extension detected: " + ext);
    getFile(__dirname + '/index.html', res, 'text/html');
    }
    });
    app.listen(3000);
    function getFile(localPath, res, mimeType) {
    fs.readFile(localPath, function(err, contents) {
    if(!err) {
    res.setHeader("Content-Length", contents.length);
    res.setHeader("Content-Type", mimeType);
    res.statusCode = 200;
    res.end(contents);
    } else {
    res.writeHead(500);
    res.end();
    }
    });
    }


    Pada script diatas saya menggunakan express untuk membuat http server pada port 3000, kemudian terdapat fungsi app.use() yang digunakan untuk mengirim resource ke sisi klien berdasarkan url yang diminta, disana saya hanya melakukan pengecekan apakah file resource yg diminta valid atau tidak dan apakah file tersebut tersedia di sisi server.

    Sekarang kita akan mulai membuat desainnya, pertama-tama buatlah file html baru beri nama index.html kemudian buatlah template HTML seperti berikut.
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="author" content="Muhammad Sayuti" />
    <meta name="viewport" content="width=device-width,minimum-scale=1">
    <meta name="theme-color" content="#EA2663">
    <title>Sliding Up Panel</title>
    </head>
    <body>
    <div class="playlist">
    <ul>
    </ul>
    </div>
    <div id="sliding-up-panel">
    <div id="sliding-up-panel-header">
    <img src="assets/img/albumart_mp_unknown.png" class="coverart header" />
    <div class="meta header">
    <span class="artist"></span>
    <span class="title"></span>
    </div>
    <div class="player-control header">
    <a href="#" id="prev-btn">Prev</a>
    <a href="#" id="play-btn" state="pause"><img src="icons/play-button.svg" style="width:25px;height:25px;"/></a>
    <a href="#" id="next-btn">Next</a>
    </div>
    </div>
    <div id="sliding-up-panel-body">
    <img src="assets/img/albumart_mp_unknown.png" class="coverart content" />
    <div class="meta content">
    <span class="artist"></span>
    <span class="title"></span>
    </div>
    <div class="player-control content">
    <a href="#" id="prev-btn">Prev</a>
    <a href="#" id="play-btn" state="pause"><img src="icons/play-button.svg" style="width:25px;height:25px;"/></a>
    <a href="#" id="next-btn">Next</a>
    </div>
    </div>
    </div>
    <audio id="player" src="" style="display:hidden;"></audio>

    </body>
    </html>
    Anda dapat menggunakan lagu yang Anda miliki dan menempatkannya di folder songs, pastikan nama file tidak ada spasi untuk menghindari error saat memainkan lagu, karena spasi akan di konversi secara otomatis menjadi karakter unicode sehingga nantinya akan muncul error bahwa file tidak ditemukan karena spasi pada nama file diubah ke karakter unicode.

    Pada template HTML diatas tag audio saya beri property style dimana value dari display adalah hidden karena nantinya kita tidak menggunakan kontrol default dari element audio,namun menggunakan beberapa link yang dapat Anda lihat pada element div dengan nama class player-control. Disini css saya bagi menjadi 2 file, 1 yang dibuat untuk mengatur tampilan SlidingUpPanel dan yang kedua untuk mengatur tampilan yang lain.
    Buat file baru dan beri nama sliding-up-panel.css kemudian isikan seperti berikut.
    #sliding-up-panel{
    display:block;
    position:fixed;
    top:0;
    left:0;
    right:0;
    bottom: 0;
    }
    #sliding-up-panel-header{
    background-color: #424242;
    box-sizing: border-box;
    position:relative;
    width: 100%;
    height: 64px;
    overflow: hidden;
    }
    #sliding-up-panel-body{
    background-color: #757575;
    overflow: auto;
    height: 100%;
    width: 100%;
    }

    Sekarang buat 1 file css lagi beri nama player.css, kemudian isikan seperti berikut.
    *{
    padding:0px;
    margin:0px;
    font-family:san-serif;
    font-size:24px;
    }
    html,body{
    background-color: #757575;
    }
    a{
    text-decoration: none;
    }
    .playlist{
    display: block;
    width:100%;
    }
    /* Playlist style */
    .playlist ul li{
    display: block;
    border-bottom: 1px solid black;

    }
    .playlist ul li a{
    height: 57px;
    display: block;
    color: white;
    }
    .playlist ul li a.active{
    background-color: rgba(0,0,0, 0.5);
    color: #42A5F5;
    }
    .playlist .metatag .title{
    font-size: 16px;
    white-space: nowrap;
    }
    .playlist .metatag.playlist{
    float:left;
    padding:10px;
    width: 87.3%;
    overflow: hidden;
    }
    .playlist .metatag .artist{
    font-size: 14px;
    white-space: nowrap;
    }
    .playlist .cover{
    height:100%;
    max-width:8%;
    }
    /* Player Control style */
    .player-control{
    display: flex;
    flex-basis: 33.3333333%;
    align-items: center;
    align-self: baseline;
    width:134px;
    }

    /* to prevent SidingUpPanel not moving when we drag the header
    * we need to set pointer-events to none.*/

    .player-control.header{
    pointer-events: none;
    height: 100%;
    padding: 0 0.5em;
    float: right;
    }

    .player-control.content{
    height: 64px;
    margin: 0 auto !important;
    pointer-events: none;
    }
    /* because it's a link with fake href set user-select to none and
    * retrieve all pointer-events */
    .player-control a{
    pointer-events: all;
    user-select: none;
    }
    .player-control img{
    margin: auto 0;
    width:100%;
    pointer-events: none;
    }
    .play-btn img{
    width: 50px;
    height: 50px;
    }
    .next-btn img{
    width: 40px;
    height: 40px;
    }
    .prev-btn img{
    width: 40px;
    height: 40px;
    }
    /* Meta style General*/
    .meta{
    pointer-events: none;
    color: #FFF;
    }
    .meta .title{
    font-size: 16px;
    white-space: nowrap;
    display: inline-block;
    position: relative;
    left:0px;
    }
    .meta .artist{
    font-size: 14px;
    white-space: nowrap;
    }
    .marquee-title{
    display: inline-block;
    transition: transform 20s linear infinite;
    animation: marquee2 20s linear infinite;
    }
    .marquee-artist{
    display: inline-block;
    transition: transform 20s linear infinite;
    animation: marquee 20s linear infinite;
    }
    /* Meta style for sliding-up-panel-header*/
    .meta.header{
    display: flex;
    flex-flow: row wrap;
    float:left;
    margin:15px;
    max-width: 200px;
    overflow: hidden;
    }

    /* Meta style for sliding-up-panel-body*/
    .meta.content{
    display: flex;
    flex-flow: row wrap;
    align-items: center;
    margin: 1.5em auto;
    max-width: 200px;
    overflow: hidden;
    text-align: center;
    }

    /* Coverart style*/
    img.coverart{
    display: hidden;
    }
    img.coverart.header[src]{
    float: left;
    pointer-events: none;
    height:100%;
    max-width: 70px;
    border: none;
    }
    img.coverart.content[src]{
    display: block;
    margin: 0.5em auto;
    height:50%;
    border: none;
    }



    /* Keyframes animation */
    @keyframes marquee {
    0% {
    transform:translateX(-25%);
    }
    25% {
    transform:translateX(-50%);
    }
    50% {
    transform:translateX(-25%);
    }
    75% {
    transform:translateX(0%);
    }
    100%{
    transform:translateX(-25%);
    }
    }
    @keyframes marquee2 {
    0% {
    transform:translateX(0%);
    }
    25% {
    transform:translateX(-25%);
    }
    50% {
    transform:translateX(-50%);
    }
    75% {
    transform:translateX(-25%);
    }
    100%{
    transform:translateX(0%);
    }
    }

    Sekarang desain awal sudah selesai, Anda dapat dapat menjalankan nodejs server dengan membuka cmd/terminal pada folder proyek Anda dan mengetikkan perintah supervisor index.js. Tampilan yang Anda lihat kurang lebih akan seperti berikut.


    Pada postingan selanjutnya kita akan mulai membuat file-file javascript sisi klien.

    Sunday, September 4, 2016

    September 04, 2016

    Membuat Efek Ripple Berbasis Material Design Menggunakan jQuery


    Pada kesempatan kali ini saya akan membahas tentang bagaimana cara membuat efek ripple seperti yang ada pada Google Material Design. Disini saya menggunakan jQuery untuk mempermudah dalam pembuatan efek ripple, versi yang saya gunakan adalah versi 1.9.1.

    Saya akan sedikit menjelaskan keseluruhan konsep yang akan digunakan dalam pembuatan efek ripple ini. Jadi ketika sebuah element HTML di klik kita akan menambahkan element baru dimana nantinya di dalam element baru ini terdapat element yang akan kita ingin beri efek. Element baru yang dibuat ini nantinya akan di berikan efek scale dengan warna background tertentu, dan ketika klik mouse selesai efek akan di fade-out(dipudarkan).

    Pertama-tama kita akan membuat element yang akan kita beri efek, buatlah file baru beri nama index.html.


    <html>
    <head>
    </head>
    <body>
    <h1>
    Ripple Click Effect</h1>
    <ul>
    <li><a class="ripple" href="#">Dashboard</a></li>
    <li><a class="ripple" href="#">My Account</a></li>
    <li><a class="ripple" href="#">Direct Messages</a></li>
    <li><a class="ripple" href="#">Chat Rooms</a></li>
    <li><a class="ripple" href="#">Settings</a></li>
    <li><a class="ripple" href="#">Logout</a></li>
    </ul>
    </body>
    </html>


    Sekarang kita akan membuat file CSS untuk mengubah tampilannya serta membuat keyframes untuk animasi ripple, buatlah file baru dan beri nama style.css.

    /*basic reset*/

    * {
    margin: 0;
    padding: 0;
    }

    body {
    background-size: cover;
    }

    h1 {
    font: normal 32px/32px Bitter;
    color: black;
    text-align: center;
    padding: 85px 100px;
    }


    /*nav styles*/

    ul {
    background: white;
    border-top: 6px solid hsl(180, 40%, 60%);
    width: 200px;
    margin: 0 auto;
    }

    ul li {
    list-style-type: none;
    /*relative positioning for list items along with overflow hidden to contain the overflowing ripple*/
    position: relative;
    overflow: hidden;
    }

    ul li a {
    font: normal 14px/28px Montserrat;
    color: hsl(180, 40%, 40%);
    display: block;
    padding: 10px 15px;
    text-decoration: none;
    cursor: pointer;
    /*since the links are dummy without href values*/
    /*prevent text selection*/
    user-select: none;
    /*static positioned elements appear behind absolutely positioned siblings(.ink in this case) hence we will make the links relatively positioned to bring them above .ink*/
    position: relative;
    }


    /*.ink styles - the elements which will create the ripple effect. The size and position of these elements will be set by the JS code. Initially these elements will be scaled down to 0% and later animated to large fading circles on user click.*/

    .ink {
    display: block;
    position: absolute;
    background: hsl(180, 40%, 80%);
    border-radius: 100%;
    transform: scale(0);
    -webkit-transform: scale(0);
    -moz-transform: scale(0);
    }

    .fade-out {
    transform: opacity(0);
    -webkit-transform: opacity(0);
    -moz-transform: opacity(0);
    }


    /* animation effect keyframes */

    .ink.animate {
    animation: ripple 0.65s forwards;
    -webkit-animation:ripple 0.65s forwards; /* For Chrome & Safari/Webkit based browser */
    -moz-animation:ripple 0.65s forwards; /* For Mozilla Firefox */
    }

    .ink.animate.end {
    transition: all 0.5s ease-in-out;
    background-color: rgba(255, 0, 0, 0.0);
    box-shadow: none;
    border-radius: 0px;
    }
    @-webkit-keyframes ripple{
    100% {
    -webkit-transform: scale(2.5);
    transform: scale(2.5);

    }
    }
    @-moz-keyframes ripple{
    100% {
    -moz-transform: scale(2.5);
    transform: scale(2.5);

    }
    }

    @keyframes ripple {
    /*scale the element to 250% to safely cover the entire link and fade it out*/
    100% {
    transform: scale(2.5);
    -webkit-transform: scale(2.5);
    -moz-transform: scale(2.5);
    }
    }


    Selanjutnya kita akan menggunakan javascript dan jquery untuk membuat animasi efek Ripple. Buatlah file javascript baru dan beri nama ripple.js, setea itu deklarasikan semua variabel yang dibutuhkan untuk membuat efe ripple.

    (function($){
    var parent,ink,d,x,y;
    }(jQuery);

    Berikut sedikit penjelasan tentang variabel yang akan digunakan
    variabelfungsi
    parent digunakan untuk menyimpan objek html parent dari objek yang di klik
    ink digunakan untuk menyimpan element html baru yang akan memberikan efek animasi ripple pada elemen yang diklik
    d digunakan untuk menyimpan lebar atau tinggi element parent untuk mendapatkan diameter lingkaran untuk efek ripple
    x digunakan untuk menyimpan posisi x dari parent element yang diklik
    y digunakan untuk menyimpan posisi y dari parent element yang diklik
    Sekarang kita akan membuat fungsi untuk melakukan animasi pada 2 event yaitu event mousedown dan mouseup, mousedown adalah event saat mousedown ditekan dan mouseup adalah event saat tombol mouse dilepas/selesai ditekan. Sebelumnya pada script html tiap element list saya beri nama class ripple sehingga kita akan menggunakan nama class untuk mengeksekusi animasi.
    Note:
    untuk mengeksekusi perintah yang melibatkan lebih dari satu element menggunakan javascript sebaiknya menggunakan class bukan id, karena id hanya akan mengambil 1 element pertama saja.

    (function($){
    var parent,ink,d,x,y;
    $('.ripple').mousedown(function(e){

    });
    $('.ripple').mouseup(function(e)){

    });
    }(jQuery);

    Selanjutnya kita akan mulai mengeksekusi perintah-perintah pada event mousedown terlebih dahulu. Didalam fungsi mousedown kita dapat mengakses objek yang sedang diklik dan menganimasikannya menggunakan css yang telah dibuat sebelumnya. Pertama kita perlu mendapatkan parent element dari element yang diklik.

    var parent = $(this).parent();

    Setelah mendapatkan element parent dari objek yang di klik kita perlu mengecek apakah element ink sudah ada pada element parent atau tidak, jika tidak ada maka buat element ink baru kemudian menyisipkannya kedalam parent element, kemudian simpan element ke variable ink.

    if (parent.find(".ink").length == 0){
    parent.prepend("
    ");
    }
    ink = parent.find(".ink");

    Agar efek ripple dapat selalu berjalan ketika mouse diklik kita perlu menghapus nama class animate dan end dari element ink jika memang pada element parent sudah terdapat element ink.

    ink.removeClass("animate");
    ink.removeClass("end");

    Selanjutnya kita perlu mengatur ukuran dari element ink menggunakan lebar atau tinggi element parent untuk membuat diameter lingkaran yang bisa untuk menutupi element.

    if (!ink.height() && !ink.width()) {
    d = Math.max(parent.outerWidth(), parent.outerHeight());
    ink.css({
    height: d,
    width: d
    });
    }

    Selanjutnya kita perlu mengatur posisi dari element ink namun kita harus mendapatkan kordinat x dan y saat mouse ditekan terlebih dahulu. Untuk mendapatkan kordinat x kita perlu mendapatkan kordinat x dari objek yang diklik relatif pada halaman kemudian dikurangi dengan posisi element parent relatif pada halaman dan dikurangi setengah dari lebar element ink, untuk kordinat y kita dapat menggunakan rumus yang sama yang berbeda hanya pada yang terakhir dimana untuk x kita menggunakan setengah dari lebar element ink sedangkan untuk y kita menggunakan setengah dari tinggi element ink.

    x = e.pageX - parent.offset().left - ink.width() / 2;
    y = e.pageY - parent.offset().top - ink.height() / 2;

    Sekarang atur posisi dari element ink dan tambahkan class animate

    ink.css({
    top: y + 'px',
    left: x + 'px'
    }).addClass("animate");

    Sekarang kita telah selesai membuat efek ripple pada event mousedown, sekarang kita perlu menambahkan 1 baris terahir di event mouseup untuk memberikan efek fade saat mouse selesai diklik dengan menambahkan nama class end pada element ink.

    ink.addClass("end");

    Sampai disini Anda telah selesai Membuat Efek Ripple Berbasis Material Design Menggunakan jQuery. Mungkin itu saja yang dapat saya berikan pada postingan kali ini.
    Semoga Bermanfaat ...!!!

    Full Code + Result

    Sunday, July 31, 2016

    Friday, June 24, 2016

    June 24, 2016

    Kombinasi HTML, CSS3 Dan Javascript Bagian 3


    Seperti janji saya sebelumnya pada postingan kali ini kita akan bermain dengan animasi css serta mengkombinasikannya dengan javascript. Pada postingan kali ini saya akan membahas tentang cara penggunaan keyframes untuk menganimasikan objek.

    Animasi pada CSS3 biasanya di deklarasikan menggunakan property animation, setiap animasi dapat dijadikan satu menggunakan keyframes. Seperti layaknya pada beberapa software animasi 3D dimana setiap pergerakan objek memiliki keyframes.


    Move To Right Animation (Animasi Bergerak Ke Kanan)

    Sekarang kita akan mencoba menggerakan sebuah objek HTML dari posisi awal menuju posisi bagian kanan. terdapat beberapa cara untuk membuat animasi ini kita dapat mengubah margin/padding dari objek atau kita juga dapat mengubah posisi dari objek tersebut. Disini saya menggunakan posisi objek dengan property left, perlu diingat bahwa ketika kita ingin menggunakan property left,right,top atau bottom kita harus terlebih dahulu mendeklarasikan properti position jika tidak maka properti yang Anda deklarasikan tidak akan dieksekusi.
    berikut contoh animasi CSS3 menggunakan keyframes yang bergerak ke kanan.

    button{
    position:relative;
    display:block;
    margin:10px auto;
    }
    @keyframes ltr {
    0% {
    left:0px;
    }
    50% {
    left:70px;
    }
    100% {
    left:0px;
    }
    }

    Pada CSS diatas saya membuat keyframes yang saya beri nama ltr dan terdapat 3 keyframes dimana saya hanya mengubah posisi left dari objek dimana objek yang saya gunakan adalah sebuah button. Ada 2 Cara dalam menggunakan keyframes yaitu menggunakan persentasi atau menggunakan from dan to. Namun disini saya hanya membahas yang menggunakan persen. Pada keyframes kedua objek digerakkan 70px ke kanan, kemudian pada keyframes ketiga objek dikembalikan ke posisi semula.

    Untuk mengimplementasikan animasi tersebut ke sebuah objek kita perlu menambahkan properti animation pada objek yang akan kita animasikan, terdapat 2 cara, membuat class baru di CSS atau menambahkannya pada attribut style di sebuah objek HTML. Namun dalam kasus ini saya memakai cara yang kedua yaitu menambahkan properti animation pada attribut style.

    Pertanyaan yang ada di benak Anda mungkin adalah "Lalu, bagaimana cara melakukannya ?" untuk melakukannya kita akan menggunakan javascript, javascript sangat berguna untuk membuat website menjadi lebih responsive, banyak situs-situs besar seperti misalnya Twitter yang memiliki framework bootstrap, kemudian jQuery dan jQuery Mobile serta masih banyak lagi framework javascript lainnya.

    Lanjut ke pembahasan, jadi untuk menambahkan properti animation kita memerlukan javascript terutama apabila kita ingin memicu animasi pada kondisi tertentu, misal saat objek diklik atau saat objek menyentuh kursor mouse dan lain sebagainya. disini saya akan memicu animasi saat objek menyentuh kursor mouse. Untuk mengakses objek menggunakan javascript kita dapat menggunakan id, class atau tag dari objek tersebut, jadi jika Anda ingin mengubah suatu objek dengan tag yang sama maka ada baiknya Anda menggunakan class atau id agar objek tidak mengeksekusi perintah yang sama. Disini saya memberikan id btn pada objek yang akan diubah.
    var tombol = document.getElementById('btn');
    tombol.onmouseover = function(){
    tombol.setAttribute("style","animation: ltr 2s");
    }
    setTimeout(function() {
    tombol.removeAttribute("style");
    }, 2000);

    Saya akan sedikit menjelaskan tentang script diatas melalui tabel berikut

    tombolVariabel yang kita buat untuk mengakses objek yang akan diberikan animasi
    documentRepresentasi halaman HTML
    onmouseoverEvent yang kita gunakan untuk memicu pengubahan attribute pada objek yaitu saat kursor mouse menyentuh objek tersebut
    setAttribute("style","animation: ltr 2s")fungsi yang digunakan untuk menambahkan attribute pada objek dimana parameter pertama adalah nama attribute sedangkan parameter kedua adalah value dari attribute dimana terdapat 2 argument, nama keyframes dan lama waktu animasi
    setTimeoutDigunakan untuk mengeksekusi suatu perintah setelah kurun waktu tertentu

    Pada script diatas saya menggunakan setTimeout untuk menghapus attribute style setelah animasi telah selesai, tujuannya adalah agar saat event onmouseover dipicu kembali objek akan tetap dianimasikan. Untuk membuat animasi yang bergerak dari Kanan ke Kiri Anda hanya perlu mengubah properti left pada keyframes menjadi right

    Full Code



    Rotate Animation(Animasi Berputar)

    Untuk membuat animasi berputar tidak berbeda jauh dengan animasi sebelumnya, yang berbeda hanya pada keyframes nya saja dimana pada keyframes saya menggunakan property transform kemudian memutar objek pada sumbu Z sebanyak 360 derajat.


    Move To Bottom Animation(Animasi Bergerak Ke Bawah)

    Animasi ini hampir sama seperti yang pertama, perbedaannya hanya pada properti left dimana saya mengubahnya menjadi top.




    Itu tadi 3 variasi animasi yang dapat digunakan untuk menganimasikan objek HTML di web Anda. Bagaimana ? mudah bukan ? tidak ada yang sulit selama Anda mau belajar :). Untuk hasil akhir dapat dilihat disini

    Semoga bermanfaat ...!!