Nurul Imam Studio

Belajar HTML, CSS, JavaScript, PHP & MySQL untuk pemula & tingkat lanjut

Jasa Pembuatan Website Profesional

Posting Kode Jadi Menarik Dengan Menggunakan Prism.js

Sebelumnya saya sudah mencoba beberapa syntax highlighter, namun sekarang saya lebih tertarik menggunakan Prism.js untuk Code Block Syntax Highlighter pada theme ini. Apa yang membuat saya merasa tertarik menggunakan Prism.js ini ? Saya menyukai kombinasi paduan warnanya, ukuran file javascript & css yang sangat kecil, juga yang tidak kalah penting adalah adanya plugin seperti file highlighter yang mana kita bisa memanggil source code langsung dari filenya hanya dengan menambahkan kode <pre class="language-css" data-src="prism.css"></pre>.

Bagi yang mau mencobanya, anda bisa mendownload kodenya di website resminya (http://prismjs.com) atau anda bisa mengcopy kode yang akan saya tulis dibawah ini.

Kode JavaScript Prism.js



/* **********************************************
     Begin prism-core.js
********************************************** */

/**
 * Prism: Lightweight, robust, elegant syntax highlighting
 * MIT license http://www.opensource.org/licenses/mit-license.php/
 * @author Lea Verou http://lea.verou.me
 */

(function(){

// Private helper vars
var lang = /\blang(?:uage)?-(?!\*)(\w+)\b/i;

var _ = self.Prism = {
   util: {
     type: function (o) { 
           return Object.prototype.toString.call(o).match(/\[object (\w+)\]/)[1];
       },
      
        // Deep clone a language definition (e.g. to extend it)
     clone: function (o) {
           var type = _.util.type(o);

          switch (type) {
             case 'Object':
                    var clone = {};
                 
                    for (var key in o) {
                        if (o.hasOwnProperty(key)) {
                            clone[key] = _.util.clone(o[key]);
                      }
                   }
                   
                    return clone;
                   
                case 'Array':
                 return o.slice();
           }
           
            return o;
       }
   },
  
    languages: {
        extend: function (id, redef) {
          var lang = _.util.clone(_.languages[id]);
           
            for (var key in redef) {
                lang[key] = redef[key];
         }
           
            return lang;
        },
      
        // Insert a token before another token in a language literal
        insertBefore: function (inside, before, insert, root) {
         root = root || _.languages;
         var grammar = root[inside];
         var ret = {};
               
            for (var token in grammar) {
            
                if (grammar.hasOwnProperty(token)) {
                    
                    if (token == before) {
                  
                        for (var newToken in insert) {
                      
                            if (insert.hasOwnProperty(newToken)) {
                              ret[newToken] = insert[newToken];
                           }
                       }
                   }
                   
                    ret[token] = grammar[token];
                }
           }
           
            return root[inside] = ret;
      },
      
        // Traverse a language definition with Depth First Search
       DFS: function(o, callback) {
            for (var i in o) {
              callback.call(o, i, o[i]);
              
                if (_.util.type(o) === 'Object') {
                    _.languages.DFS(o[i], callback);
                }
           }
       }
   },

  highlightAll: function(async, callback) {
       var elements = document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');

     for (var i=0, element; element = elements[i++];) {
          _.highlightElement(element, async === true, callback);
      }
   },
      
    highlightElement: function(element, async, callback) {
      // Find language
        var language, grammar, parent = element;
        
        while (parent && !lang.test(parent.className)) {
            parent = parent.parentNode;
     }
       
        if (parent) {
           language = (parent.className.match(lang) || [,''])[1];
            grammar = _.languages[language];
        }

       if (!grammar) {
         return;
     }
       
        // Set language on the element, if not present
      element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
      
        // Set language on the parent, for styling
      parent = element.parentNode;
        
        if (/pre/i.test(parent.nodeName)) {
         parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; 
       }

       var code = element.textContent;
     
        if(!code) {
         return;
     }
       
        code = code.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
     
        var env = {
         element: element,
           language: language,
         grammar: grammar,
           code: code
      };
      
        _.hooks.run('before-highlight', env);
     
        if (async && self.Worker) {
         var worker = new Worker(_.filename);    
            
            worker.onmessage = function(evt) {
              env.highlightedCode = Token.stringify(JSON.parse(evt.data), language);

              _.hooks.run('before-insert', env);

                env.element.innerHTML = env.highlightedCode;
                
                callback && callback.call(env.element);
             _.hooks.run('after-highlight', env);
          };
          
            worker.postMessage(JSON.stringify({
             language: env.language,
             code: env.code
          }));
        }
       else {
          env.highlightedCode = _.highlight(env.code, env.grammar, env.language)

          _.hooks.run('before-insert', env);

            env.element.innerHTML = env.highlightedCode;
            
            callback && callback.call(element);
         
            _.hooks.run('after-highlight', env);
      }
   },
  
    highlight: function (text, grammar, language) {
     return Token.stringify(_.tokenize(text, grammar), language);
    },
  
    tokenize: function(text, grammar, language) {
       var Token = _.Token;
        
        var strarr = [text];
        
        var rest = grammar.rest;
        
        if (rest) {
         for (var token in rest) {
               grammar[token] = rest[token];
           }
           
            delete grammar.rest;
        }
                               
        tokenloop: for (var token in grammar) {
         if(!grammar.hasOwnProperty(token) || !grammar[token]) {
             continue;
           }
           
            var pattern = grammar[token], 
              inside = pattern.inside,
                lookbehind = !!pattern.lookbehind,
              lookbehindLength = 0;
           
            pattern = pattern.pattern || pattern;
           
            for (var i=0; i<strarr.length; i++) { // Don’t cache length as it changes during the loop
                
                var str = strarr[i];
                
                if (strarr.length > text.length) {
                   // Something went terribly wrong, ABORT, ABORT!
                 break tokenloop;
                }
               
                if (str instanceof Token) {
                 continue;
               }
               
                pattern.lastIndex = 0;
              
                var match = pattern.exec(str);
              
                if (match) {
                    if(lookbehind) {
                        lookbehindLength = match[1].length;
                 }

                   var from = match.index - 1 + lookbehindLength,
                      match = match[0].slice(lookbehindLength),
                       len = match.length,
                     to = from + len,
                        before = str.slice(0, from + 1),
                        after = str.slice(to + 1); 

                 var args = [i, 1];
                  
                    if (before) {
                       args.push(before);
                  }
                   
                    var wrapped = new Token(token, inside? _.tokenize(match, inside) : match);
                  
                    args.push(wrapped);
                 
                    if (after) {
                        args.push(after);
                   }
                   
                    Array.prototype.splice.apply(strarr, args);
             }
           }
       }

       return strarr;
  },
  
    hooks: {
        all: {},
        
        add: function (name, callback) {
            var hooks = _.hooks.all;
            
            hooks[name] = hooks[name] || [];
            
            hooks[name].push(callback);
     },
      
        run: function (name, env) {
         var callbacks = _.hooks.all[name];
          
            if (!callbacks || !callbacks.length) {
              return;
         }
           
            for (var i=0, callback; callback = callbacks[i++];) {
               callback(env);
          }
       }
   }
};

var Token = _.Token = function(type, content) {
  this.type = type;
   this.content = content;
};

Token.stringify = function(o, language, parent) {
  if (typeof o == 'string') {
       return o;
   }

   if (Object.prototype.toString.call(o) == '[object Array]') {
      return o.map(function(element) {
            return Token.stringify(element, language, o);
       }).join('');
  }
   
    var env = {
     type: o.type,
       content: Token.stringify(o.content, language, parent),
      tag: 'span',
      classes: ['token', o.type],
       attributes: {},
     language: language,
     parent: parent
  };
  
    if (env.type == 'comment') {
      env.attributes['spellcheck'] = 'true';
  }
   
    _.hooks.run('wrap', env);
 
    var attributes = '';
  
    for (var name in env.attributes) {
      attributes += name + '="' + (env.attributes[name] || '') + '"';
 }
   
    return '<' + env.tag + ' class="' + env.classes.join(' ') + '" ' + attributes + '>' + env.content + '</' + env.tag + '>';
   
};

if (!self.document) {
 // In worker
    self.addEventListener('message', function(evt) {
      var message = JSON.parse(evt.data),
         lang = message.language,
            code = message.code;
        
        self.postMessage(JSON.stringify(_.tokenize(code, _.languages[lang])));
      self.close();
   }, false);
  
    return;
}

// Get current script and highlight
var script = document.getElementsByTagName('script');

script = script[script.length - 1];

if (script) {
  _.filename = script.src;
    
    if (document.addEventListener && !script.hasAttribute('data-manual')) {
       document.addEventListener('DOMContentLoaded', _.highlightAll);
    }
}

})();

/* **********************************************
     Begin prism-markup.js
********************************************** */

Prism.languages.markup = {
   'comment': /&lt;!--[\w\W]*?-->/g,
    'prolog': /&lt;\?.+?\?>/,
    'doctype': /&lt;!DOCTYPE.+?>/,
 'cdata': /&lt;!\[CDATA\[[\w\W]*?]]>/i,
 'tag': {
      pattern: /&lt;\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|\w+))?\s*)*\/?>/gi,
       inside: {
           'tag': {
              pattern: /^&lt;\/?[\w:-]+/i,
              inside: {
                   'punctuation': /^&lt;\/?/,
                   'namespace': /^[\w-]+?:/
             }
           },
          'attr-value': {
               pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,
               inside: {
                   'punctuation': /=|>|"/g
               }
           },
          'punctuation': /\/?>/g,
           'attr-name': {
                pattern: /[\w:-]+/g,
               inside: {
                   'namespace': /^[\w-]+?:/
             }
           }
           
        }
   },
  'entity': /&amp;#?[\da-z]{1,8};/gi
};

