Tampilkan postingan dengan label Menengah. Tampilkan semua postingan
Tampilkan postingan dengan label Menengah. Tampilkan semua postingan

Selasa, 02 Februari 2016

Menggunakan `b:include` dan `b:includable`

Kita menggunakan perintah b:include dan b:includable untuk menciptakan bagian halaman tertentu di dalam widget, yang mana bagian halaman tersebut dapat kita tempatkan atau kita panggil berkali-kali. Pertama kali, kita akan menggunakan b:includable untuk membuat sebuah bagian pada halaman, dan kemudian menggunakan b:include untuk memanggil bagian halaman tersebut.

Ambil sebuah contoh, Saya akan membuat sebuah bagian halaman berupa deretan tombol berbagi. Agar Saya bisa meletakkan deretan tombol berbagi tersebut di bagian atas judul posting dan di bagian bawah konten posting tanpa harus menuliskan kode HTML yang sama sebanyak dua kali, maka di sini Saya akan menggunakan b:includable untuk mencatat kode HTML–nya terlebih dahulu..

Kode di bawah ini bisa Anda tuliskan di mana saja di dalam elemen <b:widget>, namun tidak di dalam elemen <b:includable> yang lain. Cara yang paling mudah adalah dengan meletakkan kode ini di bawah tag </b:includable> yang pertama kali Anda temukan:

<b:includable id='my-custom-share-buttons'>
<!-- Kode HTML tombol berbagi di sini… -->
</b:includable>

Setelah Anda membuat bagian halaman tersebut, maka Anda bisa memanggilnya dengan menggunakan perintah b:include seperti ini:

<b:include name='my-custom-share-buttons'/>

Contoh:

<b:include name='my-custom-share-buttons'/>
<h2 class='post-title'>
<a expr:href='data:post.url'>
<data:post.title/>
</a>
</h2>
<div class='post-body'>
<data:post.body/>
</div>
<b:include name='my-custom-share-buttons'/>
<footer class='post-footer'>

</footer>

Sabtu, 30 Agustus 2014

Efisien dengan `inherit`

CSS ‘inherit’

Terkadang kita menemui sebuah saat dimana kita harus membuat sebuah elemen judul bersatu dengan tautan, namun keduanya harus tetap memiliki warna yang sama. Bagian yang paling sering mendapatkan kondisi seperti ini adalah ada pada bagian header sebuah halaman web:

<header class="blog-header">
<h1 class="blog-title">
<a href="/">Blog Title</a>
</h1>
<p class="blog-slogan">Blog slogan goes here.</p>
</header>

Pada web-web standar, umumnya bagian ini memiliki sebuah sikap yang unik, yaitu ketika seorang pengguna sedang berada di halaman muka, maka tautan tidak akan diterapkan pada judul tersebut, akan tetapi ketika pengguna tersebut sedang berada di halaman yang lain, maka tautan menuju halaman muka akan diterapkan pada judul tersebut. Seperti inilah kira-kira kondisinya:

<header class='blog-header'>
<b:if cond='data:blog.url != data:blog.homepageUrl'>
<h1 class='blog-title'>
<a expr:href='data:blog.url'>Blog Title</a>
</h1>
<b:else/>
<h1 class='blog-title'>Blog Title</h1>
</b:if>
<p class='blog-slogan'>Blog slogan goes here.</p>
</header>

Memastikan agar warna elemen judul tetap sama di mana saja itu penting agar semuanya terlihat konsisten. Katakanlah kita akan membuat warna judul blog di atas menjadi hijau:

.blog-header h1 {color:green}

Ini akan berhasil jika kita sedang berada di halaman depan. Judul halaman akan berwarna hijau. Akan tetapi ketika kita berpindah ke halaman lain, warna judul akan berubah menjadi sama dengan warna tautan karena teks judul sekarang terbungkus oleh tautan yang posisinya berada di dalam elemen judul.

Untuk mengatasi masalah tersebut, biasanya kita akan melakukan hal ini:

.blog-header h1 {color:green}
.blog-header h1 a {color:green}

Saya biasa menemui deklarasi CSS semacam itu pada judul-judul posting di dalam sebuah templat Blogger:

.post-title {
font:normal normal 20px/1.4 "Open Sans",Sans-Serif;
margin:0 0 .5em;
text-shadow:none;
color:#5686D6;
}

.post-title a,
.post-title a:focus,
.post-title a:hover,
.post-title a:active {
color:#5686D6;
text-decoration:none;
}

Ini tidak efisien, karena jika suatu hari nanti kita ingin mengganti warna elemen judul tersebut, maka kita harus mengubah kode warnanya sebanyak minimal dua kali. Seandainya jumlah deklarasi semacam ini cuma ada satu saja mungkin tidak masalah, tapi bagaimana kalau ada banyak? Apalagi jika posisinya tidak berdekatan seperti contoh di atas. Mungkin posisi deklarasi warna elemen judul berada di sebelah sini dan posisi deklarasi warna tautan judul berada di sebelah sana. Pasti akan tambah susah lagi untuk mencarinya.

“Each property may also have a cascaded value of ‘inherit’, which means that, for a given element, the property takes the same specified value as the property for the element’s parent.” — CSS2 – The ‘inherit’ Value

Menggunakan nilai inherit bisa menjadi solusi. Dengan menuliskan nilai inherit pada properti CSS tertentu, maka nilai properti tersebut akan mengikuti nilai properti yang sama dari elemen induknya:

.blog-header h1 {color:green}
.blog-header h1 a {color:inherit}

Dengan begitu, setiap kali kita mengubah warna elemen judul pada contoh di atas, maka warna tautan di dalamnya akan selalu mengikuti.

Contoh lain ada pada masalah warna border. Terkadang kita menemui sebuah kasus dimana kita harus membuat sebuah tata letak halaman dengan beberapa border di dalamnya yang semua warnanya harus sama. Dengan memanfaatkan nilai inherit, kita bisa mewarnai semua border cukup pada elemen induknya saja:

Contoh lain lagi adalah mengenai cara paling efisien untuk mengubah tipe fon pada elemen-elemen formulir menjadi sama dengan tipe fon pada halaman:

button,
input,
select,
textarea {font:inherit}

Kamis, 03 April 2014

PHP Konversi Array Menjadi HTML List

PHP

function array_to_list($array, $list_type = 'ul') {
$output = '<' . $list_type . '>';
foreach($array as $key => $values) {
if(is_array($values)) {
$output .= '<li><a href="#">' . $key . '</a>' . array_to_list($values, $list_type) . '</li>';
} else {
$output .= '<li><a href="#' . $values . '">' . $key . '</a></li>';
}
}
return $output . '</' . $list_type . '>';
}

Penggunaan

Ubah array $test menjadi elemen HTML daftar:

// Testing...
$test = array(
'A' => 'list-A',
'B' => 'list-B',
'C' => 'list-C',
'D' => array(
'AA' => 'list-AA',
'AB' => 'list-AB',
'AC' => 'list-AC',
'AD' => array(
'ADA' => 'list-ADA',
'ADB' => 'list-ADB',
'ADC' => 'list-ADC'
),
'AE' => 'list-AE'
),
'E' => 'list-E'
);

echo array_to_list($test, 'ol');

Akan menghasilkan ini:

Selasa, 01 April 2014

Range Slider Kustom Sederhana

Simplest JavaScript Custom Range Slider

Dapat digunakan sebagai alternatif JQuery UI Slider atau plugin-plugin sejenis yang memiliki ukuran berkas cukup besar. Terkadang Saya memerlukan sesuatu yang sejenis dengan itu, tetapi dengan fitur yang lebih sederhana. Asalkan bisa digunakan untuk memperbaharui nilai dengan cara menggeser-geser dragger maka itu sudah cukup. Jadi Saya membuat ini:

Dasar Penggunaan

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test</title>
<link href="css/shell.css" rel="stylesheet">
</head>
<body>

<div id="range-slider-1"></div>

<script src="js/range-slider.js"></script>
<script>
rangeSlider(document.getElementById('range-slider-1'), {
drag: function(v) {
console.log(v + '%');
}
});
</script>
</body>
</html>

Konfigurasi

OpsiKeterangan
valueDigunakan untuk menentukan posisi dragger saat inisiasi. Nilai yang bisa diterima adalah dari angka 1 sampai 100 (berdasarkan persentase).
verticalSet sebagai true untuk membuat range slider vertikal.
rangeClassDigunakan untuk menambahkan kelas ekstra pada jalur penggeser.
draggerClassDigunakan untuk menambahkan kelas ekstra pada penggeser.
dragFungsi untuk menampilkan nilai range slider ke elemen tertentu.
var defaults = {
value: 0, // set default value on initiation from `0` to `100` (percentage based)
vertical: false, // vertical or horizontal?
rangeClass: "", // add extra custom class for the range slider track
draggerClass: "", // add extra custom class for the range slider dragger
drag: function(v) { /* console.log(v); */ } // function to return the range slider value into something
};

Lolos tes pada semua peramban mayor, termasuk Internet Explorer 8.

Sabtu, 06 Juli 2013

Widget Artikel Terkait Blogger: 6 dalam 1

Pembaharuan 7 Februari 2015: Halaman proyek dipindah dari blogger-json-experiment ke dte-project untuk memperbaiki bug pada URL yang memiliki kueri ?m=0 atau ?m=1 di dalamnya.

Contoh tampilan widget artikel terkait Blogger yang paling populer
Contoh-contoh tampilan widget. Klik untuk memperbesar gambar.

Saat ini terdiri dari 6 jenis tampilan yang bisa Anda sesuaikan sendiri. Widget ini merupakan pengembangan dari konsep random post ringan yang pernah Saya tuliskan di sini. Hanya saja, karena pemanggilan feed posting difilter melalui label posting yang spesifik, maka widget random post ini sekarang bisa dijadikan sebagai widget artikel terkait (random post dengan sortir label otomatis berdasarkan posting).

Widget-widget artikel terkait yang lama kurang bersahabat menurut Saya, sehingga Saya membuatnya lagi secara pribadi. Dan untuk menyingkat jumlah posting, maka model-model widget artikel terkait yang sudah populer kini telah Saya gabungkan menjadi satu kesatuan. Tujuan utamanya tetap. Mencoba untuk menampilkan posting-posting lama dengan jarak waktu penerbitan yang tidak terbatas namun dengan tenaga sesedikit mungkin:

Klik tombol Preview & Get Code! Di situ nanti Anda akan mendapatkan kode CSS dan XML template. Masuk ke halaman editor HTML template kemudian letakkan kode CSS yang dihasilkan di atas kode ]]></b:skin>. Kode XML bisa Anda letakkan di mana saja di dalam elemen <b:includable id='post' var='post'/>, tapi Saya sarankan untuk meletakkan kode tersebut di atas kode ini karena posisinya yang mudah ditemukan dan lebih minim resiko:

<div class='post-footer'>

Tabel Pengaturan

Pengaturannya tidak banyak, dan karena Saya sudah membuat generatornya, jadi Anda sebenarnya tidak perlu lagi menyentuh variabel-variabel di dalam widget ini secara langsung. Tabel ini Saya buat untuk kepentingan dokumentasi saja:

OpsiKeterangan
widgetStyleKode model widget artikel terkait berupa angka. Mengubah nilai variabel ini akan mengubah markup HTML widget, sehingga kode CSS harus disesuaikan ulang. Lebih baik gunakan generator.
homePageDigunakan untuk menentukan URL blog Anda. Nilai sudah diotomatisasikan melalui elemen <data:blog.homepageUrl/>
widgetTitleMarkup HTML untuk judul/kepala widget. Bisa digunakan untuk menyisipkan kode HTML lain juga jika mau. Kode tersebut nantinya akan tampil di atas daftar item posting di dalam widget.
numPostsDigunakan untuk menentukan jumlah posting yang ingin ditampilkan.
summaryLengthDigunakan untuk menentukan panjang karakter ringkasan posting.
titleLengthDigunakan untuk memotong jumlah karakter judul posting sesuai dengan besar angka yang dituliskan. Ubah menjadi "auto" untuk menonaktifkan pemotongan karakter pada judul posting.
thumbnailSizeDigunakan untuk menentukan lebar/tinggi thumbnail posting yang berbentuk kotak.
noImageIsi dengan URL gambar cadangan untuk posting yang tidak memiliki gambar.
containerIdID elemen HTML untuk menampung daftar posting yang berhasil terpanggil.
newTabLinkUbah nilainya menjadi true untuk membuat tautan-tautan di dalam widget ini membuka di tab/jendela baru secara otomatis ketika diklik.
moreTextTeks “Baca Selengkapnya”.
callBackFungsi tambahan yang akan bekerja setelah daftar posting termuat ke dalam kontainer widget. Lihat penjelasannya di bawah.

Menerapkan Fungsi callBack Widget

Opsi ini berfungsi untuk menciptakan perilaku tambahan pada widget. Fungsi ini akan bekerja setelah widget berhasil dimuat. Cocok digunakan untuk menambahkan efek-efek khusus. Dasar penerapannya adalah seperti ini. Kode di bawah ini akan menampilkan pesan peringatan bahwa widget telah berhasil termuat jika widget berhasil termuat:

var relatedPostConfig = {
callBack: function() {
alert('Widget successfully loaded.');
}
};

Contoh 1: Membuat Efek Transisi Hover pada Tooltip

Set tampilan widget menjadi artikel terkait dengan tooltip, kemudian buat fungsi JQuery seperti ini:

var relatedPostConfig = {
...
widgetStyle: 4,
containerId: "random-post",
callBack: function() {
$('#' + this.containerId + ' li').hover(function() {
$('.related-post-item-tooltip', this).filter(':not(:animated)').animate({
marginBottom: -5,
opacity: "show"
}, 400);
}, function() {
$('.related-post-item-tooltip', this).animate({
marginBottom: 10,
opacity: "hide"
}, 200);
}).find('.related-post-item-tooltip').css('margin-bottom', 10);
}
};

Hapus efek :focus dan :hover pada CSS:

.related-post-style-4 .related-post-item:focus .related-post-item-tooltip,
.related-post-style-4 .related-post-item:hover .related-post-item-tooltip {display:block}

Contoh 2: Membuat Efek Sliding pada Tabir Judul

Set tampilan widget menjadi artikel terkait dengan tabir tooltip:

var relatedPostConfig = {
...
widgetStyle: 5,
titleLength: 50,
thumbnailSize: 130,
containerId: "random-post",
callBack: function() {
$('#' + this.containerId + ' li').hover(function() {
$('.related-post-item-tooltip', this).filter(':not(:animated)').animate({
marginTop: "50%"
}, 400);
}, function() {
$('.related-post-item-tooltip', this).animate({
marginTop: "100%"
}, 200);
}).find('.related-post-item-tooltip').css('margin-top', '100%');
}
};

Hapus deklarasi display:none pada selektor tooltip widget, hapus juga efek :focus dan :hover pada CSS:

.related-post-style-5 .related-post-item-tooltip {
display:block;
background-color:black;
background-color:rgba(0,0,0,.9);
position:absolute;
top:0;
right:0;
bottom:0;
left:0;
padding:10px;
line-height:normal;
font-style:italic;
color:white;
overflow:hidden;
display:none;
}
.related-post-style-5 .related-post-item:focus .related-post-item-tooltip,
.related-post-style-5 .related-post-item:hover .related-post-item-tooltip {display:block}

