DTE :]

Saturday, April 4, 2020

Pilih Mana: Memuat JSON Blogger dengan Metode Tradisional atau dengan Metode AJAX?

Menambahkan parameter alt dengan nilai json atau json-in-script pada URL umpan blog akan memberikan hasil keluaran data berupa JSON. Pengembang bisa memanfaatkan data tersebut untuk membuat gawai blog. Namun untuk bisa memproses data, kita perlu menemukan cara untuk menampung data tersebut ke dalam parameter fungsi:

function recentPosts(json) {
    // Ubah data `json` menjadi gawai di sini…
}

recentPosts( /* Masukan data JSON di sini… */ );

Metode Tradisional

Blogger memberikan akses kepada para pengembang untuk memproses data yang diberikan melalui parameter callback. Dengan menyatakan nama fungsi pada parameter tersebut, maka hasil keluaran JSON mentah yang diberikan akan dilengkapi dengan kode eksekusi fungsi yang membungkus data JSON tersebut. Sebenarnya tidak ada hal yang ajaib dalam sistem pemuatan data seperti itu. Tanpa parameter callback, hasil keluaran yang akan diberikan adalah seperti ini:

{
  "version": "1.0",
  "encoding": "UTF-8",
  "feed": { … }
}

Sedangkan ketika menggunakan parameter callback dengan nilai recentPosts, maka hasil keluaran yang akan diberikan adalah seperti ini:

recentPosts({
  "version": "1.0",
  "encoding": "UTF-8",
  "feed": { … }
});

Sehingga ketika umpan blog berhasil dimuat, maka data yang akan termuat bukan hanya terdiri dari JSON saja tetapi juga fungsi global yang memproses data JSON tersebut pada saat yang bersamaan ketika JSON termuat:

<!-- Tanpa eksekusi fungsi -->
<script src="/feeds/posts/summary?alt=json"></script>

<!-- Dengan eksekusi fungsi -->
<script src="/feeds/posts/summary?alt=json&amp;callback=recentPosts"></script>

Menerapkan metode seperti ini bukan berarti tidak memiliki kekurangan. Karena umpan blog perlu menerima nama fungsi yang bersifat global, maka kita harus mengaitkan fungsi gawai yang kita buat pada objek window. Satu-satunya cara yang bisa kita lakukan adalah dengan mendeklarasikan fungsi tersebut pada bagian terluar dari berkas JavaScript, atau dengan mendeklarasikan fungsi tersebut sebagai salah satu properti dari window jika fungsi tersebut berada di dalam fungsi-fungsi yang lain:

// Metode 1
function recentPosts(json) { … }

// Metode 2
window.recentPosts = function(json) { … };

// Metode 3
(function(w) {
    w.recentPosts = function(json) { … };
})(window);

// Metode 4
function start() {
    function createRecentPostsFunction() {
        function a() { … }
        function b() { … }
        function c() {
            window.recentPosts = function(json) { … };
        }
        a();
        b();
        c();
    }
    function hasRecentPostsFunction() {
        return 'recentPosts' in window && 'function' === typeof window.recentPosts;
    }
    if (!hasRecentPostsFunction()) {
        createRecentPostsFunction();
    }
}

start();

Karena JavaScript memungkinkan kita untuk menimpa fungsi yang telah dibuat sebelumnya dengan cara membuat fungsi yang baru (atau membuat variabel) menggunakan nama yang sama, maka akan sangat mudah bagi fungsi tersebut untuk mengalami konflik-konflik penamaan seperti ini:

<!-- Kode pihak ke 1 (kamu) -->
<script>
function recentPosts(json) { … }
</script>

<!-- Kode pihak ke 3 (orang lain) yang akan merusak fungsi `recentPosts()` -->
<script>
var recentPosts = null;
</script>

<!-- Di sini akan muncul pesan kesalahan “TypeError: recentPosts is not a function” -->
<script src="/feeds/posts/summary?alt=json&amp;callback=recentPosts"></script>

Ada dua cara yang dapat kamu lakukan untuk menghindari masalah tersebut. Cara yang pertama adalah dengan mendeklarasikan fungsi recentPosts sebagai konstanta agar nama fungsi tersebut tidak bisa digunakan lagi di tempat lain setelah konstanta tersebut dinyatakan:

<script>
const recentPosts = json => { … };
</script>

<!-- Akan muncul pesan kesalahan “SyntaxError: redeclaration of const recentPosts” -->
<script>
function recentPosts(json) { … };
</script>

<!-- Akan muncul pesan kesalahan “SyntaxError: redeclaration of const recentPosts” -->
<script>
let recentPosts = json => { … };
</script>

<!-- Akan muncul pesan kesalahan “SyntaxError: redeclaration of const recentPosts” -->
<script>
const recentPosts = json => { … };
</script>

Cara yang ke dua adalah dengan membuat nama fungsi yang tidak permanen dan bersifat acak. Cara di bawah ini memungkinkan kita untuk membuat fungsi global yang bisa berubah-ubah namanya setiap kali halaman dimuat, sehingga akan memperkecil kemungkinan pihak lain untuk mendeklarasikan fungsi gawai dengan nama yang sama:

let id = Math.floor(Math.random() * 1000),
    node = document.createElement('script');

window['recentPosts_' + id] = json => { … };

node.src = '/feeds/posts/summary?alt=json&callback=recentPosts_' + id;

document.head.appendChild(node);

Metode AJAX

Memuat data menggunakan AJAX relatif lebih praktis, walaupun dari segi sintaks mungkin akan terlihat rumit bagi orang-orang yang belum terbiasa. Kamu bisa menggunakan fungsi ini sebagai contekan selama kamu masih belum menguasai konsep AJAX. Dengan menggunakan AJAX, kamu tidak perlu menambahkan parameter callback karena data yang dimuat nantinya akan secara otomatis tertampung ke dalam parameter fungsi untuk menyatakan kesuksesan proses pemuatan data. Kamu bisa menggunakan XMLHttpRequest atau fetch. Pilih salah satu:

let xhr = new XMLHttpRequest;

// Buka tautan umpan dengan metode `GET`
xhr.open('GET', '/feeds/posts/summary?alt=json', true);

// Atur tipe respons sebagai JSON, bukan teks
xhr.responseType = 'json';

// Proses manipulasi data dilakukan di dalam acara `readystate`
xhr.addEventListener('readystate', function() {
    if (4 === this.readyState && 200 === this.status) {
        let json = this.response;
        // Ubah data `json` menjadi gawai mulai dari sini…
    }
}, false);

// Memulai permintaan data!
xhr.send();
// Memulai permintaan data!
fetch('/feeds/posts/summary?alt=json').then(response => {
    return response.json(); // Atur tipe respons sebagai JSON, bukan teks
}).then(json => {
    // Ubah data `json` menjadi gawai mulai dari sini…
});

Pakai jQuery juga bisa! Tapi akhir-akhir ini jQuery sudah ketinggalan zaman:

$.ajax({
    type: 'GET',
    url: '/feeds/posts/summary?alt=json',
    dataType: 'json'
}).done(function(json) {
    // Ubah data `json` menjadi gawai di sini…
});
$.get('/feeds/posts/summary?alt=json', function(json) {
    // Ubah data `json` menjadi gawai di sini…
}, 'json');

Mengeksekusi fungsi recentPosts() melalui respons AJAX dapat dilakukan dengan cara seperti ini:

xhr.addEventListener('readystate', function() {
    if (4 === this.readyState && 200 === this.status) {
        recentPosts(this.response);
    }
}, false);
fetch('/feeds/posts/summary?alt=json').then(response => response.json()).then(recentPosts);
$.ajax({
    type: 'GET',
    url: '/feeds/posts/summary?alt=json',
    dataType: 'json'
}).done(recentPosts);
$.get('/feeds/posts/summary?alt=json', recentPosts, 'json');

Kelebihan dari menggunakan metode AJAX adalah kamu tidak diharuskan untuk membuat fungsi gawai sebagai fungsi yang bersifat global, sehingga akan lebih ramah bagi lingkungan di luar gawai, serta dapat membebaskan fungsi tersebut dari kemungkinan-kemungkinan terjadinya konflik penamaan fungsi seperti yang telah Saya jelaskan sebelumnya pada metode pemuatan data umpan secara tradisional. Nama fungsi juga dapat dikompres dengan alat pengompres JavaScript tanpa memberikan pengaruh apa-apa pada hasil keluarannya:

(function() {
    function recentPosts(json) { … }
    fetch('/feeds/posts/summary?alt=json').then(response => response.json()).then(recentPosts);
})();

// Akan muncul pesan kesalahan “ReferenceError: recentPosts is not defined”
console.log(recentPosts);

Setiap metode tentu memiliki kekurangan dan kelebihannya masing-masing. Beberapa hal yang sudah Saya jabarkan di sini hanyalah sebagian kecilnya saja. Selebihnya mungkin dapat dijelaskan dengan contoh kasus. Jadi, mau pilih yang mana?

Labels: , , ,

Saturday, August 30, 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:

Lihat Demo

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}

Lihat Demo

Labels: ,

Friday, April 4, 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:

Lihat Demo

Labels: , ,

Saturday, July 6, 2013

Widget Artikel Terkait Blogger · 6 dalam 1

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:

Buka Generator Widget Kode Sumber

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:

Opsi Keterangan
widgetStyle Kode 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.
homePage Digunakan untuk menentukan URL blog Anda. Nilai sudah diotomatisasikan melalui elemen <data:blog.homepageUrl/>
widgetTitle Markup 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.
numPosts Digunakan untuk menentukan jumlah posting yang ingin ditampilkan.
summaryLength Digunakan untuk menentukan panjang karakter ringkasan posting.
titleLength Digunakan untuk memotong jumlah karakter judul posting sesuai dengan besar angka yang dituliskan. Ubah menjadi "auto" untuk menonaktifkan pemotongan karakter pada judul posting.
thumbnailSize Digunakan untuk menentukan lebar/tinggi thumbnail posting yang berbentuk kotak.
noImage Isi dengan URL gambar cadangan untuk posting yang tidak memiliki gambar.
containerId ID elemen HTML untuk menampung daftar posting yang berhasil terpanggil.
newTabLink Ubah nilainya menjadi true untuk membuat tautan-tautan di dalam widget ini membuka di tab/jendela baru secara otomatis ketika diklik.
moreText Teks “Baca Selengkapnya”.
callBack Fungsi 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}

Lihat Demo

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}

Lihat Demo

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();
    }
};

Lihat Demo

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.

Labels: , ,

Monday, April 22, 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>
  //<![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.

Labels: , ,

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>
//<![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.

Labels: , , , ,

Wednesday, March 27, 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:

Lihat Demo

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;
}

Lihat Demo

Labels: ,

Monday, February 11, 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

Labels: , , ,

Monday, January 14, 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)

Labels: , ,

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, ""];

Labels: , ,

Wednesday, January 9, 2013

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

Pembaharuan 2018/05/17: Sintaks dan struktur HTML sudah berubah. Beberapa diskusi yang terdapat di dalam ruang komentar mungkin sudah tidak relevan lagi dengan isi artikel.

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:

Lihat Demo


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:

/* Begin custom comments */

