DTE :]

Wednesday, January 30, 2019

Kompresi Hasil Keluaran PHP `var_export` Tanpa Regex

Fungsi ini akan menghapus semua indentasi dan ganti baris pada hasil keluaran yang dihasilkan oleh PHP var_export untuk mengurangi alokasi memori penyimpanan data statis:

function minify_var_export($input) {
    if (is_array($input)) {
        $output = [];
        foreach ($input as $k => $v) {
            $output[] = var_export($k, true) . '=>' . minify_var_export($v);
        }
        return 'array(' . implode(',', $output) . ')';
    }
    return var_export($input, true);
}

Contoh Penggunaan

$test = [1, 2, ['a', 'b', 'c']];

$A = var_export($test, true);
$B = minify_var_export($test);

Hasil keluaran:

$A = array (
  0 => 1,
  1 => 2,
  2 => 
  array (
    0 => 'a',
    1 => 'b',
    2 => 'c',
  ),
);

$B = array(0=>1,1=>2,2=>array(0=>'a',1=>'b',2=>'c'));

Referensi

Labels: ,

Saturday, October 6, 2018

Lis Berkas dengan PHP `glob`

Kebanyakan dari kita akan menggunakan cara ini untuk mendapatkan daftar berkas pada sebuah direktori, yang mana ini akan menampilkan semua jalur berkas dan folder, namun tidak dengan jalur berkas dan folder yang memiliki awalan ., misalnya pada berkas dengan nama .htaccess:

$files = glob('.\path\to\folder\*');

Untuk mengatasi masalah ini, biasanya kita akan menggabungkan dua pola yaitu .* untuk menelusuri berkas dan folder dengan awalan . dan pola * untuk menelusuri berkas dan folder generik:

$files = array_unique(array_merge(
    glob('.\path\to\folder\.*'),
    glob('.\path\to\folder\*')
));

Kendala sekarang ada pada jalur .\path\to\folder\. dan .\path\to\folder\.. yang sebenarnya tidak kita perlukan, namun muncul juga di dalam daftar. Sehingga kita perlu melakukan usaha ekstra untuk menyingkirkan item tersebut dari daftar:

$files = array_filter(array_unique(array_merge(
    glob('.\path\to\folder\.*'),
    glob('.\path\to\folder\*')
)), function($v) {
    $n = basename($v);
    return $n !== '.' && $n !== '..';
});

Cara paling sederhana untuk menampilkan semua jalur berkas dan folder, termasuk berkas dan folder yang memiliki awalan nama . adalah seperti ini:

$files = glob('.\path\to\folder\{,.}[!.,!..]*', GLOB_BRACE);

Meskipun berkas dengan nama seperti ...foo-bar.baz akan gagal lolos pada pola penelusuran di atas, namun penamaan berkas dengan awalan . lebih dari satu sepertinya sangat jarang ada, jadi Saya kira pola ini cukup aman.


Referensi: Stack Overflow

Labels: , ,

Saturday, September 22, 2018

Mendeteksi Arah Gulungan Layar dengan JavaScript

Google+
Google+

Saat menggunakan aplikasi Google+, tajuk dan navigasi di bagian atas dan bawah akan menghilang ketika Anda menggulung layar ke bawah, sebaliknya, ketika Anda menggulung layar ke atas, tajuk dan navigasi akan muncul kembali.

JavaScript

var currentPageXOffset = 0,
    currentPageYOffset = 0;
window.addEventListener("scroll", function() {
    var X = this.pageXOffset,
        Y = this.pageYOffset;
    if (currentPageXOffset < X) {
        console.log('scroll right');
    } else if (currentPageXOffset > X) {
        console.log('scroll left');
    }
    if (currentPageYOffset < Y) {
        console.log('scroll down');
    } else if (currentPageYOffset > Y) {
        console.log('scroll up');
    }
    currentPageXOffset = X;
    currentPageYOffset = Y;
}, false);

Contoh

Demonstrasi penggunaan deteksi arah gulungan layar untuk menentukan kapan elemen <header> dan <footer> harus ditampilkan atau disembunyikan:

Lihat Demo

Demonstrasi penggunaan deteksi arah gulungan layar untuk menciptakan efek seperti aplikasi Google+:

Lihat Demo

Labels: ,

Saturday, September 8, 2018

Fungsi PHP dan JavaScript untuk Navigasi Halaman Angka

Pagination

Berikut ini adalah fungsi navigasi halaman angka yang paling standar dan paling sesuai untuk diterapkan pada semua kasus. Saya sediakan dalam bahasa JavaScript dan PHP, karena menurut Saya tampilan navigasi ini sangat sederhana namun sudah mencakup semua fitur yang ada. Yaitu fitur navigasi halaman Awal, Akhir, Berikutnya, Sebelumnya, dan navigasi halaman angka yang memungkinkan kita untuk melompati beberapa halaman sekaligus.

