Showing posts with label Posting. Show all posts
Showing posts with label Posting. Show all posts

Membuat Posting Layar Penuh

Mode layar penuh.
Mode layar penuh.

Saya membuat sebuah aplikasi/widget kecil untuk membuat posting di blog menjadi memiliki alternatif tampilan “layar penuh”. Tidak benar-benar layar penuh sebenarnya, karena widget ini hanya bekerja dengan cara menyisipkan tabir baru berisi duplikat judul dan konten posting. Kalau Anda ingin membuat fitur full screen sungguhan yang bisa memenuhi seluruh layar, Anda bisa mempelajari API JavaScript ini ⇒ MDN - Using Full Screen Mode

Untuk memasang widget ini, masuklah ke halaman editor HTML Templat, lalu letakkan kode ini di atas </body>:

<b:if cond='data:blog.pageType == &quot;item&quot;'>
<script src='http://dte-project.googlecode.com/svn/trunk/full-screen.min.js'/>
<script>
//<![CDATA[
postFullScreen({
titleSource: document.querySelector('.post-title'),
contentSource: document.querySelector('.post-body'),
background: "#fff",
color: "inherit",
fontSize: "120%",
padding: 50,
maxWidth: 750,
openText: "Full Screen Mode",
closeText: "Exit full screen mode",
appendButtonTo: null,
beforeInit: null,
afterInit: null
});
//]]>
</script>
</b:if>

Atau Saya sarankan lebih baik letakkan kode di atas sedekat mungkin dengan posting. Lebih tepatnya di bagian paling bawah dari posting:

<b:section class='main' id='main' showaddelement='no'>
<b:widget id='Blog1' locked='true' title='Posting Blog' type='Blog'> … </b:section>
</b:section>
<!-- Letakkan di sini -->

Klik Simpan Templat.

Konfigurasi

OpsiKeterangan
titleSourceSelektor elemen HTML dimana di dalamnya berisi teks judul. Di atas Saya menggunakan selektor document.querySelector('.post-title') untuk memperoleh teks judul dari dalam elemen <h3 class='post-title'></h3>. Sebagai alternatif, Anda bisa mencoba untuk menggunakan selektor document.title untuk memperoleh judul dari address bar.
contentSourceSelektor elemen HTML dimana di dalamnya terdapat konten artikel/posting. Pengaturannya sama persis dengan opsi titleSource.
backgroundDigunakan untuk menentukan warna latar tabir layar penuh.
colorDigunakan untuk menentukan warna teks mode layar penuh. inherit artinya warna menyesuaikan dengan warna teks posting.
fontSizeDigunakan untuk menentukan besar teks di artikel layar penuh.
paddingDigunakan untuk menentukan padding tabir layar penuh.
maxWidthDigunakan untuk menentukan lebar maksimal area artikel layar penuh.
openTextDigunakan untuk menentukan teks tombol pemicu layar penuh.
closeTextDigunakan untuk menentukan teks tombol penutup tampilan layar penuh.
createButtonDigunakan untuk membuat tombol kustom. Lihat penjelasan di bawah.
appendButtonToNilai berupa selektor elemen HTML. Jika nilainya null, tombol akan secara otomatis disisipkan di bawah posting. Jika nilainya false, tombol tidak akan disisipkan secara otomatis (bermanfaat jika Anda ingin membuat tombol pemicu tersendiri secara terpisah).
beforeInitLihat penjelasan di bawah.
afterInitLihat penjelasan di bawah.

Penjelasan Ekstra

createButton

Opsi ini digunakan sebagai alternatif jika Anda tidak suka dengan tampilan tombol pemicu layar penuh secara normal. Anda bisa memanfaatkan opsi ini untuk menentukan/membuat elemen tombol kustom. Sebagai contoh di sini Saya menggunakan elemen tautan sebagai tombol:

var buttonMarkup = document.createElement('a');
buttonMarkup.className = "custom-button";
buttonMarkup.style.display = "block";
buttonMarkup.style.marginTop = "20px";

postFullScreen({
openText: "Layar Penuh!",
createButton: buttonMarkup
});

/*

akan menghasilkan ini:

<a class="custom-button" style="display:block;margin-top:20px;">Layar Penuh!</a>

*/

Atau Anda juga bisa menentukan nilainya sebagai objek yang sudah ada. Sebagai contoh Anda membuat tombol pemicu secara manual di tempat tertentu, misalnya di sidebar:

<aside>
...
<button id="full-screen-button">Layar Penuh</button>
...
...
</aside>

Kemudian Anda bisa melakukan ini untuk membuat tombol tersebut menjadi aktif:

postFullScreen({
createButton: document.getElementById('full-screen-button'),
appendButtonTo: false
});

Jangan lupa untuk mengatur opsi appendButtonTo menjadi false karena jika tidak tombol tersebut mungkin akan berpindah tempat. Secara umum akan berpindah ke bagian akhir posting:

appendButtonTo

Opsi ini digunakan untuk menentukan ke mana tombol pemicu tampilan layar penuh akan disisipkan. Berikut ini adalah sebuah contoh jika Anda ingin menyisipkan tombol pemicu layar penuh di dalam elemen #button-container:

<div id="button-container"></div>
postFullScreen({
...
appendButtonTo: document.getElementById('button-container')
});

beforeInit dan afterInit

Ini adalah opsi untuk membuat fungsi bebas yang akan tereksekusi sebelum (untuk beforeInit) dan sesudah (untuk afterInit) markup tabir tersisip ke blog. Yang paling berguna adalah beforeInit. Fungsi ini bisa Anda gunakan untuk memastikan bahwa manipulasi konten posting yang dilakukan oleh JavaScript telah dilakukan sebelum widget ini tereksekusi. Misalnya mengenai Syntax Highlighter atau JavaScript emotikon. Jika Syntax Highlighter atau JavaScript emotikon tidak diaktifkan sebelum widget ini aktif, maka kemungkinannya posting-posting kode yang berada di dalam artikel layar penuh tidak akan berwarna, dan emotikon-emotikon di dalam artikel tidak akan berubah menjadi gambar:

postFullScreen({
beforeInit: function() {
repText('post-12345');
hljs.initHighlighting();
},
afterInit: function() {
alert('OK!');
}
});

Pengguna JQuery

Jangan lupa untuk menambahkan indeks [0] setelah selektor jika Anda menggunakan API selektor elemen JQuery:

postFullScreen({
titleSource: $('.post-title')[0],
contentSource: $('.post-body')[0]
});

Memposisikan Judul dan Ringkasan Posting di Samping Thumbnail atau Thumbnail di atas Judul dan Ringkasan Posting

