Tampilkan postingan dengan label JSON. Tampilkan semua postingan
Tampilkan postingan dengan label JSON. Tampilkan semua postingan

Rabu, 18 Februari 2015

Parser JSON untuk Blogger: Posting dan Halaman Statis

Berikut adalah generalisasi fungsi untuk mengubah data JSON posting dan halaman statis Blogger menjadi markup HTML sesuai dengan keinginan. Di sini Saya membagi fungsinya menjadi dua macam yaitu generatePostsData untuk menangani posting dan halaman dalam bentuk daftar dan generatePostData untuk menangani posting dan halaman dalam bentuk tunggal:

Bentuk Daftar

function generatePostsData(json) {

// Poor configuration settings, develop them yourself!
var config = {
containerID: 'result-container', // Container ID to show the generated data
avatarSize: 50, // Default avatar size
noThumbnail: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABIAQMAAABvIyEEAAAABGdBTUEAALGPC/xhBQAAAAZQTFRFOjo6JycnNkxyjQAAADZJREFUKM9j+A8DDFRnNTCAACP9WewPGNgfkMmiwN7GH0CGfCPdWZT5V/7/DwZyWeSHFa1SHQDDGF2E0US40gAAAABJRU5ErkJggg==',
text: {
anon: 'Anonymous',
untagged: 'Untagged',
monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
}
};

var html = "",
item = "",
w = window,
d = document,
feed = json.feed,
container = d.getElementById(config.containerID),
postTotal = +feed.openSearch$totalResults.$t, // The post/page feeds' total (all)
postStartIndex = +feed.openSearch$startIndex.$t, // The post/page feeds' start index
postPerPage = +feed.openSearch$itemsPerPage.$t, // The post/page feeds' max results per page or per feed request
blogID = /\:blog-?(\d+)(\.|$)/.exec(feed.id.$t) ? /\:blog-?(\d+)(\.|$)/.exec(feed.id.$t)[1] : false, // The blog ID
blogTitle = feed.title.$t, // The post/page feeds' title
blogTags = false, // The available post/page tags (all)
blogSubTitle = feed.subtitle.$t, // The post/page feeds' subtitle
blogAuthorName = feed.author[0].name ? feed.author[0].name.$t : config.text.anon, // The blog/post author name
blogAuthorAvatar = feed.author[0].gd$image.src.replace(/\/s\d+(\-c)?\//, '/s' + config.avatarSize + '-c/'), // The blog/post author profile avatar URL
blogGeneratorName = feed.generator.$t, // The blog generator name (Blogger)
blogGeneratorURL = feed.generator.uri; // The blog generator URL (http://www.blogger.com)

// Remove the leading `http://` or `https://` in blog/post author profile avatar URL
// blogAuthorAvatar = blogAuthorAvatar.replace(/^https?\:/, "");

// No container found
if (!container) {
alert('Container not found.');
return;
}

// Getting the blog tags
if (feed.category && feed.category.length) {
blogTags = [];
for (var h = 0, hen = feed.category.length; h < hen; ++h) {
blogTags.push(feed.category[h].term);
}
// Sort the blog tags alphabetically
blogTags = blogTags.sort();
}

// No posts/pages yet
if (!feed.entry || feed.entry.length === 0) {
container.innerHTML = '<p>No posts/pages yet.</p>';
return;
}

// Building the markup ...
html += '<h1>' + blogTitle + '</h1>';
html += '<h2>' + blogSubTitle + '</h2>';
html += '<p><b>Blog ID:</b> ' + blogID + '</p>';
html += '<p><b>Blog Tags:</b> ' + (blogTags !== false ? blogTags.join(', ') : config.text.untagged) + '</p>';
html += '<p><b>Blog Author Name:</b> ' + blogAuthorName + '</p>';
html += '<p><b>Blog Author Avatar URL:</b> ' + blogAuthorAvatar + '</p>';
html += '<p><b>Total Posts:</b> ' + postTotal + '</p>';
html += '<p><b>Posts Per Page:</b> ' + postPerPage + '</p>';
html += '<p><b>Posts Start Index:</b> ' + postStartIndex + '</p>';
html += '<hr>';
html += '<ol>';

var posts = feed.entry;

for (var i = 0, ien = posts.length; i < ien; ++i) {

var post = posts[i], // A single post/page object
postID = post.id.$t, // The post/page ID
postPublish = post.published.$t, // The post/page publishing time in ISO format
postUpdate = post.updated.$t, // The post/page updating time in ISO format
postDate = postPublish, // The post/page publishing time in human-readable format
postURL = false, // The post/page URL
postTags = false, // The post/page tags
postCommentTotal = post.thr$total ? +post.thr$total.$t : 0, // The post/page comments total
postCommentFeedURL = false, // The post/page comments feed URL
postThumbnail = post.media$thumbnail ? post.media$thumbnail.url : config.noThumbnail, // The post/page thumbnail
postAuthorName = post.author[0].name ? post.author[0].name.$t : config.text.anon, // The post/page author name
postAuthorURL = post.author[0].uri ? post.author[0].uri.$t : false, // The post/page author profile URL
postAuthorAvatar = post.author[0].gd$image.src.replace(/\/s\d+(\-c)?\//, '/s' + config.avatarSize + '-c/'), // The post/page author profile avatar URL
postTitle = post.title.$t, // The post/page title
postContent = post.content ? post.content.$t : post.summary.$t.replace(/<br *\/?>|[\s]+/gi, ' ').replace(/<.*?>|[<>]/g, ""), // The post/page content
postEditURL = false; // The post/page edit URL

// Generate human-readable post/page date format
var date = postDate.split('T')[0].split('-');
postDate = date[2] + ' ' + config.text.monthNames[(+date[1]) - 1] + ' ' + date[0];

// Remove the leading `http://` or `https://` in post/page thumbnail URL
// postThumbnail = postThumbnail.replace(/^https?\:/, "");

// Remove the leading `http://` or `https://` in post/page author profile avatar URL
// postAuthorAvatar = postAuthorAvatar.replace(/^https?\:/, "");

for (var j = 0, jen = post.link.length; j < jen; ++j) {
item = post.link[j];
if (item.rel == 'self') {
// Getting the original post/page ID
postID = item.href.split('/').pop();
// Getting the post/page edit URL
postEditURL = item.href.replace(/\/feeds\/(\d+)\/(post|page)s?\/(default|summary)\/(\d+)/, '/$2-edit.g?blogID=$1&$2ID=$4');
}
// Getting the post/page URL
if (item.rel == 'alternate') {
postURL = item.href;
}
// Getting the post/page comment feed URL
if (item.rel == 'replies' && item.type == 'application/atom+xml') {
postCommentFeedURL = item.href;
}
}

// Trying to get the external image URL from post/page content
if (post.content && postThumbnail == config.noThumbnail) {
var image = /<img +(.*?)src=(['"])([^'"]+?)(['"])(.*?) *\/?>/i.exec(post.content.$t);
postThumbnail = image && image[3] ? image[3] : config.noThumbnail;
}

// Getting the post/page tags
if (post.category && post.category.length) {
postTags = [];
for (var k = 0, ken = post.category.length; k < ken; ++k) {
postTags.push(post.category[k].term);
}
// Sort the post/page tags alphabetically
postTags = postTags.sort();
}

// Building the markup ...
html += '<li>';
html += '<p><b>ID:</b> ' + postID + '</p>';
html += '<p><b>Publish:</b> ' + postPublish + '</p>';
html += '<p><b>Update:</b> ' + postUpdate + '</p>';
html += '<p><b>Date:</b> ' + postDate + '</p>';
html += '<p><b>URL:</b> ' + postURL + '</p>';
html += '<p><b>Tags:</b> ' + (postTags !== false ? postTags.join(', ') : config.text.untagged) + '</p>';
html += '<p><b>Comment Total:</b> ' + postCommentTotal + '</p>';
html += '<p><b>Comment Feed URL:</b> ' + postCommentFeedURL + '</p>';
html += '<p><b>Thumbnail:</b> ' + postThumbnail + '</p>';
html += '<p><b>Author:</b> ' + postAuthorName + '</p>';
html += postAuthorURL !== false ? '<p><b>Author URL:</b> ' + postAuthorURL + '</p>' : "";
html += '<p><b>Author Avatar URL:</b> ' + postAuthorAvatar + '</p>';
html += '<p><b>Edit URL:</b> ' + postEditURL + '</p>';
html += '<p><b>Title:</b> ' + postTitle + '</p>';
html += '<p><b>Content:</b></p>';
html += '<div>' + postContent + '</div>';
html += '</li>';

}

// Building the markup ...
html += '</ol>';

// Show the generated data to the container ...
container.innerHTML = html;

}

Penggunaan

Urutannya dimulai dari penulisan HTML untuk menampung data yang akan digenerasikan oleh fungsi di atas, dilanjutkan dengan memasukkan fungsi di atas ke dalam tag <script>, lalu memanggil data JSON dengan menggunakan nilai parameter URL callback berupa generatePostsData, sesuai dengan nama fungsi di atas:

<div id="result-container">Loading&hellip;</div>
<script>
function generatePostsData(json) { … }
</script>
<script src="http://nama_blog.blogspot.com/feeds/posts/default?alt=json-in-script&orderby=published&callback=generatePostsData"></script>

Bentuk Tunggal

function generatePostData(json) {

// Poor configuration settings, develop them yourself!
var config = {
containerID: 'result-container', // Container ID to show the generated data
avatarSize: 50, // Default avatar size
noThumbnail: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABIAQMAAABvIyEEAAAABGdBTUEAALGPC/xhBQAAAAZQTFRFOjo6JycnNkxyjQAAADZJREFUKM9j+A8DDFRnNTCAACP9WewPGNgfkMmiwN7GH0CGfCPdWZT5V/7/DwZyWeSHFa1SHQDDGF2E0US40gAAAABJRU5ErkJggg==',
text: {
anon: 'Anonymous',
untagged: 'Untagged',
monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
}
};

var html = "",
item = "",
w = window,
d = document,
container = d.getElementById(config.containerID);

// No container found
if (!container) {
alert('Container not found.');
return;
}

var post = json.entry, // The post/page object
postID = post.id.$t, // The post/page ID
postPublish = post.published.$t, // The post/page publishing time in ISO format
postUpdate = post.updated.$t, // The post/page updating time in ISO format
postDate = postPublish, // The post/page publishing time in human-readable format
postURL = false, // The post/page URL
postTags = false, // The post/page tags
postCommentTotal = post.thr$total ? +post.thr$total.$t : 0, // The post/page comments total
postCommentFeedURL = false, // The post/page comments feed URL
postThumbnail = post.media$thumbnail ? post.media$thumbnail.url : config.noThumbnail, // The post/page thumbnail
postAuthorName = post.author[0].name ? post.author[0].name.$t : config.text.anon, // The post/page author name
postAuthorURL = post.author[0].uri ? post.author[0].uri.$t : false, // The post/page author profile URL
postAuthorAvatar = post.author[0].gd$image.src.replace(/\/s\d+(\-c)?\//, '/s' + config.avatarSize + '-c/'), // The post/page author profile avatar URL
postTitle = post.title.$t, // The post/page title
postContent = post.content ? post.content.$t : post.summary.$t.replace(/<br *\/?>|[\s]+/gi, ' ').replace(/<.*?>|[<>]/g, ""), // The post/page content
postEditURL = false; // The post/page edit URL

// Generate human-readable post/page date format
var date = postDate.split('T')[0].split('-');
postDate = date[2] + ' ' + config.text.monthNames[(+date[1]) - 1] + ' ' + date[0];

// Remove the leading `http://` or `https://` in post/page thumbnail URL
// postThumbnail = postThumbnail.replace(/^https?\:/, "");

// Remove the leading `http://` or `https://` in post/page author profile avatar URL
// postAuthorAvatar = postAuthorAvatar.replace(/^https?\:/, "");

for (var j = 0, jen = post.link.length; j < jen; ++j) {
item = post.link[j];
if (item.rel == 'self') {
// Getting the original post/page ID
postID = item.href.split('/').pop();
// Getting the post/page edit URL
postEditURL = item.href.replace(/\/feeds\/(\d+)\/(post|page)s?\/(default|summary)\/(\d+)/, '/$2-edit.g?blogID=$1&$2ID=$4');
}
// Getting the post/page URL
if (item.rel == 'alternate') {
postURL = item.href;
}
// Getting the post/page comment feed URL
if (item.rel == 'replies' && item.type == 'application/atom+xml') {
postCommentFeedURL = item.href;
}
}

// Trying to get the external image URL from post/page content
if (post.content && postThumbnail == config.noThumbnail) {
var image = /<img +(.*?)src=(['"])([^'"]+?)(['"])(.*?) *\/?>/i.exec(post.content.$t);
postThumbnail = image && image[3] ? image[3] : config.noThumbnail;
}

// Getting the post/page tags
if (post.category && post.category.length) {
postTags = [];
for (var k = 0, ken = post.category.length; k < ken; ++k) {
postTags.push(post.category[k].term);
}
// Sort the post/page tags alphabetically
postTags = postTags.sort();
}

// Building the markup ...
html += '<li>';
html += '<p><b>ID:</b> ' + postID + '</p>';
html += '<p><b>Publish:</b> ' + postPublish + '</p>';
html += '<p><b>Update:</b> ' + postUpdate + '</p>';
html += '<p><b>Date:</b> ' + postDate + '</p>';
html += '<p><b>URL:</b> ' + postURL + '</p>';
html += '<p><b>Tags:</b> ' + (postTags !== false ? postTags.join(', ') : config.text.untagged) + '</p>';
html += '<p><b>Comment Total:</b> ' + postCommentTotal + '</p>';
html += '<p><b>Comment Feed URL:</b> ' + postCommentFeedURL + '</p>';
html += '<p><b>Thumbnail:</b> ' + postThumbnail + '</p>';
html += '<p><b>Author:</b> ' + postAuthorName + '</p>';
html += postAuthorURL !== false ? '<p><b>Author URL:</b> ' + postAuthorURL + '</p>' : "";
html += '<p><b>Author Avatar URL:</b> ' + postAuthorAvatar + '</p>';
html += '<p><b>Edit URL:</b> ' + postEditURL + '</p>';
html += '<p><b>Title:</b> ' + postTitle + '</p>';
html += '<p><b>Content:</b></p>';
html += '<div>' + postContent + '</div>';
html += '</li>';

// Building the markup ...
html += '</ol>';

// Show the generated data to the container ...
container.innerHTML = html;

}

Penggunaan

Sisipkan ID posting/halaman statis setelah path default atau summary:

<div id="result-container">Loading&hellip;</div>
<script>
function generatePostData(json) { … }
</script>
<script src="http://nama_blog.blogspot.com/feeds/posts/default/1962799387619194999?alt=json-in-script&callback=generatePostData"></script>

Ekstra

Halaman Statis

Data halaman statis dapat dipanggil dengan menggunakan format URL seperti ini:

http://nama_blog.blogspot.com/feeds/pages/default?alt=json-in-script&orderby=published&callback=generatePostsData
http://nama_blog.blogspot.com/feeds/pages/default?alt=json-in-script&callback=generatePostData

Mode Ringkas

Mode ringkas dapat dipanggil dengan menggunakan format URL seperti ini:

http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&orderby=published&callback=generatePostsData
http://nama_blog.blogspot.com/feeds/pages/summary?alt=json-in-script&orderby=published&callback=generatePostsData
http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&callback=generatePostData
http://nama_blog.blogspot.com/feeds/pages/summary?alt=json-in-script&callback=generatePostData

Parser JSON untuk Blogger: Komentar

Berikut adalah generalisasi fungsi untuk mengubah data JSON komentar Blogger menjadi markup HTML sesuai dengan keinginan. Saya sudah mendefinisikan ulang data-data yang penting ke dalam variabel, sehingga Anda bisa memodifikasi skrip ini dengan lebih mudah:

Bentuk Daftar

function generateCommentsData(json) {

// Poor configuration settings, develop them yourself!
var config = {
containerID: 'result-container', // Container ID to show the generated data
avatarSize: 50, // Default avatar size
text: {
anon: 'Anonymous'
}
};

var html = "",
item = "",
w = window,
d = document,
feed = json.feed,
container = d.getElementById(config.containerID),
postCommentTotal = +feed.openSearch$totalResults.$t, // The comment feeds' total (all)
postCommentStartIndex = +feed.openSearch$startIndex.$t, // The comment feeds' start index
postCommentPerPage = +feed.openSearch$itemsPerPage.$t, // The comment feeds' max results per page or per feed request
blogID = /\:blog-?(\d+)(\.|$)/.exec(feed.id.$t) ? /\:blog-?(\d+)(\.|$)/.exec(feed.id.$t)[1] : false, // The blog ID
postID = /\.post-?(\d+)(\.|$)/.exec(feed.id.$t) ? /\.post-?(\d+)(\.|$)/.exec(feed.id.$t)[1] : false, // The current post ID (if any)
postURL = false, // The current post URL (if any)
blogTitle = feed.title.$t, // The comment feeds' title
blogAuthorName = feed.author[0].name ? feed.author[0].name.$t : config.text.anon, // The blog/post author name
blogAuthorAvatar = feed.author[0].gd$image.src.replace(/\/s\d+(\-c)?\//, '/s' + config.avatarSize + '-c/'), // The blog/post author profile avatar URL
blogGeneratorName = feed.generator.$t, // The blog generator name (Blogger)
blogGeneratorURL = feed.generator.uri; // The blog generator URL (http://www.blogger.com)

// Remove the leading `http://` or `https://` in blog/post author profile avatar URL
// blogAuthorAvatar = blogAuthorAvatar.replace(/^https?\:/, "");

// No container found
if (!container) {
alert('Container not found.');
return;
}

// Getting the current post URL (if any)
if (postID) {
for (var h = 0, hen = feed.link.length; h < hen; ++h) {
item = feed.link[h];
if (item.rel == 'alternate') {
postURL = item.href;
break;
}
}
}

// No comments yet
if (!feed.entry || feed.entry.length === 0) {
container.innerHTML = '<p>No comments yet.</p>';
return;
}

// Building the markup ...
html += '<h1>' + blogTitle + '</h1>';
html += '<p><b>Blog ID:</b> ' + blogID + '</p>';
html += '<p><b>Post ID:</b> ' + postID + '</p>';
html += '<p><b>Post URL:</b> ' + postURL + '</p>';
html += '<p><b>Blog Author Name:</b> ' + blogAuthorName + '</p>';
html += '<p><b>Blog Author Avatar URL:</b> ' + blogAuthorAvatar + '</p>';
html += '<p><b>Total Comments:</b> ' + postCommentTotal + '</p>';
html += '<p><b>Comments Per Page:</b> ' + postCommentPerPage + '</p>';
html += '<p><b>Comments Start Index:</b> ' + postCommentStartIndex + '</p>';
html += '<hr>';
html += '<ol>';

var comments = feed.entry;

for (var i = 0, ien = comments.length; i < ien; ++i) {

var comment = comments[i], // A single comment feed object
commentID = comment.id.$t, // The comment ID
commentPublish = comment.published.$t, // The comment publishing time in ISO format
commentUpdate = comment.updated.$t, // The comment updating time in ISO format
commentDate = commentPublish, // The comment publishing time in timestamp format you defined in the dashboard
commentAuthorName = comment.author[0].name ? comment.author[0].name.$t : config.text.anon, // The comment author name
commentAuthorURL = comment.author[0].uri ? comment.author[0].uri.$t : false, // The comment author profile URL
commentAuthorAvatar = comment.author[0].gd$image.src.replace(/\/s\d+(\-c)?\//, '/s' + config.avatarSize + '-c/'), // The comment author profile avatar URL
commentContent = comment.content ? comment.content.$t : comment.summary.$t.replace(/<br *\/?>|[\s]+/gi, ' ').replace(/<.*?>|[<>]/g, ""), // The comment content
commentParent = false, // The comment parent ID (if any, for child comments)
commentPermalink = false, // The comment permalink
commentIsAdmin = commentAuthorName === blogAuthorName || commentAuthorAvatar === blogAuthorAvatar, // Is this comment was created by the blog/post author?
commentDeleteURL = false; // The comment delete URL

// Remove the leading `http://` or `https://` in comment author profile avatar URL
// commentAuthorAvatar = commentAuthorAvatar.replace(/^https?\:/, "");

for (var j = 0, jen = comment.link.length; j < jen; ++j) {
item = comment.link[j];
if (item.rel == 'self') {
// Getting the original comment ID
commentID = item.href.split('/').pop();
// Getting the comment delete URL
commentDeleteURL = item.href.replace(/\/feeds\/(\d+)\/(\d+)\/comments?\/(default|summary)\/(\d+)/, '/delete-comment.g?blogID=$1&postID=$4');
}
// Getting the comment permalink URL
if (item.rel == 'alternate') {
commentPermalink = item.href;
}
// Getting the comment parent ID (if any)
if (item.rel == 'related') {
var parentID = item.href.split('/').pop();
commentParent = commentID !== parentID ? parentID : false;
}
}

// Getting the comment publishing time in timestamp format you defined in the dashboard
for (var k = 0, ken = comment.gd$extendedProperty.length; k < ken; ++k) {
item = comment.gd$extendedProperty[k];
if (item.name == 'blogger.displayTime') {
commentDate = item.value;
break;
}
}

// Building the markup ...
html += '<li>';
html += '<p><b>ID:</b> ' + commentID + '</p>';
html += '<p><b>Publish:</b> ' + commentPublish + '</p>';
html += '<p><b>Update:</b> ' + commentUpdate + '</p>';
html += '<p><b>Date:</b> ' + commentDate + '</p>';
html += '<p><b>Author:</b> ' + commentAuthorName + '</p>';
html += commentAuthorURL !== false ? '<p><b>URL:</b> ' + commentAuthorURL + '</p>' : "";
html += '<p><b>Avatar URL:</b> ' + commentAuthorAvatar + '</p>';
html += commentParent !== false ? '<p><b>Parent ID:</b> ' + commentParent + '</p>' : "";
html += '<p><b>Permalink:</b> ' + commentPermalink + '</p>';
html += '<p><b>Status:</b> ' + (commentIsAdmin ? 'admin' : 'guest') + '</p>';
html += '<p><b>Delete URL:</b> ' + commentDeleteURL + '</p>';
html += '<p><b>Message:</b></p>';
html += '<div>' + commentContent + '</div>';
html += '</li>';

}

// Building the markup ...
html += '</ol>';

// Show the generated data to the container ...
container.innerHTML = html;

}

Penggunaan

Urutannya dimulai dari penulisan HTML untuk menampung data yang akan digenerasikan oleh fungsi di atas, dilanjutkan dengan memasukkan fungsi di atas ke dalam tag <script>, lalu memanggil data JSON dengan menggunakan nilai parameter URL callback berupa generateCommentsData, sesuai dengan nama fungsi di atas:

<div id="result-container">Loading&hellip;</div>
<script>
function generateCommentsData(json) { … }
</script>
<script src="http://nama_blog.blogspot.com/feeds/comments/default?alt=json-in-script&reverse=false&orderby=published&callback=generateCommentsData"></script>

Ekstra

Memanggil Data Komentar untuk Posting Tertentu

Gunakan format URL seperti ini untuk membatasi pemanggilan data komentar hanya untuk komentar-komentar yang terdapat pada posting dengan ID 6427706034645358331:

http://nama_blog.blogspot.com/feeds/6427706034645358331/comments/default?alt=json-in-script&reverse=false&orderby=published&callback=generateCommentsData

Sayangnya Saya tidak berhasil menemukan referensi resmi mengenai JSON Blogger versi 1.0 di Google Developer. Dulu memang pernah ada tapi sekarang sudah tidak ada lagi. Yang ada sekarang lebih banyak ditujukan untuk API Blogger versi 3.0+ yang membutuhkan autentikasi.

Sabtu, 02 Maret 2013

Eksperimen Infinite Scroll dengan JSON Blogger

Blogger Infinite Scroll Experiment
Blogger Infinite Scroll Experiment

Eksperimen membuat infinite scroll dengan JSON Blogger. Sebuah sistem yang akan memperbaharui jumlah item posting setiap kali pengguna mencapai batas akhir layar ketika pengguna sedang menggulung halaman. Metode ini sebenarnya sudah pernah Saya tuliskan di sini. Saya mengganti kondisional batas akhir yang tadinya berupa perbandingan antara tinggi kontainer dengan batas akhir gulungan area seperti ini:

container.onscroll = function() {
if ((this.scrollTop + this.offsetHeight) == inner.offsetHeight) {
myFunction();
}
};

Menjadi berdasarkan perbandingan antara tinggi layar dengan batas akhir gulungan layar seperti ini:

window.onscroll = function() {
if (navigator.userAgent.toLowerCase().indexOf("chrome") > -1 || navigator.userAgent.toLowerCase().indexOf("safari") > -1) {
if (document.documentElement.scrollHeight == (document.body.scrollTop + document.documentElement.clientHeight)) {
myFunction();
}
} else {
if (document.documentElement.scrollHeight == (document.documentElement.scrollTop + document.documentElement.clientHeight)) {
myFunction();
}
}
};

Selengkapnya mengenai potongan kode untuk mengecek batas akhir gulungan layar bisa Anda baca di sini.

Silakan dipelajari dan dimodifikasi sesuka hati Anda dengan mengikuti persetujuan yang Saya tuliskan di dalam kode sumbernya. Eksperimen ini akan diperbaharui jika memang ada yang perlu diperbaharui. Begitu.

Minggu, 13 Januari 2013

JSON (JavaScript Object Notation)

JSON

JSON merupakan sekumpulan objek JavaScript. Titik.

Pada dasarnya sebuah JSON hanyalah teks biasa yang tertulis dalam pola tertentu, yang kemudian disimpan dengan ekstensi .json, untuk kemudian bisa kita terjemahkan/konversi menjadi data yang terstruktur dan dapat dilihat dalam bentuk-bentuk yang bisa dibaca oleh manusia untuk keperluan interaksi (misalnya dalam bentuk tabel, daftar atau paragraf).

Data JSON berbasis teks, oleh karena itu dia tidak bergantung pada bahasa pemprograman apapun, itulah yang menjadikan JSON ideal sebagai bahasa pertukaran data. Jika Anda melihat footer pada situs JSON, maka Anda akan mendapati begitu banyak tautan yang mengarah pada beberapa bahasa untuk menangani JSON selain dengan . Dan semuanya tampak tidak terlalu berbeda dalam hal logika dan penerapannya.

Kali ini Saya hanya akan membicarakan tentang penanganan JSON dengan JavaScript. Sebagai catatan, pada dasarnya format dan pola teks di dalam JSON semuanya sama, hanya cara memparse/menerjemahkan datanya itu yang berbeda-beda.

Sekumpulan Objek

JSON tidak akan jauh-jauh dari array dan object, karena JSON memang merupakan penjabaran dari dua tipe data tersebut. Sebuah JSON paling sederhana dapat dinyatakan sebagai objek tunggal seperti ini:

var memberCard = {
"nama": "Taufik Nurrohman",
"memberId": 777,
"address": "http://nama_situs.com"
};

Sebuah variabel memberCard, secara umum hanya bisa menyimpan satu nilai/data saja. Namun ketika nilai variabel tersebut menjadi objek, maka kemampuan variabel tersebut akan meningkat dan bisa memuat data lebih banyak lagi dan lebih kompleks dibandingkan variabel biasa. Untuk menampilkan nilai objek satu per satu, Anda bisa membaca artikel mengenai JavaScript Array dan JavaScript Object:

var memberCard = {
"nama": "Taufik Nurrohman",
"memberId": 777,
"address": "http://nama_situs.com"
};

// Menampilkan data JSON sebagai kartu anggota (member card) virtual:
document.write('<div class="member-card">');
document.write('<ol>');
document.write('<li><strong>Nama:</strong> ' + memberCard.nama + '</li>');
document.write('<li><strong>ID Member:</strong> ' + memberCard.memberId + '</li>');
document.write('<li><strong>Alamat Situs:</strong> <a href="' + memberCard.address + '">' + memberCard.address + '</a></li>');
document.write('</ol>');
document.write('</div>');

Lebih Banyak Data

Untuk memasukkan data yang lebih banyak ke dalam JSON, Anda bisa mengelompokkan objek menjadi array. Untuk menciptakan cabang, Anda bisa mengubah nilai properti objek menjadi objek baru.

Sampel Pertama: Daftar Kartu Anggota

Untuk membuat kartu anggota yang berjumlah lebih dari satu, kita bisa menggabungkan beberapa objek kartu anggota menjadi array. Setelah itu, semua data bisa kita akses/panggil menggunakan loop:

var memberCard = [
{
"nama": "Taufik Nurrohman",
"memberId": 777,
"address": "http://nama_situs.com"
},
{
"nama": "Agus Bolagus",
"memberId": 778,
"address": "http://nama_situs_agus.com"
},
{
"nama": "Bejo Subejo",
"memberId": 230,
"address": "http://the_bejo_site.com"
},
{
"nama": "Paimin Bin Paimun",
"memberId": 411,
"address": "http://blog_paimin.com"
}
];

// Menampilkan data JSON sebagai deret kartu anggota (member card) virtual:
for (var i = 0; i < memberCard.length; i++) {
document.write('<div class="member-card">');
document.write('<ol>');
document.write('<li><strong>Nama:</strong> ' + memberCard[i].nama + '</li>');
document.write('<li><strong>ID Member:</strong> ' + memberCard[i].memberId + '</li>');
document.write('<li><strong>Alamat Situs:</strong> <a href="' + memberCard[i].address + '">' + memberCard[i].address + '</a></li>');
document.write('</ol>');
document.write('</div>');
}

Sampel ke Dua: Cabang Baru

Untuk menciptakan cabang baru, kita bisa menyatakan nilai salah satu properti objek menjadi objek baru:

var memberCard = {
"nama": "Taufik Nurrohman",
"memberId": 777,
"address": {
"address1": "http://nama_situs_pertamax.com",
"address2": "http://nama_situs_keduax.com",
"address3": "http://nama_situs_ketigax.com"
}
};

// Menampilkan data JSON sebagai kartu anggota (member card) virtual:
document.write('<div class="member-card">');
document.write('<ol>');
document.write('<li><strong>Nama:</strong> ' + memberCard.nama + '</li>');
document.write('<li><strong>ID Member:</strong> ' + memberCard.memberId + '</li>');
document.write('<li><strong>Alamat Situs:</strong>');
document.write('<div>1. <a href="' + memberCard.address.address1 + '">' + memberCard.address.address1 + '</a></div>');
document.write('<div>2. <a href="' + memberCard.address.address2 + '">' + memberCard.address.address2 + '</a></div>');
document.write('<div>3. <a href="' + memberCard.address.address3 + '">' + memberCard.address.address3 + '</a></div>');
document.write('</li>');
document.write('</ol>');
document.write('</div>');

Membuat Fungsi Untuk Memparse JSON

Jika JSON telah dinyatakan ke dalam variabel, maka kita bisa meletakkan variabel tersebut sebagai bagian dari parameter sebuah fungsi:

var memberCard = {
"nama": "Taufik Nurrohman",
"memberId": 777,
"address": "http://nama_situs.com"
};

function makeCard(json) {
document.write('<div class="member-card">');
document.write('<ol>');
document.write('<li><strong>Nama:</strong> ' + json.nama + '</li>');
document.write('<li><strong>ID Member:</strong> ' + json.memberId + '</li>');
document.write('<li><strong>Alamat Situs:</strong> <a href="' + json.address + '">' + json.address + '</a></li>');
document.write('</ol>');
document.write('</div>');
}

// Menampilkan data JSON sebagai kartu anggota (member card) virtual...
makeCard(memberCard);

JSON Dalam Dunia Nyata

Dalam dunia nyata, sebuah JSON tidak hanya terdiri dari data sependek itu. Beberapa bisa menampung konten yang lebih besar seperti posting atau identitas anggota yang kompleks. Sebuah JSON eksternal disimpan dengan ekstensi .json

Contoh JSON yang paling mudah kita lihat ada pada feed blog Blogger. Anda bisa melihatnya dengan cara mengakses URL feed blog yang diakhiri dengan parameter ?alt=json:

Contoh lain: Coba Anda lihat kode sumber halaman blog Anda. Pada bagian paling bawah, seharusnya Anda akan mendapati kode seperti ini. Ini adalah JSON, yang “sedang diterjemahkan” oleh sebuah fungsi bernama _WidgetManager._SetDataContext():

_WidgetManager._SetDataContext([{
'name': 'blog',
'data': {
'blogId': '298900102869691923',
'bloggerUrl': 'http://www.blogger.com',
'title': 'DTE :]',
'pageType': 'item',
'url': 'http://hompimpaalaihumgambreng.blogspot.com/2013/01/konsep-auto-read-more-dengan-bantuan.html',
'canonicalUrl': 'http://hompimpaalaihumgambreng.blogspot.com/2013/01/konsep-auto-read-more-dengan-bantuan.html',
'canonicalHomepageUrl': 'http://hompimpaalaihumgambreng.blogspot.com/',
'homepageUrl': 'http://hompimpaalaihumgambreng.blogspot.com/',
'blogspotFaviconUrl': 'http://hompimpaalaihumgambreng.blogspot.com/favicon.ico',
'enabledCommentProfileImages': true,
'adultContent': false,
'disableAdSenseWidget': false,
'analyticsAccountNumber': 'UA-27593783-1',
'searchLabel': '',
'searchQuery': '',
'pageName': 'Konsep Auto Read-More Baru dengan Bantuan Textarea',
'pageTitle': 'DTE :]: Konsep Auto Read-More Baru dengan Bantuan Textarea',
'metaDescription': 'Metode baru untuk mengurangi beban HTML posting yang biasa terjadi pada script auto read-more versi lama dengan memanfaatkan \46lt;textarea\46gt; untuk mencegah peramban memparse kode HTML di dalam posting.',
'encoding': 'UTF-8',
'locale': 'in',
'localeLanguage': 'in',
'isPrivate': false,
'isMobile': false,
'isMobileRequest': false,
'mobileClass': '',
'isPrivateBlog': false,
'languageDirection': 'ltr',
'feedLinks': '\74link rel\75\42alternate\42 type\75\42application/atom+xml\42 title\75\42DTE :] - Atom\42 href\75\42http://hompimpaalaihumgambreng.blogspot.com/feeds/posts/default\42 /\76\n\74link rel\75\42alternate\42 type\75\42application/rss+xml\42 title\75\42DTE :] - RSS\42 href\75\42http://hompimpaalaihumgambreng.blogspot.com/feeds/posts/default?alt\75rss\42 /\76\n\74link rel\75\42service.post\42 type\75\42application/atom+xml\42 title\75\42DTE :] - Atom\42 href\75\42http://www.blogger.com/feeds/298900102869691923/posts/default\42 /\76\n\74link rel\75\42EditURI\42 type\75\42application/rsd+xml\42 title\75\42RSD\42 href\75\42http://www.blogger.com/rsd.g?blogID\075298900102869691923\42 /\76\n\74link rel\75\42alternate\42 type\75\42application/atom+xml\42 title\75\42DTE :] - Atom\42 href\75\42http://hompimpaalaihumgambreng.blogspot.com/feeds/6023732528357300917/comments/default\42 /\76\n',
'meTag': '',
'openIdOpTag': '',
'googleProfileUrl': 'https://plus.google.com/108949996304093815163',
'postImageThumbnailUrl': 'http://2.bp.blogspot.com/-PLdSyiYy8Os/UOaEAHS8SQI/AAAAAAAAGHE/Q2521ahg5Jk/s72-c/auto-readmore-hack-for-blogger-with-textarea.png',
'imageSrcTag': '\74link rel\75\42image_src\42 href\75\42http://2.bp.blogspot.com/-PLdSyiYy8Os/UOaEAHS8SQI/AAAAAAAAGHE/Q2521ahg5Jk/s72-c/auto-readmore-hack-for-blogger-with-textarea.png\42 /\76\n',
'latencyHeadScript': '\74script type\75\42text/javascript\42\76(function() { var a\75window,b\75\42jstiming\42,d\75\42tick\42;var e\75function(c){this.t\75{};this.tick\75function(c,p,h){h\75void 0!\75h?h:(new Date).getTime();this.t[c]\75[h,p]};this[d](\42start\42,null,c)},f\75new e;a.jstiming\75{Timer:e,load:f};if(a.performance\46\46a.performance.timing){var g\75a.performance.timing,j\75a[b].load,k\75g.navigationStart,l\75g.responseStart;0\74k\46\46l\76\75k\46\46(j[d](\42_wtsrt\42,void 0,k),j[d](\42wtsrt_\42,\42_wtsrt\42,l),j[d](\42tbsd_\42,\42wtsrt_\42))}\ntry{var m\75null;a.chrome\46\46a.chrome.csi\46\46(m\75Math.floor(a.chrome.csi().pageT),j\46\0460\74k\46\46(j[d](\42_tbnd\42,void 0,a.chrome.csi().startE),j[d](\42tbnd_\42,\42_tbnd\42,k)));null\75\75m\46\46a.gtbExternal\46\46(m\75a.gtbExternal.pageT());null\75\75m\46\46a.external\46\46(m\75a.external.pageT,j\46\0460\74k\46\46(j[d](\42_tbnd\42,void 0,a.external.startE),j[d](\42tbnd_\42,\42_tbnd\42,k)));m\46\46(a[b].pt\75m)}catch(n){};a.tickAboveFold\75function(c){var i\0750;if(c.offsetParent){do i+\75c.offsetTop;while(c\75c.offsetParent)}c\75i;750\76\75c\46\46a[b].load[d](\42aft\42)};var q\75!1;function r(){q||(q\75!0,a[b].load[d](\42firstScrollTime\42))}a.addEventListener?a.addEventListener(\42scroll\42,r,!1):a.attachEvent(\42onscroll\42,r);\n })();\74/script\076',
'mobileHeadScript': '',
'adsenseClientId': 'pub-4884309229437815',
'view': '',
'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js',
'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/20497177ec370ede',
'plusOneApiSrc': 'https://apis.google.com/js/plusone.js'
}
}, {
'name': 'skin',
'data': {
'vars': {},
'override': ''
}
}, {
'name': 'view',
'data': {
'classic': {
'name': 'classic',
'url': '/?view\75classic'
},
'flipcard': {
'name': 'flipcard',
'url': '/?view\75flipcard'
},
'magazine': {
'name': 'magazine',
'url': '/?view\75magazine'
},
'mosaic': {
'name': 'mosaic',
'url': '/?view\75mosaic'
},
'sidebar': {
'name': 'sidebar',
'url': '/?view\75sidebar'
},
'snapshot': {
'name': 'snapshot',
'url': '/?view\75snapshot'
},
'timeslide': {
'name': 'timeslide',
'url': '/?view\75timeslide'
}
}
}]);

JavaScript Object

JavaScript Object

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

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

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

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

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

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

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

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

Lainnya

Beberapa Cara Penulisan Object

Cara paling ringkas:

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

Mendeklarasikan objek kosong, kemudian menuliskan anggotanya satu per satu:

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

Metode lama/primitif:

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

Pemanggilan Data seperti halnya Array

Ini adalah cara pemanggilan data yang disarankan:

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

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

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

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

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

Objek Bertingkat/Beranak/Bercabang

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

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

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

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

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

JavaScript Array

JavaScript Array

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

Saya mulai dengan variabel biasa:

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

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

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

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

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

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

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

Lainnya

Beberapa Cara Penulisan Array

Cara paling ringkas:

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

Mendeklarasikan array kosong, kemudian menuliskan anggotanya satu per satu:

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

Metode lama/primitif:

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

Data yang Berbeda

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

Jumat, 16 November 2012

Kotak Penelusuran Blogger dengan AJAX JQuery

Ajax Search Form with JQuery
Kotak Penelusuran Blogger dengan Ajax JQuery

Beberapa waktu yang lalu Saya pernah menuliskan cara menampilkan hasil penelusuran dengan JSON Blogger tanpa harus berpindah dari halaman awal menuju halaman hasil penelusuran dengan JavaScript (Anda bisa membacanya di sini).

Melalui JQuery $.ajax() kita bisa meniadakan penyisipan script callback dan langsung memanggil JSON dengan cara seperti ini:

$('#search-form').on("submit", function() {
$.ajax({
url: '/feeds/posts/summary?alt=json-in-script&q=KATA_KUNCI',
type: 'get',
dataType: 'jsonp',
success: function(json) {

}
});
});

Sehingga jika dijabarkan akan menjadi seperti ini:

HTML Formulir

<form action="/search" id="ajax-search-form">
<input type="text" name="q">
<input type="submit" value="Search">
</form>

JQuery

(function($) {
var $form = $('#ajax-search-form'),
$input = $form.find(':text');
$form.append('<div id="search-result"></div>');
var $result_container = $('#search-result');
$form.on("submit", function() {
var keyword = $input.val();
$result_container.show().html('Loading...');
$.ajax({
url: 'http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&q=' + keyword + '&max-results=9999',
type: 'get',
dataType: 'jsonp',
success: function(json) {
var entry = json.feed.entry,
link, skeleton = "";
if (typeof entry !== "undefined") {
skeleton = '<h4>Search results for keyword &quot;' + keyword + '&quot;</h4>';
skeleton += '<a class="close" href="/">&times;</a><ol>';
for (var i = 0; i < entry.length; i++) {
for (var j = 0; j < entry[i].link.length; j++) {
if (entry[i].link[j].rel == "alternate") {
link = entry[i].link[j].href;
}
}
skeleton += '<li><a href="' + link + '">' + entry[i].title.$t + '</a></li>';
}
skeleton += '</ol>';
$result_container.html(skeleton);
} else {
$result_container.html('<a class="close" href="/">&times;</a><strong>No result!</strong>');
}
},
error: function() {
$result_container.html('<a class="close" href="/">&times;</a><strong>Error loading feed.</strong>');
}
});
return false;
});
$form.on("click", ".close", function() {
$result_container.fadeOut();
return false;
});
})(jQuery);

Cara Kerja

Pertama-tama kita tangkap beberapa elemen penting yaitu formulir pencarian dan elemen input kata kunci pencarian:

var $form = $('#ajax-search-form'), // Mendapatkan elemen formulir
$input = $form.find(':text'); // Mendapatkan elemen input bertipe teks (penampung kata kunci pencarian)

Sisipkan sebuah elemen HTML secara tidak langsung sebagai kontainer hasil pencaran:

$form.append('<div id="search-result"></div>');
var $result_container = $('#search-result');

Setelah itu kita berlakukan event .submit() atau .on("submit") pada formulir untuk kemudian kita bisa langsung memproses data JSON yang akan ditransfer pada saat yang bersamaan ketika kita menekan tombol Enter pada papan ketik atau mengeklik tombol penelusuran di dalam formulir:

$form.on("submit", function() {
$.ajax(url, type, dataType, success, error); // Dapatkan data dan proses data di sini...
return false; // <= Ini digunakan untuk mencegah formulir membawa kita menuju halaman hasil penelusuran saat kita men-submit kata kunci pencarian
});

Pengambilan data JSON dilakukan oleh JQuery $.ajax(), sehingga kita tidak perlu menyisipkan skrip callback ke dalam area <head> seperti dalam metode JavaScript mentah pada umumnya:

$.ajax({
url: 'http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&q=' + keyword + '&max-results=9999',
type: 'get',
dataType: 'jsonp',
success: function(json) {
var entry = json.feed.entry,
link, skeleton = "";
if (typeof entry !== "undefined") {
skeleton = '<h4>Search results for keyword &quot;' + keyword + '&quot;</h4>';
skeleton += '<a class="close" href="/">&times;</a><ol>';
for (var i = 0; i < entry.length; i++) {
for (var j = 0; j < entry[i].link.length; j++) {
if (entry[i].link[j].rel == "alternate") {
link = entry[i].link[j].href;
}
}
skeleton += '<li><a href="' + link + '">' + entry[i].title.$t + '</a></li>';
}
skeleton += '</ol>';
$result_container.html(skeleton);
} else {
$result_container.html('<a class="close" href="/">&times;</a><strong>No result!</strong>');
}
},
error: function() {
$result_container.html('<a class="close" href="/">&times;</a><strong>Error loading feed.</strong>');
}
});

keyword adalah variabel. Nilainya diambil dari elemen input teks:

var keyword = $input.val();
// `/feeds/posts/summary?alt=json-in-script&q=keyword&max-results=9999`

Integrasi Widget ke Blogger

Widget ini hanya akan bekerja jika blog Anda sudah dilengkapi dengan JQuery.

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

<style scoped="scoped">
#ajax-search-form {
position:relative;
font:normal normal 13px/normal Helmet,FreeSans,Sans-Serif;
}
#ajax-search-form a {
color:#741F27;
text-decoration:none;
}
#ajax-search-form input {
border:1px solid #ccc;
border-top-color:#999;
background-color:white;
font:inherit;
color:black;
margin:0 0;
padding:5px 5px;
width:180px;
}
#ajax-search-form input::-moz-focus-inner {
margin:0;
padding:0;
border:none;
outline:none;
}
#ajax-search-form input[type="submit"] {
width:auto;
background-color:#084670;
border-color:transparent;
color:#B4D8F0;
font-weight:bold;
cursor:pointer;
padding-left:7px;
padding-right:7px;
}
#ajax-search-form input[type="submit"]:hover,
#ajax-search-form input[type="submit"]:focus {background-color:#083E5F}
#search-result {
border:1px solid #bbb;
background-color:white;
padding:10px 15px;
margin:2px 0;
width:auto;
height:auto;
position:absolute;
top:100%;
left:0;
z-index:99;
-webkit-box-shadow:0 1px 3px rgba(0,0,0,.4);
-moz-box-shadow:0 1px 3px rgba(0,0,0,.4);
box-shadow:0 1px 3px rgba(0,0,0,.4);
display:none;
}
#search-result ol,
#search-result li,
#search-result h4 {
margin:0;
padding:0;
}
#search-result h4,
#search-result strong {
display:block;
margin:0 30px 10px 0;
}
#search-result ol {margin:0 0 10px 28px}
#search-result ol a:hover {text-decoration:underline}
#search-result .close {
display:block;
position:absolute;
top:6px;
right:10px;
line-height:normal;
color:#17950F;
}
#search-result strong {color:#B75252}
</style>
<form action="/search" id="ajax-search-form">
<input type="text" name="q"/>
<input type="submit" value="Search"/>
</form>
<script>
(function($) {

var $form = $('#ajax-search-form'),
$input = $form.find(':text');

// Append a search result container to the search form
$form.append('<div id="search-result"></div>');
var $result_container = $('#search-result');

// When the keyword is submitted…
$form.on("submit", function() {

// Get the input value
var keyword = $input.val();

// Show the search result container and insert a `Loading...` text
$result_container.show().html('Loading...');

// Get the blog JSON via $.ajax() to show the search result
// The URL format: http://blog_name.blogspot.com/feeds/posts/summary?alt=json-in-script&q={THE_KEYWORD}&max-results=9999
$.ajax({
url: 'http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&q=' + keyword + '&max-results=9999',
type: 'get',
dataType: 'jsonp',

// If success, grab the search result list…
success: function(json) {
var entry = json.feed.entry,
link, skeleton = "";
if (typeof entry !== "undefined") {
skeleton = '<h4>Search results for keyword &quot;' + keyword + '&quot;</h4>';
skeleton += '<a class="close" href="/">&times;</a><ol>';
for (var i = 0; i < entry.length; i++) {
for (var j = 0; j < entry[i].link.length; j++) {
if (entry[i].link[j].rel == "alternate") {
link = entry[i].link[j].href;
}
}
skeleton += '<li><a href="' + link + '">' + entry[i].title.$t + '</a></li>';
}
skeleton += '</ol>';
$result_container.html(skeleton);
} else {
// If the JSON is empty … (entry === undefined)
// Show the `not found` or `no result` message
$result_container.html('<a class="close" href="/">&times;</a><strong>No result!</strong>');
}
},
error: function() {
// If error, show an error message
$result_container.html('<a class="close" href="/">&times;</a><strong>Error loading feed.</strong>');
}
});
return false;
});

// Fade out the search result container if the close button is clicked
$form.on("click", ".close", function() {
$result_container.fadeOut();
return false;
});

})(jQuery);
</script>