Contoh 3: Membuat Efek News Ticker

Set tampilan widget menjadi artikel terkait tipe thumbnail dan summary:

var relatedPostConfig = {
...
numPosts: 10,
widgetStyle: 2,
containerId: "random-post",
callBack: function() {
var $container = $('#' + this.containerId + ' > ul'),
$list = $container.find('li'),
innerHeight = $list.first().height(),
outerHeight = $list.first().outerHeight(true);
// Container & list height setup
$container.css({
"height": outerHeight * $list.length / 2,
"overflow": "hidden"
});
$list.css({
"height": innerHeight,
"overflow": "hidden"
});
// Animation
function newsTicker() {
window.setTimeout(function() {
$container.find('li:last').stop().animate({
opacity: 0
}, 1000, function() {
$(this).hide().prependTo($container).slideDown(1000, function() {
$(this).stop().animate({
opacity: 1
}, 1000, newsTicker);
});
});
}, 3000);
} newsTicker();
}
};

Dan seterusnya. Buat efek-efek baru yang lain sesuka hati melalui opsi callBack.

Catatan: Saat menerapkan beberapa fungsi di atas, mungkin templat Anda nanti menjadi tidak bisa disimpan. Cobalah untuk mengelilingi fungsi callBack dengan komentar CDATA seperti ini:

var relatedPostConfig = {
callBack: function() {
//<![CDATA[

Tuliskan fungsi di sini...

//]]>
}
};

Atau baca posting ini sebagai referensi tambahan.

Senin, 22 April 2013

Mengaktifkan Fitur Komentar Google+ (Untuk yang Gagal)

Baru-baru ini Blogger telah merilis fitur komentar baru yang memungkinkan kita untuk mengintegrasikan komentar Blogger ke Google+. Untuk mengaktifkannya mudah. Masuk saja ke tab Google+ kemudian centang pilihan “Gunakan Google+ Komentar di blog ini”:

Beralih ke sistem komentar Google+
Berpindah ke sistem komentar Google+

Jika template blog yang digunakan masih standar, seharusnya area komentar lama akan langsung digantikan dengan komentar baru dari Google+. Tapi jika template yang dipakai sudah tidak standar lagi, kita masih bisa menggunakan cara manual untuk menampilkan komentar Google+. Berikut ini adalah langkah-langkahnya:

Pertama-tama masuk ke halaman editor HTML template kemudian cari kode ini (loncat saja ke widget Blog1, kemudian jabarkan):

<b:includable id='comments' var='post'>

Jangan lupa untuk menyimpan salinan template ke komputer sebelum melakukan modifikasi.

Setelah ditemukan, salin kode di bawah ini kemudian letakkan di atasnya:

<b:includable id='g-comments' var='post'>

<div id='g-comments-outer'>
<div class='g-comments' expr:data-href='data:blog.canonicalUrl' data-width='600' data-first_party_property='BLOGGER' data-view_type='FILTERED_POSTMOD'>
<a href='#g-comments-outer' id='g-comments-loader'>Add Comments</a>
</div>
</div>

<!-- For slow connection -->
<script type='text/javascript'>
//<![CDATA[
(function() {
var btn = document.getElementById('g-comments-loader'),
showGC = function() {
var script = document.createElement('script'),
head = document.getElementsByTagName('head')[0], old;
script.type = "text/javascript";
script.id = "g-comments-script";
script.src = "//apis.google.com/js/plusone.js";
if (document.getElementById('g-comments-script')) {
old = document.getElementById('g-comments-script');
old.parentNode.removeChild(old);
}
head.appendChild(script);
};
btn.onclick = function() {
this.innerHTML = "Memuat...";
showGC();
return false;
};
})();
//]]>
</script>

</b:includable>

Kode 600 merupakan variabel untuk menentukan lebar area komentar. Sesuaikan dengan lebar area posting blog Anda. Jika perlu ganti juga label Add Comments dengan kata-kata yang lain.

Setelah itu cari kode ini kemudian jabarkan:

<b:includable id='main' var='top'>

Temukan kode yang kurang lebih tampak seperti ini:

<b:include data='post' name='post'/>
<b:if cond='data:blog.pageType == &quot;static_page&quot;'>
<b:include data='post' name='comment_picker'/>
</b:if>
<b:if cond='data:blog.pageType == &quot;item&quot;'>
<b:include data='post' name='comment_picker'/>
</b:if>

Ganti dengan kode ini:

<b:include data='post' name='post'/>
<b:if cond='data:blog.pageType == &quot;static_page&quot;'>
<!-- b:include data='post' name='comment_picker'/ -->
<b:include data='post' name='g-comments'/>
</b:if>
<b:if cond='data:blog.pageType == &quot;item&quot;'>
<!-- b:include data='post' name='comment_picker'/ -->
<b:include data='post' name='g-comments'/>
</b:if>

Atau jika tidak ada kode yang tampak seperti di atas, mungkin karena bentuknya masih seperti ini:

<b:include data='post' name='post'/>
<b:if cond='data:blog.pageType == &quot;static_page&quot;'>
<b:include data='post' name='comments'/>
</b:if>
<b:if cond='data:blog.pageType == &quot;item&quot;'>
<b:include data='post' name='comments'/>
</b:if>

Ganti dengan kode ini, jika yang ditemukan adalah kode dengan pola yang ke dua:

<b:include data='post' name='post'/>
<b:if cond='data:blog.pageType == &quot;static_page&quot;'>
<!-- b:include data='post' name='comments'/ -->
<b:include data='post' name='g-comments'/>
</b:if>
<b:if cond='data:blog.pageType == &quot;item&quot;'>
<!-- b:include data='post' name='comments'/ -->
<b:include data='post' name='g-comments'/>
</b:if>

Klik Simpan Template. Seharusnya sekarang komentar Google+ sudah tampil di bawah posting.

Langkah Terakhir

Langkah terakhir adalah menghilangkan tanda centang pada pilihan “Gunakan Google+ Komentar di blog ini” di tab Google+. Mengapa? Karena fitur komentar Google+ yang kita buat sekarang sudah ditampilkan dengan cara manual. Dengan cara menampilkan komentar Google+ secara manual, maka ini memungkinkan kita untuk melakukan modifikasi area komentar dengan lebih leluasa karena markup HTML yang dibuat telah disisipkan secara manual juga. Sehingga —sebenarnya— kita bisa menampilkan komentar Google+ ini di area manapun yang kita suka, yaitu berdasarkan letak elemen #g-comments-outer.

Suatu saat mungkin Anda ingin membuat tampilan komentar ini menjadi berbentuk seperti jendela munculan.

Tapi jujur saja, secara pribadi Saya tidak begitu tertarik untuk mengaktifkan fitur ini, sama halnya dengan ketidaktertarikan Saya untuk menyisipkan komentar Facebook di dalam blog Blogger. Jika Saya bisa menggunakan fitur bawaan yang ada, mengapa Saya harus menggunakan pihak ke tiga? Tapi ini cuma pendapat. Jika Anda berminat untuk berpindah ke sistem komentar Google+, ikuti saja langkah-langkah di atas. Lagipula komentar yang masuk akan terintegrasi secara langsung dengan komentar Blogger, sehingga jika suatu saat Anda ingin kembali untuk menggunakan fitur komentar bawaan dari blog, maka komentar-komentar yang sebelumnya telah terbit ke Google+ akan tampil kembali di komentar Blogger.

Seharusnya sih begitu.

Membuat Navigasi Halaman AJAX pada Blogger

Prinsipnya sederhana. Di sini Saya menggunakan navigasi Posting Lebih Lama sebagai navigasi AJAX dan menggunakan JQuery $.get() untuk memanggil URL pada navigasi tersebut:

// Menyingkirkan navigasi posting lebih baru (Navigasi ini tidak diperlukan)
$('#blog-pager').find('#blog-pager-newer-link').remove();

// Dasar AJAX navigasi
$('#blog-pager').on("click", "#blog-pager-older-link a", function() {
$.get(this.href, {}, function(data) {
// Proses...
}, "html");
return false;
});

Kita akan menggunakan elemen .blog-posts untuk memuat posting-posting baru dari halaman selanjutnya.

Menerapkan AJAX pada Navigasi Halaman

Pastikan JQuery sudah terpasang pada template. Masuk ke editor HTML template, kemudian salin kode ini dan letakkan di atas </body>:

<b:if cond='data:blog.pageType != &quot;item&quot;'>
<b:if cond='data:blog.pageType != &quot;static_page&quot;'>
<script type='text/javascript'>
//<![CDATA[
(function($) {
var $pager = $('#blog-pager'),
$posts = $('.blog-posts');
$pager.find('#blog-pager-newer-link').remove(); // Menyingkirkan navigasi posting lebih baru
$pager.on("click", "#blog-pager-older-link a", function() {
$.get(this.href, {}, function(data) {
var source = $(data).find('.post').length ? $(data) : $('<div></div>');
$posts.append(source.find('.blog-posts').html()); // Menyisipkan posting
$pager.html(source.find('#blog-pager-older-link').clone()); // Memperbaharui navigasi
}, "html");
$(this).replaceWith('<span>Memuat...</span>'); // Ubah navigasi posting menjadi indikator memuat saat sedang memuat
return false;
});
})(jQuery);
//]]>
</script>
</b:if>
</b:if>

Klik Simpan Template.

Sekarang coba buka halaman blog Anda kemudian klik navigasi Posting Lama atau Older Post. Jika navigasi tersebut berubah menjadi teks bertuliskan “memuat...” seperti ini, maka itu artinya AJAX sedang bekerja:

Ini adalah gambar navigasi halaman yang sedang memuat halaman baru dengan AJAX
Indikator sedang memuat

Tunggu sampai posting-posting baru muncul di bawah posting-posting yang sedang terlihat saat ini.

Infinite Scroll (?)

Untuk menciptakan infinite scroll pada sistem navigasi halaman, cukup nyatakan event .scroll() pada $(window) dan cek apakah jarak gulungan layar telah mencapai batas akhir atau belum. Jika ya, picu event .click() pada navigasi AJAX yang telah kita buat sebelumnya.

Dalam kasus ini, Saya menentukan batas akhir gulungan layar bukan berdasarkan tinggi halaman, melainkan berdasarkan posisi navigasi terhadap bagian teratas dari layar:

(function($) {

var $pager = $('#blog-pager'),
$posts = $('.blog-posts'),
loading = false;

// AJAX
$pager.find('#blog-pager-newer-link').remove(); // Menyingkirkan navigasi posting lebih baru
$pager.on("click", "#blog-pager-older-link a", function() {
$.get(this.href, {}, function(data) {
var source = $(data).find('.post').length ? $(data) : $('<div></div>');
$posts.append(source.find('.blog-posts').html());
$pager.html(source.find('#blog-pager-older-link').clone());
loading = false;
}, "html");
$(this).replaceWith('<span>Memuat...</span>'); // Ubah navigasi posting menjadi indikator memuat saat sedang memuat
return false;
});

// INFINITE SCROLL
$(window).on("scroll resize", function() {
// Jika AJAX sedang tidak memuat dan jika jarak gulungan layar + tinggi layar telah mencapai
// tinggi yang sama dengan/lebih besar dari offset navigasi halaman terhadap bagian teratas dari layar...
if (!loading && ($(this).scrollTop() + $(this).height()) >= $pager.offset().top) {
$pager.find('#blog-pager-older-link a').trigger("click"); // Picu event `.click()` pada navigasi AJAX posting
loading = true; // Mulai antre pemuatan
}
});

})(jQuery);

Catatan: JavaScript Auto Read-More akan tereksekusi saat halaman dimuat dengan cara biasa, sehingga jangan kaget jika posting-posting baru yang dimuat oleh AJAX tidak akan terpotong menjadi ringkasan posting. Saya sarankan Anda untuk menggunakan konsep ringkasan posting tanpa JavaScript yang pernah Saya tuliskan sebelumnya di sini.

Rabu, 27 Maret 2013

Tentang Tooltip Deskripsi pada Formulir HTML

Gambaran Tooltip pada Formulir HTML

Memaksimalkan kerja selektor adjacent sibling sangat bermanfaat untuk menciptakan komunikasi yang lebih hidup pada saat proses pengisian formulir untuk pengunjung/anggota. Idenya adalah, seorang calon anggota mencoba untuk mengisi formulir. Dan saat kursor teks aktif di dalam elemen formulir tersebut, maka akan muncul pesan singkat di sebelahnya yang menjelaskan tentang apa saja yang harus calon anggota lakukan terhadap formulir yang sedang aktif tersebut.

Ide di atas bisa kita realisasikan hanya dengan cara seperti ini:

HTML

<input type="text">
<label>Mohon ketik setiap awalan dengan huruf kapital</label>

CSS

/* Menyembunyikan label-label formulir */
label {visibility:hidden}

/* Menampilkan label formulir saat elemen input terfokus */
input:focus + label {visibility:visible}

Yang kemudian akan menghasilkan komunikasi antarmuka seperti ini:

Melakukan beberapa pembaharuan pada tampilan elemen <label> untuk membuatnya tampak sebagai tooltip serta menambahkan efek transisi untuk memperlembut proses tampilnya deskripsi/pesan formulir, maka akan membuat komunikasi antarmuka menjadi semakin tegas tanpa harus meminta pengunjung yang sedang mengisi formulir tersebut pergi menuju ke halaman khusus mengenai panduan cara mengisi formulir. Dengan cara ini, pengunjung/calon anggota akan dipandu pada saat yang sama ketika mereka sedang mengisi formulir:

HTML

<div class="form-item">
<input type="text">
<label>Descriptions...</label>
</div>

CSS

/* Form item wrapper */
.form-item {
margin:1em 0 0;
position:relative;
}

/* Form item title */
.form-item strong {
display:block;
margin:0 0 5px;
}

/* Form items */
.form-item input,
.form-item textarea {
display:block;
border:1px solid #ccc;
padding:4px;
margin:0 0;
width:250px;
font:inherit;
line-height:normal;
color:inherit;
-webkit-box-shadow:inset 0 1px 3px -1px rgba(0,0,0,.2);
-moz-box-shadow:inset 0 1px 3px -1px rgba(0,0,0,.2);
box-shadow:inset 0 1px 3px -1px rgba(0,0,0,.2);
}

/* Tooltip */
.form-item label {
display:block;
position:absolute;
bottom:100%;
left:150px;
margin-bottom:2em;
font-size:11px;
font-weight:bold;
color:white;
white-space:nowrap;
line-height:normal;
padding:.6em 1em;
background-color:black;
-webkit-border-radius:3px;
-moz-border-radius:3px;
border-radius:3px;
visibility:hidden;
opacity:0;
/* Transition effect */
-webkit-transition:all .2s ease-out;
-moz-transition:all .2s ease-out;
-ms-transition:all .2s ease-out;
-o-transition:all .2s ease-out;
transition:all .2s ease-out;
}

/* Tooltip arrow */
.form-item label:after {
content:"";
display:block;
width:0;
height:0;
border:5px solid transparent;
position:absolute;
top:100%;
left:2em;
border-top-color:black;
}

.form-item input:focus,
.form-item textarea:focus {border-color:#aaa}

/* Show tooltip when the form is being focused */
.form-item input:focus + label,
.form-item textarea:focus + label {
visibility:visible;
opacity:1;
margin-bottom:-.5em;
}

Senin, 11 Februari 2013

Input Teks dengan Ikon Pembersih

Text Input with Clear Button

Pada peramban WebKit seperti Google Chrome dan Safari, sebuah elemen input bertipe search memiliki kemampuan untuk menampilkan ikon/tombol pembersih kecil di samping input teks jika kita telah mengetikkan sesuatu di dalamnya. Tapi tidak pada peramban yang lain. Terkadang kita merasa butuh dan menyukai fitur itu, dan berharap bisa bekerja pada semua peramban.

Kita bisa menggunakan markup ekstra dan sedikit JavaScript untuk menciptakan rekayasa seperti itu. Tapi untuk memastikan tampilannya polos, gunakan elemen input bertipe text, bukan search:

HTML

<form id="search-form" action="/search" method="get">
<span class="text-input-wrapper">
<input type="text" name="q" size="18"><span title="Clear">&times;</span>
</span>
<input type="submit" value="Submit">
</form>

CSS

.text-input-wrapper {
border:1px solid;
background-color:white;
padding:1px 6px 1px 1px;
display:inline-block;
}

.text-input-wrapper input {
border:none;
background:none;
outline:none;
padding:0 0;
margin:0 0;
font:inherit;
}

.text-input-wrapper span {
cursor:pointer;
color:blue;
font-weight:bold;
visibility:hidden;
}

JavaScript

(function() {
var searchForm = document.getElementById('search-form'),
textInput = searchForm.q,
clearBtn = textInput.nextSibling;
textInput.onkeyup = function() {
// Show the clear button if text input value is not empty
clearBtn.style.visibility = (this.value.length) ? "visible" : "hidden";
};
// Hide the clear button on click, and reset the input value
clearBtn.onclick = function() {
this.style.visibility = "hidden";
textInput.value = "";
};
})();

Demo

Minggu, 13 Januari 2013

JavaScript Object

JavaScript Object

Pada dasarnya tujuan object tidak jauh berbeda dengan array, yaitu berfungsi untuk mengumpulkan beberapa data/nilai variabel menjadi satu kesatuan. Sebuah objek merupakan sekumpulan data yang disatukan menjadi satu kesatuan di dalam braket keriting/kurung kurawal ({}). Setiap objek terdiri dari beberapa properti yang dipisahkan dengan tanda koma, dan setiap properti terdiri dari kunci/key dan nilai yang dipisahkan dengan tanda titik dua:

// var identity = { property1, property2, property3 };
// var identity = { key1: value1, key2: value2, key3: value3 };

var identity = { "nama": "Taufik", "usia": 21, "lajang": true };

Saya mulai dengan array. Saat kita menuliskan array, maka cara kita memanggil anggotanya adalah dengan menuliskan nama variabel yang diikuti oleh indeks anggota tersebut seperti ini:

var text = ["Taufik", 21, true];
document.write(text[0]); // Hasil => `Taufik`

Dalam objek, kita memanggil data tidak melalui indeks, melainkan melalui kunci properti. Pemanggilan dimulai dengan menuliskan nama variabel, kemudian diikuti dengan kunci properti yang diinginkan dengan pemisah berupa tanda titik:

var identity = {
"nama": "Taufik",
"usia": 21,
"lajang": true
};

document.write(identity.nama); // Hasil => `Taufik`
document.write(identity.usia); // Hasil => `21`
document.write(identity.lajang); // Hasil => `true`

Lainnya

Beberapa Cara Penulisan Object

Cara paling ringkas:

var x = { "nama": "Taufik", "usia": 21, "lajang": true };

Mendeklarasikan objek kosong, kemudian menuliskan anggotanya satu per satu:

var x = {};
x["nama"] = "Taufik";
x["usia"] = 21;
x["lajang"] = true;

Metode lama/primitif:

var x = new Object();
x["nama"] = "Taufik";
x["usia"] = 21;
x["lajang"] = true;

Pemanggilan Data seperti halnya Array

Ini adalah cara pemanggilan data yang disarankan:

var identity = {
"nama": "Taufik",
"usia": 21,
"lajang": true
};

document.write(identity.nama); // Hasil => `Taufik`

Namun kita juga bisa menggunakan konsep pemanggilan data seperti halnya penanganan data di dalam array, hanya saja indeks anggota tidak dituliskan sebagai angka melainkan sebagai nama properti:

var identity = {
"nama": "Taufik",
"usia": 21,
"lajang": true
};

document.write(identity["nama"]); // Hasil => `Taufik`

Objek Bertingkat/Beranak/Bercabang

Sebuah objek tidak terbatas pada isi berupa properti. Sebuah objek juga bisa berisi objek lain, fungsi, atau bahkan array seperti ini:

var identity = {
"nama": "Taufik",
"usia": 21,
"lajang": true,
"hobi": {
"makan": "roti",
"menggambar": ["arsitektur", "kartun", "abstrak"],
"favorit": {
"makanan": "roti",
"minuman": "air bening",
}
},
"visi": {},
"misi": {
2013: "apa ya?",
2014: "2013 saja belum apalagi 2014!"
},
"fungsi": function() {
alert("Say no to free sex!");
}
};

// Contoh-contoh pemanggilan...
document.write(identity.nama); // Hasil => `Taufik`
document.write(identity.hobi.makan); // Hasil => `roti`
document.write(identity.hobi["makan"]); // Hasil => `roti`
document.write(identity.hobi.favorit.minuman); // Hasil => `air bening`
document.write(identity["hobi"]["favorit"]["minuman"]); // Hasil => `air bening`
document.write(identity.hobi.menggambar[1]); // Hasil => `kartun`

identity.fungsi(); // Akan memicu tampilnya kotak pesan bertuliskan `Say no to free sex!`

Sebuah objek dengan data yang kompleks seperti contoh di atas bisa kita sebut sebagai JavaScript Object Notation (JSON)

JavaScript Array

JavaScript Array

Array merupakan suatu variabel dimana di dalamnya terdapat beberapa anggota yang disatukan menjadi satu kesatuan dalam braket kotak ([]). Setiap data dapat diakses/dipanggil melalui nama variabel yang diikuti dengan indeks anggota. Berikut ini adalah sebuah gambaran bagaimana kita meringkas beberapa nama variabel menjadi satu kelompok array sebuah variabel…

Saya mulai dengan variabel biasa:

var text1 = "Aku";
var text2 = "Cinta";
var text3 = "Kamu";

Variabel di atas dapat dipanggil dengan cara menuliskan namanya satu per satu seperti ini:

document.write(text1 + " " + text2 + " " + text3); // Hasil => `Aku Cinta Kamu`

Dengan array, kita bisa menggabungkan beberapa nilai variabel ke dalam satu nama variabel menggunakan braket kotak:

var text = ["Aku", "Cinta", "Kamu"];

Untuk memanggil data di dalam array, kita tuliskan nama variabel yang kemudian diikuti dengan indeks anggota array tersebut. Indeks anggota dimulai dari 0:

document.write(text[0]); // Hasil => `Aku`
document.write(text[0] + " " + text[1] + " " + text[2]); // Hasil => `Aku Cinta Kamu`
document.write(text[2] + " " + text[1] + " " + text[0]); // Hasil => `Kamu Cinta Aku`
document.write(text[0] + " dan " + text[2]); // Hasil => `Aku dan Kamu`

Lainnya

Beberapa Cara Penulisan Array

Cara paling ringkas:

var x = ["lorem", "ipsum", "dolor", "sit", "amet"];

Mendeklarasikan array kosong, kemudian menuliskan anggotanya satu per satu:

var x = [];
x[0] = "lorem";
x[1] = "ipsum";
x[2] = "dolor";
x[3] = "sit";
x[4] = "amet";

Metode lama/primitif:

var x = new Array("lorem", "ipsum", "dolor", "sit", "amet");
var x = new Array();
x[0] = "lorem";
x[1] = "ipsum";
x[2] = "dolor";
x[3] = "sit";
x[4] = "amet";

Data yang Berbeda

var x = ["lorem", "ipsum", false, null, 0, 30, ""];

Selasa, 08 Januari 2013

Membuat Fitur Komentar Berbalas (Threaded Comments) pada Blogger dengan Fungsional yang Asli

Membuat Fitur Komentar Berbalas (Threaded Comments) pada Blogger dengan Fungsional yang Asli
Mengaktifkan fitur threaded commenting non-standar pada Blogger.

Setelah berhasil menemukan beberapa metode untuk menciptakan komentar bersarang (atau berbalas??) pada Blogger, Saya rasa metode dari bX-NicoNico adalah yang paling bagus. Mengapa?

  1. Dia tidak menggunakan elemen <data:post.commentJso/> sebagai salah satu elemen yang dibutuhkan untuk sistem ini, sehingga markup HTML akan menjadi lebih pendek dari markup HTML pada template dengan fitur komentar bersarang yang masih standar. (Fitur komentar bersarang yang masih standar akan menampilkan JSON komentar sebelum daftar komentar, sehingga jumlah karakter markup HTML pada fitur komentar bersarang yang masih standar akan menjadi dua kali lipat lebih panjang dibandingkan markup komentar biasa.
  2. Layout komentar tertata secara otomatis. JavaScript hanya digunakan untuk mengubah URL pada iframe formulir komentar dan juga untuk memindahkan posisinya sesuai dengan ID komentar induk masing-masing.
  3. Karena layout komentar ditata secara otomatis oleh Blogger, maka saat JavaScript dimatikan, tata letak komentar balasan akan tetap berada pada posisi yang benar. Ini berbeda dengan beberapa hack komentar bersarang Blogger yang hanya menggunakan JavaScript (yang juga telah Saya pakai sampai sekarang) untuk memposisikan komentar-komentar balasan, sehingga saat JavaScript dimatikan, layout komentar akan berantakan.

Berikut ini adalah fitur komentar versi Saya yang lebih pendek dan lebih mudah dalam hal instalasi yang Saya buat berdasarkan konsep dari Felipe, yaitu dengan cara menggunakan elemen data baru bernama <data:comment.inReplyTo/> untuk menyaring anak-anak komentar yang tampil. Elemen ini berfungsi untuk menampilkan ID komentar induk pada masing-masing komentar balasan. Saya bisa mengatakan bahwa metode ini adalah metode yang paling tepat dan bukan merupakan “hack”, karena kita menerapkan elemen yang ada dari Blogger untuk dimanfaatkan sesuai dengan tugasnya:


Mengaktifkan Fitur Komentar Bersarang pada Blogger

Pertama-tama buka editor HTML template Anda kemudian cek Expand Template Widget. Temukan kode ini:

]]></b:skin>