Beberapa orang bertanya mengenai bagaimana caranya memposisikan judul dan ringkasan posting di samping thumbnail, atau mengenai bagaimana cara memposisikan thumbnail di atas judul dan ringkasan posting (biasanya untuk membuat templat List & Masonry Grid). Di sini Saya mencoba untuk membuat kode XML posting khusus yang Saya buat sefleksibel mungkin untuk keperluan modifikasi di masa datang. Kode ini sudah mencakup modifikasi ringkasan posting, sehingga jika Anda sudah mengimplementasikan modifikasi ini, maka Anda tidak perlu lagi repot-repot untuk mengimplementasikan tutorial pembuatan posting auto read-more.

Namun sebelum melakukan modifikasi ini, perlu dipertimbangkan bahwa nanti Anda akan mengubah struktur posting secara keseluruhan, sehingga beberapa kustomisasi lama Anda seperti penambahan widget artikel terkait, widget berbagi dan semuanya akan menghilang. Disarankan untuk menyimpan salinan templat Anda terlebih dahulu sebelum melakukan modifikasi ini.

Kode XML

Langkah pertama adalah mengedit XML templat. Kode XML ini cukup diterapkan sekali saja. Mengenai pengaturan posisi setiap elemen bisa kita lakukan dengan CSS yang sudah Saya tuliskan di bawah:

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

<article expr:class='&quot;_post _post-&quot; + data:blog.pageType' expr:id='&quot;post-&quot; + data:post.id'>

<b:if cond='data:blog.pageType != &quot;item&quot;'>
<b:if cond='data:blog.pageType != &quot;static_page&quot;'>
<div class='_post-part _post-thumbnail-area'>
<b:if cond='data:post.thumbnailUrl'>
<img class='_post-thumbnail' expr:alt='data:post.title' expr:src='data:post.thumbnailUrl' height='72' width='72'/>
</b:if>
</div> <!-- ._post-thumbnail-area -->
</b:if>
</b:if>

<div class='_post-part _post-body-area'>

<h3 class='_post-title'>
<b:if cond='data:post.title'>
<b:if cond='data:post.link'>
<a expr:href='data:post.link'><data:post.title/></a>
<b:else/>
<b:if cond='data:post.url'>
<b:if cond='data:blog.url != data:post.url'>
<a expr:href='data:post.url'><data:post.title/></a>
<b:else/>
<data:post.title/>
</b:if>
<b:else/>
<data:post.title/>
</b:if>
</b:if>
<b:else/>
[Untitled]
</b:if>
</h3> <!-- ._post-title -->

<div class='_post-body'>
<b:if cond='data:blog.pageType == &quot;item&quot;'>
<data:post.body/>
<b:else/>
<b:if cond='data:blog.pageType == &quot;static_page&quot;'>
<data:post.body/>
<b:else/>
<b:if cond='data:post.snippet'>
<data:post.snippet/>
<b:else/>
No content.
</b:if>
</b:if>
</b:if>
</div> <!-- ._post-body -->

<footer class='_post-footer'>
<div class='_post-footer-line _post-footer-line-1'>
<span class='_post-author vcard'>
<b:if cond='data:top.showAuthor'>
<data:top.authorLabel/> <span class='fn'>
<b:if cond='data:post.authorProfileUrl'>
<a class='g-profile' expr:href='data:post.authorProfileUrl' rel='author' title='Author Profile'><data:post.author/></a>
<b:else/>
<span class='g-profile'><data:post.author/></span>
</b:if>
</span>
</b:if>
</span> <span class='_post-timestamp'>
<b:if cond='data:top.showTimestamp'>
<data:top.timestampLabel/> <a class='_post-timestamp-link' expr:href='data:post.url' rel='bookmark' title='Permanent Link'><time class='_post-published published' expr:datetime='data:post.timestampISO8601'><data:post.timestamp/></time></a>
</b:if>
</span> <span class='_post-comment-link'>
<b:if cond='data:blog.pageType != &quot;item&quot;'>
<b:if cond='data:blog.pageType != &quot;static_page&quot;'>
<b:if cond='data:post.allowComments'>
<a expr:href='data:post.url + &quot;#comments&quot;'><data:post.commentLabelFull/></a>
</b:if>
</b:if>
</b:if>
</span>
</div> <!-- ._post-footer-line-1 -->
<div class='_post-footer-line _post-footer-line-2'>
<span class='_post-labels'>
<b:if cond='data:post.labels'>
<data:postLabelsLabel/> <b:loop values='data:post.labels' var='label'>
<a expr:href='data:label.url' rel='tag'><data:label.name/></a><b:if cond='data:label.isLast != &quot;true&quot;'>, </b:if>
</b:loop>
</b:if>
<!-- b:include data='post' name='postQuickEdit'/ -->
</span>
</div> <!-- ._post-footer-line-2 -->
</footer> <!-- ._post-footer -->

</div> <!-- ._post-body-area -->

</article> <!-- ._post -->

</b:includable>

Salin semua kode di atas untuk menggantikan kode yang tampak seperti ini di dalam templat:

<b:includable id='post' var='post'> ... </b:includable>

Langkah berikutnya adalah menambahkan CSS khusus. Pilih salah satu saja.

Tata Letak 1: Thumbnail di Sebelah Kiri Judul dan Ringkasan Posting

Post Thumbnail on the Left
Thumbnail di sebelah kiri judul dan ringkasan posting.

Salin kode CSS ini lalu letakkan di atas ]]></b:skin> atau </style>:

/*!
Thumbnail width: 200
Thumbnail height: 200
*/

._post {
background-color:white;
height:200px; /* Thumbnail height */
margin:0 0 10px;
overflow:hidden;
*zoom:1;
}

._post:after {
content:" ";
display:block;
clear:both;
}

._post-title {
font:normal bold 20px/1.2 Arial,Sans-Serif;
margin:0 0 10px;
padding:0;
}

._post-thumbnail-area {
width:200px; /* Thumbnail width */
height:200px; /* Thumbnail height */
background-color:#2D3957;
float:left;
overflow:hidden;
}

._post-thumbnail {
display:block;
width:100%;
height:100%;
max-width:none;
max-height:none;
min-width:0;
min-height:0;
margin:0;
padding:0;
border:none;
outline:none;
position:static;
}

._post-body-area {
padding:20px;
margin-left:200px; /* Thumbnail width */
font-size:11px;
}

._post-footer {
margin:10px 0 0;
padding:10px 0 0;
border-top:1px dotted #ddd;
font:normal bold 8px/1.5 Verdana,Tahoma,Arial,Sans-Serif;
text-transform:uppercase;
color:#999;
}

/* Item + Static Page */
._post-item,
._post-static_page {height:auto}

._post-item ._post-body-area,
._post-static_page ._post-body-area {
margin:0;
padding:20px;
font-size:13px;
}

._post-item ._post-title,
._post-static_page ._post-title {font-size:40px}

Tata Letak 2: Thumbnail di Sebelah Atas Judul dan Ringkasan Posting

