Wednesday, September 19, 2012

Thumbnail Scroller

Pembaharuan: 25 September 2013

jQuery Thumbnail Scroller
Thumbnail scroller.

HTML

<div id="thumbnail-scroller">
    <div class="container">
        <figure>
            <a href="#" title="Title for Caption 1">
                <img alt="" src="img/thumbnail-1.jpg">
            </a>
        </figure>
        <figure>
            <a href="#" title="Title for Caption 2">
                <img alt="" src="img/thumbnail-2.jpg">
            </a>
        </figure>
        <figure>
            <a href="#" title="Title for Caption 3">
                <img alt="" src="img/thumbnail-3.jpg">
            </a>
        </figure>
    </div>
</div>

CSS

#thumbnail-scroller {
  height:130px;
  background-color:#810A0A;
  border:10px solid #12559D;
  position:relative;
  margin:50px;
  overflow:auto;
}

/* Create shadow effect on the left and right of container */
#thumbnail-scroller:before,
#thumbnail-scroller:after {
  content:"";
  display:block;
  position:absolute;
  top:0;
  bottom:0;
  left:-4px;
  width:4px;
  height:100%;
  box-shadow:0 0 4px black;
  z-index:10;
}

#thumbnail-scroller:after {
  left:auto;
  right:-4px;
}

#thumbnail-scroller .container {
  position:absolute;
  top:0;
  left:0;
  margin:5px 0 0 5px;
  width:300%;
  height:120px;
}

#thumbnail-scroller figure {
  display:block;
  background-color:white;
  float:left;
  width:100px;
  height:120px;
  margin:0 5px 0 0;
  position:relative;
  overflow:hidden;
}

#thumbnail-scroller figcaption {
  display:block;
  position:absolute;
  right:0;
  bottom:-50px;
  left:0;
  background-color:black;
  font:italic normal 11px/normal Arial,Sans-Serif;
  color:white;
  padding:4px 10px;
  text-align:left;
  opacity:.8;
}

#thumbnail-scroller figure img {
  display:block;
  border:none;
  margin:0;
}

jQuery

(function($) {

    var $thumbnailScroller = $('#thumbnail-scroller'),
        $container = $thumbnailScroller.find('.container'),
        $item = $container.find('figure'),
        item_length = $item.length,
        item_width = $item.outerWidth(true),
        total_width = item_width * item_length,
        $window = $(window);

    $thumbnailScroller.css('overflow', 'hidden');
    $container.css('width', total_width);

    // Auto caption builder & hover effect
    $item.each(function() {
        if ($(this).children().attr('title')) {
            var cap = $(this).children().attr('title');
            $(this).append('<figcaption>' + cap + '</figcaption>').children().removeAttr('title');
        }
    }).on("mouseenter mouseleave", function(e) {
        $('figcaption', this).stop().animate({
            bottom: e.type == "mouseenter" ? 0 : -50
        }, 200);
    });

    $window.on("resize", function() {
        var o_l = $thumbnailScroller.offset().left,
            t_w = $thumbnailScroller.width(),
            c_w = total_width;
        $thumbnailScroller.off().on("mousemove", function(e) {
            if ($(this).width() < $container.width()) {
                $container.css('left', -((e.pageX - o_l) * ((c_w - t_w) / t_w)));
            }
        });
    }).trigger("resize");

})(jQuery);

Lihat Demo


Template JSON - #c4612763938057608800

<div id="thumbnail-scroller"></div>
<script>
//<![CDATA[
var noimg = "img/no-image.png";
function showThumbs(json) {
    var entry = json.feed.entry,
        title, url, skeleton = '<div class="container">';
    for (var i = 0; i < entry.length; i++) {
        for (var j = 0; j < entry[i].link.length; j++) {
            if (entry[i].link[j].rel == 'alternate') {
                url = entry[i].link[j].href;
                break;
            }
        }
        title = entry[i].title.$t;
        img = ("media$thumbnail" in entry[i]) ? entry[i].media$thumbnail.url.replace(/\/s72\-c/, "/s120-c") : noimg;
        skeleton += '<figure><a href="' + url + '" title="' + title + '"><img src="' + img + '" alt="" /></a></figure>';
    }
    skeleton += '</div>';
    document.getElementById('thumbnail-scroller').innerHTML = skeleton;
}
//]]>
</script>
<script src='http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&amp;max-results=30&amp;callback=showThumbs'></script>

Lihat Demo

Tip untuk Thumbnail Scroller Berjamak

Gunakan jQuery .each() untuk menerapkan fungsi kepada setiap target yang diinginkan, sehingga penargetan variabel $thumbnailScroller menjadi seperti ini:

$('.t-s').each(function() {
    var $thumbnailScroller = $(this);
});

Lihat Demo

Labels: , , ,

Tuesday, September 18, 2012

Apa Itu Sticky Footer?

Non Sticky Footer
Efek yang timbul pada ujung halaman jika tinggi halaman lebih pendek dari tinggi layar.

Karena Saya lihat masih banyak yang salah paham dengan istilah Sticky Footer, jadi Saya akan membahasnya. Kebanyakan orang menganggap bahwa sticky footer itu artinya footer menempel di bawah layar dan akan tetap berada pada posisinya meskipun layar digulung.

Baiklah, memang bisa dibilang begitu, mengingat kata 'stick' juga berarti 'menempel'. Tapi bukan seperti itu pengertian sticky footer yang sebenarnya. Sticky Footer maksudnya adalah footer akan tetap berada di bawah layar meskipun tinggi halaman/dokumen lebih pendek dari tinggi layar. Sticky Footer digunakan untuk memastikan agar tampilan halaman yang rendah tidak tampak jelek saat berada pada device yang ukuran layarnya lebih tinggi dari ukuran halaman.

Berikut ini adalah sebuah demonstrasi footer biasa dimana di atasnya hanya terdapat beberapa teks, sehingga tinggi halaman tidak mampu meraih bagian bawah:

Lihat Demo

Bisa Anda lihat bahwa footer tampak menggantung di atas dan menjadikannya tidak menarik. Nah, Sticky Footer berguna untuk mengatasi masalah ini, untuk memastikan agar footer tetap berada di bawah meskipun tinggi halaman lebih rendah dari tinggi layar. Ini adalah contoh sticky footer:

Lihat Demo

Anda lihat bahwa meskipun tinggi halaman/dokumen lebih pendek dari tinggi layar, CSS Sticky Footer tetap menjaga agar halaman menekan ke sisi atas dan sisi bawah (dengan menggunakan ukuran tinggi dominan sebesar 100% pada masing-masing elemen) sehingga tidak akan ada ruang kosong yang tersisa di bagian bawah.

Masih Belum Yakin dengan Istilah Sticky Footer?

Cek situs ini ⇒ http://www.cssstickyfooter.com/

Pada bagian prolog sudah jelas tertulis, "It Sticks to the Bottom of the Page!", bukan "It Sticks to the Bottom of the Window!"

Dan ini adalah halaman demonstrasi tampilan footer biasa beserta masalahnya, yang juga terdapat pada sub-halaman dari situs tersebut: http://www.cssstickyfooter.com/non-stick-footer.html

Sticky Footer bukan berarti bahwa footer melayang di bawah layar. Sticky Footer lebih tepat dikatakan sebagai metode untuk memastikan footer tetap berada di bawah halaman meskipun tinggi halaman lebih pendek dari tinggi layar. Sticky Footer hanya akan terlihat efeknya jika tinggi halaman lebih pendek dari tinggi layar. Jika tinggi halaman tidak lebih pendek dari tinggi layar (atau katakanlah: Jika Anda bisa memastikan bahwa halaman situs Anda tidak pernah lebih pendek dari tinggi layar), maka Anda tidak perlu menggunakan Sticky Footer.

Saat tinggi halaman sudah melebihi tinggi layar, maka efek Sticky Footer akan menghilang. Dan CSS Sticky Footer sudah tidak ada gunanya lagi saat itu:

Lihat Demo


CSS & HTML Sticky Footer

HTML

<div id="wrap">
    <section id="main"> ... </section>
</div>
<footer id="footer"></footer>

CSS

/**  
 * Sticky Footer Solution
 * by Steve Hatcher 
 * http://stever.ca
 * http://www.cssstickyfooter.com
 */

* {margin:0;padding:0;} 

/* Must declare 0 margins on everything, also for main layout components use padding, not vertical margins (top and bottom) to add spacing, else those margins get added to total height and your footer gets pushed down a bit more, creating vertical scroll bars in the browser */

html, body {
  height:100%;
}

#wrap {
  min-height:100%;
}

#main {
  overflow:auto;
  padding-bottom:180px; /* must be same height as the footer */
}

#footer {
  position:relative;
  margin-top:-180px; /* negative value of footer height */
  height:180px;
  clear:both;
} 

/* Opera Fix */
body:before { /* thanks to Maleika (Kohoutec)*/
  content:"";
  height:100%;
  float:left;
  width:0;
  margin-top:-32767px; /* thank you Erik J - negate effect of float */
}

Tambahan Untuk Internet Explorer

<!--
You also need to include this conditional style in the <head> of your HTML file
to feed this style to IE 6 and lower and 8 and higher...
-->

<!--[if !IE 7]>
    <style>
        #wrap {display:table;height:100%}
    </style>
<![endif]-->

Labels: , , ,

Membangun Aplikasi Quick Search dengan JSON Blogger