Ganti kode yang Saya beri tanda dengan URL blog Anda kemudian klik Simpan Widget.

Senin, 12 November 2012

Memperbaharui Pemuatan JSON berdasarkan Event Scroll

Sebuah kumpulan data dalam daftar akan menampilkan indikator sedang memuat dan akan memulai pemuatan data baru saat jarak gulungan telah mencapai titik maksimal
Sebuah kumpulan data dalam daftar akan menampilkan indikator sedang memuat dan akan memulai pemuatan data baru saat jarak gulungan telah mencapai titik maksimal.

Metode ini masih sama dengan metode-metode penundaan pemuatan JSON yang biasa Saya lakukan untuk widget-widget Saya yaitu dengan cara menyisipkan script callback secara tidak langsung ke dalam area <head> dengan ID tertentu. Kemudian, jika Saya ingin memperbaharui muatan JSON yang sudah ada, Saya tinggal menyingkirkan script callback yang lama kemudian menggantinya dengan duplikat baru dengan parameter yang sudah diperbaharui.

Bayangkan saja bahwa sudah terdapat sebuah script callback dengan ID foo di dalam area <head> seperti ini:

...
...
<script id="foo" src="../feeds/posts/summary?alt=json-in-script&callback=functionName" type="text/javascript"></script>
</head>