// Plugin to make entity title show the real entity, idea by Roman Komarov
Prism.hooks.add('wrap', function(env) {

  if (env.type === 'entity') {
      env.attributes['title'] = env.content.replace(/&amp;/, '&');
    }
});

/* **********************************************
     Begin prism-css.js
********************************************** */

Prism.languages.css = {
    'comment': /\/\*[\w\W]*?\*\//g,
 'atrule': {
       pattern: /@[\w-]+?.*?(;|(?=\s*{))/gi,
     inside: {
           'punctuation': /[;:]/g
        }
   },
  'url': /url\((["']?).*?\1\)/gi,
  'selector': /[^\{\}\s][^\{\};]*(?=\s*\{)/g,
    'property': /(\b|\B)[\w-]+(?=\s*:)/ig,
    'string': /("|')(\\?.)*?\1/g,
    'important': /\B!important\b/gi,
    'ignore': /&(lt|gt|amp);/gi,
  'punctuation': /[\{\};:]/g
};

if (Prism.languages.markup) {
   Prism.languages.insertBefore('markup', 'tag', {
     'style': {
            pattern: /(&lt;|<)style[\w\W]*?(>|&gt;)[\w\W]*?(&lt;|<)\/style(>|&gt;)/ig,
         inside: {
               'tag': {
                  pattern: /(&lt;|<)style[\w\W]*?(>|&gt;)|(&lt;|<)\/style(>|&gt;)/ig,
                  inside: Prism.languages.markup.tag.inside
               },
              rest: Prism.languages.css
           }
       }
   });
}

/* **********************************************
     Begin prism-clike.js
********************************************** */

Prism.languages.clike = {
    'comment': {
      pattern: /(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,
       lookbehind: true
    },
  'string': /("|')(\\?.)*?\1/g,
    'class-name': {
       pattern: /((?:class|interface|extends|implements|trait|instanceof|new)\s+)[a-z0-9_\.\\]+/ig,
        lookbehind: true,
       inside: {
           punctuation: /(\.|\\)/
       }
   },
  'keyword': /\b(if|else|while|do|for|return|in|instanceof|function|new|try|catch|finally|null|break|continue)\b/g,
   'boolean': /\b(true|false)\b/g,
 'function': {
     pattern: /[a-z0-9_]+\(/ig,
     inside: {
           punctuation: /\(/
      }
   },
  'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,
  'operator': /[-+]{1,2}|!|=?&lt;|=?&gt;|={1,2}|(&amp;){1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,
 'ignore': /&(lt|gt|amp);/gi,
  'punctuation': /[{}[\];(),.:]/g
};

/* **********************************************
     Begin prism-javascript.js
********************************************** */

Prism.languages.javascript = Prism.languages.extend('clike', {
    'keyword': /\b(var|let|if|else|while|do|for|return|in|instanceof|function|new|with|typeof|try|catch|finally|null|break|continue)\b/g,
   'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g
});

Prism.languages.insertBefore('javascript', 'keyword', {
  'regex': {
        pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,
        lookbehind: true
    }
});

if (Prism.languages.markup) {
   Prism.languages.insertBefore('markup', 'tag', {
     'script': {
           pattern: /(&lt;|<)script[\w\W]*?(>|&gt;)[\w\W]*?(&lt;|<)\/script(>|&gt;)/ig,
           inside: {
               'tag': {
                  pattern: /(&lt;|<)script[\w\W]*?(>|&gt;)|(&lt;|<)\/script(>|&gt;)/ig,
                    inside: Prism.languages.markup.tag.inside
               },
              rest: Prism.languages.javascript
            }
       }
   });
}

// Plugin Line Number

Prism.hooks.add('after-highlight', function (env) {
  // works only for <code> wrapped inside <pre data-line-numbers> (not inline)
    var pre = env.element.parentNode;
   if (!pre || !/pre/i.test(pre.nodeName) || pre.className.indexOf('line-numbers') === -1) {
     return;
 }

   var linesNum = (1 + env.code.split('\n').length);
    var lineNumbersWrapper;

 lines = new Array(linesNum);
    lines = lines.join('<span></span>');

  lineNumbersWrapper = document.createElement('span');
  lineNumbersWrapper.className = 'line-numbers-rows';
   lineNumbersWrapper.innerHTML = lines;

   if (pre.hasAttribute('data-start')) {
     pre.style.counterReset = 'linenumber ' + (parseInt(pre.getAttribute('data-start'), 10) - 1);
    }

   env.element.appendChild(lineNumbersWrapper);

});

Kode CSS Prism.js

/**
 * okaidia theme for JavaScript, CSS and HTML
 * Loosely based on Monokai textmate theme by http://www.monokai.nl/
 * @author ocodia
 */

code[class*="language-"],
pre[class*="language-"] {
 color: #f8f8f2;
 text-shadow: 0 1px rgba(0,0,0,0.3);
 font-family: Consolas, Monaco, 'Andale Mono', monospace;
  direction: ltr;
 text-align: left;
   white-space: pre;
   word-spacing: normal;

   -moz-tab-size: 4;
   -o-tab-size: 4;
 tab-size: 4;

    -webkit-hyphens: none;
  -moz-hyphens: none;
 -ms-hyphens: none;
  hyphens: none;
}

/* Code blocks */
pre[class*="language-"] {
 padding: 1em;
   margin: .5em 0;
 overflow: auto;
 border-radius: 0.3em;
}

:not(pre) > code[class*="language-"],
pre[class*="language-"] {
 background: #272822;
}

/* Inline code */
:not(pre) > code[class*="language-"] {
   padding: .1em;
  border-radius: .3em;
}

.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
 color: slategray;
}

.token.punctuation {
  color: #f8f8f2;
}

.namespace {
    opacity: .7;
}

.token.property,
.token.tag,
.token.constant,
.token.symbol {
 color: #f92672;
}

.token.boolean,
.token.number{
   color: #ae81ff;
}

.token.selector,
.token.attr-name,
.token.string,
.token.builtin {
 color: #a6e22e;
}


.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
 color: #f8f8f2;
}

.token.atrule,
.token.attr-value
{
    color: #e6db74;
}


.token.keyword{
color: #66d9ef;
}

.token.regex,
.token.important {
  color: #fd971f;
}

.token.important {
  font-weight: bold;
}

.token.entity {
  cursor: help;
}
pre.line-numbers {
    position: relative;
 padding-left: 3.8em;
    counter-reset: linenumber;
}

pre.line-numbers > code {
 position: relative;
}

.line-numbers .line-numbers-rows {
  position: absolute;
 pointer-events: none;
   top: 0;
 font-size: 100%;
    left: -3.8em;
   width: 3em; /* works for line-numbers below 1000 lines */
   letter-spacing: -1px;
   border-right: 1px solid #999;

   -webkit-user-select: none;
  -moz-user-select: none;
 -ms-user-select: none;
  user-select: none;

}

 .line-numbers-rows > span {
      pointer-events: none;
       display: block;
     counter-increment: linenumber;
  }

       .line-numbers-rows > span:before {
           content: counter(linenumber);
           color: #999;
            display: block;
         padding-right: 0.8em;
           text-align: right;
      }

Untuk mencobanya, anda hanya diharuskan mengupload file tersebut & memanggilnya dengan kode <pre class="language-markup"><code>Masukkan Kode Disini</code></pre>, untuk lebih jelasnya silahkan coba dengan menerapkan kode dibawah ini.

<!DOCTYPE html>
<html>
<head>
<title>Demo Syntax Highlighter (Prism.js)</title>
<style type="text/css">
body {
   background: #eee;
   font-size: 1.3em;
}
.utama {
  width: 70%;
 margin: 50px 15%;
}
.bersih  {
    clear: both;
}
h1, p {
    text-align: center;
}
a, a:hover, a:link, a:active {
  color: #000;
    text-decoration: none;
}
</style>
<link rel="stylesheet" href="prism.css" data-noprefix />
<script src="prism.js"></script>
</head>
<body>
<article class="utama">
<h1>Demo Syntax Highlighter (Prism.js)</h1>
<pre class="language-markup line-numbers"><code>&lt;p class="test"&gt;Test&lt;/p&gt;</code></pre>
<pre class="language-css line-numbers" data-src="prism.css"></pre>
<section class="bersih">&nbsp;</section>
<p><a href="http://www.nurulimam.com/2013/11/posting-kode-jadi-menarik-dengan-menggunakan-prism-js.html">Kembali ke Tutorial</a></p>
</article>
<script src="prism-file-highlight.js"></script>
</body>
</html>
Demo Prism.js Syntax Highlighter   Download Source

Bagus bukan tampilannya ? Jadi dengan adanya syntax highlighter ini, kegiatan posting artikel terutama tutorial yang sering menyisipkan kode-kode akan terasa lebih menarik & menyenangkan. Selamat mencoba :)

20 Comments

  1. Rohis FacebookReply

    dlu sempat pasang tp cz membuat blog jd berat makax sy hapus tp asalx bukan dr Prism.js, klo sy liat2 diatas kayak gk trlalu bikin berat ya?

    • Nurul ImamReply

      Loading halaman ini tidak berat kan ? Hayuk dicoba mas :)

  2. Mizz AizaReply

    kelihatan menarik tampilannya.. terima kasih sharing nya.. :D

    • Nurul ImamReply

      Sama-sama kak :)

  3. Ismail NReply

    This is way too advance for me. Yg simple-simple coding pun belum mahir lagi. Tapi, thanks for sharing.

    • Nurul ImamReply

      Just copy paste if mumet :D

  4. Cara RirinReply

    Lumayan banyak juga ya mas kode nya. Sampai sakit kepala saya membaca nya hehe :D peace :D

    • Nurul ImamReply

      Yakin nih kodenya dibaca :D

  5. Indi SugarReply

    keliatan lebih rapi, ya :)

    • Nurul ImamReply

      Iya mas, jadi lebih menarik kelihatannya :)

  6. Lucu Unik KonyolReply

    pusing liat code2 diatas gan

    • Nurul ImamReply

      Siapin obat sakit kepala klo kagak pantokin ke dinding palanya :D

  7. One'HeartReply

    ini kode buat blogger apa wp

    • Nurul ImamReply

      Bisa untuk keduanya :)
      Bebas dipakai dimana saja :D

      • One'HeartReply

        untuk menguploadnya di directory mana gan thema apa plugin

        • Nurul ImamReply

          Di direktori tema saja, nanti tinggal load url tempat script disimpan :)

  8. FEBRIKA SETIYAWANReply

    Wah…menarik nih kayaknya. Izin coba, mas. =)

    • Nurul ImamReply

      Silahkan :)

  9. Miss Universe PenasaReply

    […] menunjukkan keragaman budaya Indonesia. Ia bangga mengenakannya karena budaya Indonesia tidak kalah menarik dengan negara lain. ”Busana tradisional dapat tampil menarik dengan dirancang modern,” […]

  10. Lilis SuryaniReply

    Thanks kkak :)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>