`
zerozone
  • 浏览: 205431 次
  • 来自: 北京
社区版块
存档分类
最新评论

How to implement a syntax hiliter in JavaScript?

阅读更多
Recently, I'd participated in an AJAX/RIA project. Our team included about 5 members: one lead, two programmers and two QAs. The main goal of this project is to provide a prototype for asset management by using <st1:city w:st="on"><st1:place w:st="on">AJAX</st1:place></st1:city> technologies. As you know, <st1:city w:st="on"><st1:place w:st="on">AJAX</st1:place></st1:city> application can provide rich and good experience to the user. For example, the application used <st1:city w:st="on"><st1:place w:st="on">AJAX</st1:place></st1:city> is almost composed of several pages and other resources like CSS and images. Therefore, the transfer amount between client and server could be down and at the same time the user's operation interruption are to avoided.

For some reasons, we chose a commercial framework SmartClient as our toolkit for developing <st1:city w:st="on"><st1:place w:st="on">AJAX</st1:place></st1:city>. SmartClient is without question the one of bested AJAX GUI system or frameworks. We expressed deeply by its functionalities and effects. It provided various client components, plentiful documents and examples. You can easily find the answer we want. But, the biggest limitation of SmartClient is that it is commercial software, so we could not see more detailed of it. As a result, the development was difficulty when you desire to extend some components. Anyway, SmartClient is good <st1:city w:st="on"><st1:place w:st="on">AJAX</st1:place></st1:city> library except for high price and development efficiency.

We spent about two months to archive this prototype. Finally, this prototype gave our teammates and the customer good impression finally.

The source code from SmartClient is high quality code; easy understanding, simple and clean. JavaScript is an object based programming language. We used to thinking in OO because we are Object-Oriented programmer. Maybe some book mentioned the techniques for writing Object-Oriented programs in JavaScript. Standing the shoulders of giants, you can get through the mountaintop more quickly and safely. Reading high quality source code could be a short cut to become a software craftsman.
js 代码
 
  1. if(window.isc&&window.isc.module_Core&&!window.isc.module_SyntaxHiliter)  
  2. {  
  3.     isc.module_SyntaxHiliter=1;  
  4.     isc._moduleStart=isc._SyntaxHiliter_start=(isc.timestamp?isc.timestamp():new Date().getTime());  
  5.     if(isc._moduleEnd&&(!isc.Log||(isc.Log && isc.Log.logIsDebugEnabled('loadTime'))))  
  6.     {  
  7.         isc._pTM=  
  8.         {  
  9.             message:'SyntaxHiliter load/parse time: ' + (isc._moduleStart-isc._moduleEnd) + 'ms', category:'loadTime'  
  10.         };  
  11.         if(isc.Log && isc.Log.logDebug)isc.Log.logDebug(isc._pTM.message,'loadTime')  
  12.         else if(isc._preLog)isc._preLog[isc._preLog.length]=isc._pTM  
  13.         else isc._preLog=[isc._pTM]  
  14.     }  
  15.     isc.defineClass("SyntaxHiliter");  
  16.     isc.A=isc.SyntaxHiliter.getPrototype();  
  17.     isc.A.spanStart=";  
  18.     isc.A.spanStartClose="'>";  
  19.     isc.A.spanEnd="";  
  20.     isc.A=isc.SyntaxHiliter.getPrototype();  
  21.     isc.B=isc._allFuncs;  
  22.     isc.C=isc.B._maxIndex;  
  23.     isc.D=isc._funcClasses;  
  24.     isc.D[isc.C]=isc.A.Class;  
  25.     isc.B.push(isc.A.init=function()  
  26.     {  
  27.         this.fixedSpanLengths=this.spanStart.length+this.spanStartClose.length+this.spanEnd.length;  
  28.         this.spanEndLength=this.spanEnd.length  
  29.     }  
  30.     ,isc.A.hilite=function(_1,_2,_3,_4)  
  31.     {  
  32.         var _5=this.regexps;  
  33.         if(!_5)return _1;  
  34.         var _6=[_1];  
  35.         for(var _7=0;_7<_5.length;_7++)  
  36.         {  
  37.             var _8=_5[_7];  
  38.             var _9=_8.regexp;  
  39.             var _10=_8.cssStyles;  
  40.             if(!isc.isAn.Array(_10))_10=[_10];  
  41.             var _11=0;  
  42.             while(_11<_6.length)  
  43.             {  
  44.                 var _12=_6[_11];  
  45.                 if(_12==null)  
  46.                 {  
  47.                     _22+=this.fixedSpanLengths+_6[_11+2].length+_6[_11+4].length;  
  48.                     _11+=6;  
  49.                     continue  
  50.                 }  
  51.                 var _13=_9.exec(_12);  
  52.                 if(_13==null)  
  53.                 {  
  54.                     _11++;  
  55.                     _22+=_12.length;  
  56.                     continue  
  57.                 }  
  58.                 if(_13.length-1!=_10.length)  
  59.                 {  
  60.                     this.logWarn("regexp: "+_9+" matched "+(_13.length-1)+" groups, but only "+_10.length+" cssStyles are defined - skipping this regexp.");  
  61.                     _11=_6.length;  
  62.                     continue  
  63.                 }  
  64.                 var _14=_13[0];  
  65.                 var _15=_13.index;  
  66.                 _22+=_15;  
  67.                 var _16=_12.substring(0,_15);  
  68.                 var _17=_12.substring(_15+_14.length);  
  69.                 if(_16.length>0)  
  70.                 {  
  71.                     _6.splice(_11++,1,_16,_17)  
  72.                 }  
  73.                 else  
  74.                 {  
  75.                     _6[_11]=_17  
  76.                 }  
  77.                 for(var _18=1;_18<_13.length;_18++)  
  78.                 {  
  79.                     var _19=_13[_18]||isc.emptyString;  
  80.                     var _20=_10[_18-1];  
  81.                     if(_20==null)  
  82.                     {  
  83.                         _6.splice(_11++,0,_19);  
  84.                         continue  
  85.                     }  
  86.                     var _21=isc.Canvas.getStyleText(_20)||isc.emptyString;  
  87.                     _6.splice(_11,0,null,this.spanStart,_21,this.spanStartClose,_19,this.spanEnd);  
  88.                     _11+=6  
  89.                 }  
  90.             }  
  91.         }  
  92.         var _22=0;  
  93.         var _23=_3!=null;  
  94.         for(var i=0;i<_6.length;i++)  
  95.         {  
  96.             var _12=_6[i];  
  97.             var _25;  
  98.             if(_12==null)  
  99.             {  
  100.                 _12=_6[i+4];  
  101.                 _25=_12.asHTML(!this.autoWrap);  
  102.                 if(_23&&_3>_22)  
  103.                 {  
  104.                     if(_3<(_22+_12.length))  
  105.                     {  
  106.                         var _26=_3-_22;  
  107.                         _27=_12.slice(0,_26);  
  108.                         _3+=_27.asHTML(!this.autoWrap).length-_27.length;  
  109.                         _3-=this.spanEndLength  
  110.                     }  
  111.                     else  
  112.                     {  
  113.                         _3+=_25.length-_12.length  
  114.                     }  
  115.                     _3+=this.fixedSpanLengths+_6[i+2].length;  
  116.                     _22+=_25.length+this.fixedSpanLengths+_6[i+2].length  
  117.                 }  
  118.                 else  
  119.                 {  
  120.                     _23=false  
  121.                 }  
  122.                 _6[i+4]=_25;  
  123.                 i+=5;  
  124.                 continue  
  125.             }  
  126.             _25=_12.asHTML(!this.autoWrap);  
  127.             if(_23&&_3>_22)  
  128.             {  
  129.                 if(_3<(_22+_12.length))  
  130.                 {  
  131.                     var _26=_3-_22;  
  132.                     var _27=_12.slice(0,_26);  
  133.                     _3+=_27.asHTML(!this.autoWrap).length-_27.length  
  134.                 }  
  135.                 else  
  136.                 {  
  137.                     _3+=_25.length-_12.length  
  138.                 }  
  139.                 _22+=_25.length  
  140.             }  
  141.             else  
  142.             {  
  143.                 _23=false  
  144.             }  
  145.             _6[i]=_25  
  146.         }  
  147.         var _28=_6.join(isc.emptyString);  
  148.         if(_3!=null)  
  149.         {  
  150.             _28=_28.slice(0,_3)+_4+_28.slice(_3,_28.length)  
  151.         }  
  152.         if(_2)  
  153.         {  
  154.             var _29=[];  
  155.             var _30;  
  156.             while((_30=_28.indexOf("
    "
    ))!=-1)  
  157.             {  
  158.                 var _31=_28.slice(0,_30+4);  
  159.                 _28=_28.substring(_30+4);  
  160.                 _29[_29.length]=_31  
  161.             }  
  162.             if(_28.length)_29[_29.length]=_28;  
  163.             return _29  
  164.         }  
  165.         else  
  166.         {  
  167.             return _28  
  168.         }  
  169.     }  
  170.     ,isc.A.containsMultilineToken=function(_1)  
  171.     {  
  172.         if(this.multilineTokens)  
  173.         {  
  174.             for(var i=0;i<this.multilineTokens.length;i++)  
  175.             if(_1.match(this.multilineTokens[i]))return true  
  176.         }  
  177.         return false  
  178.     }  
  179.     );  
  180.     isc.B._maxIndex=isc.C+3;  
  181.     isc.defineClass("JSSyntaxHiliter","SyntaxHiliter");  
  182.     isc.A=isc.JSSyntaxHiliter.getPrototype();  
  183.     isc.A.regexps=[  
  184.     {  
  185.         regexp:/(\/\*.*?\*\/)/,cssStyles:"js_multilineComment"  
  186.     }  
  187.     ,  
  188.     {  
  189.         regexp:/(\/\/.*)/,cssStyles:"js_lineComment"  
  190.     }  
  191.     ,  
  192.     {  
  193.         regexp:/("(?:[^"\n]|\\")*")/,cssStyles:"js_doubleQuotedString"  
  194.     }  
  195.     ,  
  196.     {  
  197.         regexp:/('(?:[^'\n]|\\')*')/,cssStyles:"js_singleQuotedString"  
  198.     }  
  199.     ,  
  200.     {  
  201.         regexp:/(\/(?:\\\/|[^\/\n])+\/)/,cssStyles:"js_regex"  
  202.     }  
  203.     ,  
  204.     {  
  205.         regexp:/([^a-zA-Z0-9_$:]|^)(abstract|boolean|break|byte|case|char|class|const|continue|default|delete|do|dougle|else|enum|extends|final|finally|float|for|fun[c]tion|goto|if|implements|import|in|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|super|switch|synchronized|this|throw|throws|transient|try|typeof|var|void|while|with)([^a-zA-Z0-9_$:]|$)/,cssStyles:[null,"js_reservedWord",null]  
  206.     }  
  207.     ,  
  208.     {  
  209.         regexp:/([^a-zA-Z0-9_$:]|^)(true|false|null)([^a-zA-Z0-9_$:]|$)/,cssStyles:[null,"js_nativeValue",null]  
  210.     }  
  211.     ,  
  212.     {  
  213.         regexp:/([a-zA-Z][a-zA-Z0-9_$]*)(\s*:)/,cssStyles:["js_label",null]  
  214.     }  
  215.     ];  
  216.     isc.A.multilineTokens=[/(\/\*)|(\*\/)/];  
  217.     isc.defineClass("CSSSyntaxHiliter","SyntaxHiliter");  
  218.     isc.A=isc.CSSSyntaxHiliter.getPrototype();  
  219.     isc.A.regexps=[  
  220.     {  
  221.         regexp:/(\/\*.*?\*\/)/,cssStyles:"css_multilineComment"  
  222.     }  
  223.     ,  
  224.     {  
  225.         regexp:/(\/\/.*)/,cssStyles:"css_lineComment"  
  226.     }  
  227.     ,  
  228.     {  
  229.         regexp:/([a-zA-Z][a-zA-Z0-9_$\-]*)(\s*:)/,cssStyles:["css_label",null]  
  230.     }  
  231.     ];  
  232.     isc.A.multilineTokens=[/(\/\*)|(\*\/)/];  
  233.     isc.defineClass("XMLSyntaxHiliter","SyntaxHiliter");  
  234.     isc.A=isc.XMLSyntaxHiliter.getPrototype();  
  235.     isc.A.regexps=[  
  236.     {  
  237.         regexp:/(<!---->)/,cssStyles:"xml_cdataBlock"  
  238.     }  
  239.     ,  
  240.     {  
  241.         regexp:/(<!---->)/,cssStyles:"xml_comment"  
  242.     }  
  243.     ,  
  244.     {  
  245.         regexp:/(\w+)(=)("(?:[^"]|\\")*")/,cssStyles:["xml_attributeName",null,"xml_attributeValue"]  
  246.     }  
  247.     ,  
  248.     {  
  249.         regexp:/(<\/?)([_:A-Za-z][A-Za-z0-9_.:\-]*)/,cssStyles:[null,"xml_tagName"]  
  250.     }  
  251.     ];  
  252.     isc.A.multilineTokens=[/(<!---->)/,/(<!---->)/];  
  253.     isc._moduleEnd=isc._SyntaxHiliter_end=(isc.timestamp?isc.timestamp():new Date().getTime());  
  254.     if(isc.Log&&isc.Log.logIsInfoEnabled('loadTime'))isc.Log.logInfo('SyntaxHiliter module init time: ' + (isc._moduleEnd-isc._moduleStart) + 'ms','loadTime');  
  255. }  
  256. else  
  257. {  
  258.     if(window.isc && isc.Log && isc.Log.logWarn)isc.Log.logWarn("Duplicate load of module 'SyntaxHiliter'.");  
  259. }  

As you see, those source codes are very clean simple. SyntaxHiliter is an interface that defines the functionality for syntax highlighting. JSSyntaxHiliter, XMLSyntaxHiliter and CSSSyntaxHiliter could be thinking as implementation for JavaScript, XML and CSS.

Reading source code can be fun!
分享到:
评论

相关推荐

    源码+书Hands-on Data Structures and Algorithms with JavaScript

    If you are a JavaScript developer looking for practical examples to implement data structures and algorithms in your web applications, then this book is for you. Familiarity with data structures and ...

    ES6 for Humans The Latest Standard of JavaScript: ES2015 and Beyond

    You'll examine how to use ES6 in functional programming and explore the new more modular and object-oriented approach to JavaScript. This book will help you sharpen and upgrade your JavaScript ...

    JavaScript.JSON.Cookbook.1785286900

    You'll also explore how to use JSON in a type-safe manner, writing programs that have fewer bugs. Table of Contents Chapter 1: Reading and Writing JSON on the Client Chapter 2 : Reading and Writing ...

    Mastering React Native 2017年出版496页

    It shows you how to develop a clear workflow to build scalable applications, and how to implement the architectural concepts covered to build applications that shine in the real world.

    Mastering TypeScript-Second Edition[February 2017]

    It then shows how to implement a simple Dependency Injection framework using Decorators. Chapter 13, Building Applications, explores the fundamental building blocks of web application development, ...

    Vue.js 2 Cookbook 2017年出版760页

    Finally, we take an in-depth look at Vuex for state management and Vue Router to route in your single page applications, and integrate a variety of technologies ranging from Node.js to Electron, and ...

    Web Developer's Reference Guide(PACKT,2016)

    Finally, you will take a walk-through Node.js, which is a server-side framework that allows you to write programs in JavaScript. What You Will Learn Explore detailed explanations of all the major ...

    Node.js Design Patterns_Second Edition

    The book is meant for developers and software architects with a basic working knowledge of JavaScript who are interested in acquiring a deeper understanding of how to design and develop enterprise-...

    Expert Angular

    To easily build applications that look great, you will learn all about template syntax and how to beautify applications with Material Design. Mastering forms and data binding will further speed up ...

    Vue.js 2 Cookbook

    Finally, we take an in-depth look at Vuex for state management and Vue Router to route in your single page applications, and integrate a variety of technologies ranging from Node.js to Electron, and ...

    Mastering React Native

    This book will show you how to apply JavaScript and other front-end skills to build cross-platform React Native applications for iOS and Android using a single codebase. This book will provide you ...

    java7帮助文档

    You can check the status variable of the applet while it is loading to determine if the applet is ready to handle requests from JavaScript code; see Handling Initialization Status With Event Handlers....

    Knockout API 中文版

    jQuery doesn’t have a concept of an underlying data model, so to get the number of items you have to infer it from the number of TRs in a table or the number of DIVs with a certain CSS class....

    php.ini-development

    If you use constants in your value, and these constants belong to a ; dynamically loaded extension (either a PHP extension or a Zend extension), ; you may only use these constants *after* the line ...

Global site tag (gtag.js) - Google Analytics