Membangun Aplikasi Quick Search dengan JSON Blogger
Membangun Aplikasi Quick Search dengan JSON Blogger

Selain melalui halaman pencarian biasa, Blogger juga mengizinkan kita untuk mengakses posting-posting acak di dalam feed yang dapat disortir berdasarkan kata kunci. Ini bisa dilakukan melalui parameter q.

Format dasar URL feed untuk memanggil data posting dengan sortir berdasarkan kata kunci adalah seperti ini:

http://nama_blog.blogspot.com/feeds/posts/summary?q=Kata Kunci

Yang jika diakses akan menghasilkan halaman berisi daftar posting tersortir berdasarkan kata kunci dari parameter q seperti ini ⇒ Daftar posting dengan kata kunci ‘css’

Dengan memanfaatkan kerangka dasar widget Blogger, event onsubmit pada formulir dan juga penargetan elemen kontainer yang tepat, maka parameter ini memungkinkan kita untuk menciptakan aplikasi quick search. Yaitu sebuah aplikasi yang bisa digunakan untuk mencari artikel/posting dalam sebuah blog tanpa harus berpindah dari halaman asal. Seluruh hasil penelusuran akan tampil pada tempat yang sama!

Pada prinsipnya, hal pertama yang Saya buat adalah sebuah fungsi yang akan menyisipkan elemen <script> secara tidak langsung ke dalam area <head> saat fungsi tersebut dieksekusi. JavaScript yang Saya bangun adalah callback widget Blogger biasa dengan pola sumber yang umum. Saya hanya menambahkan parameter kata kunci pencarian sebagai penyortir posting yang akan dikirim nantinya:

http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&q=Kata Kunci&callback=functionName

Nilai parameter sumber diambil dari sebuah elemen <input> yang Saya letakkan di dalam formulir. Logikanya seperti ini:

Menyisipkan Nilai Elemen Input ke dalam Parameter 'q'
Menyisipkan Nilai Elemen Input ke dalam Parameter q pada URL Feed
function insertScript() {
    // Membangun elemen <script> untuk disisipkan ke dalam area <head> ...
    // ... dengan parameter kueri yang ditentukan oleh nilai elemen 'feed-q-input'
    var query = document.getElementById('feed-q-input').value,
        s = document.createElement('script');
    s.type = "text/javascript";
    s.src = "//nama_blog.blogspot.com/feeds/posts/summary?q="+query+"&alt=json-in-script&callback=functionName";
    document.getElementsByTagName('head')[0].appendChild(s);
}
<form onsubmit="insertScript();return false;"> ... </form>

Kode aslinya lebih panjang, tapi pada intinya inilah dasar yang Saya gunakan untuk membangun aplikasi pencarian cepat. Anda bisa mengunduh JavaScript dan melihat demonya melalui tombol-tombol ini:

Lihat Demo Unduh JavaScript


Integrasi Widget ke Blogger

Pertama-tama masuk ke halaman editor HTML template Anda, kemudian salin kode CSS ini dan letakkan di atas kode ]]></b:skin> atau </style>:

#search-form-feed {
  width:200px; /* lebar kotak penelusuran */
  position:relative;
  margin:0 0 10px;
  padding:0;
  font:normal normal 11px/normal Arial,Sans-Serif;
  color:#333;
}

#feed-q-input {
  display:block;
  width:100%;
  border:2px solid #bbb;
  background-color:white;
  padding:5px;
  font:normal bold 13px/normal Tahoma,Arial,Sans-Serif;
  color:#ccc;
  margin:0;
  -webkit-border-radius:4px;
  -moz-border-radius:4px;
  border-radius:4px;
  -webkit-box-shadow:inset 0 1px 5px rgba(0,0,0,.2);
  -moz-box-shadow:inset 0 1px 5px rgba(0,0,0,.2);
  box-shadow:inset 0 1px 5px rgba(0,0,0,.2);
  -webkit-box-sizing:border-box;
  -moz-box-sizing:border-box;
  box-sizing:border-box;
}

#feed-q-input:focus {
  border-color:#0D6786;
  color:#333;
  outline:none;
  -webkit-box-shadow:0 0 5px #153E95,0 0 7px #153E95;
  -moz-box-shadow:0 0 5px #153E95,0 0 7px #153E95;
  box-shadow:0 0 5px #153E95,0 0 7px #153E95;
}

#search-result-container {
  width:400px;
  height:300px;
  overflow:auto;
  position:absolute;
  top:100%;
  right:0;
  z-index:999;
  background-color:#E5EDF7;
  border:2px solid white;
  padding:10px 10px 0;
  margin:10px 0 0;
  -webkit-box-shadow:0 1px 2px rgba(0,0,0,.4),0 7px 7px -4px rgba(0,0,0,.4);
  -moz-box-shadow:0 1px 2px rgba(0,0,0,.4),0 7px 7px -4px rgba(0,0,0,.4);
  box-shadow:0 1px 2px rgba(0,0,0,.4),0 7px 7px -4px rgba(0,0,0,.4);
  -webkit-border-radius:5px;
  -moz-border-radius:5px;
  border-radius:5px;
  display:none;
}

#search-result-container mark {
  background-color:yellow;
  color:black;
}

#search-result-container a {
  text-decoration:none;
  color:#0D3E71;
  font-weight:bold;
  font-size:12px;
  display:block;
}

#search-result-container a:hover {color:#052748}

#search-result-container h4 {
  margin:0 0 10px;
  font:normal bold 12px/normal "Trebuchet MS",Trebuchet,Tahoma,Arial,Sans-Serif;
  color:#B50001;
}

#search-result-container ol {
  background:transparent;
  border:none;
  margin:0 0 10px;
  padding:0;
}

#search-result-container li {
  margin:0 0 1px;
  padding:7px 8px;
  list-style:none;
  border:1px solid #B7C1CE;
  background-color:white;
  overflow:hidden;
  word-wrap:break-word;
}

#search-result-container li img {
  display:block;
  float:left;
  margin:0 10px 4px 0;
  border:1px solid #B7C1CE;
  background-color:#F5F5F5;
  padding:2px;
}

#search-result-loader {
  position:absolute;
  top:100%;
  left:5px;
  z-index:999;
  background-color:#0D6786;
  color:white;
  padding:3px 5px;
  margin:-2px 0 0;
  font:normal bold 10px/normal Arial,Sans-Serif;
  -webkit-border-radius:0 0 3px 3px;
  -moz-border-radius:0 0 3px 3px;
  border-radius:0 0 3px 3px;
  display:none;
}

Setelah itu masuk ke halaman Tata Letak, kemudian tambahkan sebuah elemen halaman HTML/JavaScript. Salin kode ini dan letakkan di dalam formulirnya:

<div id="search-form-feed">
  <form action="/search" onsubmit="return updateScript();">
    <input name="q" type="text" placeholder="Telusuri..." id="feed-q-input" onkeyup="resetField();"/>
  </form>
  <div id="search-result-container"></div>
  <div id="search-result-loader">Loading...</div>
</div>
<script>
//<![CDATA[
var searchFormConfig = {
    url: "http://nama_blog.blogspot.com", // URL Blog
    numPost: 9999, // Jumlah maksimal temuan
    summaryPost: true, // `true` jika ingin menampilkan deskripsi posting
    summaryLength: 400, // Jumlah karakter ringkasan posting
    resultTitle: "Hasil penelusuran untuk kata kunci", // Judul hasil pencarian
    noResult: "No result", // Deskripsi `tak ditemukan`
    resultThumbnail: true, // `true` untuk menampilkan thumbnail posting
    thumbSize: 40, // Ukuran & resolusi thumbnail
    fallbackThumb: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAA3NCSVQICAjb4U/gAAAADElEQVQImWOor68HAAL+AX7vOF2TAAAAAElFTkSuQmCC" // Fallback thumbnail untuk posting tak bergambar
};
//]]>
</script>
<script src="//cdn.rawgit.com/tovic/dte-project/2fd2d2971c3398029ea5e149696447243e7f4d94/blogger-quick-search.js"></script>

Klik Simpan Widget.

Konfigurasi Widget

Semua opsi sangat umum. Saya yakin Anda bisa dengan cepat mempelajarinya:

Opsi Keterangan
url URL blog Anda
numPost Jumlah posting yang akan ditampilkan dalam hasil pencarian. Nilai 9999 maksudnya adalah Anda mencoba untuk menampilkan semua posting yang ditemukan
summaryPost Pilihan untuk menampilkan atau menyembunyikan ringkasan posting dalam hasil pencarian
summaryLength Digunakan untuk menentukan jumlah karakter ringkasan hasil pencarian
resultTitle Judul hasil pencarian
noResult Peringatan yang menunjukkan bahwa posting tidak ditemukan
resultThumbnail Pilihan untuk menampilkan atau menyembunyikan thumbnail posting dalam hasil pencarian
thumbSize Digunakan untuk menentukan ukuran dan resolusi thumbnail hasil pencarian
fallbackThumb Gambar cadangan untuk posting tak bergambar.

CSS untuk Tema Minimalis (Layout Dasar)

Digunakan sebagai pengganti kode CSS di atas demi kemudahan dalam hal penyesuaian tema:

#search-form-feed {
  width:200px; /* lebar kotak penelusuran */
  position:relative;
  margin:0 0 10px;
  padding:0;
  font:normal normal 11px/normal Arial,Sans-Serif;
  color:#333;
}