.comments,
.comment {
  margin: 0;
  padding: 0;
  list-style: none;
  letter-spacing: 0;
}
.comments::after,
.comment::after,
.comment-header::after,
.comment-body::after,
.comment-footer::after {
  content: "";
  display: table;
  clear: both;
}
.custom-comments {
  margin: 3em 0 0;
  font: normal normal 13px/1.4 Tahoma, Helmet, FreeSans, sans-serif;
}
.custom-comments a {
  color: #2143b4;
  text-decoration: none;
}
.custom-comments a:hover {
  text-decoration: underline;
}
.custom-comments .comment {
  margin: 0 0 .5em;
  padding: 0 0 .75em 0;
  border-bottom: 1px solid #eee;
  position: relative;
}
.custom-comments .comment-header {
  margin: 0 0 1em 0;
}
.custom-comments .comment-author {
  float: left;
}
.custom-comments .comment-url {
  float: right;
}
.custom-comments .comment-avatar {
  width: 65px;
  float: left;
}
.custom-comments .comment-avatar a,
.custom-comments .comment-avatar img {
  margin: 0;
  padding: 0;
  background: none;
  border: none;
  display: block;
  float: none;
  width: 50px;
  height: 50px;
  min-width: 0;
  min-height: 0;
  max-width: 100%;
  max-height: 100%;
}
.custom-comments .comment-avatar img {
  border: 1px solid #ddd;
  padding: 4px;
  background: #fafafa;
}
.custom-comments .comment-body {
  margin: -5px 0 1em 75px;
}
.custom-comments .comment.reply {
  margin: 0 0 1em 75px;
  padding: 1em 1.2em;
  background: #fff7d1;
  border: 0;
  position: relative;
  font-size: 86%;
}
.custom-comments .comment.reply::after {
  content: "";
  display: block;
  width: 0;
  height: 0;
  position: absolute;
  top: 0;
  left: 0;
  border: 10px solid transparent;
  border-color: #fff #f5f2d8 #f5f2d8 #fff;
}
.custom-comments .comment.reply .comment-author {
  margin-left: 15px;
}
.custom-comments .comment.reply a {
  color: #767643;
}
.custom-comments .comment.reply .comment-avatar img {
  border-color: #eae5c4;
  background: #f5f0d3;
}
.custom-comments .comment-footer {
  margin: 0 0 .125em 75px;
  text-align: right;
}
.custom-comments .comment-footer a,
.custom-comments .a-undo {
  display: inline-block;
  border: 1px solid #ddd;
  padding: .15em .65em .2em;
  margin: 0 0 0 .25em;
  border-radius: 1em;
  text-decoration: none;
  outline: none;
}
.custom-comments .comment.reply .comment-footer a {
  border-color: #eae5c4;
}
.custom-comments .comment-footer .a-reply::before {
  content: '\2714';
  color: #3db537;
  display: inherit;
  margin: 0 .25em 0 -.125em;
}
.custom-comments .comment-footer .a-delete::before {
  content: '\2718';
  color: #b42a21;
  display: inherit;
  margin: 0 .25em 0 -.125em;
}
.custom-comments .comment-footer a:hover,
.custom-comments .a-undo:hover {
  border-color: #ccc;
  text-decoration: none;
}
.custom-comments .comment-footer a:focus,
.custom-comments .comment-footer a:active,
.custom-comments .a-undo:focus,
.custom-comments .a-undo:active {
  border-color: #aaa;
}
.custom-comments .comment.reply .comment-footer a {
  background: #fffad6;
  border-color: #e3deb7;
}
.custom-comments .comment.reply .comment-footer a:hover {
  border-color: #d6d1aa;
}
.custom-comments .comment.reply .comment-footer a:focus,
.custom-comments .comment.reply .comment-footer a:active {
  border-color: #bcb795;
}
.custom-comments .custom-comment-form {
  margin: 1em 0 2em;
  clear: both;
}
.custom-comments .comment .custom-comment-form {
  border: 1px solid #eee;
  padding: 1em;
  margin-left: 75px;
}
.custom-comments #comment-editor {
  max-width: none;
  width: 100%;
  height: 250px;
  background: none;
  border: 0;
}
.custom-comments .custom-comment-form .a-undo {
  display: none;
}
.custom-comments .comment .custom-comment-form .a-undo {
  display: inline-block;
}
.custom-comments .comment .custom-comment-form h4 {
  display: none;
}
.custom-comments .custom-comment-editor-wrapper {
  background: transparent url('data:image/gif;base64,R0lGODlhEgAEAKEAAH9/fwAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJDwACACwAAAAAEgAEAAACB5SPqcvtrwoAIfkECQ8AAgAsAAAAAAQABAAAAgSEjwkFACH5BAkPAAIALAAAAAALAAQAAAIMjCMJC4fKXBKsnVkLACH5BAkPAAIALAAAAAASAAQAAAIRjCN5mOCwkojt0Xnkg1l1sRUAIfkECQ8AAgAsAAAAABIABAAAAhGEIRkbKRwOUsxBaStdeDdfAAAh+QQJDwACACwHAAAACwAEAAACDIQhGRuHylwSrJ1ZCwAh+QQFDwACACwOAAAABAAEAAACBISPCQUAOw==') no-repeat 50% 50%;
}
.custom-comments-pager {
  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-pager .unneeded-paging-control {
  display: none;
}
.custom-comments-pager .paging-control {
  display: inline;
}

/* Author comment style */
.custom-comments .comment.is-author {}
.custom-comments .comment.is-author > .comment-header {}

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

/* End custom comments */

Kemudian cari kode ini:

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

Salin kode ini, dan letakkan di atasnya:

<b:includable id='custom-comments' var='post'>
  <b:with value='{
      delete: &quot;Delete&quot;,
      reply: &quot;Reply&quot;,
      undo: &quot;Cancel Reply&quot;
  }' var='text'>
    <section class='custom-comments' id='custom-comments'>
      <b:if cond='data:post.allowComments'>
        <h4>
          <b:if cond='data:post.numComments == 1'>
            <span>1</span> <data:commentLabel/>
          <b:else/>
            <span><data:post.numComments/></span> <data:commentLabelPlural/>
          </b:if>
        </h4>
        <b:if cond='data:post.comments.size &gt; 0'>
          <ul class='comments'>
            <b:loop values='data:post.comments' var='comment'>
              <b:if cond='!data:comment.inReplyTo'>
                <b:include data='comment' name='custom-comments-comment'/>
              </b:if>
            </b:loop>
          </ul>
        </b:if>
        <b:include data='post' name='custom-comments-pager'/>
        <b:include data='post' name='custom-comments-form'/>
      </b:if>
    </section>
  </b:with>