Thumbnail Before Post Title and Summary
Thumbnail di sebelah atas judul dan ringkasan posting.

Salin kode CSS ini lalu letakkan di atas ]]></b:skin> atau </style>:

/*!
Thumbnail width: 300
Thumbnail height: 300
*/

._post {
background-color:white;
width:300px; /* Thumbnail width */
margin:0 10px 10px 0;
overflow:hidden;
*zoom:1;
/* float:left; */
}

._post:after {
content:" ";
display:block;
clear:both;
}

._post-title {
font:normal bold 16px/1.2 Arial,Sans-Serif;
margin:0 0 10px;
padding:0;
}

._post-thumbnail-area {
width:300px; /* Thumbnail width */
height:300px; /* Thumbnail height */
background-color:#2D3957;
overflow:hidden;
}

._post-thumbnail {
display:block;
width:100%;
height:100%;
max-width:none;
max-height:none;
min-width:0;
min-height:0;
margin:0;
padding:0;
border:none;
outline:none;
position:static;
}

._post-body-area {
padding:20px;
margin:10px 0 0;
font-size:11px;
}

._post-footer {
margin:10px 0 0;
padding:10px 0 0;
border-top:1px dotted #ddd;
font:normal bold 8px/1.5 Verdana,Tahoma,Arial,Sans-Serif;
text-transform:uppercase;
color:#999;
}

/* Item + Static Page */
._post-item,
._post-static_page {width:auto}

._post-item ._post-body-area,
._post-static_page ._post-body-area {
margin:0;
padding:20px;
font-size:13px;
}

._post-item ._post-title,
._post-static_page ._post-title {font-size:40px}

Sampai di sini sudah selesai. Kemudian, mungkin Anda ingin memperbaiki resolusi gambar yang saat ini masih berada pada resolusi s72-c, sehingga gambar masih terlihat buram. Anda bisa menggunakan JavaScript yang pernah Saya berikan sebelumnya.

Memperbaiki Resolusi Gambar

Salin kode ini:

<b:if cond='data:blog.pageType != &quot;static_page&quot;'>
<b:if cond='data:blog.pageType != &quot;item&quot;'>
<script>
//<![CDATA[
function resizeThumb(parentID, size) {
var parent = document.getElementById(parentID),
image = parent.getElementsByTagName('img');
for (var i = 0; i < image.length; i++) {
image[i].src = image[i].src.replace(/\/s72\-c/, "/s" + size + "-c");
image[i].width = size;
image[i].height = size;
}
} resizeThumb('Blog1', 200);
//]]>
</script>
</b:if>
</b:if>

Kemudian letakkan dengan posisi seperti ini terhadap widget Blog1:

<b:section class='main' id='main' showaddelement='no'>
<b:widget id='Blog1' locked='true' title='Posting Blog' type='Blog'/>
</b:section>
<b:if cond='data:blog.pageType != &quot;static_page&quot;'>
<b:if cond='data:blog.pageType != &quot;item&quot;'>
<script> ... </script>
</b:if>
</b:if>

Kode 200 adalah resolusi gambar baru yang ingin Anda terapkan. Ini tergantung dari ukuran standar masing-masing gambar posting di atas, yang sudah Saya sertakan dalam komentar CSS.

Simpan perubahan.


Struktur Posting yang Tercipta

Berikut ini adalah diagram markup HTML yang akan tercipta secara garis besar. Semoga bisa sedikit membantu untuk memberikan gambaran modifikasi lanjutan:

  • ._post
    • ._post-part._post-thumbnail-area
      • ._post-thumbnail
    • ._post-part._post-body-area
      • ._post-title
      • ._post-body
      • ._post-footer
        • ._post-footer-line._post-footer-line-1
          • ._post-author
          • ._post-timestamp
          • ._post-comment-link
        • ._post-footer-line._post-footer-line-2
          • ._post-labels
._post {}
._post-part {}
._post-thumbnail-area {}
._post-body-area {}
._post-title {}
._post-body {}
._post-footer {}
._post-footer-line {}
._post-footer-line-1 {}
._post-footer-line-2 {}
._post-author {}
._post-timestamp {}
._post-comment-link {}
._post-labels {}

Catatan Tambahan: Setelah ini lebih baik Anda hapus beberapa kode CSS yang memiliki selektor seperti ini. Markup posting sudah berubah secara total, sehingga CSS ini sudah tidak diperlukan lagi:

.post {}
.post-title {}
.post-body {}
.post-footer {}
.post-footer-line {}
.post-footer-line-1 {}
.post-footer-line-2 {}
.post-footer-line-3 {}
.post-header-line {}
.post-header-line-1 {}
.post-header-line-2 {}
.post-header-line-3 {}
.post-author {}
.post-timestamp {}
.post-comment-link {}
.post-labels {}

JQuery Find and Highlight Text

HTML, CSS & JQuery

<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="utf-8">
<title>JQuery Find and Highlight Text</title>
<style>
body {
background-color:white;
padding:40px 10px 10px;
font:normal normal 13px/1.4 Arial,Sans-Serif;
color:black;
}
.text-finder {
position:fixed;
top:0;
right:0;
left:0;
z-index:999;
background-color:white;
border-bottom:1px solid gray;
padding:5px 6px;
box-shadow:0 1px 2px rgba(0,0,0,.4);
}
.highlight {
background-color:yellow; /* highlight color */
font-weight:bold;
}
</style>
<script src="http://code.jquery.com/jquery-2.0.2.js"></script>
<script>
/*!
highlight v4
Highlights arbitrary terms.
<http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html>
MIT license.
Johann Burkard
<http://johannburkard.de>
<mailto:jb@eaio.com>
*/
(function($) {
$.fn.highlight = function(pat) {
function innerHighlight(node, pat) {
var skip = 0;
if (node.nodeType == 3) {
var pos = node.data.toUpperCase().indexOf(pat);
if (pos >= 0) {
var spannode = document.createElement('span');
spannode.className = 'highlight';
var middlebit = node.splitText(pos);
var endbit = middlebit.splitText(pat.length);
var middleclone = middlebit.cloneNode(true);
spannode.appendChild(middleclone);
middlebit.parentNode.replaceChild(spannode, middlebit);
skip = 1;
}
} else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
for (var i = 0; i < node.childNodes.length; ++i) {
i += innerHighlight(node.childNodes[i], pat);
}
}
return skip;
}
return this.length && pat && pat.length ? this.each(function() {
innerHighlight(this, pat.toUpperCase());
}) : this;
};
$.fn.removeHighlight = function() {
return this.find("span.highlight").each(function() {
this.parentNode.firstChild.nodeName;
with (this.parentNode) {
replaceChild(this.firstChild, this);
normalize();
}
}).end();
};
})(jQuery);