#feed-q-input {
  -webkit-box-sizing:border-box;
  -moz-box-sizing:border-box;
  box-sizing:border-box;
  display:block;
  width:100%;
  border:1px solid #bbb;
  background-color:white;
  padding:5px 5px;
  font:inherit;
  font-size:13px;
  margin:0;
}

#search-result-container {
  width:400px;
  height:300px;
  overflow:auto;
  position:absolute;
  top:100%;
  left:0; /* ganti menjadi `right:0` untuk mendorong kontainer ke kanan */
  z-index:9999;
  border:1px solid #ccc;
  padding:10px 10px 0;
  margin:10px 0 0;
  -webkit-box-shadow:0 3px 5px rgba(0,0,0,.2);
  -moz-box-shadow:0 3px 5px rgba(0,0,0,.2);
  box-shadow:0 3px 5px rgba(0,0,0,.2);
  display:none;
}

#search-result-container mark {
  font:inherit;
  display:inline;
  background-color:#ff0;
  color:black;
}

#search-result-container a {
  text-decoration:none;
  font-weight:bold;
  font-size:110%;
  display:block;
}

#search-result-container h4 {
  margin:0 0 10px;
  font:inherit;
  font-weight:bold;
  color:#B50001;
}

#search-result-container ol {
  background:none;
  border:none;
  margin:0 0 10px;
  padding:0;
}

#search-result-container li {
  margin:0 0 15px;
  list-style:none;
  overflow:hidden;
  word-wrap:break-word;
  padding-left:65px;
}

#search-result-container li img {
  display:block;
  float:left;
  margin:0 0 2px -55px;
  border:1px solid #ccc;
  padding:2px;
}

#search-result-loader {
  position:absolute;
  top:100%;
  left:5px;
  z-index:9999;
  margin-top:4px;
  font-size:10px;
  display:none;
}

Labels: , , , ,

Sunday, September 16, 2012

Menampilkan Semua Daftar Label Posting dengan JSON Blogger

Menampilkan Semua Daftar Label Posting dengan JSON Blogger
Konten Feed Blogger

Kode ini digunakan untuk menampilkan semua daftar nama label yang berada di dalam array category feed Blogger (lihat di sini):

<script>
//<![CDATA[
var homepage = "http://nama_blog.blogspot.com";
function showLabels(json) {
    var label = json.feed.category;
    document.write('<ul>');
    for (var i = 0; i < label.length; i++) {
        document.write('<li><a href="' + homepage + '/search/label/' + encodeURIComponent(label[i].term) + '" target="_blank">' + label[i].term + '</a></li>');
    }
    document.write('</ul>');
}
document.write('<scr' + 'ipt src="' + homepage + '/feeds/posts/summary?max-results=0&alt=json-in-script&callback=showLabels"><\/scr' + 'ipt>');
//]]>
</script>

Lihat Demo

Susunan markup tidak mutlak. Anda juga bisa mengubahnya menjadi sesuatu yang lain, misalnya mengubahnya menjadi elemen select box seperti ini:

var homepage = "//nama_blog.blogspot.com";
function showLabels(json) {
    var label = json.feed.category;
    document.write('<select onchange="window.open(this.value);"><option selected disabled>-- Daftar Kategori --</option>');
    for (var i = 0; i < label.length; i++) {
        document.write('<option value="' + homepage + '/search/label/' + encodeURIComponent(label[i].term) + '">' + label[i].term + '</option>');
    }
    document.write('</select>');
}

Lihat Demo

Labels: , , , ,

Tuesday, September 11, 2012

Menandai Komentar Admin pada Thread Komentar Blogger

Fitur komentar Blogger yang sekarang tidak mengizinkan kita untuk memodifikasi tampilan komentar admin. Blogger hanya memberikan sebuah ikon kecil secara otomatis untuk menunjukkan bahwa komentar yang memiliki ikon tersebut adalah komentar dari administrator blog:

Blogger Admin Comments Highlight
Tampilnya ikon administrator pada komentar yang ditulis oleh pemilik blog. (Gambar ikon umumnya berwarna hitam dengan gambar pena di dalamnya. Saya sudah memodifikasi tampilannya menjadi favicon).

Lalu bagaimana jika kita ingin membuat tampilan komentar yang berbeda pada blok komentar administrator secara keseluruhan? Dulu kita bisa menggunakan tag kondisional, tapi sekarang tidak lagi. Yang bisa kita lakukan adalah memanfaatkan JavaScript untuk mengecek keberadaan ikon komentar admin, kemudian menggunakan ikon tersebut sebagai elemen awalan untuk menyeleksi induk-induk yang mengelilinginya. Beberapa ada yang menggunakan jQuery, tapi Saya bisa menggunakan JavaScript mentah untuk ini:

Masuk ke Editor HTML template Anda, kemudian letakkan kode ini di atas tag </body>:

<script>
//<![CDATA[
// Highlight Blogger Admin Comments with JavaScript by Taufik Nurrohman
// URL: https://plus.google.com/108949996304093815163/about
(function() {
    if (document.getElementById('comment-holder')) {
        var comments = document.getElementById('comment-holder'),
            icon = comments.getElementsByTagName('span');
        for (var i = 0; i < icon.length; i++) {
            if (icon[i].className == "icon user blog-author") {
                icon[i].parentNode.parentNode.className += " admin-comment";
                icon[i].parentNode.parentNode.parentNode.className += " admin-comment-wrapper";
            }
        }
    }
})();
//]]>
</script>

Kemudian, tambahkan kode ini di atas ]]></b:skin> atau </style>:

.admin-comment-wrapper {
  padding-top:0 !important;
  padding-left:10px !important;
  padding-bottom:0 !important;
  border-left:4px solid green;
}

.admin-comment-wrapper a,
.admin-comment-wrapper a:visited {color:brown}

.admin-comment-wrapper .admin-comment {
  padding:10px 15px;
  border:1px solid darkgreen;
  background-color:skyblue;
  color:black;
}

Klik Simpan Template. Kode CSS bisa dimodifikasi sesuka hati.

Lihat Demo

Labels: , ,

Sunday, September 9, 2012

jQuery Efek Nivo Slider Tanpa Plugin

Nivo Slider Like Effect Slideshow Without Plugin

Eksperimen membuat slideshow berdasarkan framework yang Saya buat di sini, untuk menciptakan slideshow dengan efek seperti Nivo Slider. Slideshow ini menggunakan konsep yang mirip dengan Nivo Slider, yaitu mengambil URL gambar untuk dijadikan sebagai latar slice. Efek bergelombang timbul dari .delay() animasi yang Saya set dengan nilai berurutan pada setiap slice:

HTML

<figure id="slider">
    <div class="container">
        <img src="image/slide-1.jpg" alt="Deskripsi slide 1">
        <img src="image/slide-2.jpg" alt="Deskripsi slide 2">
        <img src="image/slide-3.jpg" alt="Deskripsi slide 3">
        <img src="image/slide-4.jpg" alt="Deskripsi slide 4">
    </div>
    <figcaption></figcaption>
    <nav id="slider-nav"></nav>
</figure>

CSS

/* Slider */
#slider {
  display:block;
  border:4px solid #000;
  width:400px; /* slider width */
  height:250px; /* slider height */
  margin:0 auto;
  background:white url('img/loading.gif') no-repeat 50% 50%;
  overflow:hidden;
  position:relative;
}

/* For caption */
#slider figcaption {
  display:block;
  background-color:black;
  font:normal normal 11px Arial,Sans-Serif;
  color:white;
  opacity:.8;
  padding:10px 15px;
  position:absolute;
  right:0;
  bottom:-100px; /* hide the caption with this way :) */
  left:0;
  z-index:99;
}

#slider img {
  display:block;
  margin:0 0;
  width:400px; /* slide width */
  height:250px; /* slide height */
  position:absolute;
  top:0;
  left:0;
}

/* Navigation */
#slider-nav {
  display:block;
  position:absolute;
  top:10px;
  right:10px;
  margin:0 0;
  padding:0 0;
  z-index:99;
}

#slider-nav a {
  display:block;
  float:left;
  width:10px;
  height:10px;
  background-color:#111;
  font-size:0;
  color:transparent;
  overflow:hidden;
  text-indent:-99px;
  margin:0 2px 0 0;
  border:2px solid white;
  -webkit-border-radius:100%;
  -moz-border-radius:100%;
  border-radius:100%;
  -webkit-box-shadow:0 1px 2px rgba(0,0,0,.4);
  -moz-box-shadow:0 1px 2px rgba(0,0,0,.4);
  box-shadow:0 1px 2px rgba(0,0,0,.4);
}

#slider-nav .active {
  background-color:#2589B4;
}

/* Hide all element inside the '#slider' until the page has been loaded! */
#slider .container, #slider figcaption {display:none}
#slider-nav {opacity:0}

jQuery

/**
 * NIVO SLIDER LIKE EFFECT SLIDESHOW BY TAUFIK NURROHMAN
 * URL: https://plus.google.com/108949996304093815163/about
 * Based on this slideshow framework: http://www.dte.web.id/2012/09/simple-useful-jquery-slideshow.html
 */