Kemudian Saya akan menyingkirkannya dengan cara menangkap ID elemen tersebut sebagai awalan untuk menyeleksi node induknya:

var a = document.getElementById('foo');
var parent = a.parentNode; // Mendapatkan elemen induk dari `foo`

Kemudian, dari induk tersebut Saya akan menyingkirkan elemen itu sendiri:

var a = document.getElementById('foo');
var parent = a.parentNode; // Mendapatkan elemen induk dari `foo`
parent.removeChild(a); // Singkirkan `foo` dari `parent`

Di sini, kita akan melakukan pekerjaan di atas berdasarkan event onscroll dengan batasan akhir berupa jarak gulungan maksimal kontainer. Kode di bawah ini akan menjalankan fungsi bernama myFunction() berdasarkan event onscroll dengan syarat jarak gulungan telah mencapai titk maksimal:

elem.onscroll = function() {
if ((this.scrollTop + this.offsetHeight) == inner.offsetHeight) {
myFunction();
}
};

Dimana elem adalah objek berupa kontainer.

Memulai Pekerjaan

Markup HTML

Kita mulai dengan pembuatan markup HTML sederhana seperti ini:

<div id="result-container" style="width:400px;height:400px;overflow:auto;">
<ol></ol>
<span class="loading">Memuat...</span>
</div>