// Text finder form function
(function($) {
$(document).ready(function() {
var $finder = $('#text-finder'),
$field = $finder.children().first(),
$clear = $field.next(),
$area = $(document.body),
$viewport = $('html, body');
$field.on("keyup", function() {
$area.removeHighlight().highlight(this.value); // Highlight text inside `$area` on keyup
$viewport.scrollTop($area.find('span.highlight').first().offset().top - 50); // Jump the viewport to the first highlighted term
});
$clear.on("click", function() {
$area.removeHighlight(); // Remove all highlight inside `$area`
$field.val('').trigger("focus"); // Clear the search field
$viewport.scrollTop(0); // Jump the viewport to the top
return false;
});
});
})(jQuery);
</script>
</head>
<body>

<form id="text-finder" class="text-finder" action="javascript:;">
<input type="text" placeholder="Find...">
<input type="reset" value="&times;">
</form>

Content goes here...

</body>
</html>

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:

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

<div class='post-footer'>

Tabel Pengaturan

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

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

Menerapkan Fungsi callBack Widget

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

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

Contoh 1: Membuat Efek Transisi Hover pada Tooltip

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

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

Hapus efek :focus dan :hover pada CSS:

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

Contoh 2: Membuat Efek Sliding pada Tabir Judul

Set tampilan widget menjadi artikel terkait dengan tabir tooltip:

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

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

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

Contoh 3: Membuat Efek News Ticker

Set tampilan widget menjadi artikel terkait tipe thumbnail dan summary:

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

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

Catatan: Saat menerapkan beberapa fungsi di atas, mungkin template 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.

Performa Widget Random Post

Saya harus mengatakan bahwa 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 — 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 kita bisa memuat posting 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:

Showing log message to indicate random number for feed start index purpose.
Angka acak yang Saya tandai akan kita manfaatkan untuk memanggil indeks feed secara acak.

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 atau orderby=popular untuk menciptakan widget posting populer. Tapi kasus ini masih dalam tahap “seandainya”.

Membuat Navigasi Halaman AJAX pada Blogger

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

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

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

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

Menerapkan AJAX pada Navigasi Halaman

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

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

Klik Simpan Template.

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

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

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

Infinite Scroll (?)

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

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

(function($) {

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

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

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

})(jQuery);

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

Widget Blogger untuk Menampilkan Daftar Posting Terbaru dalam Label-Label yang Spesifik

Screenshot of multiple recent post widget for Blogger.

Judulnya sangat panjang karena Saya sendiri tidak tahu harus memberi nama apa kepada widget ini. Pada intinya widget ini adalah widget recent post biasa, namun memiliki kemampuan untuk menggandakan diri agar bisa menampilkan daftar posting terbaru lebih dari satu buah berdasarkan label yang spesifik:

Pada awalnya Saya membuat widget ini agar bisa menampilkan posting-posting terbaru dari blog tunggal saja, namun mengingat ada juga beberapa blog yang suka menampilkan daftar posting dari blog lain, jadi sekarang widget ini tidak hanya berfungsi untuk menampilkan daftar posting dari satu feed blog, melainkan juga bisa menampilkan daftar posting dari feed blog Blogger yang lain.

Pemasangan Widget

Masuk ke halaman Tata Letak kemudian tambahkan sebuah widget HTML/JavaScript. Salin kode ini dan letakkan di dalam formulirnya:

<link rel="stylesheet" type="text/css" scoped="scoped" href="http://blogger-json-experiment.googlecode.com/svn/resources/multi-feed/multi-feed.min.css"/>
<style type="text/css" scoped="scoped">
/* Custom CSS */
.list-entries {
margin:5px;
width:270px; /* Lebar widget */
float:left;
font-size:11px;
}
</style>

<div id="feed-list-container"></div>
<div style="clear:both;"></div>

<script type="text/javascript">
var multiFeed = {
feedsUri: [
{
name: "Judul Widget 1",
url: "http://nama_blog-1.blogspot.com",
tag: "JQuery"
},
{
name: "Judul Widget 2",
url: "http://nama_blog-2.blogspot.com",
tag: "CSS"
},
{
name: "Judul Widget 1",
url: "http://nama_blog-3.blogspot.com",
tag: "Widget"
}
],
numPost: 4,
showThumbnail: true,
showSummary: true,
summaryLength: 80,
titleLength: "auto",
thumbSize: 72,
containerId: "feed-list-container",
readMore: {
text: "Selengkapnya",
endParam: "?max-results=20"
}
};
</script>
<script type="text/javascript" src="http://blogger-json-experiment.googlecode.com/svn/resources/multi-feed/multi-feed.min.js"></script>

Konfigurasi

OpsiKeterangan
feedsUriBerupa array objek dimana di dalamnya terdapat beberapa data berupa name, url dan tag: name digunakan untuk menentukan judul widget, url digunakan untuk menentukan URL feed, tag digunakan untuk menentukan tag/label posting yang ingin ditampilkan.
numPostDigunakan untuk menentukan jumlah posting yang ingin ditampilkan
showThumbnailGanti nilainya menjadi false untuk menyembunyikan gambar posting
showSummaryGanti nilainya menjadi false untuk menyembunyikan ringkasan posting
summaryLengthDigunakan untuk menentukan jumlah karakter ringkasan posting
titleLengthDigunakan untuk memotong karakter judul posting yang terlalu panjang. Ganti nilainya menjadi angka untuk memotong karakter sebanyak angka tersebut, atau set sebagai "auto" untuk membiarkan judul posting sebagai apa adanya
thumbSizeDigunakan untuk menentukan ukuran thumbnail posting
containerIdDigunakan untuk menentukan ID kontainer yang akan digunakan untuk memuat widget
readMoreTerdiri dari text dan endParam. text digunakan untuk menentukan label tautan “Baca Selengkapnya” yang terletak di bawah masing-masing widget dan endParam digunakan untuk menentukan parameter akhir tautan tersebut (abaikan jika tidak perlu).

Opsi feedsUri merupakan array objek dimana setiap objek akan mewakili masing-masing widget:

// Tiga objek = tiga widget
feedsUri: [{}, {}, {}]

Setiap objek berisi beberapa data yang digunakan untuk menentukan judul widget, sumber URL dan tag/kategori posting spesifik:

feedsUri: [
{
name: "Judul Widget 1",
url: "http://nama_blog-1.blogspot.com",
tag: "Blogger"
},
{
name: "Judul Widget 2",
url: "http://nama_blog-2.blogspot.com",
tag: "WordPress"
},
{
name: "Judul Widget 3",
url: "http://nama_blog-3.blogspot.com",
tag: "SEO"
}
]

Setelah semua konfigurasi sudah diatur dengan benar, klik Simpan Widget. Modifikasi tampilan bisa dilakukan di dalam tag <style> yang Saya tambahkan pada widget di atas.