</b:includable>
<b:includable id='custom-comments-comment' var='comment'>
  <li class='comment' expr:id='data:comment.anchorName'>
    <b:class cond='data:comment.authorClass' name='is-author'/>
    <b:class cond='data:comment.isDeleted' name='is-deleted'/>
    <header class='comment-header'>
      <strong class='comment-author'>
        <b:if cond='data:comment.authorUrl'>
          <a expr:href='data:comment.authorUrl' rel='nofollow' target='_blank'><data:comment.author/></a>
        <b:else/>
          <data:comment.author/>
        </b:if> <data:commentPostedByMsg/>
      </strong>
      <a class='comment-url' expr:href='data:comment.url'><data:comment.timestamp/></a>
    </header>
    <figure class='comment-avatar'>
      <img alt='' expr:src='resizeImage(data:comment.authorAvatarSrc, 50)'/>
    </figure>
    <div class='comment-body'>
      <data:comment.body/>
    </div>
    <b:with value='data:post.comments filter (i =&gt; i.inReplyTo == data:comment.id)' var='replies'>
      <b:if cond='data:replies.size &gt; 0'>
        <ul class='comments replies'>
          <b:loop values='data:replies' var='reply'>
            <b:include data='reply' name='custom-comments-comment-reply'/>
          </b:loop>
        </ul>
      </b:if>
    </b:with>
    <footer class='comment-footer'>
      <b:if cond='!data:comment.isDeleted'>
        <a class='a-reply' expr:href='&quot;javascript:replyTo(&amp;quot;&quot; + data:comment.id + &quot;&amp;quot;);&quot;'><data:text.reply/></a>
      </b:if>
      <a class='a-delete' expr:href='data:comment.deleteUrl' expr:title='data:top.deleteCommentMsg'><data:text.delete/></a>
    </footer>
  </li>
</b:includable>
<b:includable id='custom-comments-comment-reply' var='reply'>
  <li class='comment reply' expr:id='data:reply.anchorName'>
    <b:class cond='data:reply.authorClass' name='is-author'/>
    <b:class cond='data:reply.isDeleted' name='is-deleted'/>
    <header class='comment-header'>
      <strong class='comment-author'>
        <b:if cond='data:reply.authorUrl'>
          <a expr:href='data:reply.authorUrl' rel='nofollow' target='_blank'><data:reply.author/></a>
        <b:else/>
          <data:reply.author/>
        </b:if> <data:commentPostedByMsg/>
      </strong>
      <a class='comment-url' expr:href='data:reply.url'><data:reply.timestamp/></a>
    </header>
    <figure class='comment-avatar'>
      <img alt='' expr:src='resizeImage(data:reply.authorAvatarSrc, 50)'/>
    </figure>
    <div class='comment-body'>
      <data:reply.body/>
    </div>
    <footer class='comment-footer'>
      <a class='a-delete' expr:href='data:reply.deleteUrl' expr:title='data:top.deleteCommentMsg'><data:text.delete/></a>
    </footer>
  </li>
