Selasa, 11 Juni 2013
Performa Widget Random Post
Saya harus mengatakan bahwa widget random post itu sangat buruk dalam hal performa. Kerja mereka sangat lambat dan membuang-buang tenaga, karena mereka bekerja dengan cara memanggil feed posting berukuran sangat besar! Kemudian mereka hanya akan menampilkannya sebagian saja secara acak:
<script src='/feeds/posts/default?alt=json-in-script&max-results=99999&callback=randomPosts'></script>Bagi Anda para pemakai mungkin tidak pernah tahu mengenai ini, tetapi sebenarnya setiap pemakai widget random post —termasuk juga widget artikel terkait— tanpa sadar telah menerima beban begitu besar. Ketika Anda membuka halaman tunggal dimana terdapat widget random post di dalamnya, pada saat yang bersamaan Anda juga sebenarnya sedang membuka semua posting yang telah Anda terbitkan dalam satu waktu. Mengapa? Karena parameter max-results pada feed menunjukkan angka 99999 yang artinya bahwa semua feed posting akan “diusahakan” untuk dipanggil (diusahakan, karena jumlah posting yang kita terbitkan tidak mungkin mencapai angka sebesar itu).
Mengacak Indeks Permulaan
Saya menyadari terdapat sebuah peluang untuk menciptakan widget random post yang lebih ringan dan cepat dimuat. Dibandingkan memuat semua posting dan memilah beberapa posting secara acak untuk ditampilkan, akan lebih baik jika kita mengacak nilai start-index pada feed sehingga posting yang dimuat bisa dimulai dari urutan sembarang:
function randomPosts(json) {
// Ubah JSON menjadi HTML...
}
var startIndex = Math.round(Math.random() * 9999); // Membuat angka acak
document.write('<scr' + 'ipt src="/feeds/posts/summary?alt=json-in-script&start-index=' + startIndex + '&max-results=7&callback=randomPosts"></scr' + 'ipt>');Ada satu masalah kecil yang mungkin akan mengganggu. Jika angka acak yang tercipta nilainya lebih besar dari total posting blog Anda saat ini, maka widget random post ini tidak akan bekerja. Oleh karena itu kita harus membatasi angka acak yang tercipta, yaitu tidak boleh kurang dari 1 dan tidak boleh lebih dari “total posting dikurangi jumlah posting yang ingin ditampilkan”.
Untuk mendapatkan jumlah posting secara keseluruhan kita bisa mengambilnya melalui objek json.feed.openSearch$totalResults.$t:
// Konfigurasi
var homePage = 'http://nama_blog.blogspot.com',
maxResults = 7;
// Fungsi untuk menggenerasikan angka acak dengan batasan minimal dan maksimal
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Mendapatkan indeks pemulai yang aman untuk memanggil feed utama
function createRandomPostsStartIndex(json) {
// Buat angka acak dengan nilai tidak boleh kurang dari `1` dan tidak boleh lebih dari `total posting - posting yang ingin ditampilkan`
var startIndex = getRandomInt(1, (json.feed.openSearch$totalResults.$t - maxResults));
// Tampilkan pesan log
console.log('Get the post feed start from ' + startIndex + ' until ' + (startIndex + maxResults));
}
document.write('<scr' + 'ipt src="' + homePage + '/feeds/posts/summary?alt=json-in-script&max-results=0&callback=createRandomPostsStartIndex"></scr' + 'ipt>');Muat ulang widget Anda berkali-kali. Seharusnya Anda akan melihat pesan log indeks pemanggilan posting yang berubah-ubah seperti ini:

Kita akan menggunakan angka acak itu sebagai angka pemulai pada parameter start-index seperti ini:
function createRandomPostsStartIndex(json) {
var startIndex = getRandomInt(1, (json.feed.openSearch$totalResults.$t - maxResults));
document.write('<scr' + 'ipt src="' + homePage + '/feeds/posts/summary?alt=json-in-script&orderby=updated&start-index=' + startIndex + '&max-results=' + maxResults + '&callback=randomPosts"></scr' + 'ipt>');
}Pada bagian akhir URL feed terdapat parameter callback=randomPosts. randomPosts di sini merupakan fungsi utama yang akan kita buat untuk mengubah JSON Blogger menjadi widget:
function randomPosts(json) {
var link, ct = document.getElementById('random-post-container'),
entry = json.feed.entry,
skeleton = "<ul>";
for (var i = 0, len = entry.length; i < len; i++) {
for (var j = 0, jen = entry[i].link.length; j < jen; j++) {
link = (entry[i].link[j].rel == "alternate") ? entry[i].link[j].href : '#';
}
skeleton += '<li><a href="' + link + '">' + entry[i].title.$t + '</a></li>';
}
ct.innerHTML = skeleton + '</ul>';
}Sentuhan akhir, acak urutan posting yang ditampilkan menggunakan fungsi ini sehingga daftar posting yang ditampilkan nantinya akan semakin acak urutannya:
// Fungsi untuk mengacak array
function shuffleArray(arr) {
var i = arr.length, j, temp;
if (i === 0) return false;
while (--i) {
j = Math.floor(Math.random() * (i + 1));
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return arr;
}
// Widget
function randomPosts(json) {
var link, ct = document.getElementById('random-post-container'),
entry = shuffleArray(json.feed.entry),
skeleton = "<ul>";
for (var i = 0, len = entry.length; i < len; i++) {
for (var j = 0, jen = entry[i].link.length; j < jen; j++) {
link = (entry[i].link[j].rel == "alternate") ? entry[i].link[j].href : '#';
}
skeleton += '<li><a href="' + link + '">' + entry[i].title.$t + '</a></li>';
}
ct.innerHTML = skeleton + '</ul>';
}Hasil Akhir
<div id='random-post-container'>Memuat...</div>
<script>
//<![CDATA[
// Feed configuration
var homePage = 'http://nama_blog.blogspot.com',
maxResults = 7,
containerId = 'random-post-container';
// Function to generate random number limited from `min` to `max`
// Used to create a valid and safe random feed `start-index`
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Function to shuffle arrays
// Used to randomize order of the generated JSON feed
function shuffleArray(arr) {
var i = arr.length, j, temp;
if (i === 0) return false;
while (--i) {
j = Math.floor(Math.random() * (i + 1));
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return arr;
}
// Get a random start index
function createRandomPostsStartIndex(json) {
var startIndex = getRandomInt(1, (json.feed.openSearch$totalResults.$t - maxResults));
// console.log('Get the post feed start from ' + startIndex + ' until ' + (startIndex + maxResults));
document.write('<scr' + 'ipt src="' + homePage + '/feeds/posts/summary?alt=json-in-script&orderby=updated&start-index=' + startIndex + '&max-results=' + maxResults + '&callback=randomPosts"></scr' + 'ipt>');
}
// Widget's main function
function randomPosts(json) {
var link, ct = document.getElementById(containerId),
entry = shuffleArray(json.feed.entry),
skeleton = "<ul>";
for (var i = 0, len = entry.length; i < len; i++) {
for (var j = 0, jen = entry[i].link.length; j < jen; j++) {
link = (entry[i].link[j].rel == "alternate") ? entry[i].link[j].href : '#';
}
skeleton += '<li><a href="' + link + '">' + entry[i].title.$t + '</a></li>';
}
ct.innerHTML = skeleton + '</ul>';
}
document.write('<scr' + 'ipt src="' + homePage + '/feeds/posts/summary?alt=json-in-script&max-results=0&callback=createRandomPostsStartIndex"></scr' + 'ipt>');
//]]>
</script>Ketika Posting Acak Dikirim Secara Langsung oleh Server
Dalam sebuah forum Saya pernah menemukan seseorang yang mencoba menyarankan Blogger untuk menyertakakan parameter orderby baru berupa random dan popular. Saya pikir ini adalah ide yang bagus. Karena berdasarkan dokumentasi, kalau tidak salah hanya ada dua macam nilai untuk parameter orderby, yaitu published dan updated:
http://nama_blog.blogspot.com/feeds/posts/summary?orderby=published
http://nama_blog.blogspot.com/feeds/posts/summary?orderby=updated
Jika suatu saat Blogger merealisasikan masukan dari pengguna ini, maka kita tidak perlu lagi menerapkan hack semacam ini. Cukup dengan membuat widget recent post biasa, kita bisa mengubah parameter URL feed dari orderby=published menjadi orderby=random untuk menciptakan widget random post. Tapi kasus ini masih dalam tahap “seandainya”.
Label: JavaScript, Pemecahan Masalah, Posting, Tingkat Lanjut, Widget
Senin, 18 Maret 2013
Plugin Feed Rotator untuk Blogger
Plugin ini pada dasarnya merupakan perpaduan antara Basic JQuery Image Rotator dengan JSON Blogger yang kemudian Saya jadikan sebagai semacam slideshow dengan konten yang akan diperbaharui secara otomatis berdasarkan posting yang sudah terbit. Saya memutuskan untuk membuat ini karena ada beberapa orang yang menanyakan melalui email mengenai bagaimana cara memadukan plugin Image Rotator dengan JSON Blogger.
Plugin JQuery Image Rotator ini juga sudah dimodifikasi hampir secara keseluruhan, khusus untuk diaplikasikan pada widget ini. Beberapa hal yang Saya tambahkan diantaranya adalah navigasi, efek animasi kontainer dan dukungan fungsi callback yang dapat dijalankan pada sesi-sesi tertentu.
Implementasi Dasar
Berikut ini adalah contoh implementasi paling mendasar yang bisa Anda lakukan untuk mengaktifkan plugin:
<link rel="stylesheet" type="text/css" href="http://blogger-json-experiment.googlecode.com/svn/resources/blogger-feed-rotator-plugin/default-style.min.css"/>
<div id="slider-rotator" class="slider-rotator loading"></div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="http://blogger-json-experiment.googlecode.com/svn/resources/blogger-feed-rotator-plugin/blogger-feed-rotator.min.js"></script>
<script type="text/javascript">
makeSlider({
url: "http://nama_blog.blogspot.com" // URL blog Anda
});
</script>Susun file CSS dan plugin Blogger Feed Rotator sesuai dengan urutan yang Saya perlihatkan di atas. Tambahkan juga elemen HTML yang berfungsi untuk menampilkan slideshow sebelum plugin. Setelah itu aktifkan fungsi makeSlider() dengan parameter berupa objek tunggal url yang diisi dengan URL blog Anda. Salin dan tempelkan di dalam formulir elemen halaman HTML/JavaScript. Dengan ini maka Anda sudah bisa menampilkan sebuah slideshow sederhana seperti yang terlihat pada halaman demo di atas.
Daftar Opsi Konfigurasi Dasar
Konfigurasi dasar Saya batasi pada opsi-opsi yang berhubungan dengan pengaturan posting:
{
url: "http://www.dte.web.id", // Your blog URL
numPost: 5, // Number of posts to display
newTabLink: false, // `true` to automatically open link in new window tab
labelName: null, // Show posts in specific label. Specify name of the post label, or `null` to show all posts
showDetail: true, // `false` to hide the blog post title & description
summaryLength: 60, // Length of post summary
titleLength: "auto", // Length of the post title. "auto" by default, or specify number to crop the post title characters and truncate it with `...`
showThumb: true, // `false` to hide the post thumbnails
thumbWidth: 250, // Width of post thumbnail in pixels
squareThumb: true, // Thumbnail mode: Square mode or use the scaled thumbnail with original width and height ratio
noThumb: "images/grey.png", // Fallback thumbnail for no picture posts
showNav: true, // `true` to show both next/prev navigation and navigation number, "next/prev" to show next/prev navigation only, "number" to show navigation number only, `false` to hide the navigation
navText: {
prev: "<", // Label of the previous navigation
next: ">" // Label of the next navigation
},
containerId: "slider-rotator" // HTML element ID that is used to display the slideshow/rotator
}| Opsi | Keterangan |
|---|---|
| url | Isi dengan URL halaman muka blog Anda |
| numPost | Digunakan untuk menentukan jumlah posting yang akan ditampilkan |
| newTabLink | Ubah nilainya menjadi true untuk membuat tautan-tautan di dalam widget ini terbuka di jendela/tab baru saat diklik |
| labelName | Digunakan untuk menampilkan daftar posting dengan label/kategori tertentu. Nilai null berarti menampilkan semua posting terbaru. Ganti nilainya menjadi nama label untuk menampilkan posting dengan label tertentu. Misalnya labelName:"Foto" untuk menampilkan semua posting yang memiliki label Foto - Contoh |
| showDetail | Ubah nilainya menjadi false untuk menyembunyikan judul dan ringkasan posting. Berguna untuk membuat slideshow foto/gambar tanpa tulisan - Contoh |
| summaryLength | Digunakan untuk membatasi panjang ringkasan posting. Akhir pemotongan ringkasan posting akan digantikan dengan simbol “…” |
| titleLength | Digunakan untuk membatasi panjang judul posting. Secara normal bernilai "auto". Ubah nilainya dengan angka tertentu untuk memotong panjang judul jika Anda merasa judul posting yang tampil terlalu panjang. Akhir pemotongan judul posting akan digantikan dengan simbol “…” |
| showThumb | Ubah nilainya menjadi false untuk menyembunyikan gambar posting. Berguna untuk membuat slideshow teks - Contoh |
| thumbWidth | Digunakan untuk menentukan lebar thumbnail posting dan juga sekaligus menentukan lebar slideshow |
| squareThumb | Opsi untuk memilih mode thumbnail. true untuk menampilkan gambar dengan resolusi /sN-c, false untuk menampilkan gambar dengan resolusi /sN |
| noThumb | Isi dengan URL gambar. Gambar ini akan digunakan sebagai cadangan jika posting yang tampil tidak memiliki gambar |
| showNav | Opsi untuk menampilkan atau menyembunyikan navigasi slideshow. Ubah nilainya menjadi false untuk menyembunyikan navigasi. "number" untuk menampilkan navigasi angka saja. "next/prev" untuk menampilkan navigasi next/prev saja. true untuk menampilkan keduanya |
| navText | Opsi untuk menentukan label navigasi Next dan Previous |
| containerId | Digunakan untuk menentukan di mana slideshow akan ditampilkan. Isi dengan ID elemen HTML. Dan jangan lupa untuk menyertakan elemen HTML tersebut sebelum eksekusi plugin. |
Pengaturan Animasi
Pengaturan animasi Saya batasi pada opsi-opsi yang berhubungan dengan animasi plugin:
{
interval: 6000, // Slideshow interval
speed: 1000, // Slideshow animation speed
hoverPause: true, // `false` to make the slideshow/rotator keep running on mouse-over
crossFade: false, // `true` if you want to make the slide change effect occurs simultaneously between disappearance and appearance
autoHeight: false, // Animate the rotator to adjust the height of the displayed item
autoSlide: true // `false` to run the slideshow manually (with navigation)
}| Opsi | Keterangan |
|---|---|
| interval | Digunakan untuk menentukan rentang waktu perpindahan setiap item slide dalam satuan milidetik |
| speed | Digunakan untuk menentukan kecepatan animasi dalam satuan milidetik |
| hoverPause | Jika bernilai true maka slideshow akan berhenti bergerak saat pointer mouse berada di atasnya |
| crossFade | Digunakan untuk menentukan apakah efek penghilangan dan pemunculan slide dilakukan secara bergantian atau bersamaan dalam waktu yang sama tanpa ada jeda |
| autoHeight | Jika bernilai true, maka tinggi slideshow akan menyesuaikan diri berdasarkan tinggi item slide yang tampil dengan efek animasi - Contoh |
| autoSlide | Ubah nilainya menjadi false untuk membuat slideshow berjalan secara manual melalui aksi klik navigasi |
Konfigurasi Lanjutan
Bagian ini Saya khususkan untuk menjelaskan fungsi-fungsi callback dan implementasi lanjutan, khususnya dalam hal modifikasi:
{
onInit: function() {}, // Callback function that will be executed when slideshow is starting
onHide: function(index) {}, // Callback function that will be executed when slideshow is start hiding the slide item
onShow: function(index) {} // Callback function that will be executed after the slideshow showing the slide item
}onInit
Fungsi ini akan dijalankan pada saat pertama kali slideshow terbentuk. Saat slideshow tampil, maka fungsi ini akan langsung dieksekusi. Contoh penerapan:
makeSlider({
url: "http://nama_blog.blogspot.com",
onInit: function() {
alert('Slideshow ready!');
}
});Kode di atas akan menampilkan pesan “Slideshow ready!” segera setelah slideshow tampil.
onHide
Fungsi ini akan dijalankan setiap kali item slide mulai menghilang. Saat item slide menghilang, maka fungsi ini akan tereksekusi. Contoh penerapan:
makeSlider({
url: "http://nama_blog.blogspot.com",
onHide: function() {
alert('Mengganti slide...');
}
});Kode di atas akan menampilkan pesan “Mengganti slide...” setiap kali slide mulai berganti.
onShow
Fungsi ini akan dijalankan setiap kali item slide tampil. Saat item slide tampil, maka fungsi ini akan tereksekusi. Contoh penerapan:
makeSlider({
url: "http://nama_blog.blogspot.com",
onShow: function(index) {
alert('Slide ke ' + index + ' berhasil tampil.');
}
});Kode di atas akan menampilkan pesan “Slide ke {nomor urut slide yang tampil} berhasil tampil.” setiap kali slide ditampilkan.
Parameter `index`
Parameter index hanya berlaku untuk onHide dan onShow. Parameter ini akan menampilkan indeks slide yang aktif:
makeSlider({
url: "http://nama_blog.blogspot.com",
onInit: function() {
console.log('Slideshow dimulai...');
},
onHide: function(index) {
console.log('Menyembunyikan slide ke ' + index);
},
onShow: function(index) {
console.log('Menampilkan slide ke ' + index);
}
});Beberapa Contoh Modifikasi Dasar
Mengubah Tampilan
Dengan mengubah ukuran lebar pada gambar dan slideshow, ukuran tinggi pada slideshow dan mengubah tampilan deskripsi/detail posting sebagai caption, maka Anda bisa semakin memperkuat status plugin ini sebagai “slideshow”:
CSS
<link rel="stylesheet" type="text/css" href="http://blogger-json-experiment.googlecode.com/svn/resources/blogger-feed-rotator-plugin/default-style.min.css"/>
<style type="text/css">
/* Custom CSS... */
.slider-rotator {
width:600px;
height:240px;
padding:0 0;
background-color:white;
font:italic normal 12px/1.4 Georgia,Serif;
color:white;
border:1px solid black;
}
.slider-rotator .slider-item {
background-color:white;
height:240px; /* Same with `.slider-rotator` height */
padding:0 0;
}
.slider-rotator h4 {margin-top:0}
.slider-rotator p {margin:2px 0 0}
/* Slider details as caption */
.slider-rotator .detail-wrapper {
position:absolute;
top:auto;
right:0;
bottom:0;
left:0;
background-color:black;
background-color:rgba(0,0,0,.9);
padding:.5em 1em;
z-index:4;
}
</style>JavaScript
makeSlider({
url: "http://nama_blog.blogspot.com", // Your blog URL
thumbWidth: 600 // Thumbnail width in pixels (same with slideshow width)
});Memanfaatkan Fungsi Callback untuk Menganimasikan Caption
Dengan memanfaatkan parameter index pada onHide dan onShow, Anda bisa memberikan efek animasi pada caption slide yang aktif setiap kali slide berganti:
makeSlider({
url: "http://nama_blog.blogspot.com", // Your blog URL
thumbWidth: 600, // Thumbnail width in pixels (same with slideshow width)
containerId: "slider-rotator",
// Hide all captions on initiation...
onInit: function() {
$('#' + this.containerId).find('.detail-wrapper').hide();
},
// Hide the caption with `.slideUp()` effect when the slide item hides
onHide: function() {
$('#' + this.containerId).find('.detail-wrapper').slideUp();
},
// Show the caption with `.slideDown()` effect when the slide item appears
onShow: function(index) {
$('#' + this.containerId).children().eq(index).find('.detail-wrapper').slideDown();
}
});Menampilkan Beberapa Slideshow Sekaligus
Karena eksekusi plugin ini dilakukan di luar, maka ini memungkinkan Anda untuk menampilkan beberapa slideshow sekaligus dalam satu halaman. Pertama-tama buatlah beberapa elemen HTML yang dibutuhkan untuk memuat slideshow:
<div id="container-1" class="slider-rotator loading"></div>
<div id="container-2" class="slider-rotator loading"></div>
<div id="container-3" class="slider-rotator loading"></div>Kemudian jalankan fungsi makeSlider() sebanyak jumlah kontainer yang dibuat. Tentukan juga konfigurasi containerId yang berbeda-beda berdasarkan ID kontainer:
makeSlider({
url: "http://nama_blog-1.blogspot.com",
containerId: "container-1"
});
makeSlider({
url: "http://nama_blog-2.blogspot.com",
containerId: "container-2"
});
makeSlider({
url: "http://nama_blog-3.blogspot.com",
containerId: "container-3"
});Mengatur Plugin dan Melihat Demo Secara Langsung
Saya sudah menyertakan halaman konfigurasi plugin yang bisa Anda gunakan untuk melakukan pengaturan dan melihat hasilnya secara langsung di sini:
Daftar Contoh
- Demo 1: Basic
- Demo 2: Show Posts under Category “Widget”
- Demo 3: About Thumbnails
- Demo 4: Thumbnail Only
- Demo 5: Text Only
- Demo 6: Multiple Feed Loading
- Demo 7: Casual Slideshow
- Demo 8: Example Callback Function to Animate the Slideshow Caption (1)
- Demo 9: Example Callback Function to Animate the Slideshow Caption (2)
Label: Gambar, JSON Blogger, Slideshow, Tingkat Lanjut, Widget
Jumat, 16 November 2012
Kotak Penelusuran Blogger dengan Ajax JQuery

Beberapa waktu yang lalu Saya pernah menuliskan cara menampilkan hasil penelusuran dengan JSON Blogger tanpa harus berpindah dari halaman awal menuju halaman hasil penelusuran dengan JavaScript (Anda bisa membacanya di sini).
Melalui JQuery $.ajax() kita bisa meniadakan penyisipan script callback dan langsung memanggil JSON dengan cara seperti ini:
$('#search-form').on("submit", function() {
$.ajax({
url: '../feeds/posts/summary?alt=json-in-script&q=KATA_KUNCI',
type: 'get',
dataType: 'jsonp',
success: function(json) {
...
}
});
});Sehingga jika dijabarkan akan menjadi seperti ini:
HTML Formulir
<form action="/search" id="ajax-search-form">
<input type="text" name="q">
<input type="submit" value="Search">
</form>JQuery
(function($) {
var $form = $('#ajax-search-form'),
$input = $form.find(':text');
$form.append('<div id="search-result"></div>');
var $result_container = $('#search-result');
$form.on("submit", function() {
var keyword = $input.val();
$result_container.show().html('Loading...');
$.ajax({
url: 'http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&q=' + keyword + '&max-results=9999',
type: 'get',
dataType: 'jsonp',
success: function(json) {
var entry = json.feed.entry,
link, skeleton = "";
if (entry !== undefined) {
skeleton = '<h4>Search results for keyword "' + keyword + '"</h4>';
skeleton += '<a class="close" href="/">×</a><ol>';
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") {
link = entry[i].link[j].href;
}
}
skeleton += '<li><a href="' + link + '">' + entry[i].title.$t + '</a></li>';
}
skeleton += '</ol>';
$result_container.html(skeleton);
} else {
$result_container.html('<a class="close" href="/">×</a><strong>No result!</strong>');
}
},
error: function() {
$result_container.html('<a class="close" href="/">×</a><strong>Error loading feed.</strong>');
}
});
return false;
});
$form.on("click", ".close", function() {
$result_container.fadeOut();
return false;
});
})(jQuery);Cara Kerja
Pertama-tama kita tangkap beberapa elemen penting yaitu formulir pencarian dan elemen input kata kunci pencarian:
var $form = $('#ajax-search-form'), // Mendapatkan elemen formulir
$input = $form.find(':text'); // Mendapatkan elemen input bertipe teks (penampung kata kunci pencarian)Sisipkan sebuah elemen HTML secara tidak langsung sebagai kontainer hasil pencaran:
$form.append('<div id="search-result"></div>');
var $result_container = $('#search-result');Setelah itu kita berlakukan event .submit() atau .on("submit") pada formulir untuk kemudian kita bisa langsung memproses data JSON yang akan ditransfer pada saat yang bersamaan ketika kita menekan tombol Enter pada papan ketik atau mengeklik tombol penelusuran di dalam formulir:
$form.on("submit", function() {
$.ajax(url, type, dataType, success, error); // Dapatkan data dan proses data di sini...
return false; // <= Ini digunakan untuk mencegah formulir membawa kita menuju halaman hasil penelusuran saat kita men-submit kata kunci pencarian
});Pengambilan data JSON dilakukan oleh JQuery $.ajax(), sehingga kita tidak perlu menyisipkan script callback ke dalam area <head> seperti dalam metode JavaScript mentah pada umumnya:
$.ajax({
url: 'http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&q=' + keyword + '&max-results=9999',
type: 'get',
dataType: 'jsonp',
success: function(json) {
var entry = json.feed.entry,
link, skeleton = "";
if (entry !== undefined) {
skeleton = '<h4>Search results for keyword "' + keyword + '"</h4>';
skeleton += '<a class="close" href="/">×</a><ol>';
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") {
link = entry[i].link[j].href;
}
}
skeleton += '<li><a href="' + link + '">' + entry[i].title.$t + '</a></li>';
}
skeleton += '</ol>';
$result_container.html(skeleton);
} else {
$result_container.html('<a class="close" href="/">×</a><strong>No result!</strong>');
}
},
error: function() {
$result_container.html('<a class="close" href="/">×</a><strong>Error loading feed.</strong>');
}
});keyword adalah variabel. Nilainya diambil dari elemen input teks:
var keyword = $input.val();
// `../feeds/posts/summary?alt=json-in-script&q=keyword&max-results=9999`Integrasi Widget ke Blogger
Widget ini hanya akan bekerja jika blog Anda sudah dilengkapi dengan JQuery.
Pertama-tama masuk ke halaman Tata Letak, kemudian tambahkan sebuah elemen halaman HTML/JavaScript. Salin kode ini dan letakkan di dalam formulirnya:
<style type="text/css" scoped="scoped">
#ajax-search-form {
position:relative;
font:normal normal 13px/normal Arial,Sans-Serif;
}
#ajax-search-form a {
color:#741F27;
text-decoration:none;
}
#ajax-search-form input {
border:1px solid #ccc;
border-top-color:#999;
background-color:white;
font:inherit;
color:black;
margin:0 0;
padding:5px 5px;
width:180px;
}
#ajax-search-form input::-moz-focus-inner {
margin:0;
padding:0;
border:none;
outline:none;
}
#ajax-search-form input[type="submit"] {
width:auto;
background-color:#084670;
border-color:transparent;
color:#B4D8F0;
font-weight:bold;
cursor:pointer;
padding-left:7px;
padding-right:7px;
}
#ajax-search-form input[type="submit"]:hover,
#ajax-search-form input[type="submit"]:focus {background-color:#083E5F}
#search-result {
border:1px solid #bbb;
background-color:white;
padding:10px 15px;
margin:2px 0;
width:auto;
height:auto;
position:absolute;
top:100%;
left:0;
z-index:99;
-webkit-box-shadow:0 1px 3px rgba(0,0,0,.4);
-moz-box-shadow:0 1px 3px rgba(0,0,0,.4);
box-shadow:0 1px 3px rgba(0,0,0,.4);
display:none;
}
#search-result ol,
#search-result li,
#search-result h4 {
margin:0;
padding:0;
}
#search-result h4,
#search-result strong {
display:block;
margin:0 30px 10px 0;
}
#search-result ol {margin:0 0 10px 28px}
#search-result ol a:hover {text-decoration:underline}
#search-result .close {
display:block;
position:absolute;
top:6px;
right:10px;
line-height:normal;
color:#17950F;
}
#search-result strong {color:#B75252}
</style>
<form action="/search" id="ajax-search-form">
<input type="text" name="q" />
<input type="submit" value="Search" />
</form>
<script type="text/javascript">
(function($) {
var $form = $('#ajax-search-form'),
$input = $form.find(':text');
// Append a search result container to the search form
$form.append('<div id="search-result"></div>');
var $result_container = $('#search-result');
// When the keyword is submitted...
$form.on("submit", function() {
// Get the input value
var keyword = $input.val();
// Show the search result container and insert a `Loading...` text
$result_container.show().html('Loading...');
// Get the blog JSON via $.ajax() to show the search result
// The URL format: http://blog_name.blogspot.com/feeds/posts/summary?alt=json-in-script&q={THE_KEYWORD}&max-results=9999
$.ajax({
url: 'http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&q=' + keyword + '&max-results=9999',
type: 'get',
dataType: 'jsonp',
// If success, grab the search result list...
success: function(json) {
var entry = json.feed.entry,
link, skeleton = "";
if (entry !== undefined) {
skeleton = '<h4>Search results for keyword "' + keyword + '"</h4>';
skeleton += '<a class="close" href="/">×</a><ol>';
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") {
link = entry[i].link[j].href;
}
}
skeleton += '<li><a href="' + link + '">' + entry[i].title.$t + '</a></li>';
}
skeleton += '</ol>';
$result_container.html(skeleton);
} else {
// If the JSON is empty ... (entry === undefined)
// Show the `not found` or `no result` message
$result_container.html('<a class="close" href="/">×</a><strong>No result!</strong>');
}
},
error: function() {
// If error, show an error message
$result_container.html('<a class="close" href="/">×</a><strong>Error loading feed.</strong>');
}
});
return false;
});
// Fade out the search result container if the close button is clicked
$form.on("click", ".close", function() {
$result_container.fadeOut();
return false;
});
})(jQuery);
</script>Ganti kode yang Saya beri tanda dengan URL blog Anda kemudian klik Simpan Widget.
Label: JQuery, JSON, JSON Blogger, Sidebar, Tingkat Lanjut, Widget
Senin, 12 November 2012
Memperbaharui Pemuatan JSON berdasarkan Event Scroll

Metode ini masih sama dengan metode-metode penundaan pemuatan JSON yang biasa Saya lakukan untuk widget-widget Saya yaitu dengan cara menyisipkan script callback secara tidak langsung ke dalam area <head> dengan ID tertentu. Kemudian, jika Saya ingin memperbaharui muatan JSON yang sudah ada, Saya tinggal menyingkirkan script callback yang lama kemudian menggantinya dengan duplikat baru dengan parameter yang sudah diperbaharui.
Bayangkan saja bahwa sudah terdapat sebuah script callback dengan ID foo di dalam area <head> seperti ini:
...
...
<script id="foo" src="../feeds/posts/summary?alt=json-in-script&callback=functionName" type="text/javascript"></script>
</head>Kemudian Saya akan menyingkirkannya dengan cara menangkap ID elemen tersebut sebagai awalan untuk menyeleksi node induknya:
var a = document.getElementById('foo');
var parent = a.parentNode; // Mendapatkan elemen induk dari `foo`Kemudian, dari induk tersebut Saya akan menyingkirkan elemen itu sendiri:
var a = document.getElementById('foo');
var parent = a.parentNode; // Mendapatkan elemen induk dari `foo`
parent.removeChild(a); // Singkirkan `foo` dari `parent`Di sini, kita akan melakukan pekerjaan di atas berdasarkan event onscroll dengan batasan akhir berupa jarak gulungan maksimal kontainer. Kode di bawah ini akan menjalankan fungsi bernama myFunction() berdasarkan event onscroll dengan syarat jarak gulungan telah mencapai titk maksimal:
elem.onscroll = function() {
if ((this.scrollTop + this.offsetHeight) == inner.offsetHeight) {
myFunction();
}
};Dimana elem adalah objek berupa kontainer.
Memulai Pekerjaan
Markup HTML
Kita mulai dengan pembuatan markup HTML sederhana seperti ini:
<div id="result-container" style="width:400px;height:400px;overflow:auto;">
<ol></ol>
<span class="loading">Memuat...</span>
</div>Elemen #result-container digunakan sebagai area scroll, elemen ol digunakan sebagai kontainer data yang nantinya akan dihasilkan dari JSON, dan elemen span.loading digunakan sebagai indikator sedang memuat.
Membangun JavaScript
Pertama-tama kita buat script untuk memparse data JSON menjadi elemen HTML. Sederhana, seperti script recent post biasa yang Saya beri nama grabList(), dan hanya akan menghasilkan elemen <li> dengan tautan dan judul posting di dalamnya:
var elem = document.getElementById('result-container'), // Mendapatkan elemen `#result-container`
inner = elem.getElementsByTagName('ol')[0], // Mendapatkan elemen `ol` pertama
loading = elem.getElementsByTagName('span')[0]; // Mendapatkan elemen `span` pertama (dalam hal ini adalah elemen indikator sedang memuat)
// Bangun sebuah script untuk menampilkan daftar posting
function grabList(json) {
var list = json.feed.entry, link, skeleton = "";
// Jalankan loop hanya jika data JSON masih ada/dapat didefinisikan
if (list !== undefined) {
for (var i = 0; i < list.length; i++) {
for (var j = 0; j < list[i].link.length; j++) {
if (list[i].link[j].rel == "alternate") {
link = list[i].link[j].href; // Mendapatkan URL posting
}
}
// Bangun beberapa elemen `<li>` yang berisi tautan dan judul posting...
skeleton += '<li><a href="' + link + '">' + list[i].title.$t + '</a></li>';
}
// ... kemudian sisipkan elemen tersebut ke dalam elemen `<ol>`
inner.innerHTML += skeleton;
// dan sembunyikan indikator sedang memuat.
loading.style.display = "none";
} else {
// Jika data JSON sudah tidak ada (list == undefined), tambahkan kelas baru kepada elemen indikator sedang memuat dengan nilai `the-end`
loading.className += ' the-end';
// kemudian ganti teks indikator sedang memuat dengan kata `Habis`
loading.textContent = 'Habis';
}
}Setelah itu buat sebuah fungsi untuk memuat script callback secara tidak langsung. Tambahkan dua buah parameter untuk menangani start-index dan max-results:
function updateScript(i, max) {
var head = document.getElementsByTagName('head')[0],
script = document.createElement('script');
script.type = 'text/javascript';
script.id = 'load-on-scroll-end';
script.src = 'http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&start-index=' + i + '&max-results=' + max + '&callback=grabList';
head.appendChild(script);
}
// Jalankan fungsi!
updateScript(1, 25);Fungsi di atas akan menyisipkan sebuah script callback JSON Blogger dengan nilai parameter start-index berupa 1 dan max-results berupa 25, sehingga sebuah elemen <script> dengan parameter yang sudah diatur akan disipkan ke dalam area <head> secara tidak langsung seperti ini:
...
...
...
<script id="load-on-scroll-end" src="http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&start-index=1&max-results=25&callback=grabList" type="text/javascript"></script>
</head>Memperbaharui JSON Berdasarkan Jarak Maksimal Gulungan Area
Setelah itu kita tambahkan sebuah kondisional untuk menyingkirkan script callback lama jika script tersebut ada. Tidak perlu membuat fungsi baru, cukup gunakan fungsi tadi agar kita bisa menggunakannya untuk dua hal sekaligus, yaitu menyisipkan script baru dan/atau menyingkirkan script lama (jika ada):
function updateScript(i, max) {
var head = document.getElementsByTagName('head')[0],
script = document.createElement('script');
script.type = 'text/javascript';
script.id = 'load-on-scroll-end';
script.src = 'http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&start-index=' + i + '&max-results=' + max + '&callback=grabList';
if (document.getElementById('load-on-scroll-end')) {
var oldScript = document.getElementById('load-on-scroll-end');
oldScript.parentNode.removeScript(oldScript);
}
head.appendChild(script);
}
updateScript(1, 25); // Jalankan fungsi!Karena kita juga akan menjalankan fungsi updateScript() berdasarkan event onscroll, maka kita juga harus memasukkan updateScript() ke dalam event yang Saya tuliskan pertama kali:
elem.onscroll = function() {
if ((this.scrollTop + this.offsetHeight) == inner.offsetHeight) {
// Muat ulang JSON Blogger dengan `start-index` yang baru melalui parameter `i`
updateScript(i, 25);
// Kemudian tampilkan indikator sedang memuat
loading.style.display = "block";
}
};Parameter i haru dinamis, dan harus bisa bertambah setiap kali gulungan kontainer berakhir. Untuk membuatnya menjadi dinamis, kita akan menggunakan variabel awalan dengan nilai 0, kemudian kita tingkatkan nilainya di dalam event onscroll setiap kali jarak gulungan telah mencapai titik maksimal:
var start = 0;
elem.onscroll = function() {
if ((this.scrollTop + this.offsetHeight) == inner.offsetHeight) {
// Tingkatkan nilai `start` dengan 1 (dari `start = 0` menjadi `start = 1`, `start = 2`, dst...)
start++;
// Muat ulang JSON Blogger dengan `start-index` yang telah diperbaharui...
// ... melalui `start` yang nilainya dikalikan dengan 25
updateScript(start*25, 25); // => dari `(1, 25)` menjadi `(25, 25)`, `(50, 25)`, `(75, 25)`, dst...
// Kemudian tampilkan indikator sedang memuat
loading.style.display = "block";
}
};Produk Final
HTML
<div id="result-container">
<ol></ol>
<span class="loading">Memuat...</span>
</div>CSS
#result-container {
height:400px;
width:400px;
overflow:auto;
margin:50px auto;
font:normal normal 12px 'Trebuchet MS',Trebuchet,Geneva,Arial,Sans-Serif;
}
#result-container ol {
margin:0 0;
padding:0 0;
background-color:#B5D68C;
}
#result-container li {
margin:0 0;
padding:0 0;
list-style:none;
}
#result-container li:nth-child(even) {background-color:#A2C179}
#result-container li a {
display:block;
padding:5px 10px;
font-weight:bold;
color:#396B18;
text-decoration:none;
}
#result-container li a:hover {
background-color:#396B18;
color:white;
text-decoration:none;
}
#result-container .loading {
display:block;
height:26px;
font:normal bold 11px/26px Arial,Sans-Serif;
color:white;
text-align:center;
background-color:#B75A6F;
border-top:2px solid #222;
}
#result-container .loading.the-end {background-color:#666}JavaScript
var widget_config = {
home_page: 'http://nama_blog.blogspot.com', // Your blog homepage
container_id: 'result-container', // ID of the result container
script_id: 'load-on-scroll-end-script', // ID of the asynchronous script
max_result: 25, // Max result post at once script loading
end_text: 'Habis' // End text if all posts has been loaded
};
var elem = document.getElementById(widget_config.container_id),
inner = elem.getElementsByTagName('ol')[0],
loading = elem.getElementsByTagName('span')[0],
start = 0, // Dynamic start-index
max = widget_config.max_result;
function grabList(json) {
var list = json.feed.entry, link, skeleton = "";
if (list !== undefined) {
for (var i = 0; i < list.length; i++) {
for (var j = 0; j < list[i].link.length; j++) {
if (list[i].link[j].rel == "alternate") {
link = list[i].link[j].href;
}
}
skeleton += '<li><a href="' + link + '">' + list[i].title.$t + '</a></li>';
}
inner.innerHTML += skeleton; // Insert the list to the container
loading.style.display = "none"; // Hide the loading indicator
} else {
// If the JSON is empty (list == undefined),
// add a new class to the loading indicator called `the-end`
loading.className += ' the-end';
// Replace the loading indicator text into `fully loaded!` for the example
loading.textContent = widget_config.end_text;
}
}
// Make an indirect script loader with two parameters: start-index and max-result post
function updateScript(a, b) {
var head = document.getElementsByTagName('head')[0],
script = document.createElement('script');
script.type = 'text/javascript';
script.id = widget_config.script_id;
script.src = widget_config.home_page + '/feeds/posts/summary?alt=json-in-script&start-index=' + a + '&max-results=' + b + '&callback=grabList';
// If there is an old script in the document...
if (document.getElementById(widget_config.script_id)) {
var oldScript = document.getElementById(widget_config.script_id);
// Remove the old script, and replace with the new one that has an updated start-index value
oldScript.parentNode.removeChild(oldScript);
}
head.appendChild(script);
}
// Start loading the callback script with start-index of 1
updateScript(1, max);
// When the container is being scrolled...
elem.onscroll = function() {
// ... check the scroll distance
if ((this.scrollTop + this.offsetHeight) == inner.offsetHeight) {
// If the distance equal to the height of the inner container...
start++; // Increase the start value by one
// then load the new script with an updated start-index
updateScript(start*max, max);
// and show the loading indicator
loading.style.display = "block";
}
};Label: JavaScript, JSON, JSON Blogger, Layar, Posting, Tingkat Lanjut, Widget
Rabu, 07 November 2012
XHTML Blogger, Item Kontrol
Tombol Edit Cepat Posting
Biasanya berbentuk gambar/ikon pensil dan terletak di dalam footer posting:
<b:includable id='postQuickEdit' var='post'>
<b:if cond='data:post.editUrl'>
<span expr:class='"item-control " + data:post.adminClass'>
<a expr:href='data:post.editUrl' expr:title='data:top.editPostMsg'>
<img alt='' class='icon-action' height='18' src='http://img2.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/>
</a>
</span>
</b:if>
</b:includable>| Data | Keterangan | Tampilan/Contoh Tampilan |
|---|---|---|
| data:post.editUrl | Elemen ini akan menghasilkan URL pengeditan posting | http://www.blogger.com/post-edit.g?blogID=489094982896596XXXX&postID=622513084927827XXXX&from=pencil |
| data:top.editPostMsg | Elemen ini akan menghasilkan deskripsi/pesan tautan pengeditan posting | Edit Entri |
| data:post.adminClass | Elemen ini akan menghasilkan kelas khusus administrator (???) | blog-admin pid-251761511 |
Tombol Edit Cepat Widget
Berbentuk gambar/ikon kunci inggris dan terletak pada bagian bawah widget:
<b:include name='quickedit'/>Tombol Penghapusan Komentar
Label: Kamus Blogspot, Komentar, Posting, Tingkat Lanjut, Widget
Selasa, 10 Juli 2012
Rilis: Galleria V2 - Widget Masonry untuk Blogger
Pembaharuan 26 Mei 2013: Terjadi perubahan besar pada penulisan variabel-variabel di dalam widget ini. Saya terpaksa melakukannya demi pengembangan dan perbaikan widget yang lebih leluasa ke depannya agar tidak mengganggu para pemakai widget ini. Bagi Anda yang sudah memakai widget ini sebelum tanggal , Anda akan mendapatkan teks peringatan bahwa widget Anda harus segera diperbaharui.
Perubahan fitur: (1) Opsi showThumbnails ditiadakan (2) Menambahkan fitur Infinite Scroll (3) Mengganti parameter indeks feed dari window.location.search menjadi window.location.hash dengan bantuan event hashchange, sehingga pengguna tidak perlu memuat ulang halaman secara keseluruhan hanya untuk mengubah window.location.search pada address bar.
Sebelum ini Saya telah membuat widget Galleria versi pertama, kali ini Saya membuat versi yang ke dua dengan dua macam pilihan layout dan konfigurasi yang lebih lengkap.
Masalah besar yang terjadi pada versi pertama adalah dia menampilkan semua feed begitu saja sehingga proses muat widget menjadi begitu lama. Kita tidak memiliki kemampuan untuk memotong proses pemuatan feed kecuali dengan cara menambahkan fitur navigasi. Inilah kabar baiknya:
Widget ini dilengkapi dengan navigasi halaman. Setiap kali halaman berganti, itu akan mengubah nilai Widget ini dilengkapi dengan navigasi halaman. Setiap kali tombol navigasi diklik, itu akan mengubah nilai window.location.search pada address bar. Saya menggunakan angka-angka itu sebagai parameter untuk menentukan nilai start-index pada widget iniwindow.location.hash pada address bar. Saya menggunakan angka-angka itu sebagai parameter untuk menentukan nilai start-index pada widget ini:
Integrasi Widget ke Blogger
Pertama-tama klik menu Laman pada sidebar. Kemudian, pada menu Laman Baru pilihlah Laman Kosong:

