Last active
November 4, 2018 10:12
-
-
Save daimor/ece6ec04866f76e18efa8d94dd7e8e0c to your computer and use it in GitHub Desktop.
Cache Javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Studio Template:<br> | |
/// Create a new Cache JavaScript Routine. | |
Class %CJS.RoutineWizard Extends %ZEN.Template.studioTemplate [ StorageStrategy = "" ] | |
{ | |
Parameter TEMPLATENAME = "Cache JavaScript"; | |
Parameter TEMPLATETITLE = "Cache JavaScript"; | |
Parameter TEMPLATEDESCRIPTION = "Create a new Cache JavaScript routine."; | |
Parameter TEMPLATETYPE = "CJS"; | |
/// What type of template. | |
Parameter TEMPLATEMODE = "new"; | |
/// If this is a TEMPLATEMODE="new" then this is the name of the tab | |
/// in Studio this template is dispayed on. If none specified then | |
/// it displays on 'Custom' tab. | |
Parameter TEMPLATEGROUP As STRING; | |
/// This XML block defines the contents of the body pane of this Studio Template. | |
XData templateBody [ XMLNamespace = "http://www.intersystems.com/zen" ] | |
{ | |
<pane id="body"> | |
<vgroup labelPosition="left" cellStyle="padding: 2px; padding-left: 5px; padding-right: 5px;"> | |
<html id="desc" OnDrawContent="%GetDescHTML"/> | |
<text label="Routine Name:" | |
id="ctrlRoutineName" | |
name="RoutineName" | |
size="40" | |
required="true" | |
labelClass="zenRequired" | |
title="Cache JavaScript Routine name" | |
onchange="zenPage.updateState();" | |
/> | |
</vgroup> | |
</pane> | |
} | |
/// Provide contents of description component. | |
Method %GetDescHTML(pSeed As %String) As %Status | |
{ | |
Quit $$$OK | |
} | |
/// This is called when the template is first displayed; | |
/// This provides a chance to set focus etc. | |
ClientMethod onstartHandler() [ Language = javascript ] | |
{ | |
// give focus to name | |
var ctrl = zenPage.getComponentById('ctrlRoutineName'); | |
if (ctrl) { | |
ctrl.focus(); | |
ctrl.select(); | |
} | |
} | |
/// Validation handler for form built-into template. | |
ClientMethod formValidationHandler() [ Language = javascript ] | |
{ | |
var rtnName = zenPage.getComponentById('ctrlRoutineName').getValue(); | |
if ('' == rtnName) { | |
return false; | |
} | |
return true; | |
} | |
/// This method is called when the template is complete. Any | |
/// output to the principal device is returned to the Studio. | |
Method %OnTemplateAction() As %Status | |
{ | |
Set tRoutineName = ..%GetValueByName("RoutineName") | |
Set %session.Data("Template","NAME") = tRoutineName_".CJS" | |
Write "// "_tRoutineName,! | |
Quit $$$OK | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Class %CJS.StudioRoutines Extends %Studio.AbstractDocument [ StorageStrategy = "" ] | |
{ | |
/// The extension name, this can be a comma separated list of extensions if this class supports more than one | |
Projection RegisterExtension As %Projection.StudioDocument(DocumentDescription = "CachéJavaScript Routine", DocumentExtension = "cjs", DocumentIcon = 1, DocumentType = "JS"); | |
Property ShortName As %String; | |
/// Set the name property | |
Method %OnNew(name As %String) As %Status [ Private ] | |
{ | |
set ..ShortName=$piece(name,".",1,$length(name,".")-1) | |
set tSC=##super(name) | |
if $$$ISERR(tSC) Quit tSC | |
quit $$$OK | |
} | |
/// Load the routine in Name into the stream Code | |
Method Load() As %Status | |
{ | |
set source=..Code | |
do source.Clear() | |
set pCodeGN=$name(^rCJS(..ShortName,0)) | |
for pLine=1:1:$get(@pCodeGN@(0),0) { | |
do source.WriteLine(@pCodeGN@(pLine)) | |
} | |
do source.Rewind() | |
Quit $$$OK | |
} | |
/// CompileDocument is called when the document is to be compiled | |
/// It has already called the source control hooks at this point | |
Method CompileDocument(ByRef qstruct As %String) As %Status | |
{ | |
Write !,"Compile: ",..Name | |
Set compiledCode=##class(%Routine).%OpenId(..ShortName_".INT") | |
Set compiledCode.Generated=1 | |
do compiledCode.Clear() | |
do compiledCode.WriteLine(" ;generated at "_$zdatetime($ztimestamp,3)) | |
do ..GenerateIntCode(compiledCode) | |
do compiledCode.%Save() | |
do compiledCode.Compile() | |
Quit $$$OK | |
} | |
Method GenerateIntCode(aCode) [ Internal ] | |
{ | |
set varMatcher=##class(%Regex.Matcher).%New("[ \t]*(var[ \t]+)?(\w[\w\d]*)[ \t]*(\=[ \t]*(.*))?") | |
set printlnMatcher=##class(%Regex.Matcher).%New("[ \t]*(?:console\.log|println)\(([^\)]+)\)?") | |
set readMatcher=##class(%Regex.Matcher).%New("[ \t]*read\((.*)\,(.*)\)") | |
set source=..Code | |
do source.Rewind() | |
while 'source.AtEnd { | |
set tLine=source.ReadLine() | |
set pos=1 | |
while $locate(tLine,"(([^\'\""\;\r\n]|[\'\""][^\'\""]*[\'\""])+)",pos,pos,tCode) { | |
set tPos=1 | |
if $zstrip(tCode,"*W")="" { | |
do aCode.WriteLine(tCode) | |
continue | |
} | |
if varMatcher.Match(tCode) { | |
set varName=varMatcher.Group(2) | |
if varMatcher.Group(1)'="" { | |
do aCode.WriteLine($char(9)_"new "_varName) | |
} | |
if varMatcher.Group(3)'="" { | |
set expr=varMatcher.Group(4) | |
set expr=..Expression(expr) | |
do:expr'="" aCode.WriteLine($char(9)_"set "_varName_" = "_expr) | |
} | |
continue | |
} elseif printlnMatcher.Match(tCode) { | |
set expr=printlnMatcher.Group(1) | |
set expr=..Expression(expr) | |
do:expr'="" aCode.WriteLine($char(9)_"Write "_expr_",!") | |
} elseif readMatcher.Match(tCode) { | |
set expr=readMatcher.Group(1) | |
set expr=..Expression(expr) | |
set var=readMatcher.Group(2) | |
do:expr'="" aCode.WriteLine($char(9)_"read "_expr_","_var_",!") | |
} | |
} | |
} | |
} | |
ClassMethod Expression(tExpr) As %String | |
{ | |
set matchers($increment(matchers),"matcher")="(?sm)([^\'\""]*)\+[ \t]*(?:\""([^\""]*)\""|\'([^\']*)\')([^\'\""]*)" | |
set matchers(matchers,"replacement")="$1_""$2$3""$4" | |
set matchers($increment(matchers),"matcher")="(?sm)([^\'\""]*)(?:\""([^\""]*)\""|\'([^\']*)\')[ \t]*\+([^\'\""]*)" | |
set matchers(matchers,"replacement")="$1""$2$3""_$4" | |
set matchers($increment(matchers),"matcher")="(?sm)([^\'\""]*)(?:\""([^\""]*)\""|\'([^\']*)\')([^\'\""]*)" | |
set matchers(matchers,"replacement")="$1""$2$3""$4" | |
set tResult=tExpr | |
for i=1:1:matchers { | |
set matcher=##class(%Regex.Matcher).%New(matchers(i,"matcher")) | |
set replacement=$get(matchers(i,"replacement")) | |
set matcher.Text=tResult | |
set tResult=matcher.ReplaceAll(replacement) | |
} | |
quit tResult | |
} | |
/// Delete the routine 'name' which includes the routine extension | |
ClassMethod Delete(name As %String) As %Status | |
{ | |
Set rtnName = $piece(name,".",1,$length(name,".")-1) | |
Kill ^rCJS(rtnName) | |
Quit $$$OK | |
} | |
/// Lock the current routine, default method just unlocks the ^rCJS global with the name of the routine. | |
/// If it fails then return a status code of the error, otherise return $$$OK | |
Method Lock(flags As %String) As %Status | |
{ | |
Lock +^rCJS(..Name):0 Else Quit $$$ERROR($$$CanNotLockRoutine,..Name) | |
Quit $$$OK | |
} | |
/// Unlock the current routine, default method just unlocks the ^rCJS global with the name of the routine | |
Method Unlock(flags As %String) As %Status | |
{ | |
Lock -^rCJS(..Name) | |
Quit $$$OK | |
} | |
/// Save the routine stored in Code | |
Method Save() As %Status | |
{ | |
set ^rCJS(..ShortName,"LANG")="CJS" | |
set pCodeGN=$name(^rCJS(..ShortName,0)) | |
kill @pCodeGN | |
set @pCodeGN=$ztimestamp | |
Set ..Code.LineTerminator=$char(13,10) | |
set source=..Code | |
do source.Rewind() | |
WHILE '(source.AtEnd) { | |
set pCodeLine=source.ReadLine() | |
set @pCodeGN@($increment(@pCodeGN@(0)))=pCodeLine | |
} | |
set @pCodeGN@("SIZE")=..Code.Size | |
Quit $$$OK | |
} | |
/// Return the timestamp of routine 'name' in %TimeStamp format. This is used to determine if the routine has | |
/// been updated on the server and so needs reloading from Studio. So the format should be $zdatetime($horolog,3), | |
/// or "" if the routine does not exist. | |
ClassMethod TimeStamp(name As %String) As %TimeStamp | |
{ | |
Set rtnName = $piece(name,".",1,$length(name,".")-1) | |
Set timeStamp=$zdatetime($get(^rCJS(rtnName,0)),3) | |
Quit timeStamp | |
} | |
/// Return 1 if the routine 'name' exists and 0 if it does not. | |
ClassMethod Exists(name As %String) As %Boolean | |
{ | |
Set rtnName = $piece(name,".",1,$length(name,".")-1) | |
Set rtnNameExt = $piece(name,".",$length(name,".")) | |
Quit $data(^rCJS(rtnName))&&($get(^rCJS(rtnName,"LANG"))=$zconvert(rtnNameExt,"U")) | |
} | |
ClassMethod ListExecute(ByRef qHandle As %Binary, Directory As %String, Flat As %Boolean, System As %Boolean) As %Status | |
{ | |
Set qHandle=$listbuild(Directory,Flat,System,"") | |
Quit $$$OK | |
} | |
/// This should return a Row in the form:<br> | |
/// $listbuild(name,date/time modified,size,directory delimitor)<ul> | |
/// <li>name - The name to display in the open dialog</li> | |
/// <li>date/time modified - In %TimeStamp format the date/time this item was last modified</li> | |
/// <li>size - The size of this item</li> | |
/// <li>directory delimitor - If this is not an directory then return "" here, if it is a directory then | |
/// return the type of delimitor to use when they double click on this directory</li> | |
ClassMethod ListFetch(ByRef qHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) As %Status [ PlaceAfter = ListExecute ] | |
{ | |
Set Row="",AtEnd=0 | |
If qHandle="" Set AtEnd=1 Quit $$$OK | |
If $list(qHandle)'=""||($list(qHandle,4)=1) Set AtEnd=1 Quit $$$OK | |
set AtEnd=1 | |
Set rtnName=$listget(qHandle,5) | |
For { | |
Set rtnName=$order(^rCJS(rtnName)) Quit:rtnName="" | |
continue:$get(^rCJS(rtnName,"LANG"))'="CJS" | |
set timeStamp=$zdatetime($get(^rCJS(rtnName,0)),3) | |
set size=+$get(^rCJS(rtnName,0,"SIZE")) | |
Set Row=$listbuild(rtnName_".cjs",timeStamp,size,"") | |
set AtEnd=0 | |
set $list(qHandle,5)=rtnName | |
Quit | |
} | |
Quit $$$OK | |
} | |
/// Return other document types that this is related to. | |
/// Passed a name and you return a comma separated list of the other documents it is related to | |
/// or "" if it is not related to anything. Note that this can be passed a document of another type | |
/// for example if your 'test.XXX' document creates a 'test.INT' routine then it will also be called | |
/// with 'test.INT' so you can return 'test.XXX' to complete the cycle. | |
ClassMethod GetOther(Name As %String) As %String | |
{ | |
Set rtnName = $piece(Name,".",1,$length(Name,".")-1)_".INT" | |
Quit:##class(%Routine).%ExistsId(rtnName) rtnName | |
Quit "" | |
} | |
/// This query scans over the documents for the Studio open dialog. | |
/// The arguments are defined in <method>ItemList</method>.<p> | |
/// This should return a row form by:<br> | |
/// $listbuild(name,date/time modified,size,directory delimitor) | |
/// <ul> | |
/// <li>name - The name to display in the open dialog</li> | |
/// <li>date/time modified - In %TimeStamp format the date/time this item was last modified</li> | |
/// <li>size - The size of this item</li> | |
/// <li>directory delimitor - If this is not an directory then return "" here, if it is a directory then | |
/// return the type of delimitor to use when they double click on this directory</li> | |
/// </ul> | |
Query List(Directory As %String, Flat As %Boolean, System As %Boolean) As %Query(ROWSPEC = "name:%String,modified:%TimeStamp,size:%Integer,directory:%String") [ SqlProc ] | |
{ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment