Đăng Nhập

Vui lòng khai báo chính xác tên truy cập và mật khẩu!

Quên mật khẩu?

Đăng Ký

Bạn phải điền đầy đủ thông tin đăng ký!

  

[Code] zzPrismjs - Tối ưu khung code

    Quản trị viên

    avatar

    Bài viết : 89

    Tài sản : 275

    Uy tín : 7

    #1

     on 21.08.15 21:22 

    Trước đây, để làm nổi bật code, mình dùng Google Code Prettify, sau một thời gian, mình dần phát hiện ra các nhược điểm của nó, nhất là với các khung code dài.
    Vì thế, mình đã tìm và thay thế nó bằng plugin Prismjs.

    Ưu điểm:

    • Gọn nhẹ, mượt mà, dễ dàng tùy chọn giao diện và ngôn ngữ lập trình.
    • Không bị lỗi treo trình duyệt(firefox) ở những khung code dài.
    • Không bị cách đầu dòng khi sao chép code.
    • Kế thừa các tính năng bổ sung từ zzPrettify.
    • Có thể tạo plugin dựa trên các API được cung cấp.

    Nhược điểm:

    • Gây lỗi trình duyệt Chrome khi gặp script có chuỗi không phân tích được (hạn chế do mã regexp).




    Giao diện zzPrismjs


    Hướng dẫn

    Bước 1: Thêm vào CSS

    ACP >> Display >> Pictures and Colors >> Colors >> CSS Stylesheet

    Code:
    /* zzPrismjs v1 by devs forumvi */
    .codebox,.codebox *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
    .codebox{background:transparent;border:0 none;margin:0 0 10px}
    .codebox dd{background:transparent;margin:0;padding:0}
    .codebox > dt{position:relative;background:url(//i83.servimg.com/u/f83/16/58/89/73/page_w10.png) no-repeat scroll 10px center #777;color:#FFF;border:1px solid #e2e2e2;height:30px!important;border-bottom-width:0;line-height:26px!important;padding:2px 10px 0 30px!important}
    .codebox dd.cont_code{background:#FFF;max-height:100%!important;overflow:visible!important;position:relative;border:1px solid #e2e2e2}
    .cont_code > code{overflow:auto;white-space:pre;display:block;line-height:17px;padding:10px;word-break:break-word}
    .pun .controlCode,.pun .controlCode *{transition:all .3s;-webkit-transition:all .3s;-moz-transition:all .3s;-o-transition:all .3s;-ms-transition:all .3s}
    .pun .controlCode{position:absolute;right:0;top:-30px;opacity:0}
    .pun .codebox:hover .controlCode{opacity:1}
    .pun .controlCode *{width:20px;height:20px!important;display:block;float:right;border:1px solid #999;background:url(http://i.imgur.com/ccn5y7c.png) no-repeat center #FFF;margin:4px 4px 0 0 !important}
    .pun .controlCode input.findLine{background:url(http://i.imgur.com/8fxbcQy.png) no-repeat center #FFF!important;padding:0!important}
    .pun .controlCode input.findLine:focus{background:#FFF!important;width:40px;text-align:center;color:#333;font-size:11px}
    .pun .controlCode img.textCode{background-image:url(http://i.imgur.com/gXbPqhr.png)}
    .pun .controlCode img.textCode.pretty{background-image:url(http://i.imgur.com/FJOia1z.png)}
    .pun .controlCode :hover{cursor:pointer;border-color:#FFF}
    /* prism.js Coy theme for JavaScript, CSS and HTML by Tim  Shedor */
    code[class*="language-"],pre[class*="language-"]{color:#000;text-shadow:0 1px #FFF;white-space:pre}
    pre.line-numbers{background-color:#fdfdfd;background-image:-webkit-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);background-image:-moz-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);background-size:3em 2.6em;background-origin:content-box;position:relative;counter-reset:linenumber;overflow-y:hidden;padding:.1em 0 .1em 3.8em}
    .token.comment,.token.block-comment,.token.prolog,.token.doctype,.token.cdata{color:#7D8B99}
    .token.punctuation{color:#5F6364}
    .token.property,.token.tag,.token.boolean,.token.number,.token.function-name,.token.constant,.token.symbol{color:#c92c2c}
    .token.selector,.token.attr-name,.token.string,.token.function,.token.builtin{color:#2f9c0a}
    .token.atrule,.token.attr-value,.token.keyword,.token.class-name{color:#1990b8}
    .token.regex,.token.important{color:#e90}
    .token.operator,.token.entity,.token.url,.token.variable,.language-css .token.string,.style .token.string{color:#a67f59;background:rgba(255,255,255,0.5)}
    .namespace{opacity:.7}
    .token.important{font-weight:700}
    .token.entity{cursor:help}
    pre.line-numbers > code{padding:.1em 0;position:relative}
    .line-numbers .line-numbers-rows{padding:.1em 0;background:#F5F2F0;position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #DDD;-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:rgba(0,0,0,0.3);display:block;padding-right:.7em;text-align:right}
    @media print {code[class*="language-"],pre[class*="language-"]{text-shadow:none}}
    Cách giới hạn chiều cao khung code 250px:
    Tìm style của pre.line-numbers, xóa thuộc tính:
    Code:
    overflow-y:hidden;
    Thêm vào thuộc tính mới:
    Code:
    max-height:250px;
    Tìm style của .pun .controlCode input.findLine, thêm vào thuộc tính
    Code:
    display:none;

    Bước 2: Thêm code vào cuối 2 temp viewtopic_bodyposting_preview

    ACP >> Display >> Templates >> QLTT >> viewtopic_body
    ACP >> Display >> Templates >> Post & Private Messages >> posting_preview

    Code:
    <script src="http://devs.forumvi.com/34660.js" type="text/javascript"></script>
    [spoiler=Source 34660.js]
    Code:
    /* Language test css - html - js by baivong <http://devs.forumvi.com> */
    $("br", "code").replaceWith("\n");
    $("code").wrap('<pre class="line-numbers"></pre>').parent().addClass(function () {
       var a = $(this).text();
       return "language-" + (/^[\s\n]*<[\s\S]+>[\s\n]*$/.test(a) ? "markup" : /\bif\s?\(.+\)\{?[\s\S]+\}?|\bif\s?\(.+\)\{?[\s\S]+\}?\s?else\s?\{?|;?\s?while\s?\(|\bfor\s?\(.+\)|\bfunction:\s?\w+|\w+\sfunction\s\(|\(function\s?\(.*?\)\s?\{|\b(var\s)?\w+\s?=\s?('|")?[\w\d]+('|")?(;|,)?|\}\);?|\}\n*(,|;)|('|")?\w+('|")?\s?:\s?('|")[\w\d]+('|")(,|\})|\b(true|false)\b|(^|[^\/])\/(?!\/)[^\*].+[^\*]\/[gimy]{0,4}(?=\s*($|[\r\n,.})]))|\(('|").+('|")\)|\((window|document)\)/g.test(a.replace(/\/\*.*\*\//g, "")) && !/DXImageTransform\.Microsoft/g.test(a) ? "javascript" : "css")
    });
    /* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript&plugins=line-numbers */
    (function () {
       var l = "undefined" != typeof window ? window : {},
          c = function () {
             var c = /\blang(?:uage)?-(?!\*)(\w+)\b/i,
                d = l.Prism = {
                   util: {
                      type: function (a) {
                         return Object.prototype.toString.call(a).match(/\[object (\w+)\]/)[1]
                      },
                      clone: function (a) {
                         switch (d.util.type(a)) {
                         case "Object":
                            var e = {},
                               b;
                            for (b in a) a.hasOwnProperty(b) && (e[b] = d.util.clone(a[b]));
                            return e;
                         case "Array":
                            return a.slice()
                         }
                         return a
                      }
                   },
                   languages: {
                      extend: function (a, e) {
                         var b = d.util.clone(d.languages[a]),
                            h;
                         for (h in e) b[h] = e[h];
                         return b
                      },
                      insertBefore: function (a, e, b, h) {
                         h = h || d.languages;
                         var f = h[a],
                            g = {},
                            k;
                         for (k in f)
                            if (f.hasOwnProperty(k)) {
                               if (k == e)
                                  for (var c in b) b.hasOwnProperty(c) && (g[c] = b[c]);
                               g[k] = f[k]
                            }
                         return h[a] = g
                      },
                      DFS: function (a, e) {
                         for (var b in a) e.call(a, b, a[b]), "Object" === d.util.type(a) && d.languages.DFS(a[b], e)
                      }
                   },
                   highlightAll: function (a, e) {
                      for (var b = document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'), h = 0, f; f = b[h++];) d.highlightElement(f, !0 === a, e)
                   },
                   highlightElement: function (a, e, b) {
                      for (var h, f, g = a; g && !c.test(g.className);) g = g.parentNode;
                      g && (h = (g.className.match(c) || [, ""])[1], f = d.languages[h]);
                      if (f && (a.className = a.className.replace(c, "").replace(/\s+/g, " ") + " language-" + h, g = a.parentNode, /pre/i.test(g.nodeName) && (g.className = g.className.replace(c, "").replace(/\s+/g, " ") + " language-" + h), g = a.textContent)) {
                         var g = g.replace(/&/g, "&amp;").replace(/</g, "<").replace(/\u00a0/g, " "),
                            k = {
                               element: a,
                               language: h,
                               grammar: f,
                               code: g
                            };
                         d.hooks.run("before-highlight", k);
                         e && l.Worker ? (a = new Worker(d.filename), a.onmessage = function (a) {
                            k.highlightedCode = p.stringify(JSON.parse(a.data), h);
                            d.hooks.run("before-insert", k);
                            k.element.innerHTML = k.highlightedCode;
                            b && b.call(k.element);
                            d.hooks.run("after-highlight", k)
                         }, a.postMessage(JSON.stringify({
                            language: k.language,
                            code: k.code
                         }))) : (k.highlightedCode = d.highlight(k.code, k.grammar, k.language), d.hooks.run("before-insert", k), k.element.innerHTML = k.highlightedCode, b && b.call(a), d.hooks.run("after-highlight", k))
                      }
                   },
                   highlight: function (a, e, b) {
                      return p.stringify(d.tokenize(a, e), b)
                   },
                   tokenize: function (a, e, b) {
                      b = d.Token;
                      var h = [a],
                         f = e.rest;
                      if (f) {
                         for (var g in f) e[g] = f[g];
                         delete e.rest
                      }
                      a: for (g in e)
                         if (e.hasOwnProperty(g) && e[g])
                            for (var f = e[g], c = f.inside, p = !!f.lookbehind, l = 0, f = f.pattern || f, s = 0; s < h.length; s++) {
                               var q = h[s];
                               if (h.length > a.length) break a;
                               if (!(q instanceof b)) {
                                  f.lastIndex = 0;
                                  var n = f.exec(q);
                                  if (n) {
                                     p && (l = n[1].length);
                                     var m = n.index - 1 + l,
                                        n = n[0].slice(l),
                                        r = m + n.length,
                                        m = q.slice(0, m + 1),
                                        q = q.slice(r + 1),
                                        r = [s, 1];
                                     m && r.push(m);
                                     n = new b(g, c ? d.tokenize(n, c) : n);
                                     r.push(n);
                                     q && r.push(q);
                                     Array.prototype.splice.apply(h, r)
                                  }
                               }
                            }
                      return h
                   },
                   hooks: {
                      all: {},
                      add: function (a, e) {
                         var b = d.hooks.all;
                         b[a] = b[a] || [];
                         b[a].push(e)
                      },
                      run: function (a, e) {
                         var b = d.hooks.all[a];
                         if (b && b.length)
                            for (var c = 0, f; f = b[c++];) f(e)
                      }
                   }
                },
                p = d.Token = function (a, d) {
                   this.type = a;
                   this.content = d
                };
             p.stringify = function (a, e, b) {
                if ("string" == typeof a) return a;
                if ("[object Array]" == Object.prototype.toString.call(a)) return a.map(function (b) {
                   return p.stringify(b, e, a)
                }).join("");
                b = {
                   type: a.type,
                   content: p.stringify(a.content, e, b),
                   tag: "span",
                   classes: ["token", a.type],
                   attributes: {},
                   language: e,
                   parent: b
                };
                "comment" == b.type && (b.attributes.spellcheck = "true");
                d.hooks.run("wrap", b);
                var c = "",
                   f;
                for (f in b.attributes) c += f + '="' + (b.attributes[f] || "") + '"';
                return "<" + b.tag + ' class="' + b.classes.join(" ") + '" ' + c + ">" + b.content + "</" + b.tag + ">"
             };
             if (!l.document) {
                if (!l.addEventListener) return l.Prism;
                l.addEventListener("message", function (a) {
                   a = JSON.parse(a.data);
                   l.postMessage(JSON.stringify(d.tokenize(a.code, d.languages[a.language])));
                   l.close()
                }, !1);
                return l.Prism
             }
             var m = document.getElementsByTagName("script");
             if (m = m[m.length - 1]) d.filename = m.src, document.addEventListener && !m.hasAttribute("data-manual") && document.addEventListener("DOMContentLoaded", d.highlightAll);
             return l.Prism
          }();
       "undefined" != typeof module && module.exports && (module.exports = c);
       c.languages.markup = {
          comment: /<!--[\w\W]*?--\x3e/g,
          prolog: /<\?.+?\?>/,
          doctype: /<!DOCTYPE.+?>/,
          cdata: /<!\[CDATA\[[\w\W]*?]]\x3e/i,
          tag: {
             pattern: /<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/gi,
             inside: {
                tag: {
                   pattern: /^<\/?[\w:-]+/i,
                   inside: {
                      punctuation: /^<\/?/,
                      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
       };
       c.hooks.add("wrap", function (c) {
          "entity" === c.type && (c.attributes.title = c.content.replace(/&amp;/, "&"))
       });
       c.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
       };
       c.languages.markup && c.languages.insertBefore("markup", "tag", {
          style: {
             pattern: /(<|<)style[\w\W]*?(>|>)[\w\W]*?(<|<)\/style(>|>)/ig,
             inside: {
                tag: {
                   pattern: /(<|<)style[\w\W]*?(>|>)|(<|<)\/style(>|>)/ig,
                   inside: c.languages.markup.tag.inside
                },
                rest: c.languages.css
             }
          }
       });
       c.languages.clike = {
          comment: {
             pattern: /(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,
             lookbehind: !0
          },
          string: /("|')(\\?.)*?\1/g,
          "class-name": {
             pattern: /((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/ig,
             lookbehind: !0,
             inside: {
                punctuation: /(\.|\\)/
             }
          },
          keyword: /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|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}|!|<=?|>=?|={1,3}|(&amp;){1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,
          ignore: /&(lt|gt|amp);/gi,
          punctuation: /[{}[\];(),.:]/g
       };
       c.languages.javascript = c.languages.extend("clike", {
          keyword: /\b(var|let|if|else|while|do|for|return|in|instanceof|function|get|set|new|with|typeof|try|throw|catch|finally|null|break|continue|this)\b/g,
          number: /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g
       });
       c.languages.insertBefore("javascript", "keyword", {
          regex: {
             pattern: /(^|[^\/])\/(?!\/)[^\*].+[^\*]\/[gimy]{0,4}(?=\s*($|[\r\n,.})]))/g,
             lookbehind: !0
          }
       });
       c.languages.markup && c.languages.insertBefore("markup", "tag", {
          script: {
             pattern: /(<|<)script[\w\W]*?(>|>)[\w\W]*?(<|<)\/script(>|>)/ig,
             inside: {
                tag: {
                   pattern: /(<|<)script[\w\W]*?(>|>)|(<|<)\/script(>|>)/ig,
                   inside: c.languages.markup.tag.inside
                },
                rest: c.languages.javascript
             }
          }
       });
       c.hooks.add("after-highlight", function (c) {
          var d = c.element.parentNode;
          if (d && /pre/i.test(d.nodeName) && -1 !== d.className.indexOf("line-numbers")) {
             var l = 1 + c.code.split("\n").length;
             lines = Array(l);
             lines = lines.join("<span></span>");
             l = document.createElement("span");
             l.className = "line-numbers-rows";
             l.innerHTML = lines;
             d.hasAttribute("data-start") && (d.style.counterReset = "linenumber " + (parseInt(d.getAttribute("data-start"), 10) - 1));
             c.element.appendChild(l)
          }
       })
    })();
    /* zzPrismjs v1 by baivong <http://devs.forumvi.com>  */
    function selectCode(a) {
       a = $(a).parent().next()[0];
       if (window.getSelection) {
          var b = window.getSelection();
          if (b.setBaseAndExtent) b.setBaseAndExtent(a, 0, a, a.innerText.length - 1);
          else {
             window.opera && "<BR>" == a.innerHTML.substring(a.innerHTML.length - 4) && (a.innerHTML += " ");
             var c = document.createRange();
             c.selectNodeContents(a);
             b.removeAllRanges();
             b.addRange(c)
          }
       } else document.getSelection ? (b = document.getSelection(), c = document.createRange(), c.selectNodeContents(a), b.removeAllRanges(), b.addRange(c)) : document.selection && (c = document.body.createTextRange(), c.moveToElementText(a), c.select())
    }
    $(function () {
       $("dd.cont_code").prepend('<div class="controlCode"><img class="selectCode" title="Click để chọn toàn bộ code" onclick="selectCode(this)" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" /><img class="textCode" title="Ẩn số dòng" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" /><input class="findLine" title="Nhập số dòng muốn chuyển đến" size="4" maxlength="4" type="text" /></div>');
       $(".findLine").on("input", function () {
          this.value = /\d+/g.exec(this.value)
       }).keydown(function (a) {
          var b = $(this);
          13 == a.keyCode ? (a = b.parent().next().find(".line-numbers-rows").find("span:eq(" + (parseInt(this.value, 10) - 1) + ")"), a.length && $("body, html").animate({
             scrollTop: a.offset().top
          }), this.value = "") : $("body, html").animate({
             scrollTop: b.offset().top - 50
          })
       }).focus(function () {
          $(this).parent().css("opacity", 1)
       }).blur(function () {
          this.value = "";
          $(this).parent().removeAttr("style")
       });
       $(".textCode").click(function () {
          var a = $(this),
             b = a.parent().next();
          a.toggleClass("pretty");
          a.hasClass("pretty") ? (b.animate({
             "padding-left": "0.8em"
          }), a.attr("title", "Hiện số dòng")) : (b.animate({
             "padding-left": "3.8em"
          }), a.attr("title", "Ẩn số dòng"))
       })
    });

    Tags: #code
    You cannot reply to topics in this forum