Setelah itu Anda akan melihat formulir halaman statis seperti ini. Klik mode HTML:

Salin kode di bawah ini kemudian letakkan di dalam formulirnya:
<link rel="stylesheet" type="text/css" href="http://hompimpa.googlecode.com/svn/trunk/Blogger-Masonry-Widget/theme/light.min.css"/>
<div id="dte-masonry-container"></div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
<script src="http://hompimpa.googlecode.com/svn/trunk/Blogger-Masonry-Widget/js/jquery.masonry.min.js" type="text/javascript"></script>
<script src="http://hompimpa.googlecode.com/svn/trunk/Blogger-Masonry-Widget/js/post.brick.min.js" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
$('#dte-masonry-container').bloggerMasonry({
// JSON Configuration
viewMode: "summary", // Widget mode? "summary" || "thumbnail"
homePage: "http://nama_blog.blogspot.com", // Your blog homepage
numPosts: 10, // Number of posts to display per request
numChars: 270, // Length of summary post
squareImage: false, // Set thumbnail mode to square
newTabLink: false, // Auto open links in new window/tab?
columnWidth: 200, // Width of the image (also will resize the brick item width)
subHeaderText: ["Diposting oleh ", "<br>pada "], // `Diposkan oleh FOO pada BAR`
monthNames: [ // Month array
"Januari",
"Februari",
"Maret",
"April",
"Mei",
"Juni",
"Juli",
"Agustus",
"September",
"Oktober",
"November",
"Desember"
],
commentLabel: " ", // Label text after total comments
navText: {
prev: "Sebelumnya", // Previous navigation label
next: "Berikutnya", // Next navigation label
disabled: "×", // Disabled navigation label
data: ["Halaman ", " dari "] // `Halaman # dari #`
},
postCategory: null, // Change to a label name to sort posts by specific label
fallbackThumb: "http://hompimpa.googlecode.com/svn/trunk/Blogger-Masonry-Widget/img/meee.png", // Fallback thumbnail for posts without images
loadingText: "Loading...", // `Loading...` text for loading indicator
loadedText: "Loaded.", // `Loaded.` text for loading indicator
infiniteScroll: false, // Enable infinite scroll?
bottomTolerance: 30, // Bottom tolerance for the end of page indicator in infinite scroll
// Shortcuts for Masonry Plugin Configuration (And Some Local Configuration)
masonryConfig: {
itemSelector: '.json_post',
fadeSpeed: 400, // Speed of thumbnail fading effect
resizeSpeed: 1000, // Speed of thumbnail resizing effect
isAnimated: false,
animateWithTransition: true, // Animate each brick with CSS transition instead of JQuery `.animate()`?
animationOptions: {
queue: false,
duration: 1000,
easing: null
},
isFitWidth: true,
gutterWidth: 0,
isRTL: false
}
});
//]]>
</script>Ganti kode yang Saya beri tanda dengan URL blog Anda. Klik Simpan dan Terbitkan.
Kode yang Saya garis bawahi adalah JQuery. Jika template Anda sudah dilengkapi dengan JQuery, singkirkan kode tersebut!
Pengaturan Lanjutan
Pengaturan widget ini dibagi menjadi dua, yaitu pengaturan JSON Blogger dan pengaturan Plugin Masonry:
Pengaturan JSON Blogger
| Opsi | Keterangan |
|---|---|
| viewMode | Digunakan untuk menentukan tipe tampilan widget. Nilainya ada dua macam: "summary" untuk menampilkan galeri berupa daftar gambar beserta ringkasannya, "thumbnail" untuk menampilkan galeri berupa foto saja |
| homePage | Digunakan untuk menentukan URL blog sumber feed |
| numPosts | Digunakan untuk menentukan jumlah posting yang akan dipanggil setiap satu kali permintaan |
| numChars | Digunakan untuk menentukan jumlah karakter ringkasan/paragraf jika mode widget berupa "summary" |
| squareImage | Jika bernilai true semua gambar dalam widget akan dikonversi menjadi berbentuk kotak persegi. Ini adalah versi kompresi Picasa versi path gambar s72-c, hanya saja di sini Saya buat lebih fleksibel (ukurannya bisa diperbesar/diperkecil) - Tentang metode kompresi gambar Picasa |
| newTabLink | Jika bernilai true, semua tautan dalam widget akan terbuka di tab/jendela baru |
| columnWidth | Digunakan untuk menentukan lebar setiap kolom/item posting. Menentukan lebar pada opsi ini juga akan mengubah resolusi gambar |
| subHeaderText | Digunakan untuk mengatur teks deskripsi kecil di bawah header pada mode "summary" (Misal: Diposting oleh Taufik di 21 April 2012) |
| monthNames | Ini adalah daftar variabel nama-nama bulan. Ganti namanya sesuka hati sesuai dengan sistem penanggalan di negara Anda |
| commentLabel | Abaikan saja. Jika nilainya diganti, maka label komentar di bawah item posting akan berubah. Misalnya: 10 Komentar dari Pembaca akan tampil jika opsi commentLabel bernilai "Komentar dari Pembaca".Jika dikosongkan, label akan menyesuaikan diri berdasarkan format bahasa dalam pengaturan blog Anda |
| navText | prev digunakan untuk menentukan label navigasi mundur |
| next digunakan untuk menentukan label navigasi maju | |
| disabled digunakan untuk menentukan label navigasi tak aktif | |
| data digunakan untuk menentukan label deskripsi posisi halaman dan jumlah total halaman | |
| postCategory | Secara normal bernilai null. Ganti nilainya dengan nama label yang spesifik untuk menyortir item feed berdasarkan kategori khusus. Misal: postCategory: "JQuery" akan membuat widget ini menampilkan posting-posting yang memiliki label JQuery |
| fallbackThumb | Gambar cadangan jika posting yang tampil tidak memiliki gambar |
| loadingText | Deskripsi indikator sedang memuat saat sedang memuat |
| loadedText | Deskripsi indikator sedang memuat saat semua item telah selesai dimuat |
| infiniteScroll | Jika bernilai true, navigasi halaman tidak berfungsi lagi. Widget akan secara otomatis memuat item-item posting baru di bawah item-item posting yang sudah ada setiap kali gulungan layar telah mencapai jarak yang diinginkan (dalam hal ini, mencapai posisi navigasi widget terdekat terhadap bagian bawah layar) |
| bottomTolerance | Digunakan untuk menentukan toleransi jarak bawah infinite scroll untuk mengurangi kalkulasi posisi navigasi widget terdekat terhadap bagian bawah layar. |
Konfigurasi Plugin Masonry
| Opsi | Keterangan |
|---|---|
| fadeSpeed | Digunakan untuk menentukan kecepatan fade pada gambar |
| resizeSpeed | Digunakan untuk menentukan kecepatan perubahan ukuran kontainer gambar pada mode widget "thumbnail" |
| isAnimated | Jalan penghubung untuk opsi isAnimated pada plugin Masonry. Jika bernilai true efek animasi akan diterapkan dengan bantuan JQuery .animate(). Saat jendela peramban diperkecil/diperbesar, setiap item akan berubah posisi dengan efek animasi |
| animateWithTransition | Alternatif lain untuk menganimasikan widget. Set opsi isAnimated menjadi false, kemudian set opsi animateWithTransition menjadi true untuk menganimasikan masonry brick dengan CSS Transisi. Ini berhubungan dengan performa plugin. Menugaskan plugin untuk melakukan perhitungan posisi sekaligus menganimasikannya terkadang menjadi sesuatu yang berat bagi peramban. Jadi kita bisa memanfaatkan CSS Transisi —yang merupakan fitur bawaan pada peramban-peramban moderen— untuk menganimasikannya agar kerja peramban tidak terlalu berat dalam menangani JavaScript. Tentang metode animasi dengan CSS Transisi pada plugin Masonry bisa dibaca di sini |
| animationOptions | Jalan penghubung untuk opsi animationOptions pada plugin Masonry. Digunakan untuk mengonfigurasikan efek animasi JavaScript (isAnimated:true) |
| isFitWidth | Jalan penghubung untuk opsi isFitWidth pada plugin Masonry. Jika bernilai true, kontainer akan menyusut sesuai dengan kalkulasi jumlah semua item dalam satu baris, sehingga widget Masonry bisa berada tepat di tengah-tengah halaman - Selengkapnya tentang isFitWidth |
| gutterWidth | Jalan penghubung untuk opsi gutterWidth pada plugin Masonry. Digunakan untuk menentukan gutter/kerenggangan antaritem pada sisi dalam. Tidak terlalu penting - Selengkapnya tentang gutterWidth |
| isRTL | Jalan penghubung untuk opsi isRTL pada plugin Masonry. Jika bernilai true, plugin akan menganimasikan item dari kanan ke kiri (RTL = Right To Left) - Selengkapnya tentang isRTL |
Lebih Banyak Demo:
- Demo Galleria Mode Thumbnail
- Demo Galleria Mode Thumbnail Kotak
- Demo Galleria Sortir Posting Berdasarkan Label Spesifik
- Demo Galleria dengan fitur Infinite Scroll
Pengembangan Widget
Proyek ini Saya hosting di Google Code: http://code.google.com/p/hompimpa/source/browse/trunk/Blogger-Masonry-Widget/ Jika Anda berminat untuk mengembangkan widget ini, Saya sudah menyimpan semuanya di sana.
JQuery Masonry Widget for Blogger JSON by Taufik Nurrohman is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
Label: JavaScript, JQuery, Posting, Tingkat Lanjut, Widget
Sabtu, 03 Maret 2012
Widget Daftar Isi Blogger dengan Navigasi Halaman
Pembaharuan: 28 Februari 2013

Pada akhirnya Saya menemukannya, seorang penggagas JSON Blogger dengan sistem navigasi halaman. Beliau berasal dari Spanyol (Vagabundia). Pada dasarnya cara kerja navigasi widget ini di dalam mengontrol JSON hanyalah dengan cara mengubah nilai parameter start-index secara tidak langsung:
http://nama_blog.blogspot.com/feeds/posts/default?start-index=1&max-results=10&orderby=published&alt=json-in-script&callback=yourfunctionKode di atas akan menampilkan posting terbaru dengan keadaan normal yaitu mulai dari posting pertama (start-index=1) dan berhenti pada posting ke sepuluh (max-results=10). Namun, dengan cara mengubah nilai start-index, Anda bisa memanggil posting dari urutan berapapun meski bukan dari urutan pertama. Misalnya:
http://nama_blog.blogspot.com/feeds/posts/default?start-index=17&max-results=10&orderby=published&alt=json-in-script&callback=yourfunctionDengan cara itu, maka posting yang ditampilkan akan dimulai dari posting ke 17 (start-index=17) dan akan berhenti pada posting ke 27 (max-results=10).
Hal itulah yang dilakukan oleh navigasi JSON, yang hanya akan mengubah nilai start-index untuk meloncat dari halaman yang satu ke halaman yang lainnya, bahkan tanpa harus memuat halaman secara keseluruhan:
Saya telah memodifikasinya untuk memperkaya konten. Selain judul dan thumbnail, Saya juga telah melengkapinya dengan ringkasan posting, keterangan komentar dan bulan terbit artikel. Selain itu, widget ini juga bisa difilter berdasarkan nama label tertentu.
Memasang Widget Daftar Isi pada Blog Anda
Di sini Saya menggunakan tema hijau dan putih. Mungkin Anda tidak suka dengan tampilannya, tapi jika Anda berminat, cukup tuliskan keinginan pada formulir komentar di bawah mengenai tema apa lagi yang sekiranya bagus untuk widget ini. Jika ada kesempatan pasti akan Saya buat tema-tema yang baru untuk widget daftar isi ini atau juga widget-widget lainnya yang ada di blog ini.
Edit: Tema-tema selengkapnya bisa Anda lihat di sini »
Untuk membuatnya, pertama-tama klik menu Laman pada sidebar. Kemudian, pada menu Laman Baru pilihlah Laman Kosong:

Setelah itu Anda akan melihat formulir halaman statis seperti ini. Klik mode HTML:

Salin kode di bawah ini kemudian letakkan di dalam formulirnya:
<link rel="stylesheet" media="screen" href="http://reader-download.googlecode.com/svn/trunk/blogger-toc-with-pagination_default-theme.css" type="text/css" />
<script type="text/javascript">
var showPostDate = true,
showComments = true,
idMode = true,
sortByLabel = false,
labelSorter = "JQuery",
loadingText = "Loading...",
totalPostLabel = "Jumlah posting:",
jumpPageLabel = "Halaman",
commentsLabel = "Komentar",
rmoreText = "Selengkapnya ►",
prevText = "Sebelumnya",
nextText = "Berikutnya",
siteUrl = "http://nama_blog.blogspot.com",
postsPerPage = 10,
numChars = 370,
imgBlank = "http://2.bp.blogspot.com/-11FkySHGB5Y/TpZ6SSbsF2I/AAAAAAAAA94/zK10UaL7jgo/s1600/images.jpeg";
</script>
<script type="text/javascript" src="http://reader-download.googlecode.com/svn/trunk/blogger-archive-with-pagination.js"></script>Ganti URL http://nama_blog.blogspot.com dengan alamat blog Anda lalu simpan.
Pengaturan
| Opsi | Nilai | Keterangan |
|---|---|---|
| showPostDate | true | Ganti nilainya menjadi false jika Anda tidak ingin menampilkan bulan terbit artikel. |
| false | ||
| showComments | true | Ganti nilainya menjadi false jika Anda tidak ingin menampilkan jumlah komentar pada artikel. |
| false | ||
| idMode | true | Jika bernilai true, sistem penaggalan artikel akan menjadi berbahasa Indonesia. Jika bernilai false sistem penanggalan artikel akan berubah menjadi berbahasa Inggris. |
| false | ||
| sortByLabel | true | Digunakan untuk memfilter artikel/posting. Jika ingin menampilkan posting dengan kategori tertentu saja, pilihlah nilai true. Setelah itu tentukan nama label pada variabel labelSorter. |
| false | ||
| labelSorter | "JavaScript", "Widget", ... (nama label) | Tentukan nama label jika opsi sortByLabel bernilai true. |
| totalPostLabel | "Jumlah posting:", ... (teks) | Tentukan keterangan jumlah posting (yang di bawah navigasi). |
| jumpPageLabel | "Halaman", ... (teks) | Tentukan keterangan lompatan posting (yang di bawah navigasi). |
| commentsLabel | "Komentar", "Comments", ... (teks) | Digunakan untuk menentukan label jumlah komentar (contoh: 10 Komentar). |
| rmoreText | "Baca Selengkapnya", "Read More", ... (teks) | Digunakan untuk menentukan label link menuju posting asli. |
| prevText | "Sebelumnya", "Previous", ... (teks) | Digunakan untuk menentukan label navigasi mundur. |
| nextText | "Berikutnya", "Next", ... (teks) | Digunakan untuk menentukan label navigasi maju. |
| siteUrl | (URL Blog) | Ganti URL ini dengan URL blog Anda. |
| postsPerPage | 10, 30, ... (numerik) | Digunakan untuk menentukan jumlah posting yang tampil pada satu halaman. |
| numChars | 100, 200, ... (numerik) | Digunakan untuk menentukan jumlah karakter ringkasan posting. |
| imgBlank | no-image.jpg (URL Gambar) | Gambar cadangan jika posting yang tampil tidak memiliki gambar. |
Label: JavaScript, Tingkat Lanjut, Widget
Rabu, 29 Februari 2012
Slideshow Otomatis Blogger dengan Imageflow 1.3.0
Hal yang paling sulit adalah tentang bagaimana caranya menyisipkan URL posting ke dalam Imageflow, karena saat gambar diklik, yang terakses bukannya URL halaman, melainkan URL gambar itu sendiri. Meskipun Saya telah berhasil memanipulasinya menggunakan JQuery, yaitu dengan cara menyimpan URL posting ke dalam atribut rel pada gambar, sehingga Saya bisa mengakses URL tersebut dan menyisipkannya ke dalam perintah window.open() seperti ini:
onclick = function() {
window.open($(this).attr('rel'));
}Tapi Saya pikir, menggunakan JQuery pada Imageflow merupakan sebuah pemborosan besar. Tidak efisien. Bahkan Imageflow bisa bekerja tanpa JQuery! Jadi Saya memutuskan untuk menggunakan ilmu sihir terakhir: Menyisipkan elemen
<a> ke dalam atribut rel gambar (karena caption setiap slide diproduksi dari atribut alt pada gambar) seperti ini:document.write('<img src="' + img[o] + '" alt="<a href='' + posturl + ''>' + postitle + '</a>">');Dan berhasil!
Tahap 1: Mengedit Template
Untuk membuatnya, pertama-tama masuklah ke menu Template kemudian klik Edit HTML dan klik Lanjutkan:

Temukan kode ini:
]]></b:skin>
Salin kode di bawah ini, kemudian letakkan di atasnya:
@charset "utf-8";
/*
Auto Content 4 Imageflow 1.3.0 by Taufik Nurrohman
URL: https://plus.google.com/108949996304093815163/about
*/
@media screen, projection {
.imageflow {
width:100%;
overflow:hidden;
position:relative;
text-align:left;
visibility:hidden;
margin:0 auto;
font:normal normal 12px/1.4 Verdana,Tahoma,Arial,Sans-Serif;
}
.imageflow img {
border:none;
padding:0;
margin:0;
background:transparent;
position:absolute;
top:0;
visibility:hidden;
/* Enables bicubic image resampling for the IE7 */
-ms-interpolation-mode:bicubic;
/* Uncomment this declaration to enable shadow around images
-webkit-box-shadow:0 1px 10px black;
-moz-box-shadow:0 1px 10px black;
box-shadow:0 1px 10px black;
*/
}
.imageflow p {
margin:0 auto;
text-align:center;
}
.imageflow .loading {
border:1px solid white;
height:15px;
left:50%;
margin-top:4px;
margin-left:-106px;
padding:5px;
position:relative;
visibility:visible;
width:200px;
}
.imageflow .loading_bar {
background:#fff;
height:15px;
visibility:visible;
width:1%;
}
.imageflow .navigation {
z-index:10000;
margin-top:160px;
}
.imageflow .caption {
font-weight:bold;
position:relative;
text-align:center;
z-index:10001;
text-shadow:0 1px 3px black;
}
.imageflow .caption a {
text-decoration:none;
color:white;
}
.imageflow .caption a:hover {
text-decoration:underline;
color:#8CD0D3;
}
.imageflow .scrollbar {
border-bottom:1px solid #b3b3b3;
position:relative;
visibility:hidden;
z-index:10002;
height:1px;
}
.imageflow .slider {
background:transparent url('http://1.bp.blogspot.com/-4lzSM34zaOA/T01-W0Mb1kI/AAAAAAAACQU/5w3WsezYvRY/s1600/slider.png') no-repeat 50% 50%;
height:14px;
margin:-6px 0 0 -7px;
position:absolute;
width:14px;
z-index:10003;
}
.imageflow .slideshow {
cursor:pointer;
height:14px;
margin:20px 0 0 20px;
position:absolute;
width:14px;
z-index:10003;
}
.imageflow .slideshow.pause {background:transparent url('http://2.bp.blogspot.com/-yt4eRgtDd6I/T01wsFn-e4I/AAAAAAAACPM/pdr8ljnrM9o/s1600/button_pause.png') no-repeat 50% 50%}
.imageflow .slideshow.play {background:transparent url('http://3.bp.blogspot.com/-H5F2nAmaVBA/T01wx0hM8oI/AAAAAAAACPc/OpMSLH-WaO8/s1600/button_play.png') no-repeat 50% 50%}
.imageflow .images {
overflow:hidden;
white-space:nowrap;
}
.imageflow .button {
cursor:pointer;
height:17px;
position:relative;
width:17px;
}
.imageflow .previous {
background:transparent url('http://4.bp.blogspot.com/-Eq4y210bsdE/T01wpORgybI/AAAAAAAACPE/AwOmlS5OrpU/s1600/button_left.png') no-repeat 0 0;
float:left;
margin:-7px 0 0 -30px;
}
.imageflow .next {
background:transparent url('http://2.bp.blogspot.com/-VwvDUzRpSOo/T01wuzhWf-I/AAAAAAAACPU/K4NQIxxIm7U/s1600/button_right.png') no-repeat 0 0;
float:right;
margin:-7px -30px 0 30px;
}
}Kemudian temukan kode ini:
</head>
Salin kode di bawah ini kemudian letakkan di atasnya:
<script type='text/javascript'>
//<![CDATA[
var loadingText = "Memuat gambar",
animationSpeed = 50,
aspectRatio = 1.964,
circular = true,
imageCursor = 'default',
opacity = false,
opacityArray = [10,8,5,3],
imagesHeight = 0.5,
imageScaling = true,
percentLandscape = 200,
percentOther = 100,
preloadImages = true,
slider = true,
sliderCursor = 'e-resize',
sliderWidth = 14,
scrollbarP = 0.7,
onClick = function() {},
startID = 1,
slideshow = true,
slideshowSpeed = 1500,
slideshowAutoplay = false,
startAnimation = false,
xStep = 200;
//]]>
</script>
<script src='http://reader-download.googlecode.com/svn/trunk/imageflow-custom.js' type='text/javascript'></script>Klik Simpan Template.
Tahap 2: Meletakkan Slideshow
Masuklah ke menu Tata Letak kemudian tambahkan sebuah elemen halaman HTML/JavaScript yang terletak di bagian atas posting:

Salin kode di bawah ini kemudian letakkan di dalam formulirnya:
<script type="text/javascript">
var showPostDate_g = false,
showComm_g = false,
slideOpenNewTab = true,
idMode = true,
slidebyLabels = false,
slideLabelName = "Mengenai",
pBlank = "http://2.bp.blogspot.com/-RdWht36FTLI/TrsqFbSraFI/AAAAAAAABO4/rTjPm97uO34/s1600/dte-darkblue.png",
text = "Komentar",
numposts_g = 10,
home_page = "http://nama_blog.blogspot.com";
</script>
<script src="http://reader-download.googlecode.com/svn/trunk/autoContent4Imageflow.1.3.js" type="text/javascript"></script>Ganti URL http://nama_blog.blogspot.com dengan alamat blog Anda lalu simpan.
Konfigurasi JSON & Imageflow 1.3.0
Pengaturan slideshow ini dibagi menjadi dua, yaitu pengaturan JSON Blogger dan pengaturan opsi dalam Imageflow itu sendiri.
| Opsi | Keterangan |
|---|---|
| showPostDate_g | Jika bernilai true, bulan terbit artikel akan ditampilkan. Jika bernilai false, bulan terbit artikel akan disembunyikan. |
| slideOpenNewTab | Jika bernilai true, setiap link akan terbuka di tab/jendela baru. Jika bernilai false, setiap link akan terbuka di tab/jendela yang sama. |
| idMode | Jika bernilai true, sistem penanggalan akan berubah menjadi berbahasa Indonesia. Jika bernilai false, sistem penanggalan akan berubah menjadi berbahasa Inggris. |
| slidebyLabels | Ubah nilainya menjadi true jika ingin menampilkan daftar slide artikel dengan label yang spesifik. Setelah itu tentukan nama label pada variabel slideLabelName. |
| slideLabelName | Digunakan untuk menentukan nama label yang spesifik setelah mengubah nilai slidebyLabels menjadi true. |
| pBlank | Adalah gambar cadangan yang akan ditampilkan jika artikel tidak memiliki gambar. |
| text | Digunakan untuk menentukan label jumlah komentar (contoh: 7 Komentar). |
| numposts_g | Digunakan untuk menentukan jumlah slide. |
| home_page | URL blog Anda. |
| Opsi | Keterangan |
|---|---|
| loadingText | Digunakan untuk menentukan deskripsi saat sedang memuat gambar. |
| animationSpeed | Digunakan untuk menentukan kecepatan gerakan slide. |
| animationSpeed | Digunakan untuk menentukan kecepatan gerakan slide. |
| aspectRatio | Rasio kontainer Imageflow (lebar dibagi dengan tinggi) |
| circular | Jika bernilai false slideshow akan memiliki titik awal dan titik akhir. Jika bernilai true slideshow akan membentuk lingkaran slide dan tidak akan pernah memiliki akhir (Saat slide telah habis, slide pertama akan muncul setelah slide terakhir). |
| imageCursor | Digunakan untuk menentukan kursor gambar. |
| opacity | Jika bernilai true setiap gambar di samping gambar yang sedang aktif akan memudar dan transparan. Semakin jauh jaraknya akan semakin transparan sesuai dengan pengaturan baris transparasi pada opacityArray. |
| imageCursor | Digunakan untuk menentukan kursor gambar (Untuk slideshow Blogger ini, tidak terlalu penting). |
| opacityArray | Digunakan untuk menentukan tingkat transparasi sesuai dengan jarak gambar dari gambar paling depan (maksudnya, gambar yang di tengah) menuju gambar terakhir/terjauh dari pandangan. |
| imagesHeight | Digunakan untuk menentukan tinggi kontainer gambar (tidak begitu jelas sebenarnya, tapi akan Saya perbaiki keterangan opsi ini jika sudah jelas). |
| imagesScaling | Jika bernilai false setiap gambar tidak akan mengecil meskipun jarak gambar sudah semakin jauh. |
| percentLandscape | Keterangan aslinya seperti ini: Scale landscape format. Tapi setelah Saya coba mengubahnya, opsi ini justru lebih mirip sebagai pengubah skala gambar sehingga gambar bisa menjadi jauh lebih besar dalam area yang tidak begitu luas (Anda harus tahu bahwa slideshow ini sebenarnya sangat responsif). |
| percentOther | Belum begitu meyakinkan. Keterangan asli: Scale portrait and square format. |
| preloadImages | Jika bernilai false, efek animasi loading tidak akan tampil. |
| slider | Jika bernilai false, slider di bagian bawah slideshow akan menghilang. |
| sliderCursor | Digunakan untuk menentukan kursor slider. |
| sliderWidth | Digunakan untuk menentukan lebar slider (tidak penting, kecuali jika Anda ingin mengubah backgrund-image slider ini). |
| scrollbarP | Digunakan untuk menentukan lebar scrollbar slider dalam persen. |
| onClick | Digunakan untuk menyisipkan fungsi tambahan saat gambar diklik. |
| startID | Digunakan untuk menentukan slide urutan ke berapa yang akan tampil terlebih dahulu. |
| slideshow | Jika bernilai false, simbol play di sebelah kiri atas akan menghilang. |

| slideshowSpeed | Digunakan untuk menentukan kecepatan slideshow jika opsi slideshow bernilai true. |
| slideshowAutoplay | Jika bernilai true, Imageflow akan mengaktifkan fungsi slideshow otomatis saat pertama kali halaman diakses. |
| startAnimation | Kurang begitu meyakinkan. Keterangan aslinya: Animate images moving in from the right on startup. |
| xStep | Digunakan untuk menentukan radius lingkaran slideshow. Semakin besar nilainya, maka jarak antara gambar yang satu dengan yang lainnya akan semakin jauh. |
Contoh Penerapan: circular:false, opacity:true
//<![CDATA[
...
...
circular = false,
opacity = true,
opacityArray = [10,8,5,3],
...
...
//]]>
button_right_dark.png
button_play_dark.png
button_pause_dark.png
button_left_dark.png
slider_dark.pngLabel: Gambar, JavaScript, Slideshow, Tingkat Lanjut, Widget