(function($) {

// ==================================================================================
// Configuration here:
// ----------------------------------------------------------------------------------
    var config = {
        slices: 10, // number of slices
        speed: 600, // slideshow speed
        easing: null, // easing type
        interval: 3000 // slideshow interval
    };
// ==================================================================================

    // Some variables...
    var $slider = $('#slider'),
        $caption = $slider.find('figcaption'),
        $container = $slider.find('.container'),
        $nav = $('#slider-nav'),
        $slide = $container.children(),
        autoSlide = null,
        $first = $slide.first();

    // Auto append navigation item based on the slides length
    $slide.each(function(index) {
        var i = index + 1;
        $nav.append('<a href="#slide-'+i+'">'+i+'</a>');
        $(this).attr('id', 'slide-'+i);
    });

    // Set the slices size
    var slice_w = $slider.width() / config.slices,
        slice_h = $slider.height();

    // Build the slices
    for (var i = 0; i < config.slices; i++) {
        $('<div class="slice" />').css({
            'position':'absolute',
            'width':slice_w,
            'height':slice_h,
            'left':slice_w*i,
            'z-index':4,
            'background-color':'transparent',
            'background-repeat':'no-repeat',
            'background-position':'-' + slice_w*i + 'px 0'
        }).appendTo($slider);
    }

    // Catch the slices, and also set the different position between odd and even slices
    var $sliceOdd = $slider.find('.slice:odd').css('bottom',0),
        $sliceEven = $slider.find('.slice:even').css('top',0);

    // Click to switch!
    $nav.find('a').on("click", function() {

        $nav.find('.active').removeClass('active');
        $(this).addClass('active');

        var pos = $(this).index(),
            text = $slide.eq(pos).attr('alt'),
            bg = $slide.eq(pos).attr('src');

        $slide.hide().eq(pos).trigger("load").show();

        // Do the caption and slices animation here!
        $caption.stop().animate({bottom:'-100px'}, config.speed/2);

        $sliceOdd.each(function(i) {
            $(this).stop().delay(i*100).animate({bottom:'-'+slice_h+'px',opacity:0}, config.speed, config.easing, function() {
                $(this).css({
                    'background-image':'url('+bg+')',
                    'bottom':0,
                    'opacity':1
                });
            });
        });
        $sliceEven.each(function(i) {
            $(this).stop().delay(i*100).animate({top:'-'+slice_h+'px',opacity:0}, config.speed, config.easing, function() {
                $(this).css({
                    'background-image':'url('+bg+')',
                    'top':0,
                    'opacity':1
                });
            });
        }).promise().done(function() {
            $caption.html(text).stop().animate({bottom:'0'}, config.speed/2);
        });

        clearInterval(autoSlide);
        autoSlide = setInterval(slideShow, config.interval);

        return false;

    }).first().addClass('active');

    // Init slideshow
    $caption.html($slide.first().attr('alt')).stop().animate({bottom:'0'}, config.speed);

    // Navigation clicker
    function slideShow() {
        if ($nav.find('.active').next().length) {
            $nav.find('.active').next().trigger("click");
        } else {
            $nav.find('a').first().trigger("click");
        }
    }

    // Run the slideshow on page load...
    $(window).on("load", function() {

        // remove the 'loading background-image' of '#slider'
        $slider.css('background-image','none');

        // Show the '.container', 'figcaption' and '#slide-nav' when the page has been loaded!
        $container.show();
        $caption.show();
        $nav.css('opacity',1);

        // Another init slideshow
        $slider.find('.slice').css('background-image', 'url('+$first.attr("src")+')');

        // Then, start the interval...
        autoSlide = setInterval(slideShow, config.interval);

    });

})(jQuery);

Lihat Demo Salinan di CSSDeck

Konfigurasi

Opsi Keterangan
slices Jumlah potingan slide.
speed Kecepatan slideshow.
easing Tipe easing animasi.
interval Interval slideshow.

Labels: , , , , ,

Beberapa Contoh Modifikasi Slideshow jQuery

Beberapa Contoh Modifikasi Slideshow jQuery

Artikel ini merupakan kelanjutan dari artikel jQuery Slideshow Otomatis dengan Navigasi Angka

1. Slideshow dengan Caption

HTML

Untuk membuat slideshow dengan caption, kita memerlukan beberapa langkah perubahan. Pertama-tama, kita ganti elemen <div class="slide"> dengan <img>. Kemudian sisipkan elemen <figcaption> ke dalam #slider. Bagian inilah yang nantinya akan diisi oleh teks dari setiap item slider:

<figure id="slider">
    <div class="container">
        <img src="img/slide-1.jpg" alt="Deskripsi gambar 1">
        <img src="img/slide-2.jpg" alt="Deskripsi gambar 2">
        <img src="img/slide-3.jpg" alt="Deskripsi gambar 3">
        <img src="img/slide-4.jpg" alt="Deskripsi gambar 4">
    </div><figcaption></figcaption>  </figure>
<nav id="slider-nav"></nav>

Supaya lebih semantik, Saya juga telah mengganti elemen #slider yang tadinya adalah elemen divisi menjadi elemen figur. Lihat kode di atas!

CSS

Setelah itu kita set beberapa perubahan pada kode CSS:

/* Slider */
#slider {
  display:block;
  position:relative;
}

/* Untuk caption */
#slider figcaption {
  display:block;
  background-color:black;
  font:normal normal 11px/normal Arial,Sans-Serif;
  color:white;
  opacity:.8;
  padding:10px 15px;
  position:absolute;
  right:0;
  bottom:-100px; /* sembunyikan dengan cara ini :) */
  left:0;
  z-index:4;
}

#slider img {
  display:block;
  margin:0;
  width:300px; /* dimensi lebar */
  height:200px; /* dimensi tinggi */
  float:left;
}

jQuery

Tangkap satu objek lagi dan simpan ke dalam variabel $caption, yaitu elemen <figcaption>:

$caption = $slider.find('figcaption');

Setelah itu, kita harus mengubah logika animasi slideshow, karena di sini kita baru saja menambahkan elemen caption. Langkah animasinya seperti ini:

Pertama-tama, tampilkan teks slide awal ke dalam elemen <figcaption> sebagai awalan (dalam kasus ini Saya mengambil teks tersebut dari atribut alt pada masing-masing gambar). Ke dua adalah langkah animasi. Urutannya:

  1. Sembunyikan caption
  2. Geser slider
  3. Ganti teks caption dengan deskripsi yang baru, kemudian tampilkan caption.

Semuanya akan menjadi seperti ini:

$nav.find('a').on("click", function() {
    $nav.find('.active').removeClass('active');
    $(this).addClass('active');
    var pos = $(this).index() * $slider.width(),

        text = $slide.eq($(this).index()).attr('alt'); // Mengambil teks dari atribut alt pada gambar ke-`$(this).index()`

    // (1) Menyembunyikan caption...
    $caption.stop().animate({bottom:'-100px'}, 400);

    // (2) Menggeser slider...
    $container.stop().animate({left:'-'+pos+'px'}, 600, function() {

        // (3) Mengganti teks caption dengan deskripsi yang baru...
        // kemudian tampilkan caption dengan efek animasi properti 'bottom'
        $caption.html(text).stop().animate({bottom:'0'}, 400);

    });
    clearInterval(autoSlide);
    autoSlide = setInterval(slideShow, 3000);
    return false;
}).first().addClass('active');

// Sebagai awalan => tampilkan caption dengan deskripsi atribut alt dari slide pertama
$caption.html($slide.first().attr('alt')).stop().animate({bottom:'0'}, 600);

Lainnya

Slideshow berupa gambar membutuhkan waktu lebih lama untuk memuat. Dan saat proses pemuatan terjadi, biasanya kita akan melihat efek yang tidak bagus dari gambar yang terpotong-potong. Cara termudah untuk mengatasi itu adalah dengan menyembunyikan semua gambar terlebih dahulu sebelum termuat. Hingga saat gambar sudah termuat, kita bisa menampilkannya:

/**
 * Tip yang baik untuk slideshow berupa gambar:
 * Sembunyikan tampilan sampai semua gambar benar-benar termuat...
 * ... agar saat gambar sedang dimuat, dia tidak merusak pemandangan kita :)
 */

#slider .container, #slider figcaption {display:none}
#slider-nav {opacity:0}
$(window).on("load", function() {

    // Tampilkan '.container', 'figcaption' dan '#slide-nav' saat halaman (semua gambar) telah termuat!
    $container.show();
    $caption.show();
    $nav.css('opacity',1);

    // Kemudian jalankan interval slideshow...
    autoSlide = setInterval(slideShow, 3000);

});

Sementara gambar sedang memuat, kita tampilkan efek animasi loading dengan menambahkan latar berupa loading.gif agar slideshow menjadi lebih menarik dan komunikatif:

#slider {
  background:white url('img/loading.gif') no-repeat 50% 50%;
}

Lihat Demo

2. Efek Fade

CSS

Pembuatan efek fade bisa dilakukan dengan perhitungan yang lebih sederhana:

Konsep dasar slideshow dengan efek fade adalah: Semua gambar bertumpuk, dan masing-masing gambar bergantian menampilkan diri dengan efek peningkatan/penurunan pemudaran.

Sehingga, kode CSS yang perlu kita ubah hanya ada pada bagian ini:

#slider img {
  display:block;
  margin:0;
  width:300px;
  height:200px;
  /* Gunakan posisi absolut untuk menumpuk masing-masing slide satu sama lain */
  position:absolute;
  top:0;
  left:0;
}

jQuery

Setelah itu, ada beberapa bagian variabel yang bisa kita buang. Kita sudah tidak perlu lagi menggunakan variabel-variabel ini, karena semua slide kini berada dalam satu tumpukan!