Elemen #result-container digunakan sebagai area scroll, elemen ol digunakan sebagai kontainer data yang nantinya akan dihasilkan dari JSON, dan elemen span.loading digunakan sebagai indikator sedang memuat.

Membangun JavaScript

Pertama-tama kita buat script untuk memparse data JSON menjadi elemen HTML. Sederhana, seperti script recent post biasa yang Saya beri nama grabList(), dan hanya akan menghasilkan elemen <li> dengan tautan dan judul posting di dalamnya:

var elem = document.getElementById('result-container'), // Mendapatkan elemen `#result-container`
inner = elem.getElementsByTagName('ol')[0], // Mendapatkan elemen `ol` pertama
loading = elem.getElementsByTagName('span')[0]; // Mendapatkan elemen `span` pertama (dalam hal ini adalah elemen indikator sedang memuat)

// Bangun sebuah script untuk menampilkan daftar posting
function grabList(json) {

var list = json.feed.entry, link, skeleton = "";

// Jalankan loop hanya jika data JSON masih ada/dapat didefinisikan
if (typeof list !== "undefined") {
for (var i = 0; i < list.length; i++) {
for (var j = 0; j < list[i].link.length; j++) {
if (list[i].link[j].rel == "alternate") {
link = list[i].link[j].href; // Mendapatkan URL posting
break;
}
}

// Bangun beberapa elemen `<li>` yang berisi tautan dan judul posting...
skeleton += '<li><a href="' + link + '">' + list[i].title.$t + '</a></li>';

}

// ... kemudian sisipkan elemen tersebut ke dalam elemen `<ol>`
inner.innerHTML += skeleton;

// dan sembunyikan indikator sedang memuat.
loading.style.display = "none";

} else {

// Jika data JSON sudah tidak ada (list === "undefined"), tambahkan kelas baru kepada elemen indikator sedang memuat dengan nilai `the-end`
loading.className += ' the-end';

// kemudian ganti teks indikator sedang memuat dengan kata `Habis`
loading.textContent = 'Habis';

}
}

