DTE :]

Saturday, April 4, 2020

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

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

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

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

Metode Tradisional

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

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

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

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

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

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

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

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

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

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

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

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

start();

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

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

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

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

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

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

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

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

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

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

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

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

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

document.head.appendChild(node);

Metode AJAX

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

let xhr = new XMLHttpRequest;

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

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

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

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

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

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

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

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

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

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

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

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

Labels: , , ,

Saturday, October 5, 2019

Tema Open-Source untuk Blogger

Open-Source Blogger Theme
Tema Blogger Dasar: BloggerPack.

Sangat sulit mencari komunitas pengembang tema Blogger yang memiliki semangat keterbukaan kode sumber seperti Saya. Selain karena Blogger bukan merupakan layanan blog yang terbuka, minimnya dokumentasi resmi akan kode-kode pada tema Blogger memaksa kita untuk menggunakan waktu dan tenaga yang banyak untuk mempelajari setiap kode yang ada secara otodidak dan tanpa bimbingan. Akibatnya, orang-orang yang berhasil tahu dan/atau menemukan sesuatu yang baru pada mesin Blogger lebih memilih untuk mengembangkan dan merilis tema-tema mereka secara mandiri dan bahkan sembunyi-sembunyi tanpa memberitahu kita tentang apa-apa saja yang telah mereka lakukan dan kembangkan pada tema yang mereka buat.

Topik-topik seperti cara menandai komentar administrator, cara menghapus CSS dan JavaScript bawaan Blogger, cara membuat komentar berbalas, dan cara menyisipkan kode CSS dan JavaScript kustom pada postingan tertentu pernah begitu populer sepanjang pengamatan Saya dari pertama kali Saya mengenal Blogger sampai sekarang.

Berat rasanya untuk membagikan temuan-temuan tersebut secara cuma-cuma karena kebanyakan dari kita selama ini memang hanya bisa menebak-nebak saja pada apa yang terjadi pada kode-kode XML Blogger dari sisi peladen dengan melihat melalui kode keluaran HTML-nya saja. Sangat memprihatinkan memang, tapi Saya bisa memaklumi hal tersebut karena dahulu Saya juga pernah menjadi seperti kalian.

Rasanya seperti sedang mencari harta karun. Ketika kalian berhasil menemukannya, maka kalian akan terburu-buru memberitahukannya kepada semua orang di seluruh alam semesta karena kalian takut nanti akan ada orang lain juga yang berhasil menemukannya setelah kalian namun lebih dahulu memberitahukannya. Ada semacam ambisi untuk menjadi yang pertama, dan temuan-temuan sederhana pada Blogger yang serba closed-source membuat kalian seolah layak untuk mendapatkan hak paten dari Pemerintah, sehingga orang lain yang ingin mengimplementasikan temuan kalian akan memiliki kewajiban untuk membayar royalti ratusan juta rupiah kepada kalian. Kalian kemudian akan menjadi orang yang kaya raya berkat Blogger.

Semangat-semangat semacam itulah yang kadang membuat para pengembang Blogger menjadi tertantang. Sampai sekarang Saya bahkan masih belum tahu tentang bagaimana cara mendeteksi kueri ?amp=1 pada URL blog.

Sudah cukup mengkhayalnya ya! Sekarang Saya mau memperkenalkan sebuah proyek tema Blogger dengan kode sumber yang terbuka dari Hermawan Yogi, namanya BloggerPack. Tema ini adalah tema mentah yang tidak bisa digunakan secara langsung tanpa dilakukan kompilasi dan pembangunan terlebih dahulu menggunakan alat pembangun (beliau menggunakan Grunt).

Dokumentasi tingkat lanjut dapat dipelajari pada halaman proyek. Di sini Saya hanya ingin menjelaskan garis besarnya saja untuk kalangan awam (para pengguna), sekedar untuk membantu memahami struktur kode sumber tema yang ada.

Struktur Sumber

Berikut ini adalah struktur berkas dan folder kode-kode mentah tema sebelum dilakukan kompilasi. Semua kode tersimpan di dalam folder src sebagai komponen-komponen yang terpisah:

.\
└── src\
    ├── _defaultmarkups\
    ├── _js\
    ├── _plugins\
    ├── _scss\
    ├── _views\
    ├── config.json
    ├── …
    └── theme.xml

Berkas-berkas tersebut tidak bisa digunakan secara langsung karena setiap komponen masih terpisah-pisah dan dibuat dengan sintaks kode pra-produksi seperti sintaks SCSS untuk membentuk kode CSS dan sintaks modul ES6 untuk membentuk kode JavaScript versi peramban.

Tujuan kita memisahkan berkas-berkas tema sebagai komponen-komponen individu adalah untuk memudahkan para pengembang dalam menambahkan dan/atau mengurangi fitur tema yang ada. Tapi mungkin itu hanya akan memudahkan dari sisi pengembang saja, sedangkan dari sisi pengguna biasanya akan berpendapat kalau hal-hal tersebut dirasa terlalu rumit.

Pengguna pada dasarnya hanya ingin tahu di sebelah mana dia bisa menemukan tombol mengunduh tema dan bagaimana cara memasang tema tersebut. Pengguna tidak mau tahu seluk-beluk proses pengembangannya secara rinci, mereka hanya peduli pada hasil akhirnya saja dan oleh karena itu penjelasan-penjelasan Saya pada beberapa paragraf di bawah mungkin tidak akan berguna bagi Anda yang hanya berniat untuk segera menggunakan tema. Silakan langsung meloncat pada penjelasan mengenai folder dist.

Konfigurasi

Kita menggunakan Grunt untuk menggabungkan berkas-berkas pada folder src. Berkas-berkas tersebut nantinya akan dibentuk menjadi beberapa berkas baru yang siap pakai (biasanya sudah dalam bentuk kode yang sudah dikompres dan digabung menjadi satu, terutama pada kode CSS dan JavaScript tema). Berkas-berkas tersebut nantinya akan tersimpan secara otomatis pada folder dist.

Sebelum menjalankan perintah ‘bangun’, terlebih dahulu Anda buka berkas config.json untuk melakukan konfigurasi tema, terutama pada bagian atribusi, versi dan waktu perilisan. Cantumkan nama tema dan nama pembuatnya sesuai kehendak (di bawah lisensi MIT):

{
  "theme": {
    "name": "Tema Pribadi",
    "version": "2.0.0",
    "date": "5 Oktober 2019",
    "homepage": "https://dte-feed.blogspot.com",
    "author": {
      "name": "Taufik Nurrohman",
      "url": "https://github.com/tovic"
    },
    …
    …
  }
}

Setelah selesai, jalankan perintah $ grunt. Saya tidak akan menjelaskannya secara rinci di sini. Silakan pelajari sendiri pada dokumentasi tema dan situs web resmi Grunt bagi Anda yang ingin serius mengembangkan tema ini.

Struktur Produk

Berikut ini adalah struktur berkas dan folder kode-kode tema setelah dilakukan kompilasi dan pembangunan. Semua kode tersimpan di dalam folder dist:

.\
└── dist\
    ├── css\
    ├── js\
    ├── …
    └── theme.xml

Di situ terdapat berkas bernama theme.xml yang dapat kalian pasang ke Blogger. Folder css dan js berisi hasil akhir dari kompilasi dan pembangunan kode-kode SCSS dan modul ES6 pada folder src. Berkas-berkas tersebut pada dasarnya tidak ada gunanya karena kode-kode CSS dan JavaScript yang sama juga sudah tergabung ke dalam berkas theme.xml secara inline. Berkas-berkas CSS dan JavaScript yang terpisah tersebut hanya akan berguna ketika kalian berniat untuk menyimpan mereka ke ruang penyimpanan web tertentu di luar Blogger, untuk kemudian dapat dimuat melalui tag <link href="./jalur/ke/main.min.css" rel="stylesheet"> dan <script src="./jalur/ke/main.min.js"></script>.

Dokumentasi dan tutorial bawaan masih belum sepenuhnya selesai. Kalian bisa memberikan kontribusi dengan cara membuat permintaan dorong atau membuat isu baru di GitHub.

Labels: , ,

Sunday, July 7, 2019

Cara Memberlakukan Kode CSS Hanya pada Tampilan Tata Letak

Warna khusus pada tampilan blok widget di halaman Tata Letak.

Cara Lama

Cara pertama ini adalah cara yang paling tua, yaitu dengan membuat selektor CSS yang diinginkan menjadi khusus untuk anak-anak elemen pada induk <body id="layout"> saja. Kekurangan dari metode ini adalah, kode CSS khusus yang seharusnya hanya dimuat pada tampilan Tata Letak akan tampil juga pada kode sumber di halaman versi publik. Kode CSS juga akan diterapkan pada halaman versi publik apabila Anda menambahkan atribut id="layout" pada elemen <body> di dalam kode XML tema:

body#layout div.section {
  background: #ff0;
  border: 4px solid #f00;
}

Cara Baru

Cara yang paling baru untuk memberlakukan kode CSS hanya pada tampilan Tata Letak adalah dengan menuliskan kode CSS di dalam elemen <b:template-skin> seperti ini:

<b:template-skin>
<![CDATA[
div.section {
  background: #ff0;
  border: 4px solid #f00;
}
]]>
</b:template-skin>

Kita mungkin bisa menggunakan tag kondisional ini sebagai cara alternatif, hanya saja Saya belum sempat mengujinya jadi Saya tidak tahu apakah cara ini bisa bekerja atau tidak. Secara logika harusnya bisa:

<b:if cond='data:view.isLayoutMode'>
<style>
div.section {
  background: #ff0;
  border: 4px solid #f00;
}
</style>
</b:if>

Anda bisa menggunakan fitur ini untuk menandai beberapa widget yang Anda anggap khusus atau penting, misalnya dengan memberikan warna yang spesial pada widget-widget tertentu sehingga Anda sebagai pengembang tema akan lebih mudah untuk membimbing pengguna tema Anda dengan cara mengarahkan mereka untuk menyunting widget tertentu berdasarkan warna atau pola yang Anda berikan. Sebagai contoh, di sini Saya memberikan warna gradiasi biru pada widget pencarian dan gradiasi kuning pada widget iklan:

body#layout div.widget.BlogSearch div.widget-content {
  background: linear-gradient(#fff, #e8ffff);
}

body#layout div.widget.AdSense div.widget-content {
  background: linear-gradient(#fff, #ffffce);
}

Kode yang Saya beri tanda adalah nama kelas HTML yang akan diterapkan secara otomatis pada widget sesuai dengan jenisnya. Anda juga bisa membuatnya menjadi lebih spesifik lagi dengan memanfaatkan ID widget seperti ini:

body#layout div.widget#BlogSearch1 div.widget-content {
  background: linear-gradient(#fff, #e8ffff);
}

Labels: , , ,

Saturday, July 6, 2019

Kreatif dengan Tag Kondisional pada Widget HTML Blogger

Sebuah widget berjenis HTML pada tema Blogger dapat Anda gunakan sebagai acuan dasar untuk memahami bagaimana cara kerja XML widget, terutama untuk para pengembang yang ingin membuat widget kustom dari kode sumber secara langsung. Berikut ini adalah sebuah contoh:

<b:section class='section-1' id='section-1' name='Bagian 1'>
  <b:widget id='HTML1' title='Judul Widget' type='HTML'>
    <b:widget-settings>
      <b:widget-setting name='content'>Konten widget.</b:widget-setting>
    </b:widget-settings>
    <b:includable id='main'>
      <h3><data:title/></h3>
      <div><data:content/></div>
    </b:includable>
  </b:widget>
</b:section>

Karena elemen <b:widget> harus berada di dalam elemen <b:section>, maka di sini Saya mengilustrasikannya sebagai sebuah widget HTML yang tersemat di dalam seksi bernama Bagian 1. Ketika kode tersebut diterjemahkan sebagai HTML, maka hasilnya akan menjadi tampak seperti ini:

<div class='section-1 section' id='section-1' name='Bagian 1'>
  <div class='widget HTML' data-version='2' id='HTML1'>
    <h3>Judul Widget</h3>
    <div>Konten widget.</div>
  </div>
</div>

Sedangkan pada halaman Tata Letak akan menjadi tampak seperti ini:

Bagian dalam widget Blogger.
Blok dengan judul Bagian 1 telah ditambahkan.

Jika Anda sunting widget tersebut melalui ikon pensil, maka Anda akan menyadari bahwa nilai data:content akan menempati bidang Konten di dalam formulir pengaturan widget. Sedangkan nilai atribut title pada elemen <b:widget> akan menempati bidang Judul (yang nilainya dapat kita tampilkan melalui data:title). Anda bisa memanfaatkan kedua elemen tersebut untuk mengubah perilaku widget berdasarkan nilainya.

Kode di bawah ini akan menampilkan markup HTML judul apabila data judul tidak kosong, dan akan menampilkan markup HTML konten apabila data konten tidak kosong:

<b:if cond='data:title != ""'>
  <h3><data:title/></h3>
</b:if>
<b:if cond='data:content != ""'>
  <div><data:content/></div>
</b:if>

Kode di bawah ini akan menampilkan markup HTML judul dan konten apabila data judul dan data konten tidak kosong:

<b:if cond='data:title != "" && data:content != ""'>
  <h3><data:title/></h3>
  <div><data:content/></div>
</b:if>

Kode di bawah ini akan menambahkan kelas HTML khusus berdasarkan kosong atau tidaknya data judul dan konten:

<div class='container'>

  <b:class cond='data:title != ""' name='has-title'/>
  <b:class cond='data:content != ""' name='has-content'/>

  <h3><data:title/></h3>
  <div><data:content/></div>

</div>

Kode di bawah ini akan menambahkan kelas HTML khusus berdasarkan nilai dari data judul secara spesifik:

<!-- https://getbootstrap.com/docs/4.3/components/alerts -->
<div class='alert' role='alert'>

  <b:comment>language: en</b:comment>
  <b:class cond='data:title in ["Danger", "Error"]' name='alert-danger'/>
  <b:class cond='data:title == "Info"' name='alert-info'/>
  <b:class cond='data:title == "Warning"' name='alert-warning'/>

  <b:comment>language: id</b:comment>
  <b:class cond='data:title in ["Bahaya", "Kesalahan"]' name='alert-danger'/>
  <b:class cond='data:title == "Informasi"' name='alert-info'/>
  <b:class cond='data:title == "Peringatan"' name='alert-warning'/>

  <h4 class='alert-heading'><data:title/></h4>
  <p class='mb-0'><data:content/></p>

</div>

Untuk manipulasi data yang lebih kompleks, Anda bisa memanfaatkan elemen <b:with> untuk mengubah sintaks objek valid yang tertulis di dalam bidang Konten sehingga nilainya dapat diperlakukan sebagai objek nyata di dalam XML widget dengan metode seperti ini.

Labels: , ,

Tuesday, June 25, 2019

Membuat Formulir Kontak dengan Google Drive

Tutorial kali ini merupakan tindak lanjut dari tutorial sejenis yang pernah Saya publikasikan sebelumnya di sini. Sebelum artikel tersebut ditandai sebagai artikel kadaluarsa, layanan Google Drive saat itu masih bernama Google Docs. Saya sempat berpikir untuk memperbarui artikel tersebut saja, tapi karena terdapat unsur historis pada artikel tersebut maka Saya memutuskan untuk membuat artikel yang baru saja.

Tutorial kali ini Saya harap akan jauh lebih mudah untuk diikuti karena di sini Anda tidak lagi membutuhkan ID spreadsheet untuk membuat formulir kontak bekerja. Tidak perlu panjang-panjang, kita langsung ke langkah-langkahnya saja ya!

Membuat Spreadsheet

Berbeda dari tutorial sebelumnya yang dimulai dengan membuat formulir baru, di sini Anda buat spreadsheet-nya terlebih dahulu. Spreadsheet ini nantinya akan kita gunakan sebagai basis-data untuk semua pesan yang berhasil dikirim. Buka https://drive.google.com/drive kemudian klik pada tombol Baru di pojok kiri atas. Pilih Google Spreadsheet kemudian pilih Spreadsheet kosong.

Membuat Spreadsheet Baru
Membuat spreadsheet baru.

Jendela baru akan terbuka untuk memuat editor spreadsheet dari Google. Setelah termuat, klik pada judulnya kemudian ubah namanya menjadi ‘Pesan Masuk’.

Mengganti nama spreadsheet.

Sekarang pilih menu Alat kemudian pilih Buat formulir.

Buat formulir baru.

Tunggu beberapa saat maka akan muncul tab baru di bagian bawah editor dengan label ‘Form Responses 1’.

Sheet baru dibuat secara otomatis.

Klik untuk mengaktifkan sheet tersebut! Anda boleh menghapus sheet sebelumnya karena itu tidak ada gunanya.

Formulir Anda sebenarnya sudah jadi, tapi masih belum berisi apa-apa kecuali satu bidang dengan label Timestamp dan satu bidang lagi yang hanya berfungsi sebagai contoh saja.

Menyunting Formulir

Pilih menu Formulir kemudian pilih Edit formulir. Maka jendela baru akan terbuka untuk memuat editor formulir.

Menyunting formulir.

Pada editor tersebut, hapus atau sunting bidang contoh, kemudian buat bidang-bidang baru dengan rincian seperti berikut:

  • Perihal
    • Tipe: Jawaban singkat
    • Wajib diisi: Ya
  • Nama
    • Tipe: Jawaban singkat
    • Wajib diisi: Ya
  • Surel
    • Tipe: Jawaban singkat
    • Wajib diisi: Ya
  • Situs Web
    • Tipe: Jawaban singkat
    • Wajib diisi: Tidak
  • Pesan
    • Tipe: Paragraf
    • Wajib diisi: Ya

Semua perubahan akan tersimpan secara otomatis.

Membuat Skrip Pemicu

Skrip ini nantinya akan bekerja setiap kali pesan dikirimkan melalui formulir terkait. Untuk membuatnya, pilih menu Alat kemudian pilih Editor skrip. Jendela baru akan terbuka untuk memuat editor skrip.

Membuka editor skrip.

Pada bidang Kode.gs, tempelkan kode ini:

function onFormSubmit(e) {
    GmailApp.sendEmail('you@example.com', 'Tes', JSON.stringify(e));
}

Simpan kode tersebut dengan nama ‘Kirim Pesan’.

Ganti kode yang Saya beri tanda dengan alamat surel Anda. Sekarang pilih menu yang tampak seperti simbol jam untuk mengaktifkan pemicu (biasanya bernama ‘Pemicu proyek saat ini’). Jendela baru akan terbuka untuk memuat halaman pemicu proyek.

Klik tombol Tambahkan Pemicu di pojok kanan bawah. Pada bidang Pilih fungsi yang ingin dijalankan pilih onFormSubmit (sesuai dengan nama fungsi yang kita buat sebelumnya). Pada bidang Pilih penerapan mana yang harus dijalankan pilih Head. Pada bidang Pilih sumber acara pilih Dari Spreadsheet. Pada bidang Pilih jenis acara pilih Saat mengirim formulir. Pada bidang Setelan notifikasi kegagalan ambil pilihan sesuai kebutuhan saja.

Setelah itu tekan tombol Simpan. Anda akan diminta untuk mengautentikasi pemicu tersebut melalui jendela munculan. Ikuti petunjuk yang ada, kemudian tekan tombol Izinkan di akhir tahapan.

Mengirim Pesan

Sekarang kita coba kirimkan pesan. Pilih menu Formulir kemudian pilih Buka formulir langsung. Jendela baru akan terbuka untuk memuat formulir publik Anda. Salin URL pada jendela tersebut untuk dibagikan nanti. Isi semua bidang yang ada kemudian tekan tombol Kirim untuk mengetes. Jika berhasil, maka Anda akan mendapatkan pesan masuk yang kurang lebihnya tampak seperti ini:

Pesan masuk.

Di situ akan tampak semua data yang telah kita kirimkan tadi. Untuk saat ini kita fokus ke bidang values dan namedValues saja. Kita pilih bidang namedValues karena bidang ini memiliki format {"key": "value"} yang lebih mudah untuk diproses.

Buka kembali editor skrip kemudian ubah fungsi onFormSubmit menjadi seperti ini:

function onFormSubmit(e) {
    var to = 'you@example.com',
        values = e.namedValues,
        key, value,
        body = "";
    for (key in values) {
        value = values[key];
        if (typeof value === "object" && value[0]) {
            value = value[0];
        }
        body += key + ': ' + value + '\n';
    }
    GmailApp.sendEmail(to, 'Pesan baru!', body.trim());
}

Simpan perubahan. Kemudian Anda coba kirim pesan lagi, maka format pesan yang masuk akan tampak lebih mudah dibaca sekarang!


Tingkat Lanjut

Mengirim HTML

Pada fungsi sebelumnya, setiap pesan yang dikirim akan diperlakukan sebagai data yang mentah, dimana karakter ganti baris akan diubah menjadi <br> dan tag-tag HTML yang lain akan dianggap sebagai teks biasa. Untuk mengirimkan kode HTML seperti apa adanya, Anda perlu mengosongkan bidang body kemudian ambil parameter berikutnya untuk menempatkan data pada bidang htmlBody agar data yang dikirimkan nantinya dapat dianggap sebagai kode HTML:

GmailApp.sendEmail(to, 'Pesan baru!', "", {
    htmlBody: body
});

Berikut ini adalah fungsi yang telah Saya modifikasi sedemikian rupa agar pesan yang masuk nantinya lebih nyaman untuk dibaca:

function onFormSubmit(e) {
    var to = 'you@example.com',
        values = e.namedValues,
        key, value,
        body = "";
    body += '<table style="width:100%;font-size:13px;font-family:sans-serif;line-height:1.5em;;background:#fff;color:#000;table-layout:fixed;border-collapse:separate;border-spacing:2px;">';
    body += '<tbody>';
    for (key in values) {
        value = values[key];
        if (typeof value === "object" && value[0]) {
            value = value[0];
        }
        // Ubah karakter `\n` menjadi `<br>`
        value = value.replace(/\n/g, '<br>');
        body += '<tr>';
        body += '<th style="font:inherit;font-size:100%;font-weight:bold;width:12em;background:#c3d9ff;padding:.5em 1em;vertical-align:top;text-align:right;">' + key + '</th>';
        body += '<td style="font:inherit;font-size:100%;background:#e0ecff;padding:.5em 1em;vertical-align:top;text-align:left;">' + value + '</td>';
        body += '</tr>';
    }
    body += '</tbody>';
    body += '</table>';
    GmailApp.sendEmail(to, values['Perihal'][0] || 'Pesan Baru!', "", {
        htmlBody: body
    });
}

Mengurutkan Data

Jika pesan yang terkirim tampak tidak sesuai dengan urutan yang seharusnya, Anda bisa mengatur data yang ditampilkan secara manual tanpa melalui pengulangan for:

values['Perihal'] && (body += 'Perihal: ' + values['Perihal'][0] + '\n');
values['Nama'] && (body += 'Nama: ' + values['Nama'][0] + '\n');
values['Surel'] && (body += 'Surel: ' + values['Surel'][0] + '\n');
values['Situs Web'] && (body += 'Situs Web: ' + values['Situs Web'][0] + '\n');
values['Pesan'] && (body += 'Pesan: ' + values['Pesan'][0]);

Atau seperti ini juga bisa:

var orders = ['Perihal', 'Nama', 'Surel', 'Situs Web', 'Pesan'],
    values = e.namedValues,
    key, value,
    body = "";
for (key in orders) {
    if (value = values[key = orders[key]]) {
        if (typeof value === "object" && value[0]) {
            value = value[0];
        }
        body += key + ': ' + value + '\n';
    }
}

Bidang Perihal sebagai Kategori

Anda bisa memanfaatkan fitur editor formulir untuk membatasi bidang yang ada agar hanya bisa diisi oleh nilai-nilai tertentu saja, misalnya dengan memilih tipe bidang Pilihan ganda.

Validasi Alamat Surel

Klik menu tambahan di samping sakelar Wajib diisi kemudian pilih Validasi respons. Pada pilihan Panjang ganti nilainya menjadi Ekspresi reguler (Anda menggunakan Panjang untuk menentukan batasan panjang pesan yang dikirimkan). Dan pada pilihan tambahan di sampingnya ganti nilainya dari Berisi menjadi Kecocokan. Pada bidang Pola, isi dengan ekspresi reguler yang cocok dengan alamat surel (tanpa awalan / dan akhiran /), misalnya seperti ini. Pada bidang Teks kesalahan khusus, isi dengan ‘Pola alamat surel tidak valid.’

Anda juga bisa menerapkan ini pada bidang Situs Web.

Labels: , , ,

Thursday, January 17, 2019

Fungsi Pembulatan pada XML Blogger

Pembulatan angka ke bawah:

<b:with value='5.2857' var='input'>
  <b:comment>Convert 5.2857 to 5.0000</b:comment>
  <b:with value='data:input - data:input % 1' var='output'>
    <b:eval expr='data:output'/>
  </b:with>
</b:with>

Referensi: https://www.facebook.com/igoynawamreh/posts/792777201056202

Labels: ,

Tuesday, September 25, 2018

Menambahkan Fitur Paginasi di dalam Artikel dengan JavaScript

Fitur Paginasi di dalam Artikel Blogger
Fitur paginasi di dalam artikel.

Fitur ini merupakan implementasi JavaScript dari plugin Mecha bernama Next yang berfungsi untuk memotong konten artikel menjadi beberapa bagian sehingga pengunjung dapat diajak untuk membaca konten artikel langkah demi langkah.

Lihat Demo


Integrasi Widget ke Blogger

Untuk menambahkan fitur ini di blog, pertama-tama buka editor HTML tema Anda kemudian temukan kode yang tampak kurang lebih seperti ini:

<b:widget id='Blog1' type='Blog'>

Pada bagian bawah kode tersebut, sisipkan kode ini:

<b:includable id='postTypeNext' var='post'>
  <b:if cond='data:view.isSingleItem and data:post.labels any (i => i.name in ["Next", "Steps", "How-To", "Berikutnya", "Langkah-Langkah", "Bagaimana-Cara", "type:next"])'>
    <b:class name='type:next'/>
    <script src='//dte-project.github.io/blogger/next.min.js'></script>
  </b:if>
</b:includable>

Kemudian cari kode ini:

<data:post.body/>

Pada setiap kode yang Anda temukan, sisipkan kode ini di bawahnya:

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

Klik Simpan Tema. Fitur paginasi artikel sekarang sudah siap untuk digunakan! Yang perlu Anda lakukan berikutnya adalah menambahkan label Langkah-Langkah atau Bagaimana-Cara atau Steps atau How-To pada artikel yang Anda inginkan.

Untuk menandai bagian-bagian yang perlu dipotong, tambahkan komentar <!-- next --> pada baris yang ingin Anda potong di dalam artikel. Pastikan Anda sedang berada pada mode HTML saat menyunting:

<p>Halaman 1</p>
<!-- next -->
<p>Halaman 2</p>
<!-- next -->
<p>Halaman 3</p>
<!-- next -->
<p>Halaman 4</p>
<!-- next -->
<p>Dan seterusnya.</p>

Jika para pembaca artikel Anda dapat dipastikan menggunakan peramban dengan JavaScript yang aktif, maka akan lebih efektif jika Anda mengaktifkan fitur pramuat gambar pada plugin ini. Cara mengaktifkan fitur pramuat gambar adalah dengan mengubah atribut src pada elemen <img> menjadi data-src sehingga gambar-gambar yang ada tidak akan dimuat sebelum potongan halaman yang berisi gambar tersebut dibuka oleh pembaca:

Sebelum

<img alt="" src="path/to/image.jpg">

Sesudah

<img alt="" src="loading.png" data-src="path/to/image.jpg">

Ganti bagian yang Saya beri tanda dengan URL gambar berukuran kecil, atau jika dirasa kurang praktis, Anda bisa menghapus atribut src pada gambar tersebut.

Pengaturan

Opsi Keterangan
hash Merupakan format fragmen URL untuk menandai pergantian halaman. Pola %i% pada !page=%i% akan diubah menjadi nomor halaman.
kin Digunakan untuk menentukan banyaknya kerabat tombol angka halaman yang akan ditampilkan sebelum dan setelah tombol angka halaman yang aktif.
top Jarak perhentian tambahan antara bagian atas layar halaman dengan bagian atas konten artikel setiap kali halaman berganti.
text Label-label yang diperlukan pada artikel. text[first] untuk menampilkan teks First, text[previous] untuk menampilkan teks Previous, text[next] untuk menampilkan teks Next, text[last] untuk menampilkan teks Last, dan text[current] untuk menampilkan teks Page 1 of 20.

Parameter-parameter di atas dapat Anda tambahkan sebagai parameter URL setelah nama berkas next.min.js:

<script src="next.min.js?top=20"></script>

Labels: , ,

Wednesday, September 19, 2018

Menambahkan Fitur AJAX Penelusuran di Blog

Fitur AJAX Penelusuran di Blogger
Fitur kotak penelusuran AJAX di blog.

Artikel ini merupakan hasil akumulasi dari temuan-temuan Saya tentang bagaimana kita bisa menggunakan JSON Blogger untuk menciptakan fitur penelusuran dinamis hanya dengan memanfaatkan parameter q pada tautan umpan. Fitur ini dapat diterapkan pada semua tema dan tidak bergantung pada apapun.

Lihat Demo


Integrasi Widget ke Blogger

Untuk mengaktifkan fitur penelusuran AJAX pada blog, Anda tidak perlu menambahkan markup HTML apapun ke dalam tema, karena widget ini akan menggunakan kotak penelusuran yang ada sebagai kotak penelusuran AJAX. Yang perlu Anda lakukan hanya menambahkan sebuah elemen halaman HTML/JavaScript dengan konten berupa kode ini:

<script src="//dte-project.github.io/blogger/search.min.js?live=true"></script>

Klik Simpan Setelan. Fitur penelusuran AJAX sekarang sudah siap untuk digunakan!

Jika kotak penelusuran AJAX tidak bekerja, mungkin itu karena Anda menambahkan widget ini sebelum widget kotak penelusuran. Untuk membuatnya bisa bekerja, Anda perlu meletakkan widget ini setelah widget kotak penelusuran. Selengkapnya bisa dibaca di sini.

Pengaturan

Opsi Keterangan
live Jika bernilai false, maka pengguna perlu mengeklik tombol Telusuri pada formulir atau menekan tombol Enter pada papan ketik untuk memulai penelusuran.
url Ganti nilainya dengan alamat blog Anda atau alamat blog orang lain yang ingin Anda tampilkan kontennya.
id Alternatif untuk menentukan sumber data selain dengan url. Ganti nilainya dengan ID blog Anda atau ID blog orang lain yang ingin Anda tampilkan kontennya. ID harus dituliskan sebagai string. Menambahkan parameter id akan mengabaikan nilai parameter url. Contoh: id="4890949828965961610"
direction Direksi teks pada blog Anda. Nilainya bisa berupa "ltr" atau "rtl".
source Selektor CSS untuk menentukan formulir kotak penelusuran yang ingin dijadikan sebagai kotak penelusuran AJAX. Menghilangkan parameter ini akan membuat widget secara otomatis menyeleksi elemen formulir pertama yang ditemukan yang memiliki nilai atribut action berupa /search pada bagian akhir. Anda bisa menentukan target yang lebih spesifik, misalnya source=%23BlogSearch1%20form untuk menyeleksi elemen formulir pada widget kotak penelusuran yang memiliki ID #BlogSearch1.
container Selektor CSS untuk menentukan di mana hasil penelusuran akan ditampilkan. Menghilangkan parameter ini akan membuat widget secara otomatis menampilkan hasil penelusuran tepat di bawah formulir penelusuran. [demo]
excerpt Ganti nilainya menjadi true untuk menampilkan ringkasan artikel. Atau gunakan angka untuk menentukan maksimal karakter yang akan ditampilkan dalam ringkasan artikel sebelum diakhiri oleh karakter .
image Ganti nilainya menjadi true untuk menampilkan gambar artikel. Atau gunakan angka untuk menentukan ukuran lebar dan tinggi gambar. Anda juga bisa menggunakan parameter standar gambar Google untuk memanipulasi ukuran, seperti "s100", "s100-c", dan "w100-h50".
target Jika bernilai "_blank", semua tautan akan terbuka di tab/jendela baru saat diklik.
chunk Digunakan untuk menentukan banyaknya hasil temuan yang ditampilkan dalam satu kali penelusuran.
text Label-label yang diperlukan pada tampilan penelusuran.

Parameter-parameter di atas dapat Anda tambahkan sebagai parameter URL setelah nama berkas search.min.js:

<script src="search.min.js?live=true&amp;chunk=100&amp;text[loading]=Memuat%E2%80%A6"></script>

Labels: , ,

Thursday, September 6, 2018

Menghilangkan CSS dan JavaScript Bawaan Blogger

Pembaharuan sintaks Blogger yang sekarang memungkinkan kita mencegah mesin Blogger untuk menyisipkan kode CSS dan JavaScript bawaan ke dalam hasil keluaran HTML tema. Caranya adalah dengan menambahkan atribut b:css dan b:js dengan nilai false.

<html b:css='false' b:js='false'> … </html>

Namun satu hal yang perlu diingat bahwa beberapa fitur bawaan yang bekerja dengan JavaScript mungkin tidak akan bisa bekerja karena perubahan ini. Fitur-fitur tersebut di antaranya adalah fitur balas komentar, fitur buka-tutup pada widget arsip hierarki, fitur formulir kontak, dan juga fitur ini.

Labels: , , ,

Mengakses Tag Kondisional Halaman Blogger di dalam JavaScript

Widget Manager
_WidgetManager._GetAllData()
document.addEventListener("DOMContentLoaded", function() {
    if (typeof _WidgetManager === "undefined") return;
    var data = _WidgetManager._GetAllData();
    // Lakukan sesuatu dengan `data` di sini …
}, false);

Contoh

if (data.view.isSingleItem) { … }
if (data.view.type === "item") { … }
var url = data.view.url;

Labels: , , ,

Wednesday, September 5, 2018

Menambahkan Fitur Komik di Blog dengan JavaScript

Fitur Komik di Blogger
Fitur komik di blog.

Artikel ini merupakan tindak lanjut dari berbagai permintaan pengguna yang mereka tambahkan pada artikel ini yang membahas tentang bagaimana caranya agar gambar-gambar di dalam komik web dapat dimuat secara bergantian untuk mengurangi beban muat halaman. Setelah sekian lama akhirnya Saya punya waktu juga untuk membuat widget yang lebih baik dengan beberapa fitur tambahan, dan yang paling penting adalah widget ini tidak lagi tergantung pada .

Lihat Demo


Integrasi Widget ke Blogger

Untuk menambahkan fitur komik di blog, pertama-tama buka editor HTML tema Anda kemudian temukan kode yang tampak kurang lebih seperti ini:

<b:widget id='Blog1' type='Blog'>

Pada bagian bawah kode tersebut, sisipkan kode ini:

<b:includable id='postTypeComic' var='post'>
  <b:if cond='data:view.isSingleItem and data:post.labels any (i => i.name in ["Comic", "Komik", "type:comic"])'>
    <b:class name='type:comic'/>
    <script src='//dte-project.github.io/blogger/comic.min.js?save=false'></script>
  </b:if>
</b:includable>

Kemudian cari kode ini:

<data:post.body/>

Pada setiap kode yang Anda temukan, sisipkan kode ini di bawahnya:

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

Klik Simpan Tema. Fitur komik sekarang sudah siap untuk digunakan! Yang perlu Anda lakukan berikutnya adalah membuat artikel-artikel baru berisi gambar-gambar, setelah itu cukup tambahkan label Komik atau Comic untuk mengaktifkan tampilan komik.

Widget ini akan mencari semua elemen <a> dan <img> di dalam artikel yang memiliki label Komik atau Comic dan akan mengambil nilai atribut href dan src pada elemen tersebut untuk dijadikan sebagai daftar antrean gambar. Khusus pada nilai atribut href pada elemen <a>, widget ini hanya akan mengambil tautan yang tampak sebagai tautan gambar, yaitu yang memiliki akhiran berupa ekstensi GIF, JPEG, JPG dan PNG.

Selain dari itu akan dianggap sebagai sinopsis atau ringkasan mengenai isi komik.

Saya perlu menambahkan alternatif berupa elemen <a> sebagai penyimpan tautan gambar karena dengan hanya mengandalkan elemen <img>, sama saja dengan meminta peramban untuk memuat semua gambar yang ada saat artikel sedang memuat. Meskipun nantinya ketika komik ditampilkan, gambar-gambar yang ada akan muncul secara bergantian, namun di balik layar sebenarnya peramban akan memuat semua gambar yang ada.

Oleh karena itu Saya sarankan untuk membuat artikel bertipe komik yang terdiri dari satu gambar saja yaitu gambar sampul komik. Sedangkan gambar-gambar yang lainnya dapat Anda tampilkan sebagai tautan biasa seperti ini:

<p>In every class, it’s not usual for there to be one or two people who seem a little strange. In Oda’s class, there is Hototogi.</p>
<p><img alt="Cover" title="Page 1" src="/path/to/image/1.png"></p>
<p><a href="/path/to/image/2.png">Page 2</a></p>
<p><a href="/path/to/image/3.png">Page 3</a></p>
<p><a href="/path/to/image/4.png">Page 4</a></p>
<p><a href="/path/to/image/5.png">Page 5</a></p>
<p><a href="/path/to/image/6.png">Page 6</a></p>
<p><a href="/path/to/image/7.png">Page 7</a></p>

Untuk memperoleh waktu muat komik yang paling cepat, Anda bisa menghapus semua gambar yang ada dan menggantinya dengan elemen <a>, namun kekurangannya adalah nanti Anda tidak akan memiliki elemen <data:post.thumbnailUrl/> untuk ditampilkan sebagai keluku artikel.

Pengaturan

Opsi Keterangan
hash Merupakan format fragmen URL untuk menandai pergantian halaman. Pola %i% pada !page=%i% akan diubah menjadi nomor halaman. [demo]
save Pilihan untuk memungkinkan para pembaca menyimpan gambar komik Anda dengan cara klik kanan pada gambar. Ganti nilainya menjadi false untuk melarang pembaca menyimpan gambar-gambar komik Anda.
image Resolusi maksimal gambar komik yang Anda simpan di Google berupa angka. [demo]
chunk Pilihan untuk menampilkan beberapa gambar sekaligus dalam satu lompatan halaman. Nilai bawaan adalah 1. Jika Anda mengubah nilainya menjadi 2, maka setiap halaman komik akan menampilkan dua gambar. [demo]
kin Digunakan untuk menentukan banyaknya kerabat tombol angka halaman yang akan ditampilkan sebelum dan setelah tombol angka halaman yang aktif.
top Jarak perhentian tambahan antara bagian atas layar halaman dengan bagian atas area komik setiap kali halaman berganti. [demo]
text Label-label yang diperlukan pada komik. text[first] untuk menampilkan teks First, text[previous] untuk menampilkan teks Previous, text[next] untuk menampilkan teks Next, text[last] untuk menampilkan teks Last, text[current] untuk menampilkan teks Page 1 of 20, dan text[enter] untuk menampilkan teks Read on….

Parameter-parameter di atas dapat Anda tambahkan sebagai parameter URL setelah nama berkas comic.min.js:

<script src="comic.min.js?save=false&amp;chunk=2&amp;text[enter]=Read%20More"></script>

Beberapa tema seperti 000000.min.css dan ffffff.min.css dapat Anda tambahkan seperti ini:

  …
  …
  <link href='//dte-project.github.io/blogger/comic/000000.min.css' rel='stylesheet'/>
</head>

Labels: , , ,

Saturday, September 1, 2018

Gawai Daftar Isi Akordion untuk Blogger

Pembaruan 2018/09/01: Berbagai perubahan dan fitur baru telah ditambahkan untuk memenuhi saran dan permintaan para pengguna. Beberapa diskusi yang terdapat di dalam ruang komentar mungkin sudah tidak relevan lagi dengan isi artikel.

Gawai Daftar Isi Akordion untuk Blogger

Kali ini Saya akan memperkenalkan gawai daftar isi akordion berdasarkan label setelah sebelumnya Saya pernah menuliskan tentang gawai daftar isi akordion berdasarkan bulan terbit:

Lihat Demo


Integrasi Gawai ke Blogger

Memasang widget ini memerlukan kemampuan dasar dalam membaca dan menulis kode HTML. Jika Anda termasuk kategori penulis blog yang masih bergantung pada perangkat tulis WYSIWYG atau pada mode Compose di editor Blogger, mungkin Anda perlu mempelajari dasar-dasar penulisan kode HTML terlebih dahulu sebelum menerapkan gawai ini. Sebuah blog dari Niagahoster menyediakan tutorial dasar tentang pemahaman kode HTML untuk pemula dimulai dari persiapan alat hingga pengenalan berbagai tag dan atribut HTML dasar, terutama yang sangat umum dijumpai di dalam konten sebuah artikel seperti format judul, efek huruf tebal dan miring, serta penjelasan tentang cara menyisipkan tautan dan gambar. Anda bisa membacanya di halaman Belajar HTML.

Pertama-tama klik menu Laman pada bilah sisi. Kemudian, pada menu Laman Baru pilihlah Laman Kosong:

Blogger Post Editor
Menambahkan halaman statis baru.

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

Blogger Post Editor
Memilih mode HTML.

Salin kode di bawah ini kemudian letakkan di dalam formulirnya:

<link href="//dte-project.github.io/blogger/stacked-toc/248ab0.min.css" rel="stylesheet">
<script src="//dte-project.github.io/blogger/stacked-toc.min.js?url=http://dte-feed.blogspot.com&amp;active=0"></script>

Ganti URL yang Saya beri tanda dengan alamat blog kamu kemudian klik tombol Publikasikan.

Menghilangkan parameter url akan membuat gawai ini secara otomatis menentukan URL halaman muka berdasarkan URL pada bilah alamat. Berkas 248ab0.min.css adalah berkas tema. Kamu bisa menghapus berkas tersebut jika kamu ingin membuat tema sendiri:

<style>
/* Kode tema kustom di sini… */
</style>
<script src="//dte-project.github.io/blogger/stacked-toc.min.js?active=0"></script>

Pengaturan

Opsi Keterangan
url Ganti nilainya dengan alamat blog kamu atau alamat blog orang lain yang ingin kamu tampilkan kontennya.
id Alternatif untuk menentukan sumber data selain dengan url. Ganti nilainya dengan ID blog kamu atau ID blog orang lain yang ingin kamu tampilkan kontennya. ID harus dituliskan sebagai string. Menambahkan parameter id akan mengabaikan nilai parameter url. Contoh: id="4890949828965961610"
direction Direksi teks pada blog kamu. Nilainya bisa berupa "ltr" atau "rtl".
container Selektor CSS untuk menentukan di mana gawai akan ditampilkan. Menghilangkan parameter ini akan membuat gawai secara otomatis menempatkan diri tepat sebelum tag <script> yang kamu sisipkan.
active Digunakan untuk menentukan urutan panel yang akan aktif saat pertama kali halaman dimuat. Nilai 0 akan membuat panel di urutan pertama menjadi aktif. Nilai "Musim Gugur" akan membuat panel dengan label Musim Gugur menjadi aktif.
toggle Digunakan untuk menentukan sifat panel ketika diklik. Menentukan nilai true akan membuat panel yang aktif menutup dirinya sendiri ketika kamu mengeklik panel tersebut, atau ketika kamu mengeklik panel yang lainnya. Menentukan nilai false akan membuat panel yang aktif menutup hanya ketika kamu mengeklik panel yang lainnya. Menentukan nilai -1 akan membuat panel yang aktif menutup dirinya sendiri hanya ketika kamu mengeklik panel tersebut; panel-panel yang lain tidak akan terpengaruh.
hide Tentukan nama-nama label yang tidak ingin kamu tampilkan.
date Ganti nilainya menjadi false untuk menyembunyikan waktu penerbitan artikel. Selain itu akan dianggap sebagai format waktu penerbitan: %Y% untuk menampilkan angka tahun, %M% untuk menampilkan angka bulan, %D% untuk menampilkan angka hari, %h% untuk menampilkan angka jam format 12, %m% untuk menampilkan angka menit, %s% untuk menampilkan angka detik, %M~% untuk menampilkan nama bulan, %D~% untuk menampilkan nama hari, %h~% untuk menampilkan angka jam format 24, dan %N% untuk menampilkan keterangan waktu format 12; nilainya bisa berupa "AM" atau "PM" tergantung dari data text[midday].
excerpt Ganti nilainya menjadi true untuk menampilkan ringkasan artikel. Atau gunakan angka untuk menentukan maksimal karakter yang akan ditampilkan dalam ringkasan artikel sebelum diakhiri oleh karakter .
image Ganti nilainya menjadi true untuk menampilkan gambar artikel. Atau gunakan angka untuk menentukan ukuran lebar dan tinggi gambar. Kamu juga bisa menggunakan parameter standar gambar Google untuk memanipulasi ukuran, seperti "s100", "s100-c", dan "w100-h50".
target Jika bernilai "_blank", semua tautan akan terbuka di tab/jendela baru saat diklik.
load Digunakan untuk menentukan waktu penundaan pemuatan JSON. Tentukan sebagai angka untuk waktu penundaan memuat dalam satuan milidetik atau true agar gawai ini memuat setelah keseluruhan halaman telah selesai termuat.
sort false untuk menyortir artikel secara normal berdasarkan bulan terbit, 1 untuk menyortir artikel dari A ke Z, -1 untuk menyortir artikel dari Z ke A.
recent false untuk menyembunyikan tanda New!. Ganti dengan angka untuk menentukan berapa banyak artikel terbaru yang ingin ditandai dengan label New!.
text[recent] Markup HTML bebas untuk membuat label New! pada artikel-artikel terbaru.
text[months] Digunakan untuk menentukan nama-nama bulan sesuai dengan sistem kalender di negara tempat kamu tinggal.
text[days] Digunakan untuk menentukan nama-nama hari sesuai dengan sistem kalender di negara tempat kamu tinggal.