var $slider = $('#slider'),
    $caption = $slider.find('figcaption'),
    $container = $slider.find('.container'),
    $nav = $('#slider-nav'),
    $slide = $container.children(),
    s_length = $slide.length,s_wide = $slider.width() * s_length,s_height = $slider.height(),
    autoSlide = null;

Efek animasi bisa dibuat dengan jQuery .fadeIn() dan .fadeOut(). Seperti ini:

$nav.find('a').on("click", function() {

    $nav.find('.active').removeClass('active');
    $(this).addClass('active');

    var pos = $(this).index() * $slider.width(),
        text = $slide.eq($(this).index()).attr('alt');
    $caption.stop().animate({bottom:'-100px'}, 400);

    // Sembunyikan semua slide dengan efek .fadeOut() ...
    // ... kemudian tampilkan slide ke-`$(this).index()` dengan efek .fadeIn()
    $slide.fadeOut(600).eq($(this).index()).fadeIn(600, function() {
        $caption.html(text).stop().animate({bottom:'0'}, 400);
    });

    clearInterval(autoSlide);
    autoSlide = setInterval(slideShow, 3000);

    return false;

}).first().addClass('active');

Lainnya

Jangan lupa untuk menghilangkan latar animasi loading saat semua gambar sudah termuat:

$(window).on("load", function() {
    $slider.css('background-image','none');
});

Lihat Demo

Labels: , , ,

Saturday, September 8, 2012

Framework jQuery Slideshow Otomatis dengan Item Navigasi Angka

Simple Useful jQuery Slideshow

HTML

<div id="slider">
    <div class="container">
        <div class="slide"> ... </div>
        <div class="slide"> ... </div>
        <div class="slide"> ... </div>
        <div class="slide"> ... </div>
        <div class="slide"> ... </div>
    </div>
</div>
<nav id="slider-nav"></nav>

CSS

/* Slider */
#slider {
  width:300px; /* dimensi lebar */
  height:200px;; /* dimensi tinggi */
  margin:0 auto;
  background-color:black;
  overflow:hidden; /* Sembunyikan muatan elemen '.container' yang berlebih dari '#slider' */
}

#slider .slide {
  width:300px; /* dimensi lebar */
  height:200px; /* dimensi tinggi */
  float:left;
}

#slide-1 {background-color:darkred}
#slide-2 {background-color:darkgreen}
#slide-3 {background-color:darkblue}
#slide-4 {background-color:gold}
#slide-5 {background-color:darkviolet}

/* Navigasi */
#slider-nav {
  display:block;
  width:300px;
  margin:10px auto;
  text-align:center;
}

#slider-nav a {
  display:inline-block;
  width:15px;
  height:15px;
  background-color:#bbb;
  font-size:0;
  color:transparent;
  overflow:hidden;
  text-indent:-99px;
  margin:0 2px 0 0;
  border:2px solid white;
  -webkit-box-shadow:0 1px 2px rgba(0,0,0,.4);
  -moz-box-shadow:0 1px 2px rgba(0,0,0,.4);
  box-shadow:0 1px 2px rgba(0,0,0,.4);
  -webkit-border-radius:100%;
  -moz-border-radius:100%;
  border-radius:100%;
}

#slider-nav .active {
  background-color:green;
}

jQuery

(function($) {

    // Tangkap semua objek yang dibutuhkan
    var $slider = $('#slider'),
        $container = $slider.find('.container'),
        $nav = $('#slider-nav'),
        $slide = $container.children(),
        s_length = $slide.length,
        s_wide = $slider.width() * s_length,
        s_height = $slider.height(),
        autoSlide = null;

    // Set posisi '.container' sebagai 'relative' (untuk kebutuhan animasi properti 'left')
    // Set lebar '.container' dengan ukuran = (lebar slideshow * jumlah slide)
    // Set tinggi '.container' dengan ukuran = tinggi slideshow
    $container.css({
        'position':'relative',
        'width':s_wide,
        'height':s_height
    });

    // Otomatis menyisipkan item navigasi berdasarkan jumlah slide
    $slide.each(function(index) {
        var i = index + 1;
        $nav.append('<a href="#slide-'+i+'">'+i+'</a>');
        $(this).attr('id', 'slide-'+i);
    });

    // Klik untuk mengganti slide
    $nav.find('a').on("click", function(pos) {
        // Tambah/lepas kelas 'active' dari item navigasi (untuk pewarnaan item navigasi yang aktif)
        $nav.find('.active').removeClass('active');
        $(this).addClass('active');
        pos = $(this).index() * $slider.width(); // Jarak animasi dihitung berdasarkan indeks navigasi yang diklik * lebar slider
        $container.animate({left:'-'+pos+'px'}, 600);
        clearInterval(autoSlide); // Bersihkan interval slideshow otomatis...
        autoSlide = setInterval(slideShow, 3000); // Kemudian set kembali interval seperti semula.
        return false;
    }).first().addClass('active');

    // Untuk keperluan event klik otomatis pada navigasi
    function slideShow() {
        if ($nav.find('.active').next().length) {
            $nav.find('.active').next().trigger("click");
        } else {
            $nav.find('a').first().trigger("click");
        }
    } autoSlide = setInterval(slideShow, 3000); // Jalankan fungsi slideShow() dengan interval 3 detik!

})(jQuery);

Lihat Demo Salinan di JSFiddle


Penjelasan Singkat

Kotak Slider

Mendefinisikan ukuran tinggi dan lebar adalah bagian terpenting, karena slideshow ini menggunakan animasi slide (bergerak menyamping dengan jarak tertentu) yang jaraknya ditentukan oleh lebar slideshow:

#slider {
  width:300px; /* lebar slider */
  height:200px;; /* tinggi slider */
  overflow:hidden;
}

#slider .slide {
  width:300px; /* lebar item sama dengan lebar kontainer */
  height:200px; /* tinggi item sama dengan lebar kontainer */
  float:left;
}

Setelah dimensi ditentukan, selanjutnya adalah menyimpan semua data objek dan ukuran yang diperlukan. Diantaranya:

var $slider = $('#slider'), // Slideshow => '#slider'
    $container = $slider.find('.container'), // Kontainer item slider => '.container'
    $nav = $('#slider-nav'), // Navigasi slider => '#slider-nav'
    $slide = $container.children(), // Item slider => '.slide'
    s_length = $slide.length, // Jumlah item slider
    s_wide = $slider.width() * s_length, // (lebar slider * jumlah slide) => digunakan untuk menentukan total ukuran lebar kontainer item slider
    s_height = $slider.height(), // Tinggi slider
    autoSlide = null; // Variabel kosong

Set ukuran kontainer item slider sesuai ukuran yang telah diperhitungkan di atas:

// Set posisi '.container' sebagai 'relative' (untuk kebutuhan animasi properti 'left')
// Set lebar '.container' dengan ukuran s_wide
// Set tinggi '.container' dengan ukuran s_height
$container.css({
    'position':'relative',
    'width':s_wide,
    'height':s_height
});

Navigasi

Anda bisa saja menyisipkan setiap item navigasi secara manual dengan jumlah yang sama berdasarkan jumlah item slider. Tapi Saya lebih menyarankan untuk menggunakan cara otomatis, dengan jQuery .each()

$slide.each(function(index) {
    var i = index + 1;
    $nav.append('<a href="#slide-'+i+'">'+i+'</a>');
    $(this).attr('id', 'slide-'+i);
});

Eksekutor

Fungsi tugas dibuat setelah navigasi terbentuk, yaitu fungsi yang akan menganimasikan elemen .container ke arah kiri dengan jarak tertentu saat sebuah item navigasi diklik:

$nav.find('a').on("click", function(pos) {

    // Tambah/lepas kelas 'active' dari item navigasi (untuk pewarnaan item navigasi yang aktif)
    $nav.find('.active').removeClass('active');
    $(this).addClass('active');

    pos = $(this).index() * $slider.width(); // Jarak animasi => Dihitung berdasarkan indeks navigasi yang diklik * lebar slider

    $container.animate({left:'-'+pos+'px'}, 600); // Animasikan '.container'

    clearInterval(autoSlide); // Bersihkan interval slideshow otomatis...

    autoSlide = setInterval(slideShow, 3000); // Kemudian set kembali interval seperti semula.

    return false;

}).first().addClass('active'); // Tambahkan kelas 'active' pada item navigasi pertama sebagai awalan

Ada dua hal yang belum dijelaskan pada kode di atas, yaitu clearInterval(slideShow) dan setInterval(slideShow, 3000). Bagian itu akan dibuat di bawah:

Utilitas Animasi Otomatis

Pertama, yang dibutuhkan adalah sebuah fungsi seperti ini:

function slideShow() {
    if ($nav.find('.active').next().length) {
       // Saat item navigasi '.active' ditemukan, dan terdapat item navigasi lain disampingnya...
       // seleksi item navigasi di sampingnya kemudian picu event .click() padanya!
        $nav.find('.active').next().trigger("click");
    } else {
        // Jika tidak ditemukan, seleksi item navigasi yang pertama kemudian picu event .click() padanya!
        $nav.find('a').first().trigger("click");
    }
}