Setelah itu buat sebuah fungsi untuk memuat script callback secara tidak langsung. Tambahkan dua buah parameter untuk menangani start-index dan max-results:

function updateScript(i, max) {
var head = document.getElementsByTagName('head')[0],
script = document.createElement('script');
script.type = 'text/javascript';
script.id = 'load-on-scroll-end';
script.src = 'http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&start-index=' + i + '&max-results=' + max + '&callback=grabList';
head.appendChild(script);
}

// Jalankan fungsi!
updateScript(1, 25);

Fungsi di atas akan menyisipkan sebuah script callback JSON Blogger dengan nilai parameter start-index berupa 1 dan max-results berupa 25, sehingga sebuah elemen <script> dengan parameter yang sudah diatur akan disipkan ke dalam area <head> secara tidak langsung seperti ini:

...
...
...
<script id="load-on-scroll-end" src="http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&start-index=1&max-results=25&callback=grabList" type="text/javascript"></script>
</head>

Memperbaharui JSON Berdasarkan Jarak Maksimal Gulungan Area

Setelah itu kita tambahkan sebuah kondisional untuk menyingkirkan script callback lama jika script tersebut ada. Tidak perlu membuat fungsi baru, cukup gunakan fungsi tadi agar kita bisa menggunakannya untuk dua hal sekaligus, yaitu menyisipkan script baru dan/atau menyingkirkan script lama (jika ada):