Salin kode CSS ini dan letakkan di atasnya:

.clearfix:after {
content:"";
display:table;
clear:both;
}

.clearfix {*zoom:1}

.pull-left {
display:block;
float:left;
}

.pull-right {
display:block;
float:right;
}

/* Start Custom Comments' CSS */
.custom-comments {
margin:3em 0 0;
font:normal normal 13px/1.4 Tahoma,Arial,Sans-Serif;
letter-spacing:0;
}

/* links */
.custom-comments a,
.custom-comments a:visited {
color:#2143B4;
text-decoration:none;
}

.custom-comments a:hover {text-decoration:underline}

/* comment item */
.custom-comments .comment-item {
margin:0 0 1em;
padding:0 0 .7em 0;
border-bottom:1px solid #eee;
position:relative;
}

/* comment header */
.custom-comments .comment-header {
overflow:hidden;
margin:0 0 1em 0;
}

/* avatar area */
.custom-comments .avatar-box {
width:65px;
margin:0 0 20px 0;
}

/* avatar */
.custom-comments .avatar-image-container,
.custom-comments .avatar-image-container a,
.custom-comments .avatar-image-container img {
border:none;
padding:0;
margin:0;
float:none;
display:block;
width:50px;
height:50px;
max-width:none;
max-height:none;
}

.custom-comments .avatar-image-container img {
border:1px solid #ddd;
padding:4px;
background-color:#fafafa;
}

/* comment body */
.custom-comments .comment-body {margin:0 0 2em 75px}

/* comment reply */
.custom-comments .comment-reply {
margin:1em 0 0 75px;
padding:1em 1.2em;
background-color:#FFF7D1;
position:relative;
font-size:11px;
}

.custom-comments .comment-reply:after {
content:"";
display:block;
width:0;
height:0;
position:absolute;
top:0;
left:0;
border:10px solid transparent;
border-color:white #F5F2D8 #F5F2D8 white;
}

