Montag, 12. Oktober 2015

SyntaxHighlighter im SharePoint

In diesem Bog verwende ich den Syntax Highlighter von Alex Gorbatchev​ - ich finde Code sieht dann gut aus.

Im SharePoint habe ich den bisher immer vermisst. Das hat nun ein ende: Ich habe eine Sandbox-Solution​ erstellt, die die Dateien des Syntax Highlighter im SharePoint (auf SiteCollectioin-Ebene) bereitstellt und zusätzlich ein Feature (auf Web-Ebene) dass jede angezeigte Seite nach Syntax Highlighter-Formatierungen durchsucht und die entsprechenden Dateien dynamisch lädt.

Dafür habe ich das folgende js-File verwendet:

if (!!window.Type) {
    //this is 'normal'
    Type.registerNamespace('SpSyntaxHighlighter');
} else {
    //this happend on i.e. EditBlog.aspx
    window.SpSyntaxHighlighter = window.SpSyntaxHighlighter || {};
}
SpSyntaxHighlighter.shAutoConfig = [[ 'applescript' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushAppleScript.js'],
[ 'actionscript3', 'as3' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushAS3.js'],
[ 'bash', 'shell' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushBash.js'],
[ 'coldfusion','cf' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushColdFusion.js'],
[ 'cpp', 'c' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushCpp.js'],
[ 'c#', 'c-sharp', 'csharp' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushCSharp.js'],
[ 'css' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushCss.js'],
[ 'delphi', 'pascal', 'pas' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushDelphi.js'],
[ 'diff', 'patch' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushDiff.js'],
[ 'erl', 'erlang' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushErlang.js'],
[ 'groovy' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushGroovy.js'],
[ 'java' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushJava.js'],
[ 'jfx', 'javafx' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushJavaFX.js'],
[ 'js', 'jscript', 'javascript' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushJScript.js'],
[ 'perl', 'Perl', 'pl' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushPerl.js'],
[ 'php' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushPhp.js'],
[ 'text', 'plain' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushPlain.js'],
[ 'powershell', 'ps' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushPowerShell.js'],
[ 'py', 'python' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushPython.js'],
[ 'ruby', 'rails', 'ror', 'rb' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushRuby.js'],
[ 'sass', 'scss' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushSass.js'],
[ 'scala' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushScala.js'],
[ 'sql' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushSql.js'],
[ 'vb', 'vbnet' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushVb.js'],
[ 'xml', 'xhtml', 'xslt', 'html' , '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/shBrushXml.js']];
SpSyntaxHighlighter.canApplySyntaxHighlighter = function () {
    /// Check, if SyntaxHighlighter should be applied. I.e. returns false, if something is in edit mode..
    /// fals, if loading of SyntaxHighlighter should be disabled
    var rteFields = document.getElementsByClassName('ms-rtefield');
    // check if page is in edit-mode or edit-form or something..
    // do not (!) modify source in an editor - because that will lead to the modification being saved...
    if (rteFields.length > 0) {
        SP.UI.Notify.addNotification('Edit-Mode detected. SyntaxHighlighter disabled.', false);
        return false;
    }
    return true;
};
SpSyntaxHighlighter.addEvent = function (elm, evt, func) {
    if (elm.addEventListener) {
        elm.addEventListener(evt, func);
    } else if (elm.attachEvent) {
        elm.attachEvent('on' + evt, func);
    } else {
        elm['on' + evt] = func;
    }
};
SpSyntaxHighlighter.removeEvent = function (elm, evt, func) {
    if (elm.removeEventListener) {
        elm.removeEventListener(evt, func);
    } else if (elm.detachEvent) {
        elm.detachEvent('on' + evt, func);
    } else {
        elm['on' + evt] = null;
    }
};
SpSyntaxHighlighter.loadScript = function (url, successHandler, errorHandler) {
    var script = document.createElement('script'),
        loaded, error;
    script.src = url;
    script.type = 'text/javascript';
    script.language = 'javascript';
    loaded = function () {
        SpSyntaxHighlighter.removeEvent(script, 'load', loaded);
        SpSyntaxHighlighter.removeEvent(script, 'error', error);
        if (successHandler) {
            successHandler(script);
        }
    };
    error = function () {
        SpSyntaxHighlighter.removeEvent(script, 'load', loaded);
        SpSyntaxHighlighter.removeEvent(script, 'error', error);
        if (errorHandler) {
            errorHandler();
        }
    };
 
    SpSyntaxHighlighter.addEvent(script, 'load', loaded);
    SpSyntaxHighlighter.addEvent(script, 'error', error);
    document.body.appendChild(script);
};
SpSyntaxHighlighter.loadCss = function (url) {
    var link = document.createElement('link');
    link.href = url;
    link.type = 'text/css';
    link.rel = 'stylesheet';
    document.head.appendChild(link);
};
SpSyntaxHighlighter.loadBrushes = function(success) {
    // replaces shAutoloader.js - I dont like the way it works...
    var oldHighlight = SyntaxHighlighter.highlight,
        highlightCalled = false,
        elements = SyntaxHighlighter.findElements(),
        processes = [{
            id: 'loadBrushes',
            done: false
        }],
        chechAllDone = function () {
            var done = true,
                i;
            for (i = 0; i < processes.length; i += 1) {
                if (!(processes[i].done)) {
                    done = false;
                    break;
                }
            }
             
            if(done){
                // everything is done. finish here...
                SyntaxHighlighter.highlight = oldHighlight;
                if(highlightCalled !== false) {
                    SyntaxHighlighter.highlight.call(SyntaxHighlighter, highlightCalled);
                }
                if (!!success) {
                    success();
                }
            }
        },
        buildBrushes = function(){
            var cfg = SpSyntaxHighlighter.shAutoConfig,
                brushes = {},
                cfgLine,
                url,
                i,j;
            for(i=0; i< cfg.length; i+=1) {
                cfgLine = cfg[i];
                url = cfgLine[cfgLine.length-1];
                for(j=(cfgLine.length-2); j >= 0; j -=1) {
                    brushes[cfgLine[j]] = url;
                }
            }
            return brushes;
        },
        brushes = buildBrushes(),
        processing = function(id) {
            var i;
            for(i=0; i < processes.length; i+=1) {
                if(id === processes[i].id) {
                    return processes[i];
                }
            }
            return false;
        },
        i,
        alias,      
        url;
    SyntaxHighlighter.highlight = function (parm) {
        // dont call highlight while Im searching
        highlightCalled = parm;
    };
    // now process the elements..
    for(i=0; i < elements.length; i+=1) {
        alias = elements[i].params.brush;
        url = brushes[alias];
         
        if(!url) {
            if(console && console.log){
                console.log('no brush defined for alias: '+ alias);
            }
            continue;
        }
         
        if(!!processing(url)){
            continue;
        }
 
        processes.push({
            id: url,
            done: false
        });
 
        if (!!window.SyntaxHighlighter.vars.discoveredBrushes) {
            if (!!window.SyntaxHighlighter.vars.discoveredBrushes[alias]) {
                // this brush was already loaded & discovered by SyntaxHighlighter. Theres nothing more to do...
                processing(url).done = true;
                continue;
            }
        }
         
        (function() {
            var urlClosure = url;
            SpSyntaxHighlighter.loadScript(urlClosure, function () {
                processing(urlClosure).done = true;
                chechAllDone();
            });
        })();
    }
     
    // finished..
    processing('loadBrushes').done = true;
    chechAllDone();
};  
SpSyntaxHighlighter.runSyntaxHighlighter = function () {
    /// 
    ///     Re-Run SyntaxHighlighter, make sure SyntaxHighlighter was loaded before calling.
    ///     i.e. call loadSyntaxHighlighter first.
    ///     this functions does nothing, if an RichTextEditor is opened in the page!
    /// 
 
    if (!SpSyntaxHighlighter.canApplySyntaxHighlighter()) return;
 
    SpSyntaxHighlighter.loadBrushes(function () {
        SyntaxHighlighter.vars.discoveredBrushes = null; // let SyntaxHighlighter re-run brush-discovery
        window.setTimeout(SyntaxHighlighter.highlight.bind(SyntaxHighlighter), 50);
    });
};
SpSyntaxHighlighter.loadSyntaxHighlighter = function () {
    var csspath = '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/styles/',
        scriptpath = '~siteCollection/SiteAssets/SpSyntaxHighlighter/syntaxhighlighter/scripts/',
        shTheme = 'shThemeDefault.css', //Possible Themes: shThemeDefault.css, shThemeDjango.css, shThemeEclipse.css, shThemeEmacs.css, shThemeFadeToGrey.css, shThemeMDUltra.css, shThemeMidnight.css, shThemeRDark.css
        loadSyntaxHighlighter = function () {
            // add SyntaxHighlighter, styles and autoloader, then run autoloader
            SpSyntaxHighlighter.loadCss(csspath + 'shCore.css');
            SpSyntaxHighlighter.loadCss(csspath + shTheme);
            SpSyntaxHighlighter.loadScript(scriptpath + 'shCore.js', function () {
                SpSyntaxHighlighter.SyntaxHighlighter = window.SyntaxHighlighter;
                SpSyntaxHighlighter.runSyntaxHighlighter();
            });
        },
        siteLoadFialed = function (err) {
            if (console && console.log) {
                console.log('accessing siteCollecion failed. ');
                console.log('err was: ' + err);
                console.log('execution aborted. :-(');
            }
            // this is the end of it. sadly.
        },
        siteLoadSucceded = function () {
            var siteCollectionUrl = siteCollection.get_url(),
                i, len, brushCfg, brushPath;
            // fix up paths...
            csspath = csspath.replace('~siteCollection', siteCollectionUrl);
            scriptpath = scriptpath.replace('~siteCollection', siteCollectionUrl);
 
            len = SpSyntaxHighlighter.shAutoConfig.length;
            for (i = 0; i < len; i += 1) {
                brushCfg = SpSyntaxHighlighter.shAutoConfig[i];
                brushPath = brushCfg[brushCfg.length - 1];
                brushCfg[brushCfg.length - 1] = brushPath.replace('~siteCollection', siteCollectionUrl);
            }
 
            // now start loading SyntaxHighlighter
            loadSyntaxHighlighter();
        },
        siteCollection,
        clientContext = SP.ClientContext.get_current(),
        highlightable = document.getElementsByTagName('pre');
 
    // check if syntaxHighlighter ist needed
    if (highlightable.length < 1) return;
 
    if (!SpSyntaxHighlighter.canApplySyntaxHighlighter()) return;
 
    // load siteCollectionData then continue
    siteCollection = clientContext.get_site();
    clientContext.load(siteCollection);
    clientContext.executeQueryAsync(siteLoadSucceded, siteLoadFialed);
};
SpSyntaxHighlighter.preLoadSyntaxHighlighter = function () {
    if (!!SpSyntaxHighlighter.SyntaxHighlighter) {
        //weve been here before :-)
        window.SyntaxHighlighter = SpSyntaxHighlighter.SyntaxHighlighter;
        SpSyntaxHighlighter.runSyntaxHighlighter();
        return;
    }
    // load all from scratch...
    SP.SOD.executeFunc('sp.js', 'SP.ClientContext', SpSyntaxHighlighter.loadSyntaxHighlighter);
};
SpSyntaxHighlighter.register = function () {
    var thisUrl;
    SpSyntaxHighlighter.preLoadSyntaxHighlighter();
    if (!!window._spPageContextInfo) {
        thisUrl = '~siteCollection/SiteAssets/SpSyntaxHighlighter/ShLoader.js'.replace('~siteCollection/', window._spPageContextInfo.siteServerRelativeUrl);
        window.RegisterModuleInit(thisUrl, SpSyntaxHighlighter.preLoadSyntaxHighlighter);
    }
};
 
//Simulate LoadAfterUi=true
window._spBodyOnLoadFunctionNames.push('SpSyntaxHighlighter.register');

Teile des Skriptes (z.B. die Verfügbaren "brushes") lasse ich dabei auto-generieren mittels eines T4-Templates.

Die Sourcen für das ganze habe ich auf bitbucket​.

Keine Kommentare:

Kommentar veröffentlichen