Contoh

Menampilkan gambar dan ringkasan:

<script src="stacked-toc.min.js?excerpt=200&amp;image=80"></script>

Membuat panel ke tiga aktif saat pertama kali halaman dimuat:

<script src="stacked-toc.min.js?active=2"></script>

Membuat panel dengan label Iklan aktif saat pertama kali halaman dimuat:

<script src="stacked-toc.min.js?active=Iklan"></script>

Menyembunyikan panel dengan label Iklan dan Tautan:

<script src="stacked-toc.min.js?hide=["Iklan","Tautan"]"></script>
<script src="stacked-toc.min.js?hide[0]=Iklan&amp;hide[1]=Tautan"></script>

Memodifikasi format waktu penerbitan (karakter % harus diubah menjadi %25):

<script src="stacked-toc.min.js?date=%25Y%25-%25M%25-%25D%25%20%25h%25%3A%25m%25%3A%25s%25"></script>

Menentukan kontainer spesifik (karakter # harus diubah menjadi %23):

<script src="stacked-toc.min.js?container=%23content"></script>

Kemudian, pada suatu tempat, Anda buat elemen HTML seperti ini:

<div id="content"></div>

Gunakan alat ini untuk mempermudah dalam mengubah karakter mentah menjadi karakter yang aman untuk URL.


Animasi

Fitur animasi pada gawai ini sudah tidak lagi dibuat menggunakan API jQuery, melainkan hanya memanfaatkan fitur CSS3 transisi. Kamu bisa memodifikasi kecepatan dan percepatan animasi dengan cara seperti ini:

<style>
.stacked-toc-panel {
  /* `ease-in-out-quart` */
  -webkit-transition-timing-function: cubic-bezier(.77, 0, .18, 1);
  -moz-transition-timing-function: cubic-bezier(.77, 0, .18, 1);
  transition-timing-function: cubic-bezier(.77, 0, .18, 1);
  /* ½ detik */
  -webkit-transition-duration: .5s;
  -moz-transition-duration: .5s;
  transition-duration: .5s;
}
</style>
<script src="stacked-toc.min.js?active=0"></script>

Contoh

Labels: , ,

Tuesday, August 14, 2018

Gawai Daftar Isi Tabulasi untuk Blogger

Pembaruan 2018/08/13: Berbagai perubahan dan fitur baru telah ditambahkan untuk memenuhi saran dan permintaan para pengguna. Beberapa diskusi yang terdapat di dalam ruang komentar mungkin sudah tidak relevan lagi dengan isi artikel.

Widget Daftar Isi Tabulasi untuk Bogger

Berikut ini adalah sebuah gawai daftar isi blog berbentuk tabulasi. Gawai ini terdiri dari dua bilah sisi berupa daftar label dan daftar artikel. Setiap nama label akan menjadi tab, sedangkan daftar artikel akan menjadi panel tab yang akan tampil setiap kali tab diklik:

Lihat Demo


Integrasi Gawai ke Blogger

Pertama-tama klik menu Laman pada bilah sisi. Kemudian, pada menu Laman Baru pilihlah Laman Kosong:

Blogger Post Editor
Menambahkan halaman statis baru.

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

Blogger Post Editor
Memilih mode HTML.

Salin kode di bawah ini kemudian letakkan di dalam formulirnya:

<link href="//dte-project.github.io/blogger/tabbed-toc/224c19.min.css" rel="stylesheet">
<script src="//dte-project.github.io/blogger/tabbed-toc.min.js?url=http://dte-feed.blogspot.com&amp;active=0"></script>

Ganti URL yang Saya beri tanda dengan alamat blog Anda kemudian klik tombol Publikasikan.

Menghilangkan parameter url akan membuat gawai ini secara otomatis menentukan URL halaman muka berdasarkan URL pada bilah alamat. Berkas 224c19.min.css adalah berkas tema. Kamu bisa menghapus berkas tersebut jika kamu ingin membuat tema sendiri:

<style>
/* Kode tema kustom di sini… */
</style>
<script src="//dte-project.github.io/blogger/tabbed-toc.min.js?active=0"></script>

Pengaturan

Opsi Keterangan
url Ganti nilainya dengan alamat blog kamu atau alamat blog orang lain yang ingin kamu tampilkan kontennya.
id Alternatif untuk menentukan sumber data selain dengan url. Ganti nilainya dengan ID blog kamu atau ID blog orang lain yang ingin kamu tampilkan kontennya. ID harus dituliskan sebagai string. Menambahkan parameter id akan mengabaikan nilai parameter url. Contoh: id="4890949828965961610"
direction Direksi teks pada blog kamu. Nilainya bisa berupa "ltr" atau "rtl".
container Selektor CSS untuk menentukan di mana gawai akan ditampilkan. Menghilangkan parameter ini akan membuat gawai secara otomatis menempatkan diri tepat sebelum tag <script> yang kamu sisipkan.
active Digunakan untuk menentukan urutan tab yang akan aktif saat pertama kali halaman dimuat. Nilai 0 akan membuat tab di urutan pertama menjadi aktif. Nilai "Musim Gugur" akan membuat tab dengan label Musim Gugur menjadi aktif.
hide Tentukan nama-nama label yang tidak ingin kamu tampilkan.
date Ganti nilainya menjadi false untuk menyembunyikan waktu penerbitan artikel. Selain itu akan dianggap sebagai format waktu penerbitan: %Y% untuk menampilkan angka tahun, %M% untuk menampilkan angka bulan, %D% untuk menampilkan angka hari, %h% untuk menampilkan angka jam format 12, %m% untuk menampilkan angka menit, %s% untuk menampilkan angka detik, %M~% untuk menampilkan nama bulan, %D~% untuk menampilkan nama hari, %h~% untuk menampilkan angka jam format 24, dan %N% untuk menampilkan keterangan waktu format 12; nilainya bisa berupa "AM" atau "PM" tergantung dari data text[midday].
excerpt Ganti nilainya menjadi true untuk menampilkan ringkasan artikel. Atau gunakan angka untuk menentukan maksimal karakter yang akan ditampilkan dalam ringkasan artikel sebelum diakhiri oleh karakter .
image Ganti nilainya menjadi true untuk menampilkan gambar artikel. Atau gunakan angka untuk menentukan ukuran lebar dan tinggi gambar. Kamu juga bisa menggunakan parameter standar gambar Google untuk memanipulasi ukuran, seperti "s100", "s100-c", dan "w100-h50".
target Jika bernilai "_blank", semua tautan akan terbuka di tab/jendela baru saat diklik.
load Digunakan untuk menentukan waktu penundaan pemuatan JSON. Tentukan sebagai angka untuk waktu penundaan memuat dalam satuan milidetik atau true agar gawai ini memuat setelah keseluruhan halaman telah selesai termuat.
sort false untuk menyortir artikel secara normal berdasarkan bulan terbit, 1 untuk menyortir artikel dari A ke Z, -1 untuk menyortir artikel dari Z ke A.
recent false untuk menyembunyikan tanda New!. Ganti dengan angka untuk menentukan berapa banyak artikel terbaru yang ingin ditandai dengan label New!.
text[recent] Markup HTML bebas untuk membuat label New! pada artikel-artikel terbaru.
text[months] Digunakan untuk menentukan nama-nama bulan sesuai dengan sistem kalender di negara tempat kamu tinggal.
text[days] Digunakan untuk menentukan nama-nama hari sesuai dengan sistem kalender di negara tempat kamu tinggal.

Contoh

Menampilkan gambar dan ringkasan:

<script src="tabbed-toc.min.js?excerpt=200&amp;image=80"></script>

Membuat tab ke tiga aktif saat pertama kali halaman dimuat:

<script src="tabbed-toc.min.js?active=2"></script>

Membuat tab dengan label Iklan aktif saat pertama kali halaman dimuat:

<script src="tabbed-toc.min.js?active=Iklan"></script>

Menyembunyikan tab dengan label Iklan dan Tautan:

<script src="tabbed-toc.min.js?hide=["Iklan","Tautan"]"></script>
<script src="tabbed-toc.min.js?hide[0]=Iklan&amp;hide[1]=Tautan"></script>

Memodifikasi format waktu penerbitan (karakter % harus diubah menjadi %25):

<script src="tabbed-toc.min.js?date=%25Y%25-%25M%25-%25D%25%20%25h%25%3A%25m%25%3A%25s%25"></script>

Menentukan kontainer spesifik (karakter # harus diubah menjadi %23):

<script src="tabbed-toc.min.js?container=%23content"></script>

Kemudian, pada suatu tempat, Anda buat elemen HTML seperti ini:

<div id="content"></div>

Gunakan alat ini untuk mempermudah dalam mengubah karakter mentah menjadi karakter yang aman untuk URL.

Menyembunyikan iklan:

<script src="tabbed-toc.min.js?ad=false"></script>

Gawai ini Saya buat sebagai kode sumber yang terbuka sehingga Saya pada dasarnya tidak menghasilkan keuntungan apa-apa secara finansial. Ada baiknya kamu bersedia membantu Saya untuk menyebarkan alamat web ini dengan cara tidak menentukan nilai parameter ad sebagai false atau dengan cara berinisiatif memasang iklan pada web ini. Dengan begitu Saya dapat terus termotivasi untuk mengembangkan gawai-gawai yang ada. Menentukan nilai berupa angka akan membuat tautan web ini muncul setiap N sekali dimana N memiliki arti seberapa banyak pengunjung yang sama memuat ulang halaman kamu:

<script src="tabbed-toc.min.js?ad=10"></script>

Contoh

Labels: , ,

Parser JSON untuk Blogger · Tahun Awal dan Tahun Akhir

var url = 'http://dte-feed.blogspot.com/feeds/posts/summary?alt=json-in-script&callback=';

// Function to load a `<script>` tag without `document.write`
function load(url) {
    var script = document.createElement('script');
    script.src = url;
    document.head.appendChild(script);
}

// Get the first and last post year…
function getFirstAndLastYear($) {
    $ = $.feed || {};
    var entry = $.entry || [],
        range = {};
    // Get the first post year from `json.feed.entry[i].published.$t` value
    range[0] = entry[0] && +entry[0].published.$t.split('-')[0] || false;
    // Get the last post year from `json.feed.updated.$t` value
    range[1] = +$.updated.$t.split('-')[0];
    // [3]. Result will be available in the `range` variable as `[from, to]` format
    console.log(range);
    // You can now do stuff using the `range` variable start from here
    document.getElementById('blog-history').innerHTML = '\u00A9 Copyright ' + range[0] + ' \u2013 ' + range[1];
}

// Get the total posts…
function getTotalPosts($) {
    $ = $.feed || {};
    var i = $.openSearch$totalResults.$t,
        entry = $.entry || [];
    // [2]. Get the first and last post year…
    // Use the `max-results` and `start-index` parameter to limit the posts
    load(url + 'getFirstAndLastYear&max-results=1&start-index=' + i);
}

// [1]. Get the total posts…
load(url + 'getTotalPosts&max-results=0');

Labels: , , ,

Wednesday, August 1, 2018

Widget Menu Navigasi Blogger Dari Sumber Berupa Objek

Konsep ini merupakan salah satu penerapan dari artikel berikut sebagai salah satu cara untuk menyederhanakan sintaks HTML elemen navigasi sebagai objek:

<b:widget id='HTML1' title='Navigation' type='HTML' version='1'>
  <b:widget-settings>
    <b:widget-setting name='content'>[{
    name: "Home",
    path: "/"
}]</b:widget-setting>
  </b:widget-settings>
  <b:includable id='main'>
    <b:with expr:value='data:content' var='array'>
      <b:include data='array' name='nav'/>
    </b:with>
  </b:includable>
  <b:includable id='nav' var='array'>
    <nav class='nav' id='nav'>
      <b:include data='array' name='ul'/>
    </nav>
  </b:includable>
  <b:includable id='ul' var='array'>
    <b:if cond='data:array.size > 0'>
      <ul>
        <b:loop values='data:array' var='this'>
          <b:include data='this' name='li'/>
        </b:loop>
      </ul>
    </b:if>
  </b:includable>
  <b:includable id='li' var='this'>
    <li>
      <b:class cond='path(data:view.url, data:this.path) == data:view.url' name='active'/>
      <b:include data='this' name='a'/>
      <b:if cond='data:this.children'>
        <b:include data='this.children' name='ul'/>
      </b:if>
    </li>
  </b:includable>
  <b:includable id='a' var='this'>
    <b:if cond='data:this.path || data:this.link'>
      <a>
        <b:attr expr:value='data:this.path ? path(data:view.url, data:this.path) : data:this.link' name='href'/>
        <b:attr cond='data:this.title' expr:value='data:this.title' name='title'/>
        <b:attr cond='data:this.target' expr:value='data:this.target' name='target'/>
        <data:this.name/>
      </a>
    <b:else/>
      <span class='a'><data:this.name/></span>
    </b:if>
  </b:includable>
</b:widget>

Kode CSS menu navigasi dapat Anda ambil dari sumber mana saja, selama selektor CSS adalah berupa .nav atau #nav (misalnya dari sini). Atau, Anda juga bisa menambahkan kelas kustom seperti ini sebagai cara untuk menyesuaikan kode HTML dengan kode CSS menu navigasi yang Anda dapatkan:

<b:includable id='nav' var='array'>
  <nav class='nav superfish' id='nav'>
    <b:include data='array' name='ul'/>
  </nav>
</b:includable>

Penggunaan

Masuk ke editor HTML Templat, salin dan tempel kode XML di atas ke dalam area <b:section> … </b:section> kemudian simpan perubahan. Anda mungkin perlu mengubah ID widget yang Saya beri tanda dengan urutan angka yang lain untuk mencegah duplikat ID widget. Setelah itu masuk ke editor Tata Letak. Di situ seharusnya sudah bertambah satu buah widget bertipe HTML/JavaScript dengan judul Navigation. Klik tombol Edit!

Setiap item menu tersimpan di dalam kontainer. Berikut ini adalah contoh kontainer menu yang masih kosong:

[]

Kemudian kita tambahkan sebuah menu, sebut saja Beranda:

[{
    name: "Beranda",
    path: "/"
}]

Kemudian kita tambahkan sebuah menu lagi bernama Profil:

[{
    name: "Beranda",
    path: "/"
}, {
    name: "Profil",
    path: "p/tentang-saya.html"
}]

Untuk tautan eksternal, gunakan atribut url sebagai pengganti path:

[{
    name: "Beranda",
    path: "/"
}, {
    name: "Profil",
    url: "//about.me/ta.tau.taufik"
}]

Judul dan target tautan juga dapat ditentukan seperti ini:

[{
    name: "Profil",
    url: "//about.me/ta.tau.taufik",
    title: "Taufik Nurrohman",
    target: "_blank"
}]

Anak-anak menu dapat dibuat kembali pada atribut children dengan aturan yang sama seperti sebelumnya:

[{
    name: "Profil",
    children: [{
        name: "Facebook",
        url: "//www.facebook.com/ta.tau.taufik"
    }, {
        name: "Google+",
        url: "//plus.google.com/+TaufikNurrohman"
    }]
}]

Contoh Objek

[{
    name: "Home",
    path: "/"
}, {
    name: "About",
    path: "p/about.html",
    children: [{
        name: "About Me",
        path: "p/about.html"
    }, {
        name: "Advertise",
        path: "p/advertise.html",
        children: [{
            name: "Method 1",
            path: "p/advertise-1.html"
        }, {
            name: "Method 2",
            path: "p/advertise-2.html"
        }]
    }]
}, {
    name: "Archive",
    path: "p/archive.html"
}, {
    name: "Contact",
    link: "//www.facebook.com/ta.tau.taufik",
    title: "Facebook",
    target: "_blank"
}]

Labels: , ,

Tuesday, July 31, 2018

Widget HTML Blogger untuk Menyimpan Data Konfigurasi

Metode ini pertama kali Saya dapatkan dari Bung Frangki dimana beliau menggunakan bidang konten pada widget HTML sebagai tempat untuk menyimpan data konfigurasi. Widget tersebut adalah widget yang dibuat secara manual, bukan dengan cara menggunakan fitur antarmuka dari Blogger.

<b:widget id='HTML1' locked='true' title='Related Post' type='HTML' version='1'>
  <b:widget-settings>
    <b:widget-setting name='content'>numPosts: 6,
widgetStyle: 3,
summaryLength: 125</b:widget-setting>
  </b:widget-settings>
  <b:includable id='main'>
    <b:if cond='data:title != ""'>
      <h4 class='widget-title'><data:title/></h4>
    </b:if>
    <div class='widget-content'>
      <script>
      var relatedPostConfig = {<data:content/>};
      </script>
    </div>
  </b:includable>
</b:widget>

Sehingga pada hasil keluaran nantinya akan menjadi seperti ini:

<div class='widget HTML' data-version='1' id='HTML1'>
  <h4 class='widget-title'>Judul Widget</h4>
  <div class='widget-content'>
    <script>
    var relatedPostConfig = {
        numPosts: 6,
        widgetStyle: 3,
        summaryLength: 125
    };
    </script>
  </div>
</div>

Sekarang kita coba lihat kembali bagaimana tag <b:with> bekerja. Selain untuk menampilkan data berupa string, tag ini juga mampu menganggap string objek sebagai data objek. Sehingga jika kita menuliskan data konten sebagai objek Blogger dan menggunakan tag <b:with> sebagai konverternya, maka kita bisa menggunakan teks data konten tersebut sebagai data objek:

<b:widget id='HTML1' title='Profil' type='HTML' version='1'>
  <b:widget-settings>
    <b:widget-setting name='content'>{
    name: "Taufik Nurrohman",
    content: "&lt;p&gt;Saya adalah pemilik blog ini.&lt;/p&gt;",
    links: [{
        title: "Facebook",
        url: "//www.facebook.com/ta.tau.taufik"
    }, {
        title: "Google+",
        url: "//plus.google.com/+TaufikNurrohman"
    }]
}</b:widget-setting>
  </b:widget-settings>
  <b:includable id='main'>
    <b:if cond='data:title != ""'>
      <h4 class='widget-title'><data:title/></h4>
    </b:if>
    <div class='widget-content'>
      <b:with var='config' expr:value='data:content'>
        <h5><data:config.name/></h5>
        <div>
          <data:config.content/>
        </div>
        <h6>Links</h6>
        <b:if cond='data:config.links.size > 0'>
          <ul>
            <b:loop values='data:config.links' var='value'>
              <li><a expr:href='data:value.url'><data:value.title/></a></li>
            </b:loop>
          </ul>
        </b:if>
      </b:with>
    </div>
  </b:includable>
</b:widget>

Referensi: https://productforums.google.com/forum/#!topic/blogger/kIszC8MjUyg;context-place=forum/blogger

Labels: , ,

Wednesday, May 16, 2018

Mengecek Adanya Komentar Balasan pada Komentar Induk di Blogger

Mengingat kembali tentang bagaimana kita membedakan antara komentar induk dengan komentar balasan pada Blogger dapat kita lakukan dengan cara mengecek adanya properti var.inReplyTo pada item komentar yang dimaksud. Properti ini bertugas untuk menyimpan ID komentar induk:

<b:loop values='data:post.comments' var='comment'>
  <b:if cond='data:comment.inReplyTo'>
    <!-- `data:comment` adalah komentar balasan -->
  <b:else/>
    <!-- `data:comment` adalah komentar induk -->
  </b:if>
</b:loop>

Dari sini kita dapat melakukan iterasi ulang di dalam iterasi komentar induk, dan kemudian menyaring anak-anak komentar yang memiliki nilai properti var.inReplyTo (dalam hal ini adalah reply.inReplyTo) yang sama dengan parent.id (dalam hal ini adalah comment.id):

<b:loop values='data:post.comments' var='comment'>
  <b:if cond='!data:comment.inReplyTo'>
    <b:loop values='data:post.comments' var='reply'>
      <b:if cond='data:reply.inReplyTo == data:comment.id'>
        <!-- komentar balasan untuk `data:comment` akan tersedia di sini sebagai `data:reply` -->
      </b:if>
    </b:loop>
  </b:if>
</b:loop>

Ekspresi lambda (fungsi anonim) pada Blogger memungkinkan kita untuk melakukan penyaringan komentar-komentar balasan terhadap ID komentar induk dengan cara yang lebih cepat seperti ini, karena penyaringan data komentar dapat dilakukan sebelum proses iterasi dilakukan:

<b:loop values='data:post.comments' var='comment'>
  <b:if cond='!data:comment.inReplyTo'>
    <b:loop values='data:post.comments filter (i => i.inReplyTo == data:comment.id)' var='reply'>
      <!-- komentar balasan untuk `data:comment` akan tersedia di sini sebagai `data:reply` -->
    </b:loop>
  </b:if>
</b:loop>

Ada satu metode yang menarik dalam fungsi anonim Blogger yaitu metode count. Metode ini memungkinkan kita untuk menghitung jumlah item yang ada setelah proses bersyarat selesai diterapkan pada koleksi data. Sebagai contoh, kode di bawah ini akan menampilkan jumlah total komentar dengan nama penulis Taufik Nurrohman:

Jumlah komentar dari Taufik Nurrohman: <b:eval expr='data:post.comments count (i => i.author == "Taufik Nurrohman")'/>

Dalam bahasa pemrograman, kita dapat melakukan sesuatu seperti ini untuk menghitung jumlah komentar dari Taufik Nurrohman, yang mana ini tidak akan dapat kita lakukan pada Blogger sebelum adanya fitur fungsi anonim:

let i = 0;
post.comments.forEach(comment => {
    if (comment.author == 'Taufik Nurrohman') {
        ++i;
    }
});

console.log('Jumlah komentar dari Taufik Nurrohman: ' + i);

Metode count pada fungsi anonim akan lebih sesuai jika disamakan dengan metode filter dan properti length pada JavaScript seperti ini:

let i = post.comments.filter(i => i.author == 'Taufik Nurrohman').length;

console.log('Jumlah komentar dari Taufik Nurrohman: ' + i);

Cara Mengecek Apakah Komentar Induk Memiliki Komentar Balasan atau Tidak

Sebuah komentar dari seorang pembaca bernama Satank Mkr pada artikel Membuat Fitur Komentar Berbalas (Threaded Comments) pada Blogger dengan Fungsional yang Asli kurang lebih menanyakan tentang bagaimana caranya menambahkan elemen pembungkus khusus yang akan melingkupi seluruh komentar balasan, sehingga jika terdapat setidaknya satu buah komentar balasan di bawah komentar induk, maka komentar-komentar balasan tersebut akan dibungkus dengan elemen HTML tertentu. Berikut adalah ilustrasi yang beliau maksudkan:

<b:if cond='data:post.numberOfComments > 0'>
  <ul class='comments'>
    <b:loop values='data:post.comments' var='comment'>
      <li class='comment'> … </li>
    </b:loop>
  </ul>
</b:if>
<ul class="comments">
  <li class="comment"> … </li>
  <li class="comment"> … </li>
  <li class="comment"> … </li>
</ul>

Melihat pada contoh di atas, akan sangat mudah untuk menambahkan elemen pembungkus <ul class="comments"> karena Blogger memiliki properti numberOfComments pada data:post yang bertugas untuk menyimpan jumlah keseluruhan komentar yang ada. Akan tetapi, kita tidak memiliki properti khusus untuk menghitung jumlah komentar balasan melalui data:comment, sehingga untuk menentukan apakah sebuah komentar induk memiliki komentar balasan atau tidak akan mustahil tanpa adanya properti khusus; katakanlah var.numReplies seperti ini:

<b:if cond='data:post.numberOfComments > 0'>
  <ul class='comments'>
    <b:loop values='data:post.comments' var='comment'>
      <li class='comment'> … </li>
        <b:if cond='data:comment.numReplies > 0'>
          <ul class='comment-replies'>
            <b:loop values='data:post.comments filter (i => i.inReplyTo == data:comment.id)' var='reply'>
              <li class='reply'> … </li>
            </b:loop>
          </ul>
      </b:if>
    </b:loop>
  </ul>
</b:if>
<ul class="comments">
  <li class="comment"> … </li>
  <li class="comment"> … </li>
  <li class="comment">
    …
    <ul class='comment-replies'>
      <li class='reply'> … </li>
      <li class='reply'> … </li>
    </ul>
  </li>
  <li class="comment"> … </li>
</ul>

Metode count datang menyelamatkan! Karena metode ini mampu menghitung jumlah komentar yang ada setelah proses bersyarat diterapkan pada data komentar, maka kita dapat menghitung jumlah komentar balasan terkait dengan komentar induk dengan cara seperti ini:

<b:with var='numReplies' value='data:post.comments count (i => i.inReplyTo == data:comment.id)'>
  Jumlah komentar balasan: <data:numReplies/>
</b:with>

Untuk menerapkannya sebagai ekspresi kondisional di dalam iterasi komentar, kita bisa menuliskannya seperti ini:

<b:if cond='data:post.numberOfComments > 0'>
  <ul class='comments'>
    <b:loop values='data:post.comments' var='comment'>
      <li class='comment'> … </li>
        <b:with var='numReplies' value='data:post.comments count (i => i.inReplyTo == data:comment.id)'>
          <b:if cond='data:numReplies > 0'>
            <ul class='comment-replies'>
              <b:loop values='data:post.comments filter (i => i.inReplyTo == data:comment.id)' var='reply'>
                <li class='reply'> … </li>
              </b:loop>
            </ul>
          </b:if>
        </b:with>
      </b:if>
    </b:loop>
  </ul>
</b:if>

Atau seperti ini juga bisa:

<b:if cond='data:post.numberOfComments > 0'>
  <ul class='comments'>
    <b:loop values='data:post.comments' var='comment'>
      <li class='comment'> … </li>
        <b:with var='replies' value='data:post.comments filter (i => i.inReplyTo == data:comment.id)'>
          <b:if cond='data:replies.size > 0'>
            <ul class='comment-replies'>
              <b:loop values='data:replies' var='reply'>
                <li class='reply'> … </li>
              </b:loop>
            </ul>
          </b:if>
        </b:with>
      </b:if>
    </b:loop>
  </ul>
</b:if>

Labels: , ,