Kode Sumber

  1. multi-feed.css
  2. multi-feed.min.css
  3. multi-feed.js
  4. multi-feed.min.js

Print/Mencetak Sebagian Halaman Saja dengan JavaScript

Gambar untuk dialog pencetakan pada Google Chrome
Mencetak sebagian halaman dengan JavaScript

Berbeda dengan dasar window.print() yang akan mencetak keseluruhan halaman, fungsi ini akan mencetak halaman pada bagian-bagian tertentu saja. Cara kerjanya adalah fungsi ini akan mencetak duplikat konten area di dalam iframe pencetakan.

Dua buah elemen, yaitu <textarea> dan <iframe> dibuat untuk keperluan ini. Area teks digunakan untuk menyimpan kode CSS pencetakan, sedangkan iframe digunakan untuk menampung salinan bagian halaman yang ingin dicetak. Saat salinan bagian halaman tersebut sudah masuk ke dalam iframe yang kita sembunyikan wujudnya, hal yang perlu kita lakukan selanjutnya adalah mencetak konten iframe tersebut, bukan halaman yang sedang aktif:

<textarea id="printing-css" style="display:none;">.no-print{display:none}</textarea>
<iframe id="printing-frame" name="print_frame" src="about:blank" style="display:none;"></iframe>
<script type="text/javascript">
//<![CDATA[
function printDiv(elementId) {
var a = document.getElementById('printing-css').value;
var b = document.getElementById(elementId).innerHTML;
window.frames["print_frame"].document.title = document.title;
window.frames["print_frame"].document.body.innerHTML = '<style>' + a + '</style>' + b;
window.frames["print_frame"].window.focus();
window.frames["print_frame"].window.print();
}
//]]>
</script>

Aktivasi bisa dilakukan dengan cara memicu fungsi printDiv(elementId) pada tautan atau tombol, dimana elementId adalah ID dari area khusus yang ingin dicetak:

<a class="no-print" href="javascript:printDiv('area-1');">Print</a>

...

<div id="area-1">Teks ini akan tercetak di kertas...</div>
<div id="area-2">Tapi tidak untuk teks ini.</div>

Kode CSS pencetakan yang digunakan Saya sarankan adalah kode CSS yang pernah Saya tuliskan di sini, untuk memastikan agar tampilan halaman yang dicetak tertata dengan rapi. Atau kosongkan saja textarea tersebut dan biarkan User Agent Stylesheet pada masing-masing peramban menangani tampilan elemen yang ada.

Alternatif lain, Anda juga bisa menggunakan CSS eksternal jika Anda merasa bahwa textarea tanpa makna di atas hanya akan mengganggu kebersihan kode sumber web Anda:

<iframe id="printing-frame" name="print_frame" src="about:blank" style="display:none;"></iframe>
<script type="text/javascript">
//<![CDATA[
function printDiv(elementId) {
var a = "/path/to/printing-css.css";
var b = document.getElementById(elementId).innerHTML;
window.frames["print_frame"].document.title = document.title;
window.frames["print_frame"].document.body.innerHTML = '<link rel="stylesheet" type="text/css" href="' + a + '">' + b;
window.frames["print_frame"].window.focus();
window.frames["print_frame"].window.print();
}
//]]>
</script>

Hasilnya akan terlihat jelas pada peramban Google Chrome yang notabene memiliki komunikasi pencetakan halaman yang berbeda dengan peramban lainnya.

Generator HTML Peta Gambar Palsu

Image Map

Alat ini digunakan untuk membuat image map palsu menggunakan elemen HTML. Beberapa orang lebih memilih menggunakan yang palsu karena lebih fleksibel. Pada intinya alat ini digunakan untuk mempermudah di dalam merancang ukuran dan posisi lokasi pada tiap bagian di dalam gambar. Mengenai elemen apa yang akan Anda gunakan dan bagaimana Anda memodifikasi tampilannya, itu terserah Anda:

Bagi para pembaca yang belum mengerti apa itu image map, kalian bisa memulai mempelajarinya di sini. Dan berikut ini adalah contoh gambar yang dihasilkan dari alat yang Saya buat di atas. Coba letakkan pointer mouse Anda di atas wajah-wajah atau badan tokoh kartun di bawah ini untuk mengetahui nama mereka:

Madagascar Animation Characters

Cara Menggunakan

Ambillah sebuah foto atau gambar dimana di dalamnya terdapat beberapa bagian yang memerlukan detail khusus. Misalnya foto keluarga atau peta negara, lalu unggah foto atau gambar tersebut pada blog Anda. Ambil URL gambarnya, kemudian letakkan di dalam input URL yang tersedia. Setelah itu klik tombol Create. Klik tombol Add Location untuk menambahkan lokasi/koordinat baru pada gambar. Geser dan ubah ukurannya sesuai keinginan. Kode HTML akan tampil di bagian area teks sebelah kanan.

DL, DT, DD dalam Layout Tabel

Definition List/Description List

Sebagai catatan, perpanjangan dl sebagai definition list pada HTML4 telah diganti menjadi description list pada HTML5 — HTML5 Doctor - The DL Element

HTML

<dl class="member-details">

<dt>Nama:</dt>
<dd>Lulu Tralala</dd>

<dt>Usia:</dt>
<dd>17</dd>

<dt>Jenis Kelamin:</dt>
<dd>Wanita</dd>

<dt>Lahir:</dt>
<dd>14 April 1992</dd>

<dt>Alamat:</dt>
<dd><em>Belum dilengkapi</em></dd>

<dt>Keterangan:</dt>
<dd>Lorem ipsum dolor sit amet...</dd>

</dl>

CSS

.member-details {
margin:0 0 1.7em 0;
padding:0 0;
overflow:hidden;
}

.member-details dt,
.member-details dd {
margin:0 0 2px 136px;
padding:5px 7px;
background-color:#eee;
}

.member-details dt {
background-color:#BC4106;
float:left;
font-weight:bold;
width:120px;
clear:left;
margin-left:0;
}

Demo

JavaScript Seleksi Teks Otomatis

Auto Selection Text with JavaScript

Membuat fitur seleksi teks otomatis pada elemen-elemen formulir seperti <textarea> atau <input> memang mudah, tetapi membuat fitur seleksi otomatis pada elemen-elemen non formulir seperti <div> dan <pre> membutuhkan sedikit langkah tambahan. Berikut ini adalah fungsinya:

function autoSelect(elem) {
var selection, range;
if (window.getSelection) {
selection = window.getSelection();
range = document.createRange();
range.selectNodeContents(elem);
selection.removeAllRanges();
selection.addRange(range);
} else if (document.selection) { // IE
selection = document.selection.createRange().text;
range = document.body.createTextRange();
range.moveToElementText(elem);
range.select();
}
}