Tugasnya adalah untuk mengecek keberadaan item navigasi yang aktif (yang memiliki kelas active). Saat item tersebut ditemukan, maka jQuery akan melihat kepada item di sampingnya kemudian akan memicu event .click(), sehingga fungsi $nav.find('a').on("click", doSomething) yang kita buat sebelumnya bisa bekerja melalui perantara ini. Tambahan lainnya, jika elemen setelah item navigasi tidak ditemukan, maka pindahkan selektor .next() menjadi .first() untuk kembali ke bagian awal, menyeleksi item navigasi pertama.

Terakhir, gunakan JavaScript setInterval() untuk menjalankan slideShow() secara otomatis berdasarkan interval tertentu. Di sini, Saya menggunakan interval selama 3 detik:

// Variabel autoSlide bisa kita gunakan mulai sekarang :)
autoSlide = setInterval(slideShow, 3000);

Selanjutnya: Tip-Tip Modifikasi

Labels: , , , ,

Friday, September 7, 2012

Mendapatkan Nama File dari URL

function getTitle(str) {
    var a = str.lastIndexOf('/') + 1,
        b = str.lastIndexOf('.');
    str = decodeURIComponent(str.substring(a, b));
    str = str.replace(/[\+\-\_]/g, " ");
    return str;
}

Penggunaan

var result = getTitle("//www.blablablah.com/files/JavaScript+Images.jpg");
// Hasil => "JavaScript Images"

Lihat Demo

URL bisa diambil dari mana saja. Sebagai contoh, di sini Saya mencoba mengambil URL dari sebuah gambar untuk disaring sebagai judul:

var a = document.getElementsByTagName('img')[0].src;
document.getElementById('title-container').innerHTML = getTitle(a);

Lihat Demo

Labels: , ,

Wednesday, September 5, 2012

Syntax Highlighter dengan PRISM

Syntax Highlighter dengan PRISM

Meskipun di blog ini Saya menggunakan syntax highlighter dari Software Maniacs, tapi jika diminta untuk memilih dari segi kecepatannya, maka Saya akan menggunakan PRISM, sebuah syntax highlighter untuk HTML, CSS, Java dan JavaScript (bekerja juga untuk PHP dengan asumsi sebagai markup):

Lihat Demo

Proses instalasi hanya membutuhkan dua langkah. Pertama-tama masuklah ke halaman editor HTML Template Anda kemudian pilih Edit HTML dan klik Lanjutkan. Temukan kode ini:

]]></b:skin>

Salin kode CSS ini dan letakkan di atasnya:

/*
Tema pribadi => RDark
Saya buat berdasarkan tema-tema SyntaxHighligter dari Alex Gorbatchev
URL: http://alexgorbatchev.com/SyntaxHighlighter/manual/themes/rdark.html*/

pre {
  padding:.5em 1em;
  margin:.5em 0;
  white-space:pre;
  word-wrap:normal;
  overflow:auto;
  background-color:#1B2426;
}

code {
  font-family:Consolas,Monaco,'Andale Mono','Courier New',Courier,Monospace;
  line-height:16px;
  color:#B43D3D;
  background-color:#eee;
  border:1px solid #ddd;
  padding:1px 2px;
}

pre code {
  display:block;
  background:none;
  border:none;
  color:#B9BDB6;
  direction:ltr;
  text-align:left;
  word-spacing:normal;
  padding:0 0;
}

code .token.punctuation {
  color:#83405A;
}

pre code .token.punctuation {
  color:#B9BDB6;
}

code .token.comment,
code .token.prolog,
code .token.doctype,
code .token.cdata {
  color:#435A4D;
}

code .namespace {
  opacity:.8;
}

code .token.property,
code .token.tag,
code .token.boolean,
code .token.number {
  color:#5BA1CF;
}

code .token.selector,
code .token.attr-name,
code .token.string {
  color:#986A7C;
}

pre code .token.selector,
pre code .token.attr-name,
pre code .token.string {
  color:#E0E8FF;
}

code .token.entity,
code .token.url,
pre .language-css .token.string,
pre .style .token.string {
  color:#E0E8FF;
}

code .token.operator {
  color:#878A85;
}

code .token.atrule,
code .token.attr-value {
  color:#48D30F;
}

pre code .token.atrule,
pre code .token.attr-value {
  color:#48E638;
}

code .token.keyword {
  color:#47A1CF;
  font-style:italic;
}

code .token.comment {
  font-style:italic;
}

code .token.regex {
  color:#B43D3D;
}

code .token.important {
  font-weight:bold;
}

code .token.entity {
  cursor:help;
}

Setelah itu temukan kode ini:

</body>

Letakkan skrip ini di atasnya:

<script "//cdn.rawgit.com/tovic/dte-project/2fd2d2971c3398029ea5e149696447243e7f4d94/prism.min.js"></script>

Klik Simpan Template.

Cara Pemakaian

Setiap tipe bahasa memiliki kelasnya masing-masing:

  • HTML, XML, PHPlanguage-markup
  • CSSlanguage-css
  • JavaScriptlanguage-javascript
  • Javalanguage-java

Kode yang ingin diberi efek harus berada di dalam tag pre > code seperti ini:

<pre><code class="language-markup"> ... kode HTML (yang sudah di`escape`) di sini ... </code></pre>
<pre><code class="language-css"> ... kode CSS di sini ... </code></pre>
<pre><code class="language-javascript"> ... kode JavaScript di sini ... </code></pre>
<pre><code class="language-java"> ... kode Java di sini ... </code></pre>

Tema-tema yang asli bisa Anda temukan di situs sumbernya, PRISM. Atau mungkin Anda mau membuatnya sendiri?

Labels: , , , ,

Tuesday, September 4, 2012

Pure CSS3 Glossy Social Media Drop Down Menu

Pure CSS3 Glossy Social Media Drop Down Menu

Sebuah menu media sosial yang terbuat dari (hampir) murni CSS3. Di sini Saya menggunakan kombinasi CSS3 Gradien dan Box Shadow untuk menciptakan efek realistis. Pada dasarnya, tombol panah di sisi kanan adalah pseudo elemen dari elemen <label> yang kemudian Saya tutupi dengan elemen checkbox.

Setelah itu, Saya menyembunyikan wujudnya dengan CSS transparasi.

Jadi, ketika Anda mengeklik tombol drop down di bagian kanan, maka yang terjadi sebenarnya adalah Anda sedang mengeklik elemen checkbox transparan yang berada di atas elemen palsu (pseudo elemen) dari <label>:

HTML

<div class="glossy-selectbox">
    <input type="checkbox">
    <label data-default="Share This Post!" data-focus="Select one of the social media service..."></label>
    <ul>
        <li><a class="social-rss" href="#" target="_blank">RSS Feed</a></li>
        <li><a class="social-facebook" href="#" target="_blank">Facebook</a></li>
        <li><a class="social-twitter" href="#" target="_blank">Twitter</a></li>
        <li><a class="social-google" href="#" target="_blank">Google+</a></li>
    </ul>
</div>

CSS

/*
 * Pure CSS3 (with some data URI images for the social media icons) Drop Down Menu for Social Media Sharing
 * Author: Taufik Nurrohman
 * URL: https://plus.google.com/108949996304093815163/about
 */

.glossy-selectbox {
  display:inline-block;
  font:normal bold 12px Arial,Sans-Serif;
  position:relative;
  width:300px;
  background-color:#111;
  text-align:left;
  /* CSS3 Browser */
  background-image:-webkit-linear-gradient(top,rgba(255,255,255,.4) 0%,rgba(255,255,255,.2) 50%,rgba(255,255,255,0) 50%,rgba(255,255,255,.1) 100%);
  background-image:-moz-linear-gradient(top,rgba(255,255,255,.4) 0%,rgba(255,255,255,.2) 50%,rgba(255,255,255,0) 50%,rgba(255,255,255,.1) 100%);
  background-image:-ms-linear-gradient(top,rgba(255,255,255,.4) 0%,rgba(255,255,255,.2) 50%,rgba(255,255,255,0) 50%,rgba(255,255,255,.1) 100%);
  background-image:-o-linear-gradient(top,rgba(255,255,255,.4) 0%,rgba(255,255,255,.2) 50%,rgba(255,255,255,0) 50%,rgba(255,255,255,.1) 100%);
  background-image:linear-gradient(top,rgba(255,255,255,.4) 0%,rgba(255,255,255,.2) 50%,rgba(255,255,255,0) 50%,rgba(255,255,255,.1) 100%);
  /* IE only */
  filter:progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr='#333333',endColorstr='#111111');
  -webkit-border-radius:7px;
  -moz-border-radius:7px;
  border-radius:7px;
  -webkit-box-shadow:inset 0 1px 1px 1px rgba(255,255,255,.1),0 1px 3px rgba(0,0,0,.7);
  -moz-box-shadow:inset 0 1px 1px 1px rgba(255,255,255,.1),0 1px 3px rgba(0,0,0,.7);
  box-shadow:inset 0 1px 1px 1px rgba(255,255,255,.1),0 1px 3px rgba(0,0,0,.7);
}

.glossy-selectbox:before,
.glossy-selectbox:after {
  content:"";
  display:block;
  width:0;
  height:0;
  border:3px solid transparent;
  border-width:5px 3px;
  border-bottom-color:#999;
  position:absolute;
  top:25%;
  right:5px;
  z-index:4;
}

.glossy-selectbox:after {
  border-color:#999 transparent transparent;
  top:auto;
  bottom:25%;
}

.glossy-selectbox input {
  display:block;
  position:absolute;
  top:0;
  right:0;
  bottom:0;
  width:15px;
  height:100%;
  opacity:0;
  z-index:10;
  cursor:pointer;
}