.custom-comments .comment-reply .user {margin-left:15px}
.custom-comments .comment-reply a {color:#767643}

.custom-comments .comment-reply .avatar-image-container img {
border-color:#EAE5C4;
background-color:#F5F0D3;
}

/* comment item footer */
.custom-comments .comment-bottom-line {
display:block;
clear:both;
margin:1em 0 .5em 75px;
text-align:right;
}

/* comment buttons */
.custom-comments .comment-bottom-line a,
.custom-comments .cancel-reply-btn {
border:1px solid #ddd;
outline:none;
padding:2px .7em 3px .5em;
margin:0 0 0 4px;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
text-decoration:none;
}

.custom-comments .comment-reply .comment-bottom-line a {border-color:#EAE5C4}
.custom-comments .comment-bottom-line a:before {content:attr(data-icon) " "}
.custom-comments .comment-bottom-line .reply-btn:before {color:#3DB537}
.custom-comments .comment-bottom-line .delete-btn:before {color:#B42A21}

.custom-comments .comment-bottom-line a:hover,
.custom-comments .cancel-reply-btn:hover {
border-color:#bbb;
text-decoration:none;
}

.custom-comments .comment-bottom-line a:focus,
.custom-comments .comment-bottom-line a:active,
.custom-comments .cancel-reply-btn:focus,
.custom-comments .cancel-reply-btn:active {border-color:#999}
.custom-comments .cancel-reply-btn {padding:3px 1em 4px}

/* comment form */
.custom-comments .custom-comment-form {
margin:1em 0 2em;
clear:both;
}

.custom-comments .comment-item .custom-comment-form {
border:1px solid #eee;
padding:1em .2em 2em 1.5em;
margin-left:75px;
}

.custom-comments #comment-editor {
max-width:none;
width:100%;
height:250px;
border:none;
background:none;
}

.custom-comments .custom-comment-form .cancel-reply-btn {display:none}
.custom-comments .comment-item .custom-comment-form .cancel-reply-btn {display:inline}
.custom-comments .comment-item .custom-comment-form h4 {display:none}

/* loading animation */
.custom-comments .custom-comment-editor-wrapper {background:transparent url('data:image/gif;base64,R0lGODlhEgAEAKEAAH9/fwAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJDwACACwAAAAAEgAEAAACB5SPqcvtrwoAIfkECQ8AAgAsAAAAAAQABAAAAgSEjwkFACH5BAkPAAIALAAAAAALAAQAAAIMjCMJC4fKXBKsnVkLACH5BAkPAAIALAAAAAASAAQAAAIRjCN5mOCwkojt0Xnkg1l1sRUAIfkECQ8AAgAsAAAAABIABAAAAhGEIRkbKRwOUsxBaStdeDdfAAAh+QQJDwACACwHAAAACwAEAAACDIQhGRuHylwSrJ1ZCwAh+QQFDwACACwOAAAABAAEAAACBISPCQUAOw==') no-repeat 50% 50%}

/* deleted comment */
.custom-comments .deleted-comment {
font-style:italic;
color:#aaa;
}

/* comments paging control */
.custom-comments .paging-control-container {
font-size:80%;
text-align:center;
width:auto;
height:auto;
line-height:normal;
margin:1em 0;
float:none;
display:block;
clear:both;
border:1px solid #eee;
padding:.5em 1em;
overflow:hidden;
}

.custom-comments .paging-control-container .unneeded-paging-control {display:none}
.custom-comments .paging-control-container .paging-control {display:inline}

/* Author Comments Style: Do whatever you want with this! */
.author-comment > .comment-item {}
.author-comment > .comment-reply {}

Kemudian cari kode ini:

<b:includable id='comments' var='post'>

Salin kode ini, dan letakkan di atasnya:

<b:includable id='custom-comments' var='post'>
<section class='custom-comments' id='custom-comments'>
<b:if cond='data:post.allowComments'>

<h4>
<b:if cond='data:post.numComments == 1'>
<span>1</span>&amp;nbsp;<data:commentLabel/>
<b:else/>
<span><data:post.numComments/></span>&amp;nbsp;<data:commentLabelPlural/>
</b:if>
</h4>

<b:if cond='data:post.commentPagingRequired'>
<nav class='paging-control-container'>
<a expr:class='data:post.oldLinkClass' expr:href='data:post.oldestLinkUrl'><data:post.oldestLinkText/></a>
<a expr:class='data:post.oldLinkClass' expr:href='data:post.olderLinkUrl'><data:post.olderLinkText/></a>&#160;
<data:post.commentRangeText/>&#160;
<a expr:class='data:post.newLinkClass' expr:href='data:post.newerLinkUrl'><data:post.newerLinkText/></a>
<a expr:class='data:post.newLinkClass' expr:href='data:post.newestLinkUrl'><data:post.newestLinkText/></a>
</nav>
</b:if>

<div id='comments-area'>
<b:loop values='data:post.comments' var='comment'>
<b:if cond='data:comment.inReplyTo'><b:else/>
<b:if cond='data:comment.author == data:post.author'>&lt;div class=&#39;author-comment&#39;&gt;</b:if>
<div class='comment-item clearfix' expr:id='data:comment.anchorName'>
<div class='comment-header clearfix'>
<strong class='user pull-left'>
<b:if cond='data:comment.authorUrl'>
<a expr:href='data:comment.authorUrl' rel='nofollow'><data:comment.author/></a>
<b:else/>
<data:comment.author/>
</b:if> <data:commentPostedByMsg/>
</strong>
<a class='comment-permalink pull-right' rel='nofollow' expr:href='data:comment.url' title='Comment Permalink'><data:comment.timestamp/></a>
</div> <!-- comment-header -->
<div class='avatar-box pull-left'>
<b:if cond='data:comment.favicon'>
<img expr:src='data:comment.favicon' height='16px' style='margin-bottom:-2px;' width='16px'/>
</b:if>
<b:if cond='data:blog.enabledCommentProfileImages'>
<data:comment.authorAvatarImage/>
</b:if>
</div> <!-- avatar-box -->
<div class='comment-body'>
<b:if cond='data:comment.isDeleted'>
<span class='deleted-comment'><data:comment.body/></span>
<b:else/>
<data:comment.body/>
</b:if>
</div> <!-- comment-body -->
<b:loop values='data:post.comments' var='replies'>
<b:if cond='data:replies.inReplyTo == data:comment.id'>
<b:if cond='data:replies.author == data:post.author'>&lt;div class=&#39;author-comment&#39;&gt;</b:if>
<div class='comment-reply clearfix' expr:id='data:replies.anchorName'>
<div class='comment-header clearfix'>
<strong class='user pull-left'>
<b:if cond='data:replies.authorUrl'>
<a expr:href='data:replies.authorUrl' rel='nofollow'><data:replies.author/></a>
<b:else/>
<data:replies.author/>
</b:if> <data:commentPostedByMsg/>
</strong>
<a class='comment-permalink pull-right' rel='nofollow' expr:href='data:replies.url' title='Comment Permalink'><data:replies.timestamp/></a>
</div> <!-- reply comment-header -->
<div class='avatar-box pull-left'>
<b:if cond='data:replies.favicon'>
<img expr:src='data:replies.favicon' height='16px' style='margin-bottom:-2px;' width='16px'/>
</b:if>
<b:if cond='data:blog.enabledCommentProfileImages'>
<data:replies.authorAvatarImage/>
</b:if>
</div> <!-- reply avatar-box -->
<div class='comment-body'>
<b:if cond='data:replies.isDeleted'>
<span class='deleted-comment'><data:replies.body/></span>
<b:else/>
<data:replies.body/>
</b:if>
</div> <!-- reply comment-body -->
<span class='comment-bottom-line'>
<a class='delete-btn' rel='nofollow' data-icon='&amp;times;' expr:href='data:replies.deleteUrl' expr:title='data:top.deleteCommentMsg'>Delete</a>
</span>
</div> <!-- reply comment-reply -->
<b:if cond='data:replies.author == data:post.author'>&lt;/div&gt;</b:if>
</b:if> <!-- replies.inReplyTo -->
</b:loop>
<span class='comment-bottom-line'>
<b:if cond='data:comment.isDeleted != &quot;true&quot;'>
<a class='reply-btn' data-icon='&amp;dArr;' expr:href='&quot;javascript:replyTo(&amp;quot;&quot; + data:comment.id + &quot;&amp;quot;);&quot;'>Reply</a>
</b:if>
<a class='delete-btn' rel='nofollow' data-icon='&amp;times;' expr:href='data:comment.deleteUrl' expr:title='data:top.deleteCommentMsg'>Delete</a>
</span>
<div expr:id='&quot;form-container-&quot; + data:comment.id'/>
</div> <!-- comment-item -->
<b:if cond='data:comment.author == data:post.author'>&lt;/div&gt;</b:if>
</b:if> <!-- comment.inReplyTo -->
</b:loop>
</div>

<b:if cond='data:post.commentPagingRequired'>
<nav class='paging-control-container'>
<a expr:class='data:post.oldLinkClass' expr:href='data:post.oldestLinkUrl'><data:post.oldestLinkText/></a>
<a expr:class='data:post.oldLinkClass' expr:href='data:post.olderLinkUrl'><data:post.olderLinkText/></a>&#160;
<data:post.commentRangeText/>&#160;
<a expr:class='data:post.newLinkClass' expr:href='data:post.newerLinkUrl'><data:post.newerLinkText/></a>
<a expr:class='data:post.newLinkClass' expr:href='data:post.newestLinkUrl'><data:post.newestLinkText/></a>
</nav>
</b:if>

<div class='custom-comment-form' id='custom-comment-form'>
<h4><data:postCommentMsg/></h4>
<p><data:blogCommentMessage/></p>
<data:blogTeamBlogMessage/>
<a expr:href='data:post.commentFormIframeSrc' id='comment-editor-src'/>
<div class='custom-comment-editor-wrapper'>
<iframe class='blogger-iframe-colorize blogger-comment-from-post' id='comment-editor' name='comment-editor' src=''/>
</div>
<data:post.friendConnectJs/>
<data:post.cmtfpIframe/>
<script>BLOG_CMT_createIframe(&#39;<data:post.appRpcRelayPath/>&#39;, &#39;<data:post.communityId/>&#39;);</script>
<a class='cancel-reply-btn' href='javascript:replyTo(&quot;cancel&quot;);'>Cancel Reply</a>
</div>

<script>
//<![CDATA[
var originalSource = document.getElementById('comment-editor').src.split('#');
function replyTo(id) {
var frame = document.getElementById('comment-editor'),
form = document.getElementById('custom-comment-form'),
container = (id != "cancel") ? document.getElementById('form-container-' + id) : document.getElementById('custom-comments'),
part = originalSource;
frame.style.height = "50px";
frame.style.visibility = "hidden";
frame.src = (id != "cancel") ? part[0] + '&parentID=' + id + '#' + part[1] : part[0] + '#' + part[1];
container.insertBefore(form, null);
frame.onload = function() {
this.style.height = "250px";
this.style.visibility = "visible";
};
}
//]]>
</script>

</b:if>
</section>
</b:includable>

Terakhir tinggal mengaktifkan fitur komentar kita. Cari semua kode yang tampak seperti ini:

<b:include data='post' name='threaded_comments'/>

atau seperti ini:

<b:include data='post' name='comments'/>

Di manapun Anda menemukan kode itu, segera ganti dengan kode ini:

<b:include data='post' name='custom-comments'/>

Klik Simpan Template.

Konfigurasi

Kode-kode yang Saya beri tanda adalah label-label tombol dan bisa Anda ganti teksnya sesuka hati sesuai dengan bahasa pada negara dimana Anda tinggal (beberapa teksnya ada yang terletak jauh di sebelah kanan, mohon gulung kontainer kodenya ke kanan sekali-kali).

Fitur penanda komentar administrator juga ada. Untuk mengaktifkannya, Anda bisa menggunakan selektor-selektor CSS yang tercantum di atas, kemudian awali dengan kelas .author-comment untuk menandai komentar penulis. Sebagai contoh, Saya akan memberikan border warna merah dan latar warna kuning pada komentar administrator, maka yang harus Anda lakukan adalah seperti ini:

.author-comment > .comment-item {
border:5px solid #900;
background-color:#ff0;
}

Catatan: Bagi Anda yang selama ini telah lama menggunakan fitur komentar bersarang lebih dari dua level (seperti blog Saya), sangat disarankan untuk tidak menerapkan modifikasi di atas, karena Saya hanya menggunakan loop komentar balasan sebanyak satu kali:

<b:loop values='data:post.comments' var='replies'>
<b:if cond='data:replies.inReplyTo == data:comment.id'>
Komentar balasan muncul di sini...
</b:if>
</b:loop>

Seperti yang Anda lihat bahwa Saya hanya membandingkan nilai data:var.inReplyTo pada komentar balasan dengan ID komentar induk sekali saja (satu kali loop), sehingga jika komentar balasan lama Anda berada di level ke tiga dan seterusnya, komentar-komentar tersebut tidak akan tampil dalam posting Anda dikarenakan ID komentar induknya tidak sempat lolos penyaringan terhadap data:var.inReplyTo pada anak komentar di level tersebut.

Blog yang masih baru atau blog lama dengan sedikit komentar dan blog dengan fitur komentar yang masih lama bisa melakukan modifikasi ini dengan aman.

Senin, 10 Desember 2012

Plugin JQuery Custom Select Box

JQuery Custom SelectBox Plugin
Plugin JQuery Custom SelectBox

Ini adalah plugin JQuery yang Saya buat berdasarkan konsep selectbox kustom yang pernah Saya temukan dan Saya catat di sini. Fungsinya adalah untuk mengubah tampilan selectbox biasa menjadi selectbox yang mudah dimodifikasi tampilannya. Saya suka dengan metodenya yang sangat sederhana untuk mengubah tampilan selectbox asli tanpa harus menghilangkan elemen aslinya dan hanya membungkusnya dengan elemen baru, sehingga kita bisa menyesuaikan dimensi selectbox palsu berdasarkan dimensi selectbox yang asli tanpa menggunakan perhitungan JavaScript yang rumit. Di sini Saya hanya memanfaatkan dimensi selectbox asli untuk mengubah ukuran lebar elemen inline-block:

Penggunaan

Letakkan CSS sebelum JQuery dan plugin setelah JQuery, kemudian aktifkan .customSelectBox() pada elemen <select> yang dikehendaki. Setelah itu Anda bisa menjalankan perintah-perintah lain yang diperlukan terhadap elemen selectbox asli melalui event .change():

<link rel="stylesheet" href="css/style.css">
<script src="js/jquery.js"></script>
<script src="js/jquery.custom.selectbox.min.js"></script>
<script>
$(document).ready(function() {
$('select').customSelectBox().change(function() {
// Lakukan sesuatu di sini seperti halnya saat kita melakukan sesuatu ...
// ... dengan event `change` JQuery pada elemen selectbox
var val = this.value;
alert(val);
});
});
</script>

Itu saja.


Konfigurasi Lanjutan

Konfigurasi lanjutan ini hanya berputar di sekitar modifikasi kelas. Tidak ada efek-efek khusus tambahan pada plugin ini:

$('select').customSelectBox({
selectboxClass: 'styled-select',
buttonClass: 'curr',
selectedClass: 'selected',
disabledClass: 'disabled',
focusedClass: 'focused'
}).change(function() {});
Pilihan Modifikasi Kelas
OpsiKeterangan
selectboxClassNama kelas pembungkus luar
buttonClassNama kelas tombol pemicu drop down menu (penayang nilai opsi terseleksi)
selectedClassNama kelas opsi terseleksi (elemen <option> dengan atribut selected="true")
disabledClassNama kelas opsi mati (elemen <option> dengan atribut disabled="true")
focusedClassNama kelas tombol selectbox terfokus (saat diklik)

Keterangan dan gambaran markup HTML tergenerasi selengkapnya bisa Anda lihat pada halaman demo

Hanya untuk proyek skala kecil. Tidak bekerja pada selectbox dengan optgroup.

Jumat, 29 Juli 2011

Langkah Pertama: Pemanggilan JQuery dan Paket Easing

Logo JQuery

Jika salah satu tutorial di situs ini memerintahkan kamu untuk mengunjungi halaman ini, maka kamu telah sampai di tempat yang tepat. Tapi jika kamu membuka halaman ini karena ketidaksengajaan atau mengira bahwa ini adalah salah satu halaman tutorial, maka kamu telah memasuki halaman yang salah. Halaman ini adalah salah satu bagian dari beberapa tutorial di blog ini. Saya sengaja memisahkannya mengingat ada beberapa tutorial yang selalu menggunakan perintah yang sama pada setiap awal langkah. Untuk menghindari duplikasi langkah, maka Saya memisahkan halaman ini dari halaman yang lainnya.
Salin script ini, kemudian letakkan tepat di atas kode </head> atau di bawah kode <head>:

<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js' type='text/javascript'></script>
<script src='http://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js' type='text/javascript'></script>

Intinya adalah, jika suatu saat kamu merasa bahwa kamu pernah menjalani langkah tutorial seperti ini, maka kamu tidak perlu melakukannya lagi.
Perhatikan juga nama-nama berkasnya (bukan URLnya):

Teliti betul-betul isi templatmu. Jika ternyata templatmu sudah dilengkapi dengan skrip-skrip tersebut, maka kamu bisa menghapusnya salah satu. Kita cukup menggunakan satu skrip saja pada setiap jenisnya. Sekarang kamu bisa melanjutkan ke langkah berikutnya.