Posting ini juga sekaligus akan Saya jadikan sebagai dokumentasi tambahan untuk memperbaharui posting Saya yang lama mengenai cara membuat fitur seleksi teks otomatis pada tag <pre> di sini. Sejak rilis JQuery 1.9, sepertinya jQuery.browser sudah ditiadakan, jadi posting tersebut sudah tidak berlaku lagi.

Potongan kode di atas lebih baik, dan bisa diaktifkan oleh pengguna mentah maupun pengguna JavaScript Library seperti .

Contoh Penggunaan

Parameter elem akan kita gunakan sebagai referensi menuju elemen yang ingin kita seleksi. Misalnya, kita ingin menyeleksi semua teks di dalam elemen yang memiliki ID foo:

autoSelect(document.getElementById('foo'));

Kode di atas merupakan contoh penerapan JavaScript mentah. Untuk menerapkannya pada JQuery, kita cukup mengganti pola selektornya saja:

autoSelect($('#foo')[0]);

Contoh Lain: Membuat Fitur Seleksi Otomatis pada Tag PRE

Versi JavaScript Mentah

var pre = document.getElementsByTagName('pre');
for (var i = 0, len = pre.length; i < len; i++) {
pre[i].onclick = function() {
autoSelect(this);
};
}

Versi JQuery

$('pre').on("click", function() {
autoSelect(this);
});

Mengubah List/Daftar Menjadi Diagram Pohon

HTML

<ul class="tree">
<li>List item 1</li>
<li>List item 2
<ul>
<li>List item 2.1</li>
<li>List item 2.2</li>
<li>List item 2.3</li>
...
...
</ul>
</li>
<li>List item 3</li>
<li>List item 4</li>
<li>List item 5</li>
...
...
</ul>

CSS

ul.tree,
ul.tree ul {
list-style:none;
margin:0;
padding:0;
}

ul.tree ul {
margin-left:10px;
background:transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAKAQMAAABPHKYJAAAAA1BMVEWIiIhYZW6zAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1ggGExMZBky19AAAAAtJREFUCNdjYMAEAAAUAAHlhrBKAAAAAElFTkSuQmCC') repeat-y 0 100%;
}

ul.tree li {
margin:0;
padding:0 12px;
font-size:14px;
line-height:20px;
color:#369;
font-weight:bold;
}

ul.tree ul li {
background:transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAUAQMAAACK1e4oAAAABlBMVEUAAwCIiIgd2JB2AAAAAXRSTlMAQObYZgAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YIBhQIJYVaFGwAAAARSURBVAjXY2hgQIf/GTDFGgDSkwqATqpCHAAAAABJRU5ErkJggg==') no-repeat 0 0;
}

ul.tree ul li.last,
ul.tree ul li:last-child {
background:white url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAUAQMAAACK1e4oAAAABlBMVEUAAwCIiIgd2JB2AAAAAXRSTlMAQObYZgAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YIBhQIIhs+gc8AAAAQSURBVAjXY2hgQIf/GbAAAKCTBYBUjWvCAAAAAElFTkSuQmCC') no-repeat 0 100%;
}

Demo

Murni CSS/Tanpa Gambar

Berikut ini adalah versi CSS yang Saya buat berdasarkan contoh di atas. Tanpa gambar, hanya menggunakan pseudo element:

CSS

ul.tree,
ul.tree ul {
list-style:none;
margin:0;
padding:0;
}

ul.tree ul {
margin-left:10px; /* indentation */
position:relative;
}

ul.tree ul:before {
content:"";
display:block;
width:0;
position:absolute;
top:0;
bottom:0;
left:0;
border-left:1px solid;
}

ul.tree li {
margin:0;
padding:0 12px; /* indentation + 2 */
font-size:14px;
line-height:20px; /* default list item `line-height` */
color:#369;
font-weight:bold;
position:relative;
}

ul.tree ul li:before {
content:"";
display:block;
width:10px; /* same with indentation */
height:0;
border-top:1px solid;
position:absolute;
top:10px;
left:0;
}

ul.tree ul li:last-child:before {
background:white; /* same with body background */
height:auto;
top:10px; /* (line-height/2) */
bottom:0;
}

Demo

Modifikasi Tampilan dan Teks pada Status Message

Custom Status Message for Blogger
Contoh tampilan ‘status message’ yang sudah dimodifikasi.

Status Message adalah sebuah pesan yang akan muncul di atas posting ketika kita sedang berada di halaman hasil pencarian atau halaman label. Memodifikasi tampilannya mungkin mudah, yaitu dengan cara menimpa CSS bawaan Blogger dengan kode CSS baru yang mengandung pengaturan tampilan yang berbeda seperti ini:

.status-msg-wrap {
font-size:110%;
width:90%;
margin:10px auto;
position:relative;
}

.status-msg-border {
border:1px solid #000;
filter:alpha(opacity=40);
-moz-opacity:.4;
opacity:.4;
width:100%;
position:relative;
}

.status-msg-bg {
background-color:#ccc;
opacity:.8;
filter:alpha(opacity=30);
-moz-opacity:.8;
width:100%;
position:relative;
z-index:1;
}

.status-msg-body {
text-align:center;
padding:.3em 0;
width:100%;
position:absolute;
z-index:4;
}

.status-msg-hidden {
visibility:hidden;
padding:.3em 0;
}

.status-msg-wrap a {
padding-left:.4em;
text-decoration:underline;
}

Tapi bagaimana jika kita ingin memodifikasi tulisan di dalamnya?

Untuk melakukan itu, kita mau tidak mau harus menghapus elemen tersebut dan menggantinya dengan markup yang baru seperti ini:

<!-- b:include data='top' name='status-message'/ -->
<b:if cond='data:blog.searchQuery'>
<b:if cond='data:numPosts != 0'>
<p class='custom-status-message'>Menampilkan semua entri dengan kata kunci <strong>&amp;#8220;<data:blog.searchQuery/>&amp;#8221;</strong></p>
<b:else/>
<p class='custom-status-message-error'>Pencarian entri dengan kata kunci <strong>&amp;#8220;<data:blog.searchQuery/>&amp;#8221;</strong> tidak ditemukan.</p>
</b:if>
</b:if>
<b:if cond='data:blog.searchLabel'>
<p class='custom-status-message'>Menampilkan semua entri dengan kategori <strong>&amp;#8220;<data:blog.searchLabel/>&amp;#8221;</strong></p>
</b:if>

Salin kode di atas, kemudian gunakan untuk menggantikan kode yang tampak seperti ini di dalam template (biasanya ada dua):

<b:include data='top' name='status-message'/>

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