function updateScript(i, max) {
var head = document.getElementsByTagName('head')[0],
script = document.createElement('script');
script.type = 'text/javascript';
script.id = 'load-on-scroll-end';
script.src = 'http://nama_blog.blogspot.com/feeds/posts/summary?alt=json-in-script&start-index=' + i + '&max-results=' + max + '&callback=grabList';
if (document.getElementById('load-on-scroll-end')) {
var oldScript = document.getElementById('load-on-scroll-end');
oldScript.parentNode.removeScript(oldScript);
}

head.appendChild(script);
}

updateScript(1, 25); // Jalankan fungsi!

Karena kita juga akan menjalankan fungsi updateScript() berdasarkan event onscroll, maka kita juga harus memasukkan updateScript() ke dalam event yang Saya tuliskan pertama kali:

elem.onscroll = function() {
if ((this.scrollTop + this.offsetHeight) == inner.offsetHeight) {
// Muat ulang JSON Blogger dengan `start-index` yang baru melalui parameter `i`
updateScript(i, 25);
// Kemudian tampilkan indikator sedang memuat
loading.style.display = "block";
}
};

Parameter i haru dinamis, dan harus bisa bertambah setiap kali gulungan kontainer berakhir. Untuk membuatnya menjadi dinamis, kita akan menggunakan variabel awalan dengan nilai 0, kemudian kita tingkatkan nilainya di dalam event onscroll setiap kali jarak gulungan telah mencapai titik maksimal:

var start = 0;
elem.onscroll = function() {
if ((this.scrollTop + this.offsetHeight) == inner.offsetHeight) {

// Tingkatkan nilai `start` dengan 1 (dari `start = 0` menjadi `start = 1`, `start = 2`, dst...)
start++;

// Muat ulang JSON Blogger dengan `start-index` yang telah diperbaharui...
// ... melalui `start` yang nilainya dikalikan dengan 25
updateScript(start*25, 25); // => dari `(1, 25)` menjadi `(25, 25)`, `(50, 25)`, `(75, 25)`, dst...

// Kemudian tampilkan indikator sedang memuat
loading.style.display = "block";

}
};

Produk Final

HTML

<div id="result-container">
<ol></ol>
<span class="loading">Memuat...</span>
</div>

CSS

#result-container {
height:400px;
width:400px;
overflow:auto;
margin:50px auto;
font:normal normal 12px 'Trebuchet MS',Trebuchet,Geneva,Arial,Sans-Serif;
}

#result-container ol {
margin:0 0;
padding:0 0;
background-color:#B5D68C;
}

#result-container li {
margin:0 0;
padding:0 0;
list-style:none;
}

#result-container li:nth-child(even) {background-color:#A2C179}

#result-container li a {
display:block;
padding:5px 10px;
font-weight:bold;
color:#396B18;
text-decoration:none;
}