JavaScript

function pager(current, count, chunk, peek, fn, first, previous, next, last) {
    var begin = 1,
        end = Math.ceil(count / chunk),
        s = "",
        i, min, max;
    if (end <= 1) {
        return s;
    }
    if (current <= peek + peek) {
        min = begin;
        max = Math.min(begin + peek + peek, end);
    } else if (current > end - peek - peek) {
        min = end - peek - peek;
        max = end;
    } else {
        min = current - peek;
        max = current + peek;
    }
    if (previous) {
        s = '<span>';
        if (current === begin) {
            s += '<b title="' + previous + '">' + previous + '</b>';
        } else {
            s += '<a href="' + fn(current - 1) + '" title="' + previous + '" rel="prev">' + previous + '</a>';
        }
        s += '</span> ';
    }
    if (first && last) {
        s += '<span>';
        if (min > begin) {
            s += '<a href="' + fn(begin) + '" title="' + first + '" rel="prev">' + begin + '</a>';
            if (min > begin + 1) {
                s += ' <span>&hellip;</span>';
            }
        }
        for (i = min; i <= max; ++i) {
            if (current === i) {
                s += ' <b title="' + i + '">' + i + '</b>';
            } else {
                s += ' <a href="' + fn(i) + '" title="' + i + '" rel="' + (current >= i ? 'prev' : 'next') + '">' + i + '</a>';
            }
        }
        if (max < end) {
            if (max < end - 1) {
                s += ' <span>&hellip;</span>';
            }
            s += ' <a href="' + fn(end) + '" title="' + last + '" rel="next">' + end + '</a>';
        }
        s += '</span>';
    }
    if (next) {
        s += ' <span>';
        if (current === end) {
            s += '<b title="' + next + '">' + next + '</b>';
        } else {
            s += '<a href="' + fn(current + 1) + '" title="' + next + '" rel="next">' + next + '</a>';
        }
        s += '</span>';
    }
    return s;
}

PHP

function pager($current, $count, $chunk, $peek, $fn, $first, $previous, $next, $last) {
    $begin = 1;
    $end = (int) ceil($count / $chunk);
    $s = "";
    if ($end <= 1) {
        return $s;
    }
    if ($current <= $peek + $peek) {
        $min = $begin;
        $max = min($begin + $peek + $peek, $end);
    } else if ($current > $end - $peek - $peek) {
        $min = $end - $peek - $peek;
        $max = $end;
    } else {
        $min = $current - $peek;
        $max = $current + $peek;
    }
    if ($previous) {
        $s = '<span>';
        if ($current === $begin) {
            $s .= '<b title="' . $previous . '">' . $previous . '</b>';
        } else {
            $s .= '<a href="' . call_user_func($fn, $current - 1) . '" title="' . $previous . '" rel="prev">' . $previous . '</a>';
        }
        $s .= '</span> ';
    }
    if ($first && $last) {
        $s .= '<span>';
        if ($min > $begin) {
            $s .= '<a href="' . call_user_func($fn, $begin) . '" title="' . $first . '" rel="prev">' . $begin . '</a>';
            if ($min > $begin + 1) {
                $s .= ' <span>&hellip;</span>';
            }
        }
        for ($i = $min; $i <= $max; ++$i) {
            if ($current === $i) {
                $s .= ' <b title="' . $i . '">' . $i . '</b>';
            } else {
                $s .= ' <a href="' . call_user_func($fn, $i) . '" title="' . $i . '" rel="' . ($current >= $i ? 'prev' : 'next') . '">' . $i . '</a>';
            }
        }
        if ($max < $end) {
            if ($max < $end - 1) {
                $s .= ' <span>&hellip;</span>';
            }
            $s .= ' <a href="' . call_user_func($fn, $end) . '" title="' . $last . '" rel="next">' . $end . '</a>';
        }
        $s .= '</span>';
    }
    if ($next) {
        $s .= ' <span>';
        if ($current === $end) {
            $s .= '<b title="' . $next . '">' . $next . '</b>';
        } else {
            $s .= '<a href="' . call_user_func($fn, $current + 1) . '" title="' . $next . '" rel="next">' . $next . '</a>';
        }
        $s .= '</span>';
    }
    return $s;
}

Tentukan nomor halaman saat ini (dimulai dari angka 1), pada current, jumlah total data pada count, jumlah data yang ingin ditampilkan per halaman pada chunk, jumlah navigasi angka yang perlu ditampilkan sebelum dan sesudah angka halaman yang aktif pada peek, fungsi untuk membuat tautan pada fn dan teks untuk masing-masing tautan navigasi pada first, previous, next dan last.

Contoh

JavaScript

container.innerHTML = '<nav>' + pager(1, 500, 10, 2, i => {
    return i === 1 ? '/article' : '/article/' + i;
}, 'Awal', 'Sebelumya', 'Berikutnya', 'Akhir') + '</nav>';

PHP

echo '<nav>' . pager(1, 500, 10, 2, function($i) {
    return $i === 1 ? '/article' : '/article/' . $i;
}, 'Awal', 'Sebelumya', 'Berikutnya', 'Akhir') . '</nav>';

Referensi: StackOverflow Like Pagination

Labels: , ,

Thursday, September 6, 2018

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: , , ,

Tuesday, August 14, 2018

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: , , ,

Monday, July 13, 2015

AJAX dengan JavaScript Mentah

Mendapatkan konten dari dokumen HTML yang lain pada domain yang sama tanpa menggunakan jQuery.

/**
 * Get data from a URL
 * @param  {String} url        The URL to get
 * @param  {Function} success  Callback to run on success
 * @param  {Function} error    Callback to run on error
 */

var getURL = function(url, success, error) {
    // Feature detection
    if (!window.XMLHttpRequest) return;
    // Create new request
    var request = new XMLHttpRequest();
    // Setup callbacks
    request.onreadystatechange = function() {
        // If the request is complete
        if (request.readyState === 4) {
            // If the request failed
            if (request.status !== 200) {
                if (error && typeof error === "function") {
                    error(request.responseText, request);
                }
                return;
            }
            // If the request succeeded
            if (success && typeof success === "function") {
                success(request.responseText, request);
            }
        }
    };
    // Get the HTML
    request.open('GET', url);
    request.send();
};

Penggunaan

Dasar:

getURL(
    '/about',
    function(data) {
        // On success…
    },
    function(data) {
        // On failure…
    }
);

Cari elemen spesifik pada halaman yang dipanggil dan masukkan kontennya ke dalam elemen tertentu pada halaman saat ini:

getURL(
    '/about',
    function(data) {
        // Create a `<div>` and inject the HTML into it
        var div = document.createElement(div);
        div.innerHTML = data;
        // Find the element you’re looking for in the `<div>`
        var from = div.querySelector('#some-element');
        var to = document.querySelector('#another-element');
        // Quit if the element or the place where you want to inject it doesn’t exist
        if (!from || !to) return;
        // Inject the element into the DOM
        to.innerHTML = from.innerHTML;
    }
);

Referensi: Making AJAX Requests with Native JavaScript

Labels: , ,

Wednesday, June 3, 2015

Pemutakhiran Sintaks dan Operator XML Blogger 2015

Blogger Logo

Baru-baru ini Blogger telah merilis beberapa operator baru untuk sintaks XML mereka. Sintaks baru ini memungkinkan kita untuk dapat menulis kode templat yang lebih baik, lebih logis dan lebih efisien. Selain dapat mengurangi ukuran berkas XML, sintaks baru ini juga memungkinkan para pengembang untuk dapat menemukan potensi-potensi baru dalam memanipulasi kode templat Blogger yang dulu sebagian besar hanya bisa kita lakukan dengan JavaScript. Berikut ini adalah ringkasannya…

And

Sebelum

<b:if cond='data:blog.searchQuery'>
  <b:if cond='data:numPosts &gt; 10'>
    Hasil pencarian dengan jumlah posting lebih dari 10…
  </b:if>
</b:if>

Sesudah

<b:if cond='data:blog.searchQuery and data:numPosts &gt; 10'>
  Hasil pencarian dengan jumlah posting lebih dari 10…
</b:if>
<b:if cond='data:blog.searchQuery &amp;&amp; data:numPosts &gt; 10'>
  Hasil pencarian dengan jumlah posting lebih dari 10…
</b:if>

Or

Sebelum

<b:if cond='data:blog.pageType == &quot;index&quot;'>
  Lolos tes…
</b:if>
<b:if cond='data:blog.pageType == &quot;item&quot;'>
  Lolos tes…
</b:if>

Sesudah

<b:if cond='data:blog.pageType == &quot;index&quot; or data:blog.pageType == &quot;item&quot;'>
  Lolos tes…
</b:if>
<b:if cond='data:blog.pageType == &quot;index&quot; || data:blog.pageType == &quot;item&quot;'>
  Lolos tes…
</b:if>

Not

Sebelum

<b:if cond='data:comment.isDeleted'>
<b:else/>
  Komentar yang tidak terhapus di sini…
</b:if>
<b:if cond='data:comment.isDeleted == &quot;false&quot;'>
  Komentar yang tidak terhapus di sini…
</b:if>

Sesudah

<b:if cond='!data:comment.isDeleted'>
  Komentar yang tidak terhapus di sini…
</b:if>
<b:if cond='not data:comment.isDeleted'>
  Komentar yang tidak terhapus di sini…
</b:if>

Yang ini tidak bisa:

<!-- TEMPLATE ERROR: 'not' term cannot be used as operator except when preceding 'in' or 'contains' -->
<b:if cond='data:comment.isDeleted not &quot;false&quot;'>
  Komentar yang tidak terhapus di sini…
</b:if>
<!-- TEMPLATE ERROR: Extra characters at end of string: buf=[!] remainder=["false"] -->
<b:if cond='data:comment.isDeleted ! &quot;false&quot;'>
  Komentar yang tidak terhapus di sini…
</b:if>

Yang ini bisa:

<b:if cond='not data:comment.isDeleted == &quot;false&quot;'>
  Komentar yang tidak terhapus di sini…
</b:if>
<b:if cond='!data:comment.isDeleted == &quot;false&quot;'>
  Komentar yang tidak terhapus di sini…
</b:if>

Ternary Selector

Sebelum

&lt;html class=&#39;<b:if cond='data:blog.pageType == &quot;item&quot;'>
  page-item
<b:else/>
  page-non-item
</b:if>&#39;&gt;
  …
&lt;/html&gt;

Sesudah

<html expr:class='data.blog.pageType == &quot;item&quot; ? &quot;page-item&quot; : &quot;page-non-item&quot;'>
  …
</html>
<html expr:class='&quot;page-&quot; + (data.blog.pageType == &quot;item&quot; ? &quot;&quot; : &quot;non-&quot;) + &quot;item&quot;'>
  …
</html>

Membership

Hampir sama dengan operator or, hanya saja semua referensi pembanding harus sama, nilainya saja yang dibedakan:

Sebelum

<b:if cond='data:comment.author == &quot;Taufik Nurrohman&quot;'>
  Admin komentar…
</b:if>
<b:if cond='data:comment.author == &quot;Taufik&quot;'>
  Admin komentar…
</b:if>
<b:if cond='data:comment.author == &quot;Admin&quot;'>
  Admin komentar…
</b:if>

Sesudah

<b:if cond='data:comment.author in {&quot;Taufik Nurrohman&quot;,&quot;Taufik&quot;,&quot;Admin&quot;}'>
  Admin komentar…
</b:if>
<b:if cond='data:comment.author in [&quot;Taufik Nurrohman&quot;,&quot;Taufik&quot;,&quot;Admin&quot;]'>
  Admin komentar…
</b:if>
<b:if cond='{&quot;Taufik Nurrohman&quot;,&quot;Taufik&quot;,&quot;Admin&quot;} contains data:comment.author'>
  Admin komentar…
</b:if>
<b:if cond='[&quot;Taufik Nurrohman&quot;,&quot;Taufik&quot;,&quot;Admin&quot;] contains data:comment.author'>
  Admin komentar…
</b:if>

Else If

Sebelum

<b:if cond='data:blog.pageType == &quot;item&quot;'>
  <data:post.body/>
<b:else/>
  <b:if cond='data:blog.pageType == &quot;static_page&quot;'>
    <data:post.body/>
  <b:else/>
    <data:post.snippet/>
  </b:if>
</b:if>

Sesudah

<b:if cond='data:blog.pageType == &quot;item&quot;'>
  <data:post.body/>
<b:elseif cond='data:blog.pageType == &quot;static_page&quot;'>
  <data:post.body/>
<b:else/>
  <data:post.snippet/>
</b:if>

atau…

<b:if cond='data:blog.pageType in {&quot;item&quot;,&quot;static_page&quot;}'>
  <data:post.body/>
<b:else/>
  <data:post.snippet/>
</b:if>

Tambahan

b:switch, b:case, b:eval, b:withreferensi


Referensi:

Labels: , ,

Sunday, April 26, 2015

Password Overlay

Di sini, JavaScript btoa digunakan untuk menyembunyikan teks, sedangkan atob digunakan untuk mengembalikan teks yang tersembunyi tersebut:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Password Overlay Test</title>

    <style>
    .body {
      padding:10% 0;
      text-align:center;
    }
    .overlay {
      position:fixed;
      top:0;
      right:0;
      bottom:0;
      left:0;
      z-index:9999;
      background-color:black;
      color:white;
      padding:10% 0;
      text-align:center;
    }
    </style>

  </head>
  <body>

    <div id="protect-body" class="body">Content goes here…</div>
    <div id="protect-overlay" class="overlay">
      <form action="#">
        <input name="answer" type="password" placeholder="Password?"/> <button type="submit">Open</button>
      </form>
    </div>

    <script>
    // https://developer.mozilla.org/En/DOM/Window.btoa
    // https://developer.mozilla.org/en/DOM/window.atob
    // to get the obfuscated text, use `console.log(btoa('your text goes here'))`
    // `aSBsb3ZlIHlvdQ==` => `i love you`
    (function() {
        var o = document.getElementById('protect-overlay');
        o.getElementsByTagName('form')[0].onsubmit = function() {
            if (this.answer.value === atob('aSBsb3ZlIHlvdQ==')) {
                o.style.display = "none"; // passed!
            } else {
                alert('Wrong password!');
            }
            return false;
        };
    })();
    </script>

  </body>
</html>

Demo

Kata kunci: i love you

Lihat Demo


Referensi

Labels: , ,

Saturday, January 3, 2015

Kompresi Kode HTML, CSS dan JavaScript dengan PHP

Berikut ini adalah fungsi PHP terpisah yang telah Saya gunakan untuk mengompresi kode HTML, CSS dan JavaScript pada CMS Mecha.

Labels: , , , ,

Sunday, August 31, 2014

Tag Facebook Open Graph untuk Blogspot

<meta property='og:title' expr:content='data:blog.pageTitle'/>
<b:if cond='data:blog.pageType == &quot;item&quot;'>
  <meta property='og:type' content='article'/>
<b:else/>
  <meta property='og:type' content='website'/>
</b:if>
<meta property='og:url' expr:content='data:blog.canonicalUrl'/>
<!-- Large image, original size -->
<b:if cond='data:blog.postImageUrl'>
  <meta property='og:image' expr:content='data:blog.postImageUrl'/>
<b:else/>
  <!-- Thumbnail image, 72 × 72 pixels -->
  <b:if cond='data:blog.postImageThumbnailUrl'>
    <meta property='og:image' expr:content='data:blog.postThumbnailUrl'/>
  <b:else/>
    <!-- Default, no image. Use favicon or your own image URL -->
    <meta property='og:image' expr:content='data:blog.blogspotFaviconUrl'/>
  </b:if>
</b:if>
<b:if cond='data:blog.metaDescription'>
  <meta property='og:description' expr:content='data:blog.metaDescription'/>
<b:else/>
  <meta property='og:description' content='{{DEFAULT SITE DESCRIPTION GOES HERE}}'/>
</b:if>
<meta property='og:site_name' expr:content='data:blog.title'/>
<!--

Optional. Read more → Insights for your Facebook App, Domain or Page<meta property='fb:admins' content='{{FB ADMINS}}'/>
<meta property='fb:app_id' content='{{APP ID}}'/>

-->

Lainnya

Labels: , ,

Friday, August 29, 2014

Mendapatkan Ukuran Folder/Direktori dengan PHP

Fungsi ini akan menunjukkan ukuran sebuah folder/direktori dengan cara menghitung jumlah total ukuran semua berkas yang ada di dalamnya.

// http://stackoverflow.com/a/21409562/1163000
function get_directory_size($path) {
    $size = 0;
    $path = realpath($path);
    if($path !== false) {
        foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)) as $object) {
            $size += $object->getSize();
        }
    }
    return $size; // in bytes
}

Penggunaan

echo (get_directory_size('path/to/folder') / 1024) . ' KB';

Labels: ,

Thursday, August 21, 2014

Lettering PHP

Versi PHP untuk lettering.js

function lettering_PHP($text) {
    $results = '<span class="word-1 char-group">';
    $skip = false;
    $entity_open = false;
    $entity_close = false;
    $index_word = 2;
    $index_letter = 1;
    $letters = preg_split('#(?<!^)(?!$)#u', $text);
    foreach($letters as $letter) {
        $entity_open = $letter == '&';
        $entity_close = $letter == ';';
        if($letter == '<' || $entity_open) $skip = true;
        if($letter == '>' || $entity_close) $skip = false;
        if( ! $skip && $letter == ' ') {
            $results .= '</span> <span class="word-' . $index_word . ' char-group">';
            $index_word++;
        } else {
            if( ! $skip && $letter != '<' && $letter != '>' && $letter != '&' && $letter != ';' && $letter != ' ') {
                $results .= '<span class="char-' . $index_letter . '">' . $letter . '</span>';
                $index_letter++;
            } else {
                if($entity_open) {
                    $results .= '<span class="char-' . $index_letter . '">';
                }
                $results .= $letter;
                if($entity_close) {
                    $results .= '</span>';
                    $index_letter++;
                }
            }
        }
    }
    return '<span aria-label="' . str_replace(array('"', '\''), array('&quot;', '&#039;'), strip_tags($text)) . '"><span aria-hidden="true" class="word-group">' . $results . '</span></span></span>';
}

Penggunaan

<h2><?php echo lettering_PHP('Lorem Ipsum Dolor Sit Amet'); ?></h2>

Sebelum

<h2>Lorem Ipsum Dolor Sit Amet</h2>

Sesudah

<h2>
  <span aria-label="Lorem Ipsum Dolor Sit Amet">
    <span aria-hidden="true" class="word-group">
      <span class="word-1 char-group">
        <span class="char-1">L</span>
        <span class="char-2">o</span>
        <span class="char-3">r</span>
        <span class="char-4">e</span>
        <span class="char-5">m</span>
      </span> 
      <span class="word-2 char-group">
        <span class="char-6">I</span>
        <span class="char-7">p</span>
        <span class="char-8">s</span>
        <span class="char-9">u</span>
        <span class="char-10">m</span>
      </span> 
      <span class="word-3 char-group">
        <span class="char-11">D</span>
        <span class="char-12">o</span>
        <span class="char-13">l</span>
        <span class="char-14">o</span>
        <span class="char-15">r</span>
      </span> 
      <span class="word-4 char-group">
        <span class="char-16">S</span>
        <span class="char-17">i</span>
        <span class="char-18">t</span>
      </span> 
      <span class="word-5 char-group">
        <span class="char-19">A</span>
        <span class="char-20">m</span>
        <span class="char-21">e</span>
        <span class="char-22">t</span>
      </span>
    </span>
  </span>
</h2>

Sumber: https://github.com/tovic/lettering-plugin-for-mecha-cms/blob/master/lettering-php/launch.php

Labels: , ,

Sunday, July 6, 2014

Fake Link

HTML

<form class="fake-link" action="//example.org" method="get" target="_blank">
  <input name="aff" type="hidden" value="1234567">
  <button type="submit">affiliate link</button>
</form>

CSS

.fake-link,
.fake-link button {
  margin:0;
  padding:0;
  width:auto;
  height:auto;
  background:none;
  border:none;
  font:inherit;
  text-transform:none;
  display:inline;
}
.fake-link button {
  color:blue;
  cursor:pointer;
}
.fake-link button::-moz-focus-inner {
  margin:0;
  padding:0;
  border:none;
  outline:none;
}
.fake-link button:focus,
.fake-link button:hover {text-decoration:underline}
.fake-link button:active {color:red}

Demo

Lihat Demo

Labels: , ,

Monday, April 21, 2014

JavaScript Brightness

/**
 * http://www.sitepoint.com/javascript-generate-lighter-darker-color/
 */

function colorLuminance(hex, lum) {
    // Validate hex string
    hex = String(hex).replace(/[^0-9a-f]/gi, "");
    if (hex.length < 6) {
        hex = hex.replace(/(.)/g, '$1$1');
    }
    lum = lum || 0;
    // Convert to decimal and change luminosity
    var rgb = '#', c;
    for (var i = 0; i < 3; ++i) {
        c = parseInt(hex.substr(i * 2, 2), 16);
        c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
        rgb += ('00' + c).substr(c.length);
    }
    return rgb;
}

Penggunaan

colorLuminance('#aabbaa', 0.5); // lighter
colorLuminance('#aabbaa', -0.5); // darker

Lihat Demo

Labels: ,

Friday, April 4, 2014

PHP Konversi Array Menjadi Objek/Objek Menjadi Array

1. Array ke Objek

Fungsi

function array_to_object($array) {
    if(is_array($array)) {
        return (object) array_map(__FUNCTION__, $array);
    } else {
        return $array;
    }
}

Contoh Kasus

Sebelum dikonversi…

$test = array(
    'A' => 'Test A',
    'B' => 'Test B',
    'C' => array(
        'CA' => 'Test CA',
        'CB' => array(
            'CBA' => 'Test CBA'
        )
    ),
    'D' => 'Test D'
);

// Pemanggilan...
echo $test['A']; // Hasil => `Test A`
echo $test['C']['CB']; // Hasil => `Test CB`
echo $test['C']['CB']['CBA']; // Hasil => `Test CBA`

Sesudah dikonversi…

...

$object_test = array_to_object($test);

// Pemanggilan...
echo $object_test->A; // Hasil => `Test A`
echo $object_test->C->CB; // Hasil => `Test CB`
echo $object_test->C->CB->CBA; // Hasil => `Test CBA`

2. Objek ke Array

Fungsi

function object_to_array($object) {
    if(is_object($object)) {
        $object = get_object_vars($object);
    }
    if(is_array($object)) {
        return array_map(__FUNCTION__, $object);
    } else {
        return $object;
    }
}

Contoh Kasus

Sebelum dikonversi…