.custom-status-message,
.custom-status-message-error {
font:normal normal 13px Segoe,"Segoe UI",Calibri,"Helvatica Neue",Arial,Sans-Serif;
color:white;
text-shadow:0 -1px 0 rgba(0,0,0,.4);
padding:7px 14px;
margin:5px 5px 1.7em;
background-color:#5A6777;
background-image:-webkit-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.1));
background-image:-moz-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.1));
background-image:-ms-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.1));
background-image:-o-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.1));
background-image:linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.1));
border:2px solid #404B55;
border-bottom-color:#212729;
border-top-color:#8E97A2;
-webkit-border-radius:5px;
-moz-border-radius:5px;
border-radius:5px;
-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);
}

.custom-status-message-error {
background-color:#600;
border-color:#700 #500 #300;
}

.custom-status-message strong {color:#AADD99}
.custom-status-message-error strong {color:#ff0}

Menciptakan Tampilan yang Berbeda Hanya Pada Posting Pertama

Ini adalah contoh tampilan pembangun deret posting yang masih normal (loop posting):

<!-- posts -->
<div class='blog-posts hfeed'>
<b:include data='top' name='status-message'/>
<data:defaultAdStart/>
<b:loop values='data:posts' var='post'>
<b:if cond='data:post.isDateStart'>
<b:if cond='data:post.isFirstPost == &quot;false&quot;'>
&lt;/div&gt;&lt;/div&gt;
</b:if>
</b:if>
<b:if cond='data:post.isDateStart'>
&lt;div class=&quot;date-outer&quot;&gt;
</b:if>
<b:if cond='data:post.dateHeader'>
<h2 class='date-header'><span><data:post.dateHeader/></span></h2>
</b:if>
<b:if cond='data:post.isDateStart'>
&lt;div class=&quot;date-posts&quot;&gt;
</b:if>
<div class='post-outer'>
<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>
</div>
<b:if cond='data:post.includeAd'>
<b:if cond='data:post.isFirstPost'>
<data:defaultAdEnd/>
<b:else/>
<data:adEnd/>
</b:if>
<div class='inline-ad'>
<data:adCode/>
</div>
<data:adStart/>
</b:if>
</b:loop>
<b:if cond='data:numPosts != 0'>
&lt;/div&gt;&lt;/div&gt;
</b:if>
<data:adEnd/>
</div>

Dan ini adalah loop posting yang sudah dimodifikasi:

<!-- posts -->
<div class='blog-posts hfeed'>
<b:include data='top' name='status-message'/>
<data:defaultAdStart/>
<b:loop values='data:posts' var='post'>
<b:if cond='data:post.isDateStart'>
<b:if cond='data:post.isFirstPost == &quot;false&quot;'>
&lt;/div&gt;&lt;/div&gt;
</b:if>
</b:if>
<b:if cond='data:post.isDateStart'>
&lt;div class=&quot;date-outer&quot;&gt;
</b:if>
<b:if cond='data:post.dateHeader'>
<h2 class='date-header'><span><data:post.dateHeader/></span></h2>
</b:if>
<b:if cond='data:post.isDateStart'>
&lt;div class=&quot;date-posts&quot;&gt;
</b:if>
<div class='post-outer'>

<b:if cond='data:post.isFirstPost'>
<div class='first-post'><b:include data='post' name='post'/></div>
<b:else/>
<b:include data='post' name='post'/>
</b:if>


<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>
</div>
<b:if cond='data:post.includeAd'>
<b:if cond='data:post.isFirstPost'>
<data:defaultAdEnd/>
<b:else/>
<data:adEnd/>
</b:if>
<div class='inline-ad'>
<data:adCode/>
</div>
<data:adStart/>
</b:if>
</b:loop>
<b:if cond='data:numPosts != 0'>
&lt;/div&gt;&lt;/div&gt;
</b:if>
<data:adEnd/>
</div>

Kode di atas akan secara otomatis meliputi posting pertama dengan elemen <div class='first-post'>, sehingga kita bisa melakukan sesuatu dengan kelas itu untuk mengubah tampilannya:

.first-post {border:10px solid red}
.first-post .post {font-size:150%}

Kuncinya ada pada kondisional <b:if cond='data:post.isFirstPost'>

Konsep Auto Read-More Baru dengan Bantuan Textarea

Auto Readmore Hack for Blogger with Textarea
Mencoba memanfaatkan <textarea> untuk mencegah peramban memparse kode HTML di dalam posting.

Selama ini kita telah mengenal kode JavaScript pembuat ringkasan posting otomatis yang hanya bekerja dengan cara mengambil HTML di dalam posting, kemudian mengurangi jumlahnya untuk menciptakan ringkasan dan menampilkannya lagi dengan cara mengganti konten posting awal dengan ringkasan teks baru yang sudah dikurangi. Namun terkadang cara ini tidak efektif, karena biasanya peramban masih tetap bisa mengakses dan memparse semua kode HTML di dalam posting. Karakter posting memang terpotong, tapi beban muat tidak berubah.

Saat ini tidak ada cara yang bisa dibilang paling tepat untuk mengatasi masalah ini, dan satu-satunya cara yang paling sesuai dengan prosedur adalah dengan memanfaatkan elemen <data:post.snippet/> yang sebenarnya merupakan elemen untuk blog tampilan seluler (baca di sini).

Tapi, sebenarnya masih ada cara yang sederhana untuk mencegah peramban mengakses semua kode HTML posting saat kita belum memasuki halaman tunggal posting tersebut, yaitu dengan cara mengubah data yang dipanggil (dalam hal ini adalah konten posting) menjadi sesuatu yang bukan kode HTML, sesuatu yang lebih ringan dan tidak memicu peramban untuk mengerjakan apapun kecuali mengunduh teks yang ada. Yaitu dengan cara memanfaatkan <textarea>

Bungkus semua konten posting yang ada dengan elemen <textarea> sehingga kode HTML apapun yang ada di dalamnya tidak akan pernah diparse oleh peramban karena peramban hanya akan menganggapnya sebagai teks biasa yang ringan dan tidak memberikan beban permintaan HTTP tambahan (misalnya dari gambar atau video yang ada di dalam posting):

<textarea id='text-1234'><data:post.body/></textarea>

Konsepnya hanya seperti itu. Dan sisanya, kita bisa menggunakan JavaScript untuk menampilkan sebagian konten dari area teks tersebut, kemudian kita masukkan hasilnya ke dalam kontainer lain sebagai HTML:

<textarea id='text-1234'>
<data:post.body/>
</textarea>
<div id='container-1234'></div>
<script>

// Ambil teks dari `<textarea>`, kemudian kurangi jumlah karakternya (menjadi 200 karakter)
var summary = document.getElementById('text-1234').value.substring(0,200);

// Sisipkan karakter yang telah dikurangi tersebut ke dalam kontainer di bawahnya
document.getElementById('container-1234').innerHTML = summary + '&hellip;';

</script>

Thumbnail posting bisa kita dapatkan melalui elemen <data:post.thumbnailUrl/> dengan resolusi yang sudah diubah, sedangkan elemen <textarea> bisa kita sembunyikan dengan CSS. Proses penerapan selengkapnya bisa Anda baca mulai dari sini.


Membuat Posting Auto Read-More Blogspot Versi Manipulasi Textarea

Sebelum melakukan modifikasi, terlebih dahulu backup kode template Anda untuk berjaga-jaga jika terjadi kesalahan.

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

</head>

Salin kode ini kemudian letakkan di atasnya:

<script type='text/javascript'>
// Lightweight `auto read-more` hack for Blogger using `Textarea` by Taufik Nurrohman
// URL: https://plus.google.com/108949996304093815163/about
//<![CDATA[
var configSummary = {
thumbnailSize: 100, // Define the post thumbnail size
summaryLength: 300, // Define the summary length
noThumbUrl: "http://3.bp.blogspot.com/-vpCFysMEZys/UOEhSGjkfnI/AAAAAAAAFwY/h1wuA5kfEhg/s72-c/grey.png" // `no image` URL
};
function createPostSummary(a,b,c) {
var text, doc = document, d = configSummary,
copyFrom = doc.getElementById(a).value,
pasteTo = doc.getElementById(b),
postThumbnail = (c === "") ? d.noThumbUrl : c;
text = copyFrom.replace(/<(.*?)>/g,"").replace(/[\n\r]+/g," ");
pasteTo.innerHTML = '<img class="post-thumbnail" src="'+postThumbnail.replace(/\/s[0-9]+(\-c)?\//,'/s'+d.thumbnailSize+'-c/')+'" alt="thumbnail" style="width:'+d.thumbnailSize+'px;height:'+d.thumbnailSize+'px;">' + text.substring(0,d.summaryLength) + '&hellip;';
}
//]]>
</script>

Setelah itu cari baris kode yang tampak kurang lebih seperti ini:

<div class='post-body entry-content' expr:id='&quot;post-body-&quot; + data:post.id'>
<data:post.body/>
<div style='clear:both;'/> <!-- clear for photos floats -->
</div>

Ganti semua kode di atas menjadi kode ini:

<div class='post-body entry-content' expr:id='&quot;post-body-&quot; + data:post.id'>
<b:if cond='data:blog.pageType == &quot;static_page&quot;'>
<data:post.body/>
<b:else/>
<b:if cond='data:blog.pageType == &quot;item&quot;'>
<data:post.body/>
<b:else/>
<textarea expr:id='&quot;postData-&quot; + data:post.id' style='display:none;'><data:post.body/></textarea>
<p class='post-summary' expr:id='&quot;summaryContainer-&quot; + data:post.id'>
<!-- for non/inactive JavaScript browsers -->
<b:if cond='data:post.thumbnailUrl'>
<img class='post-thumbnail' expr:alt='data:post.title' expr:src='data:post.thumbnailUrl' height='72' itemprop='image' width='72'/>
</b:if>
<b:if cond='data:post.snippet'>
<data:post.snippet/>
</b:if>
<!-- end for non/inactive JavaScript browsers -->
</p>
<p class='post-more-link'>
<a expr:href='data:post.url + &quot;#more&quot;' expr:title='data:post.jumpText + &quot; &quot; + data:post.title'>
<data:post.jumpText/>
</a>
</p>
<script>createPostSummary(&quot;postData-<data:post.id/>&quot;,&quot;summaryContainer-<data:post.id/>&quot;,&quot;<b:if cond='data:post.thumbnailUrl'><data:post.thumbnailUrl/></b:if>&quot;);</script>
</b:if>
</b:if>
<div style='clear:both;'/> <!-- clear for photos floats -->
</div>

Sisanya tinggal menambahkan kode CSS ini yang berfungsi untuk menggeser thumbnail gambar ke samping kiri ringkasan artikel. Letakkan kode ini di atas ]]></b:skin> atau </style>:

.post-thumbnail {
display:block;
float:left;
margin:.2em 1em 0 0;
}

Klik Simpan Template.

Untuk template versi standar yang sekarang mungkin kodenya menjadi sedikit lebih rumit karena ada beberapa microdata yang disusun secara otomatis oleh Blogger. Mungkin suatu saat yang Anda temukan adalah baris kode seperti ini:

<b:if cond='data:blog.metaDescription == &quot;&quot;'>
<!-- Then use the post body as the schema.org description,
for good G+/FB snippeting. -->
<div class='post-body entry-content' expr:id='&quot;post-body-&quot; + data:post.id' itemprop='description articleBody'>
<data:post.body/>
<div style='clear:both;'/> <!-- clear for photos floats -->
</div>
<b:else/>
<div class='post-body entry-content' expr:id='&quot;post-body-&quot; + data:post.id' itemprop='articleBody'>
<data:post.body/>
<div style='clear:both;'/> <!-- clear for photos floats -->
</div>
</b:if>

Tidak masalah. Ganti semua kode di atas dengan kode ini:

<div class='post-body entry-content' expr:id='&quot;post-body-&quot; + data:post.id' itemprop='articleBody'>
<b:if cond='data:blog.pageType == &quot;static_page&quot;'>
<data:post.body/>
<b:else/>
<b:if cond='data:blog.pageType == &quot;item&quot;'>
<data:post.body/>
<b:else/>
<textarea expr:id='&quot;postData-&quot; + data:post.id' style='display:none;'><data:post.body/></textarea>
<p class='post-summary' expr:id='&quot;summaryContainer-&quot; + data:post.id'>
<!-- for non/inactive JavaScript browsers -->
<b:if cond='data:post.thumbnailUrl'>
<img class='post-thumbnail' expr:alt='data:post.title' expr:src='data:post.thumbnailUrl' height='72' itemprop='image' width='72'/>
</b:if>
<span itemprop='description'>
<b:if cond='data:post.snippet'>
<data:post.snippet/>
</b:if>
</span>
<!-- end for non/inactive JavaScript browsers -->
</p>
<p class='post-more-link'>
<a expr:href='data:post.url + &quot;#more&quot;' expr:title='data:post.jumpText + &quot; &quot; + data:post.title'>
<data:post.jumpText/>
</a>
</p>
<script>createPostSummary(&quot;postData-<data:post.id/>&quot;,&quot;summaryContainer-<data:post.id/>&quot;,&quot;<b:if cond='data:post.thumbnailUrl'><data:post.thumbnailUrl/></b:if>&quot;);</script>
</b:if>
</b:if>
<div style='clear:both;'/> <!-- clear for photos floats -->
</div>

Unduh Sampel Template

Template Minima Black dengan posting yang sudah dimodifikasi. Silakan dipelajari:

 
Support : Creating Website | Johny Template | Mas Template
Copyright © 2011. Homtimpa - All Rights Reserved
Template Modify by Creating Website
Proudly powered by Blogger