.glossy-selectbox label {
  display:block;
  line-height:45px;
  color:rgba(255,255,255,.5);
  padding:0 15px;
  -webkit-transition:all 0s ease-out;
  -moz-transition:all 0s ease-out;
  -ms-transition:all 0s ease-out;
  -o-transition:all 0s ease-out;
  transition:all 0s ease-out;
}

.glossy-selectbox label:before {
  content:attr(data-default);
}

.glossy-selectbox label:after {
  content:"";
  display:block;
  position:absolute;
  top:0;
  right:0;
  bottom:0;
  width:15px;
  border-left:1px solid rgba(0,0,0,.4);
  -webkit-border-radius:0 7px 7px 0;
  -moz-border-radius:0 7px 7px 0;
  border-radius:0 7px 7px 0;
  -webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.1),-1px 0 0 rgba(255,255,255,.1);
  -moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.1),-1px 0 0 rgba(255,255,255,.1);
  box-shadow:inset 1px 0 0 rgba(255,255,255,.1),-1px 0 0 rgba(255,255,255,.1);
}

.glossy-selectbox input:hover + label {
  color:white;
}

.glossy-selectbox input:hover + label:after {
  background-color:rgba(255,255,255,.04);
}

.glossy-selectbox ul {
  margin:0 0;
  padding:0 0;
  position:absolute;
  top:100%;
  left:14px;
  right:14px;
  background-color:#222;
  border:1px solid #111;
  -webkit-box-shadow:0 1px 2px rgba(0,0,0,.4),0 5px 7px -2px rgba(0,0,0,.4);
  -moz-box-shadow:0 1px 2px rgba(0,0,0,.4),0 5px 7px -2px rgba(0,0,0,.4);
  box-shadow:0 1px 2px rgba(0,0,0,.4),0 5px 7px -2px rgba(0,0,0,.4);
  visibility:hidden;
  opacity:0;
  z-index:99;
}

.glossy-selectbox li {
  margin:0 0;
  padding:0 0;
  list-style:none;
  float:left;
  width:50%;
  display:inline;
}

.glossy-selectbox a {
  display:block;
  position:relative;
  color:#999;
  text-decoration:none;
  text-shadow:0 0 2px black;
  line-height:30px;
  border-top:1px solid #111;
  border-right:1px solid #111;
  padding:0 15px 0 32px;
  -webkit-box-shadow:inset 0 0 0 1px #333;
  -moz-box-shadow:inset 0 0 0 1px #333;
  box-shadow:inset 0 0 0 1px #333;
  /* Opera note: An unstable box shadow will appear if you don't define the border radius less than 1 pixel. Weird! */
  -webkit-border-radius:1px;
  -moz-border-radius:1px;
  border-radius:1px;
}

.glossy-selectbox a:nth-child(even) {
  border-right-width:0;
}

.glossy-selectbox a:before {
  content:"";
  display:block;
  width:16px;
  height:16px;
  position:absolute;
  top:7px;
  left:7px;
  background-color:transparent;
  background-repeat:no-repeat;
  background-position:50% 0;
}

.glossy-selectbox a:hover:before {
  background-position:50% 100%;
}

.glossy-selectbox .social-rss:before      {background-image:url('img/social_rss.png');}
.glossy-selectbox .social-facebook:before {background-image:url('img/social_facebook.png');}
.glossy-selectbox .social-twitter:before  {background-image:url('img/social_twitter.png');}
.glossy-selectbox .social-google:before   {background-image:url('img/social_google.png');}

.glossy-selectbox a:hover {
  background-color:rgba(0,0,0,.2);
  color:#ccc;
}

/* On click, then... */
.glossy-selectbox input:checked + label {
  color:rgba(255,255,255,.4);
  -webkit-transition-duration:.4s;
  -moz-transition-duration:.4s;
  -ms-transition-duration:.4s;
  -o-transition-duration:.4s;
  transition-duration:.4s;
}

.glossy-selectbox input:checked + label:before {
  content:attr(data-focus);
}

.glossy-selectbox input:checked + label:after {
  background-color:rgba(0,0,0,.2);
  -webkit-box-shadow:inset 1px 0 1px rgba(0,0,0,.4),-1px 0 0 rgba(255,255,255,.1);
  -moz-box-shadow:inset 1px 0 1px rgba(0,0,0,.4),-1px 0 0 rgba(255,255,255,.1);
  box-shadow:inset 1px 0 1px rgba(0,0,0,.4),-1px 0 0 rgba(255,255,255,.1);
}

.glossy-selectbox input:checked ~ ul {
  visibility:visible;
  opacity:1;
}

Demo

JSFiddle CSSDeck

Labels: ,

Monday, September 3, 2012

Widget Translator Halaman ยท Versi 2

Widget Translator Halaman Ringan - Versi 2

Widget ini dibuat sebagai pengganti aplikasi Google Translate yang berat. Murni, dibuat dari kode HTML dan JavaScript, sehingga Anda bisa terbebas dari permintaan HTTP yang biasanya datang dari JavaScript bawaan widget Google Translate. Di sini JavaScript berfungsi untuk melakukan pemformatan URL translasi berdasarkan pola query string dari Google Translate yang berbentuk seperti ini agar kita bisa menuju ke halaman Google Translate tanpa harus terlibat dengannya pada saat awal kunjungan:

http://translate.google.com/translate?u=http://www.nama-situs.com&langpair=from|to&hl=en
  • from ⇒ Bahasa Asal
  • to ⇒ Bahasa Tujuan

Kode Widget

<style>
#translator-wrapper {
  display:block;
  width:200px;
  border:1px solid #0A340A;
  background-color:white;
  overflow:hidden;
  position:relative;
}
#translator-wrapper select {
  border:none;
  background:transparent;
  font:normal normal 11px Tahoma,Verdana,Arial,Sans-Serif;
  width:100%;
  color:black;
  -webkit-box-sizing:border-box;
  -moz-box-sizing:border-box;
  box-sizing:border-box;
  -webkit-appearance:none;
  cursor:text;
  padding:5px 10px;
}
#translator-wrapper a,
#translator-wrapper a:hover {
  display:block;
  background-color:#0A340A;
  border:none;
  color:white;
  margin:0 0;
  text-decoration:none;
  position:absolute;
  top:0;
  right:0;
  bottom:0;
  cursor:pointer;
  width:30px;
}
#translator-wrapper a:before {
  content:"";
  display:block;
  width:0;
  height:0;
  border:5px solid transparent;
  border-left-color:white;
  position:absolute;
  top:50%;
  left:13px;
  margin-top:-5px;
}
#translator-wrapper a:hover {background-color:#0A2C0A}
#translator-wrapper a:active {background-color:#082408}
#translator-wrapper select:focus,
#translator-wrapper a:focus,
#translator-wrapper select:active,
#translator-wrapper a:active {
  border:none;
  outline:none;
  cursor:pointer;
}
</style>
<h3>Translate this page to:</h3>
<div id="translator-wrapper">
    <select id="translate-language">
        <option value="en" selected="selected">English</option>
        <option value="id">Indonesian</option>
        <option value="af">Afrikaans</option>
        <option value="sq">Albanian</option>
        <option value="ar">Arabic</option>
        <option value="hy">Armenian</option>
        <option value="az">Azerbaijani</option>
        <option value="eu">Basque</option>
        <option value="be">Belarusian</option>
        <option value="bn">Bengali</option>
        <option value="bg">Bulgarian</option>
        <option value="ca">Catalan</option>
        <option value="zh-CN">Chinese</option>
        <option value="hr">Croatian</option>
        <option value="cs">Czech</option>
        <option value="da">Danish</option>
        <option value="nl">Dutch</option>
        <option value="en">English</option>
        <option value="eo">Esperanto</option>
        <option value="et">Estonian</option>
        <option value="tl">Filipino</option>
        <option value="fi">Finnish</option>
        <option value="fr">French</option>
        <option value="gl">Galician</option>
        <option value="ka">Georgian</option>
        <option value="de">German</option>
        <option value="el">Greek</option>
        <option value="gu">Gujarati</option>
        <option value="ht">Haitian Creole</option>
        <option value="iw">Hebrew</option>
        <option value="hi">Hindi</option>
        <option value="hu">Hungarian</option>
        <option value="is">Icelandic</option>
        <option value="id">Indonesian</option>
        <option value="ga">Irish</option>
        <option value="it">Italian</option>
        <option value="ja">Japanese</option>
        <option value="kn">Kannada</option>
        <option value="ko">Korean</option>
        <option value="la">Latin</option>
        <option value="lv">Latvian</option>
        <option value="lt">Lithuanian</option>
        <option value="mk">Macedonian</option>
        <option value="ms">Malay</option>
        <option value="mt">Maltese</option>
        <option value="no">Norwegian</option>
        <option value="fa">Persian</option>
        <option value="pl">Polish</option>
        <option value="pt">Portuguese</option>
        <option value="ro">Romanian</option>
        <option value="ru">Russian</option>
        <option value="sr">Serbian</option>
        <option value="sk">Slovak</option>
        <option value="sl">Slovenian</option>
        <option value="es">Spanish</option>
        <option value="sw">Swahili</option>
        <option value="sv">Swedish</option>
        <option value="ta">Tamil</option>
        <option value="te">Telugu</option>
        <option value="th">Thai</option>
        <option value="tr">Turkish</option>
        <option value="uk">Ukrainian</option>
        <option value="ur">Urdu</option>
        <option value="vi">Vietnamese</option>
        <option value="cy">Welsh</option>
        <option value="yi">Yiddish</option>
    </select><a id="translate-me" href="#" title="Translate!"></a>