#result-container li a:hover {
background-color:#396B18;
color:white;
text-decoration:none;
}

#result-container .loading {
display:block;
height:26px;
font:normal bold 11px/26px Arial,Sans-Serif;
color:white;
text-align:center;
background-color:#B75A6F;
border-top:2px solid #222;
}

#result-container .loading.the-end {background-color:#666}

JavaScript

var widget_config = {
home_page: 'http://nama_blog.blogspot.com', // Your blog homepage
container_id: 'result-container', // ID of the result container
script_id: 'load-on-scroll-end-script', // ID of the asynchronous script
max_result: 25, // Max result post at once script loading
end_text: 'Habis' // End text if all posts has been loaded
};

var elem = document.getElementById(widget_config.container_id),
inner = elem.getElementsByTagName('ol')[0],
loading = elem.getElementsByTagName('span')[0],
start = 0, // Dynamic start-index
max = widget_config.max_result;

function grabList(json) {
var list = json.feed.entry, link, skeleton = "";
if (typeof list !== "undefined") {
for (var i = 0; i < list.length; i++) {
for (var j = 0; j < list[i].link.length; j++) {
if (list[i].link[j].rel == "alternate") {
link = list[i].link[j].href;
break;
}
}
skeleton += '<li><a href="' + link + '">' + list[i].title.$t + '</a></li>';
}
inner.innerHTML += skeleton; // Insert the list to the container
loading.style.display = "none"; // Hide the loading indicator
} else {
// If the JSON is empty (list === "undefined"),
// add a new class to the loading indicator called `the-end`
loading.className += ' the-end';
// Replace the loading indicator text into `fully loaded!` for the example
loading.textContent = widget_config.end_text;
}
}

// Make an indirect script loader with two parameters: start-index and max-result post
function updateScript(a, b) {
var head = document.getElementsByTagName('head')[0],
script = document.createElement('script');
script.type = 'text/javascript';
script.id = widget_config.script_id;
script.src = widget_config.home_page + '/feeds/posts/summary?alt=json-in-script&start-index=' + a + '&max-results=' + b + '&callback=grabList';
// If there is an old script in the document...
if (document.getElementById(widget_config.script_id)) {
var oldScript = document.getElementById(widget_config.script_id);
// Remove the old script, and replace with the new one that has an updated start-index value
oldScript.parentNode.removeChild(oldScript);
}
head.appendChild(script);
}

// Start loading the callback script with start-index of 1
updateScript(1, max);

// When the container is being scrolled...
elem.onscroll = function() {
// ... check the scroll distance
if ((this.scrollTop + this.offsetHeight) == inner.offsetHeight) {
// If the distance equal to the height of the inner container...
start++; // Increase the start value by one
// then load the new script with an updated start-index
updateScript(start*max, max);
// and show the loading indicator
loading.style.display = "block";
}
};