</b:includable>
<b:includable id='custom-comments-form' var='post'>
  <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='a-undo' href='javascript:replyTo(0);'><data:text.undo/></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 ? document.getElementById('c' + id) : document.getElementById('custom-comments'),
          part = originalSource;
      frame.style.height = "50px";
      frame.style.visibility = "hidden";
      frame.src = id ? 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:includable>
<b:includable id='custom-comments-pager' var='post'>
  <b:if cond='data:post.commentPagingRequired'>
    <nav class='custom-comments-pager'>
      <a expr:class='data:post.oldLinkClass' expr:href='data:post.olderLinkUrl'><data:post.olderLinkText/></a>&#160;
      <a expr:class='data:post.oldLinkClass' expr:href='data:post.oldestLinkUrl'><data:post.oldestLinkText/></a>&#160;
      <data:post.commentRangeText/>&#160;
      <a expr:class='data:post.newLinkClass' expr:href='data:post.newestLinkUrl'><data:post.newestLinkText/></a>&#160;
      <a expr:class='data:post.newLinkClass' expr:href='data:post.newerLinkUrl'><data:post.newerLinkText/></a>
    </nav>
  </b:if>
</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. Fitur penanda komentar administrator juga ada. Untuk mengaktifkannya, Anda bisa menggunakan selektor-selektor CSS yang tercantum di atas, kemudian awali dengan kelas .is-author 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:

.comment.is-author {
  border: 5px solid #900;
  background-color: #ff0;
}
.comment.is-author > .comment-body {
  font-size: 200%;
}

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='reply'>
  <b:if cond='data:reply.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.

Labels: ,

Tuesday, December 11, 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:

Lihat Demo Unduh Plugin Unduh Plugin (Minified) Unduh CSS Unduh CSS (Minified)

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 href="css/jquery.select.min.css" rel="stylesheet">
<script src="js/jquery.min.js"></script>
<script src="js/jquery.select.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
Opsi Keterangan
selectboxClass Nama kelas pembungkus luar
buttonClass Nama kelas tombol pemicu drop down menu (penayang nilai opsi terseleksi)
selectedClass Nama kelas opsi terseleksi (elemen <option> dengan atribut selected="true")
disabledClass Nama kelas opsi mati (elemen <option> dengan atribut disabled="true")
focusedClass Nama 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.

Labels: , ,

Tuesday, September 18, 2012

Apa Itu Sticky Footer?

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

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

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

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

Lihat Demo

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

Lihat Demo

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

Masih Belum Yakin dengan Istilah Sticky Footer?

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

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

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

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

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

Lihat Demo


CSS & HTML Sticky Footer

HTML

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

CSS

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

* {margin:0;padding:0;} 

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

html, body {
  height:100%;
}

#wrap {
  min-height:100%;
}

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

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

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

Tambahan Untuk Internet Explorer

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

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

Labels: , , ,

Membangun Aplikasi Quick Search dengan JSON Blogger

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

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

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

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

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

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

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

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

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

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

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

Lihat Demo Unduh JavaScript


Integrasi Widget ke Blogger

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Klik Simpan Widget.

Konfigurasi Widget

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

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

CSS untuk Tema Minimalis (Layout Dasar)

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

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

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

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

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

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

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

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

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

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

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

Labels: , , , ,

Sunday, September 16, 2012

Menampilkan Semua Daftar Label Posting dengan JSON Blogger

Menampilkan Semua Daftar Label Posting dengan JSON Blogger
Konten Feed Blogger

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

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

Lihat Demo

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

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

Lihat Demo

Labels: , , , ,

Tuesday, September 11, 2012

Menandai Komentar Admin pada Thread Komentar Blogger

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

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

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

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

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

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

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

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

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

Klik Simpan Template. Kode CSS bisa dimodifikasi sesuka hati.

Lihat Demo

Labels: , ,