$test = new stdClass;
$test->A = 'Test A';
$test->B = 'Test B';
$test->C = new stdClass;
$test->C->CA = 'Test CA';
$test->C->CB = new stdClass;
$test->C->CB->CBA = 'Test CBA';
$test->D = 'Test D';

// Pemanggilan
echo $test->A; // Hasil => `Test A`

Sesudah dikonversi…

...

$array_test = object_to_array($test);

// Pemanggilan
echo $array_test['A']; // Hasil => `Test A`

Labels: , ,

PHP Konversi Array Menjadi HTML List

PHP

function array_to_list($array, $list_type = 'ul') {
    $output = '<' . $list_type . '>';
    foreach($array as $key => $values) {
        if(is_array($values)) {
            $output .= '<li><a href="#">' . $key . '</a>' . array_to_list($values, $list_type) . '</li>';
        } else {
            $output .= '<li><a href="#' . $values . '">' . $key . '</a></li>';
        }
    }
    return $output . '</' . $list_type . '>';
}

Penggunaan

Ubah array $test menjadi elemen HTML daftar:

// Testing...
$test = array(
    'A' => 'list-A',
    'B' => 'list-B',
    'C' => 'list-C',
    'D' => array(
        'AA' => 'list-AA',
        'AB' => 'list-AB',
        'AC' => 'list-AC',
        'AD' => array(
            'ADA' => 'list-ADA',
            'ADB' => 'list-ADB',
            'ADC' => 'list-ADC'
        ),
        'AE' => 'list-AE'
    ),
    'E' => 'list-E'
);

echo array_to_list($test, 'ol');

Akan menghasilkan ini:

Lihat Demo

Labels: , ,

Sunday, March 23, 2014

JavaScript “Extend”

Fungsi ini setara dengan jQuery.extend() yang memungkinkan kita untuk menciptakan variabel opsional, dimana variabel tersebut bisa dinyatakan ataupun ditiadakan. Jika tidak dinyatakan, maka nilai variabel yang tidak hadir tersebut akan jatuh pada nilai default yang telah ditentukan di dalam fungsi:

function extend(def, alt) {
    alt = alt || {};
    for (var i in def) {
        if (typeof alt[i] === "undefined") {
            alt[i] = def[i];
        } else if (
            typeof def[i] === "object" &&
            typeof alt[i] === "object" &&
            alt[i] !== null
        ) {
            alt[i] = extend(def[i], alt[i]);
        }
    }
    return alt;
}

Contoh Penggunaan

function myFunction(config) {

    var defaults = {
        firstName: 'Taufik',
        lastName: 'Nurrohman',
        age: 22
    };

    // Extend...
    config = extend(defaults, config);

    return config;

}

Ketika Anda mengubah beberapa nilai variabel konfigurasi, maka variabel-variabel konfigurasi default yang lain yang tidak diubah akan menyesuaikan:

myFunction({
    firstName: 'Foo'
});

Hasil

JavaScript Extend Test via Window Console
Taufik telah berubah menjadi Foo.

Sebenarnya dulu Saya sudah pernah menulis posting yang sejenis dengan ini. Tapi metode yang Saya tuliskan dalam posting tersebut tidak mampu untuk menangani objek multi-dimensi seperti ini:

var defaults = {
    option_1: value_1,
    option_2: value_2,
    option_3: {
        option_3_1: {
            option_3_1_1: value_3_1_1,
            option_3_1_2: value_3_1_2
        },
        option_3_2: value_3_2,
        option_3_3: value_3_3
    },
    option_4: value_4
};

Labels: , ,

Sunday, March 9, 2014

Sortir Array Berdasarkan Nilai dari Key

// http://stackoverflow.com/a/2699110/1163000
function sort_array_by_value($key, &$array) {

    $sorter = array();
    $ret = array();

    reset($array);

    foreach($array as $ii => $value) {
        $sorter[$ii] = $value[$key];
    }

    asort($sorter);

    foreach($sorter as $ii => $value) {
        $ret[$ii] = $array[$ii];
    }

    $array = $ret;

}

Contoh Kasus

Sampel array:

$my_array = array(
    array(
        'id' => 1,
        'title' => 'Orange',
        'time' => '2014-03-05 03:00:42'
    ),
    array(
        'id' => 2,
        'title' => 'Banana',
        'time' => '2013-01-06 13:05:15'
    ),
    array(
        'id' => 3,
        'title' => 'Grape',
        'time' => '2011-05-15 01:30:45'
    )
);

Menyortir data berdasarkan nilai dari title

sort_array_by_value('title', $my_array);

print_r($my_array);

Akan menghasilkan urutan seperti ini:

Array
(
    [1] => Array
        (
            [id] => 2
            [title] => Banana            [time] => 2013-01-06 13:05:15
        )

    [2] => Array
        (
            [id] => 3
            [title] => Grape            [time] => 2011-05-15 01:30:45
        )

    [0] => Array
        (
            [id] => 1
            [title] => Orange            [time] => 2014-03-05 03:00:42
        )

)

Labels: ,

Monday, March 3, 2014

Syntax Highlighter Generik dengan PHP

PHP

<?php

/**
 * Original => http://phoboslab.org/log/2007/08/generic-syntax-highlighting-with-regular-expressions
 * Usage => `echo SyntaxHighlight::process('source code here');`
 */

class SyntaxHighlight {
    public static function process($s) {
        $s = htmlspecialchars($s);

        // Workaround for escaped backslashes
        $s = str_replace('\\\\','\\\\<e>', $s); 

        $regexp = array(

            // Comments/Strings
            '/(
                \/\*.*?\*\/|
                \/\/.*?\n|
                \#.[^a-fA-F0-9]+?\n|
                \&lt;\!\-\-[\s\S]+\-\-\&gt;|
                (?<!\\\)&quot;.*?(?<!\\\)&quot;|
                (?<!\\\)\'(.*?)(?<!\\\)\'
            )/isex' 
            => 'self::replaceId($tokens,\'$1\')',

            // Punctuations
            '/([\-\!\%\^\*\(\)\+\|\~\=\`\{\}\[\]\:\"\'<>\?\,\.\/]+)/'
            => '<span class="P">$1</span>',

            // Numbers (also look for Hex)
            '/(?<!\w)(
                (0x|\#)[\da-f]+|
                \d+|
                \d+(px|em|cm|mm|rem|s|\%)
            )(?!\w)/ix'
            => '<span class="N">$1</span>',

            // Make the bold assumption that an
            // all uppercase word has a special meaning
            '/(?<!\w|>|\#)(
                [A-Z_0-9]{2,}
            )(?!\w)/x'
            => '<span class="D">$1</span>',

            // Keywords
            '/(?<!\w|\$|\%|\@|>)(
                and|or|xor|for|do|while|foreach|as|return|die|exit|if|then|else|
                elseif|new|delete|try|throw|catch|finally|class|function|string|
                array|object|resource|var|bool|boolean|int|integer|float|double|
                real|string|array|global|const|static|public|private|protected|
                published|extends|switch|true|false|null|void|this|self|struct|
                char|signed|unsigned|short|long
            )(?!\w|=")/ix'
            => '<span class="K">$1</span>',

            // PHP/Perl-Style Vars: $var, %var, @var
            '/(?<!\w)(
                (\$|\%|\@)(\-&gt;|\w)+
            )(?!\w)/ix'
            => '<span class="V">$1</span>'

        );

        $tokens = array(); // This array will be filled from the regexp-callback

        $s = preg_replace(array_keys($regexp), array_values($regexp), $s);

        // Paste the comments and strings back in again
        $s = str_replace(array_keys($tokens), array_values($tokens), $s);

        // Delete the "Escaped Backslash Workaround Token" (TM)
        // and replace tabs with four spaces.
        $s = str_replace(array('<e>', "\t"), array('', '    '), $s);

        return '<pre><code>' . $s . '</code></pre>';
    }

    // Regexp-Callback to replace every comment or string with a uniqid and save
    // the matched text in an array
    // This way, strings and comments will be stripped out and wont be processed
    // by the other expressions searching for keywords etc.
    private static function replaceId(&$a, $match) {
        $id = "##r" . uniqid() . "##";

        // String or Comment?
        if(substr($match, 0, 2) == '//' || substr($match, 0, 2) == '/*' || substr($match, 0, 2) == '##' || substr($match, 0, 7) == '&lt;!--') {
            $a[$id] = '<span class="C">' . $match . '</span>';
        } else {
            $a[$id] = '<span class="S">' . $match . '</span>';
        }
        return $id;
    }
}

?>

CSS

pre {
  display:block;
  background-color:#3F3F3F;
  margin:1em 0;
  padding:1em;
  font:normal normal 13px/1.4 Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,Monospace;
  color:#E3CEAB;
  overflow:auto;
  white-space:pre;
  word-wrap:normal;
}
pre code {
  font:inherit;
  color:inherit;
}
pre span.N {color:#8CD0D3} /* Numbers */
pre span.S {color:#CC9385} /* Strings */
pre span.C {color:#7F9F7F} /* Comments */
pre span.K {color:#DFC47D} /* Keywords */
pre span.V {color:#CEDF99} /* Vars */
pre span.D {color:#FFFFFF} /* Defines */
pre span.P {color:#9F9D65} /* Punctuations */

Lihat Demo

Labels: ,