</div>
<script>
(function() {
    var mylang = "id", // Your website language
        anchor = document.getElementById('translate-me');
    anchor.onclick = function() {
        window.open('http://translate.google.com/translate?u=' + encodeURIComponent(location.href) + '&langpair=' + mylang + '%7C' + document.getElementById('translate-language').value + '&hl=en');
        return false;
    };
})();
</script>

Salin saja kode di atas lalu letakkan di dalam sebuah widget HTML/JavaScript. Klik Simpan dan lihat hasilnya:

Lihat Demo

Labels: , , ,

jQuery Parallax Background

jQuery Paralax Background

HTML

<section> ... </section>

CSS

body {
  background:black url('img/bg-1.png') repeat-y 0 0;
  margin:0 0;
  padding:0 0;
}

section {
  background:transparent url('img/bg-2.png') repeat-y 0 0;
  padding:50px;
}

jQuery

$(function() {
    var $window = $(window),
        $body = $('body'),
        $section = $('section');
    $window.on("scroll", function() {
        var distance = $(this).scrollTop();
        $body.css('background-position', '0 -' + distance + 'px');
        $section.css('background-position', '0 -' + distance * 2 + 'px');
    });
});

Lihat Demo

Pembaharuan: Versi JavaScript Murni

Menggunakan pageYOffset sebagai pengganti $(window).scrollTop():

(function() {
    var bgLayer = document.getElementsByTagName('div');
    window.onscroll = function() {
        var top = pageYOffset;
        document.body.style.backgroundPosition = '0 ' + (top*2) + 'px';
        bgLayer[0].style.backgroundPosition = '0 ' + (top*0.5) + 'px';
        bgLayer[1].style.backgroundPosition = '0 ' + (top*1.5) + 'px';
        // Dan seterusnya...
    };
})();

Lihat Demo

Labels: , ,

Sunday, September 2, 2012

Solusi Meletakkan Kode CSS Kustom Blogazine Blogspot Sesuai Prosedur Dokumen HTML

Tidak seperti WordPress dengan plugin Art Direction-nya, blogspot tidak memiliki kemampuan untuk menyisipkan sesuatu seperti kode CSS atau JavaScript ke dalam area <head> melalui editor posting karena blogspot tidak dilengkapi dengan fitur khusus untuk menyisipkan kode modifikasi secara sepihak pada posting tunggal.

Saya berbicara mengenai Blogazine, sebuah konsep blog dimana setiap posting memiliki keunikan tampilan sendiri-sendiri. Selama ini para Blogazinist blogspot menggunakan cara yang sederhana untuk menciptakan posting-posting unik, namun cara ini tidak sesuai dengan prosedur dokumen HTML:

Kode CSS di dalam Posting
Kode CSS di dalam Posting

Bukan masalah jika kita meletakkan JavaScript di dalam area <body>, tapi meletakkan CSS di dalam <body> akan menimbulkan resiko ketidakstabilan tampilan pada saat awal halaman termuat. Dan mereka juga tidak valid!

Line 294, Column 23: Element style not allowed as child of element div in this context. (Suppressing further errors from this subtree.) - W3C Markup Validation Service

Baiklah, validasi memang tidak penting. Tapi jika kita masih bisa menghilangkan kesalahan tersebut, kenapa tidak?


Tag Meta Deskripsi

Belum lama ini Blogger memperkenalkan fitur barunya yaitu preferensi penelusuran. Salah satu fitur yang paling menarik menurut Saya adalah formulir meta deskripsi yang memungkinkan kita untuk menambahkan deskripsi penelusuran yang berbeda-beda pada setiap posting – pelajari di sini:

<b:if cond='data:blog.metaDescription'>
  <meta expr:content='data:blog.metaDescription' name='description'/>
</b:if>

Pada intinya, deskripsi yang kita tuliskan di dalam formulir akan ditampilkan pada bagian data:blog.metaDescription yang nantinya akan menjadi deskripsi penelusuran yang Saya maksudkan saat posting sudah diterbitkan. Seperti ini:

<meta content='Deskripsi penelusuran yang Anda tuliskan di dalam formulir…' name='description'/>

Anda bisa menemukan dan mengenali kode-kode XML Blogger seperti yang Saya tuliskan di atas jika Anda sudah mengaktifkan fitur preferensi penelusuran pada bagian Tag Meta dan memodifikasi template yang Anda pakai untuk optimasi mesin penelusuran. Jika Anda tidak menemukannya, Anda harus mulai mempelajari tentang fitur ini dari luar. Artikel ini tidak bermanfaat untuk Anda.

Formulir meta deskripsi inilah yang ingin Saya manfaatkan, karena dia memiliki kemampuan untuk menyimpan data yang berbeda-beda pada setiap posting. Idenya sebenarnya sederhana, yaitu Saya akan menggunakan data meta deskripsi sebagai konten tag <style> secara tidak langsung:

<b:if cond='data:blog.metaDescription'>
<style id='custom-post'>
  <data:blog.metaDescription/>
</style>
</b:if>

Bisa Anda bayangkan bukan? Dengan cara mengubah status data deskripsi penelusuran menjadi konten dari tag <style> seperti di atas, maka kita bisa menyisipkan kode CSS di dalam formulir deskripsi penelusuran untuk ditampilkan di dalam tag <style> sebagai CSS seperti ini:

Formulir Meta Deskripsi Sebagai Penyimpan Data CSS
Formulir Meta Deskripsi sebagai Penyimpan Data CSS

Dan hasilnya, kode CSS yang kita masukkan ke dalam formulir meta deskripsi akan tampil di dalam tag <style id='custom-post'> sebagai CSS saat posting telah diterbitkan:

Hasil Tampilan Setelah Posting Diterbitkan
Hasil Keluaran Setelah Posting Diterbitkan

CSS Eksternal

Alternatif lain, Anda juga bisa menggunakan data meta deskripsi sebagai nilai atribut href pada elemen <link> untuk tipe CSS eksternal, dan Anda bisa menggunakan formulir deskripsi penelusuran untuk menyimpan URL file:

URL File CSS Eksternal
Menyimpan URL File CSS Eksternal ke dalam Formulir Meta Deskripsi

Selanjutnya, format kode template bisa Anda ubah menjadi seperti ini:

<b:if cond='data:blog.metaDescription'>
  <link expr:href='data:blog.metaDescription' media='screen' rel='stylesheet'/>
</b:if>

Hasil akhirnya bisa Anda tebak:

Tag Link Dinamis
Hasil Keluaran

Dengan cara ini maka Anda tidak perlu lagi meletakkan kode CSS di dalam posting dan membuat isi posting Anda menjadi berantakan. Dan proses perbaikan (maintenance) juga akan menjadi lebih mudah. Misalnya, jika Anda ingin menonaktifkan fitur posting unik pada blog Anda, maka Anda cukup menghapus kode <data:blog.metaDescription/> dari template sehingga data tidak akan terpanggil. Saya sudah beberapa kali mengetes formulir tag meta yang ada pada editor posting dan dia bisa menampung teks tanpa batas!

Pahami Resiko

Walau bagaimanapun juga, metode ini adalah metode yang tidak standar dan tidak sesuai dengan prosedur perkembangan Blogger, karena kita menggunakan direktori deskripsi penelusuran sebagai direktori CSS. Saya hanya sedang mencoba untuk memecahkan masalah dengan apa yang ada dari Blogger saat ini. Karena tidak ada rotan, maka Saya gunakan akar.

Ya, itu jika dilihat dari sisi Blogger, tapi jika dilihat dari sisi hasil akhir, maka metode ini bisa dijadikan sebagai jalan keluar untuk mengikuti prosedur dokumen HTML yang benar, yaitu: “Tag <style> harus berada di dalam tag <head>!”

Saya juga tidak bisa menjamin bahwa formulir deskripsi penelusuran akan terus bisa menampung teks tanpa batas. Bukan hal yang tidak mungkin jika suatu saat Blogger memutuskan untuk membatasi jumlah teks deskripsi penelusuran. Saya sudah mencobanya sampai sejauh ini dan semuanya baik-baik saja. Selanjutnya adalah pilihan Anda, apakah Anda mau mengambil resiko atau tidak, karena Anda berada dalam situasi yang penuh dengan keterbatasan.

Lupakan SEO! – Seperti perkataan para Blogazinist pada umumnya, sayangnya Anda harus sedikit mengabaikan mengenai SEO karena Anda telah menggunakan data:blog.metaDescription untuk hal lain yang sama sekali tidak berhubungan dengan meta deskripsi.

Tapi itu juga bukan berarti bahwa Anda akan kehilangan deskripsi penelusuran Anda. Anda masih bisa menggunakan cara lama, yaitu menuliskan deskripsi tag meta secara manual. Hanya saja nilainya tidak bisa berubah-ubah:

<!-- Manual Meta Description -->
<meta content='Deskripsi penelusuran utama Anda...' name='description'/>
<!-- Hack: Art Direction Plugin for Blogger with Meta Description Data -->
<b:if cond='data:blog.metaDescription'>
<style id='custom-post'>
  <data:blog.metaDescription/>
</style>
</b:if>

Labels: , , , ,