Disable JavaScript in Webbrowser Control in AutoHotkey - dom

I thought even after rendering the page, removing script tags and the relevant attributes in tags would work but didn't.
The following code removes the script tag and the onclick attribute but it does not have any effect.
Any idea?
I'd like to avoid:
editing the registroy since it requires admin rights.
fetching web contents separately and using doc.write() since it make the code complex.
Files:
javascript.html
test.ahk
javascript.html
<!DOCTYPE html>
<html>
<head>
<script> function displayDate() { document.getElementById("demo").innerHTML=Date(); }</script>
</head>
<body>
<p id="demo" onclick="displayDate()">This is a paragraph. Click here.</p>
</body>
</html>
test.ahk
Gui, Add, ActiveX, vWB w400 h300, Shell.Explorer
Gui, Show, w420 h320
WB.Navigate("file:///" A_ScriptDir "/javascript.html")
Loop
Sleep 10
Until (WB.readyState=4 && WB.document.readyState="complete" && !WB.busy)
doc := WB.document
nodeScript := doc.getElementsByTagName("script")[0]
nodeScript.parentNode.removeChild(nodeScript)
nodeP := doc.getElementsByTagName("p")[0]
nodeP.removeAttribute("onclick")
msgbox % doc.documentElement.outerHTML
Return

It is possible to force scripting enabled/disabled for a given WebBrowser control by implementing three specific COM interfaces (IOleClientSite, IServiceProvider and IInternetSecurityManager) and calling the SetClientSite method of the control's IOleObject interface.
Ultimately, you need to implement the IInternetSecurityManager::ProcessUrlAction method. When the WebBrowser calls it with the dwAction parameter set to URLACTION_SCRIPT_RUN, you can set *pPolicy to URLPOLICY_DISALLOW to prevent scripting or URLPOLICY_ALLOW to enable scripting, and return S_OK (zero) to enforce the policy.
The necessary code is shown below, and can be implemented by simply calling SetWBClientSite() after creating the control but before navigating. The global variable WB must contain a reference to the WebBrowser control.
/* Complex workaround to override "Active scripting" setting
* and ensure scripts can't run within the WebBrowser control.
*/
global WBClientSite
SetWBClientSite()
{
interfaces := {
(Join,
IOleClientSite: [0,3,1,0,1,0]
IServiceProvider: [3]
IInternetSecurityManager: [1,1,3,4,8,7,3,3]
)}
unkQI := RegisterCallback("WBClientSite_QI", "Fast")
unkAddRef := RegisterCallback("WBClientSite_AddRef", "Fast")
unkRelease := RegisterCallback("WBClientSite_Release", "Fast")
WBClientSite := {_buffers: bufs := {}}, bufn := 0,
for name, prms in interfaces
{
bufn += 1
bufs.SetCapacity(bufn, (4 + prms.MaxIndex()) * A_PtrSize)
buf := bufs.GetAddress(bufn)
NumPut(unkQI, buf + 1*A_PtrSize)
NumPut(unkAddRef, buf + 2*A_PtrSize)
NumPut(unkRelease, buf + 3*A_PtrSize)
for i, prmc in prms
NumPut(RegisterCallback("WBClientSite_" name, "Fast", prmc+1, i), buf + (3+i)*A_PtrSize)
NumPut(buf + A_PtrSize, buf + 0)
WBClientSite[name] := buf
}
global wb
if pOleObject := ComObjQuery(wb, "{00000112-0000-0000-C000-000000000046}")
{ ; IOleObject::SetClientSite
DllCall(NumGet(NumGet(pOleObject+0)+3*A_PtrSize), "ptr"
, pOleObject, "ptr", WBClientSite.IOleClientSite, "uint")
ObjRelease(pOleObject)
}
}
WBClientSite_QI(p, piid, ppvObject)
{
static IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"
static IID_IOleClientSite := "{00000118-0000-0000-C000-000000000046}"
static IID_IServiceProvider := "{6d5140c1-7436-11ce-8034-00aa006009fa}"
iid := _String4GUID(piid)
if (iid = IID_IOleClientSite || iid = IID_IUnknown)
{
NumPut(WBClientSite.IOleClientSite, ppvObject+0)
return 0 ; S_OK
}
if (iid = IID_IServiceProvider)
{
NumPut(WBClientSite.IServiceProvider, ppvObject+0)
return 0 ; S_OK
}
NumPut(0, ppvObject+0)
return 0x80004002 ; E_NOINTERFACE
}
WBClientSite_AddRef(p)
{
return 1
}
WBClientSite_Release(p)
{
return 1
}
WBClientSite_IOleClientSite(p, p1="", p2="", p3="")
{
if (A_EventInfo = 3) ; GetContainer
{
NumPut(0, p1+0) ; *ppContainer := NULL
return 0x80004002 ; E_NOINTERFACE
}
return 0x80004001 ; E_NOTIMPL
}
WBClientSite_IServiceProvider(p, pguidService, piid, ppvObject)
{
static IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"
static IID_IInternetSecurityManager := "{79eac9ee-baf9-11ce-8c82-00aa004ba90b}"
if (_String4GUID(pguidService) = IID_IInternetSecurityManager)
{
iid := _String4GUID(piid)
if (iid = IID_IInternetSecurityManager || iid = IID_IUnknown)
{
NumPut(WBClientSite.IInternetSecurityManager, ppvObject+0)
return 0 ; S_OK
}
NumPut(0, ppvObject+0)
return 0x80004002 ; E_NOINTERFACE
}
NumPut(0, ppvObject+0)
return 0x80004001 ; E_NOTIMPL
}
WBClientSite_IInternetSecurityManager(p, p1="", p2="", p3="", p4="", p5="", p6="", p7="", p8="")
{
if (A_EventInfo = 5) ; ProcessUrlAction
{
if (p2 = 0x1400) ; dwAction = URLACTION_SCRIPT_RUN
{
NumPut((URLPOLICY_DISALLOW := 3), p3+0) ; *pPolicy := URLPOLICY_DISALLOW
return 0 ; S_OK
}
}
return 0x800C0011 ; INET_E_DEFAULT_ACTION
}
_String4GUID(pGUID)
{
VarSetCapacity(String,38*2)
DllCall("ole32\StringFromGUID2", "ptr", pGUID, "str", String, "int", 39)
Return String
}
The current AutoHotkey installer contains code identical to this, with the exception that it sets URLPOLICY_ALLOW (0) rather than URLPOLICY_DISALLOW (3). This was necessary to allow the installer to work on systems which have scripting disabled.
As you can see, implementing COM interfaces directly in an AutoHotkey script is no simple matter. It is a little easier in plain C (see COM in plain C), and much easier in C++.

Related

Global variable doesn't update until function finishes?

I'm trying to prevent a function (^F1) from being run twice at the same time.
To do this, I'm trying to use a global lock variable; the function needs to release the lock to enable another function call.
Now, this below code would work in Java, but it's not working in AHK. The problem is that, in AHK, the global "is_locked" does not update until ^F1 has finished. This defeats the purpose of using a global lock variable to prevent simultaneous function calls.
How can I fix this?
is_locked := False
set_lock()
{
global is_locked
is_locked := True
}
remove_lock()
{
global is_locked
is_locked := False
}
^F1::
global is_locked
if(is_locked)
{
; doesn't print until after 10 seconds, even if I am spamming ^F1
MsgBox, "locked"
return
}
set_lock()
Sleep 10000
return
Take note that is_locked is a super-global variable.
global is_locked := false
set_lock()
{
is_locked := true
}
remove_lock()
{
is_locked := false
}
^F1::
if (is_locked)
return
set_lock()
MsgBox, "locked"
Sleep 10000
remove_lock()
return
global is_locked
toggle_lock() {
is_locked := !is_locked
OutputDebug, % is_locked
}
^F1::
toggle_lock()
if is_locked
ToolTip, locked
Else
ToolTip, NOT locked
return

FB_FileOpen stays busy, Statemachine not working - TwinCat3

i am trying to get into the beckhoff/twincat universe, therefore is was following along with some twincat tutorials. While programming a simple event-logger I encountered the following problem:
After executing FB_FileOpen, it´s bBusy variable stays True - therefore my statemachine won´t execute any further and is stuck in FILE_OPEN. Any idea, what I did wrong? Here is my code:
VAR
FileOpen : FB_FileOpen := (sPathName := 'C:\Events-log.txt', nMode := FOPEN_MODEAPPEND OR FOPEN_MODETEXT);
FileClose :FB_FileClose;
FilePuts : FB_FilePuts;
stEventWrittenToFile : ST_Event;
CsvString : T_MaxString;
eWriteState :(TRIGGER_FILE_OPEN, FILE_OPEN, WAIT_FOR_EVENT,TRIGGER_WRITE_EVENT, WRITE_EVENT, FILE_CLOSE, ERROR);
END_VAR
CASE eWriteState OF
TRIGGER_FILE_OPEN :
FileOpen(bExecute := TRUE);
eWriteState := FILE_OPEN;
FILE_OPEN :
FileOpen(bExecute := FALSE);
IF FileOpen.bError THEN
eWriteState := ERROR;
ELSIF NOT FileOpen.bBusy AND FileOpen.hFile <> 0 THEN
eWriteState := WAIT_FOR_EVENT;
END_IF
WAIT_FOR_EVENT :
//Do nothing, triggered externally by method
TRIGGER_WRITE_EVENT :
CsvString := ConvertStructureToString(stEvent := stEventWrittenToFile);
FilePuts( sLine:= CsvString,
hFile := FileOpen.hFile,
bExecute := TRUE,);
eWriteState := WRITE_EVENT;
WRITE_EVENT :
FilePuts(bExecute := FALSE);
IF FilePuts.bError THEN
eWriteState := ERROR;
ELSIF NOT FilePuts.bBusy THEN
eWriteState := FILE_CLOSE;
END_IF
FILE_CLOSE :
FileClose( hFile := FileOpen.hFile,
bExecute := TRUE);
IF FileClose.bError = TRUE THEN
FileClose.bExecute := FALSE;
eWriteState := ERROR;
ELSIF NOT FileClose.bBusy THEN
FileClose.bExecute := FALSE;
eWriteState := TRIGGER_FILE_OPEN;
END_IF
ERROR : // Do nothing
END_CASE
The issue probably lies in how you call the function block. You need to make sure to call the function block with the input bExecute := FALSE and only after that calling it with bExecute := TRUE will trigger the function block execution. Caliing the fb with its "exectue" input to false after it has had the input triggered, will always work so just invert your order of TRUE and FALSE executes for all your states.
TRIGGER_FILE_OPEN:
fileOpen(bExecute := FALSE);
eWriteState := FILE_OPEN;
FILE_OPEN:
fileOpen(bExecute := TRUE);
...
You could also follow the Beckhoff example provided on their website, not a fan of this, but calling the function block twice, back to back in a single PLC cycle :
(* Open source file *)
fbFileOpen( bExecute := FALSE );
fbFileOpen( sNetId := sSrcNetId,
sPathName := sSrcPathName,
nMode := FOPEN_MODEREAD OR FOPEN_MODEBINARY,
ePath := PATH_GENERIC,
tTimeout := tTimeOut,
bExecute := TRUE );
Full example can be found here : https://infosys.beckhoff.com/english.php?content=../content/1033/tcplclib_tc2_system/30977547.html&id=
I found the error.
My mistake was, that I started the state machine with a positive edge from a start variable. Since I am running the task in a 1ms cycle, the whole thing would´ve needed to complete within 1ms then.

How to make `ifWinActive` and `WinActivateBottom` to use only the current desktop?

I have an autohotkey script that search if specific window exists, if so, it will activate it.
I want that it will search only in the current desktop (I'm using Windows 10).
Do you have a suggestion how to do it?
My Script:
#c::
IfWinExist ,ahk_class ConsoleWindowClass
{
ifWinActive
WinActivatebottom ,ahk_class ConsoleWindowClass
else
WinActivate
return
}
#c:: WinActivateBottomOnCurrentVirtualDesktop("ConsoleWindowClass")
WinActivateBottomOnCurrentVirtualDesktop(Class){
IfWinExist, ahk_class %Class%
{
list := ""
LastWin := ""
; get a list of those windows on the current desktop
WinGet, id, list, ahk_class %Class%
Loop, %id%
{
this_ID := id%A_Index%
If IsWindowOnCurrentVirtualDesktop(this_ID)
LastWin := this_ID ; retrieves the bottommost matching window ID
}
WinActivate, ahk_id %LastWin%
}
}
; https://autohotkey.com/boards/viewtopic.php?p=64295#p64295
; Indicates whether the provided window is on the currently active virtual desktop:
IsWindowOnCurrentVirtualDesktop(hWnd) {
onCurrentDesktop := ""
CLSID := "{aa509086-5ca9-4c25-8f95-589d3c07b48a}"
IID := "{a5cd92ff-29be-454c-8d04-d82879fb3f1b}"
IVirtualDesktopManager := ComObjCreate(CLSID, IID)
Error := DllCall(NumGet(NumGet(IVirtualDesktopManager+0), 3*A_PtrSize), "Ptr", IVirtualDesktopManager, "Ptr", hWnd, "IntP", onCurrentDesktop)
ObjRelease(IVirtualDesktopManager)
if !(Error=0)
return false, ErrorLevel := true
return onCurrentDesktop, ErrorLevel := false
}

How to execute 7zip without blocking the Inno Setup UI?

My Inno Setup GUI is frozen during unzip operations.
I've a procedure DoUnzip(source: String; targetdir: String) with the core
unzipTool := ExpandConstant('{tmp}\7za.exe');
Exec(unzipTool, ' x "' + source + '" -o"' + targetdir + '" -y',
'', SW_HIDE, ewWaitUntilTerminated, ReturnCode);
This procedure is called multiple times and the Exec operation blocks the user interface. There is only a very short moment between the executions, where the Inno GUI is dragable/moveable.
I know that there are other options for TExecWait instead of ewWaitUntilTerminated, like ewNoWait and ewWaitUntilIdle, but unfortunately they are not helpful in this case. Using ewNoWait would result in the execution of multiple unzip operations at the same time.
I'm looking for a way to execute an external unzip operation and wait for it to finish, but without blocking the user interface. How can i implement that?
Here are my notes and ideas:
Waiting for a process to finish, is blocking, unless you'll be waiting in a thread different from the main one. I think some kind of callback is needed, which is executed, when the unzip operation finishes.
I'm aware that Inno Setup doesn't provide this feature out of the box, see https://github.com/jrsoftware/issrc/issues/149
While searching for related issues on Stack Overflow, I came up with the question Using callback to display filenames from external decompression dll in Inno Setup, where I found Mirals's answer. It's using InnoCallback combined with another DLL.
I think, in my case this could be 7zxa.dll for the unzip operation. But it doesn't accept a callback. So, the following code is just a concept / idea draft. One problem is, that 7zxa.dll doesn't accept a callback.
Another problem is that the 7zxa API is not really inviting to work with.
[Code]
type
TMyCallback = procedure(Filename: PChar);
{ wrapper to tell callback function to InnoCallback }
function WrapMyCallback(Callback: TMyCallback; ParamCount: Integer): LongWord;
external 'WrapCallback#files:innocallback.dll stdcall';
{ the call to the unzip dll }
{ P!: the 7zxa.dll doesn't accept a callback }
procedure DoUnzipDll(Blah: Integer; Foo: String; ...; Callback: LongWord);
external 'DoUnzipDll#files:7zxa.dll stdcall';
{ the actual callback action }
procedure MyCallback(Filename: PChar);
begin
{ refresh the GUI }
end;
{ ----- }
var Callback : LongWord;
{ tell innocallback the callback procedure as 1 parameter }
Callback := WrapMyCallback(#MyCallback, 1);
{ pass the wrapped callback to the unzip DLL }
DoUnzipDll(source, target, ..., Callback);
procedure DoUnzip(src, target : String);
begin
DoUnzipDll(ExpandConstant(src), ExpandConstant(target));
end;
Update: #Rik suggested to combine the WinAPI function ShellExecuteEx() with INFINITE WaitForSingleObject.
I've implemented and tested this approach. The code is below.
The unzipping works, but the Inno Setup window is only moveable/dragable for a short moment between the individual unzip operations. During a long running unzip the GUI is fully unresponsive - no dragging/no cancel button.
I've added BringToFrontAndRestore(), but it seems the new process has the focus.
const
WAIT_OBJECT_0 = $0;
WAIT_TIMEOUT = $00000102;
SEE_MASK_NOCLOSEPROCESS = $00000040;
INFINITE = $FFFFFFFF; { Infinite timeout }
type
TShellExecuteInfo = record
cbSize: DWORD;
fMask: Cardinal;
Wnd: HWND;
lpVerb: string;
lpFile: string;
lpParameters: string;
lpDirectory: string;
nShow: Integer;
hInstApp: THandle;
lpIDList: DWORD;
lpClass: string;
hkeyClass: THandle;
dwHotKey: DWORD;
hMonitor: THandle;
hProcess: THandle;
end;
function ShellExecuteEx(var lpExecInfo: TShellExecuteInfo): BOOL;
external 'ShellExecuteEx{#AW}#shell32.dll stdcall';
function WaitForSingleObject(hHandle: THandle; dwMilliseconds: DWORD): DWORD;
external 'WaitForSingleObject#kernel32.dll stdcall';
function CloseHandle(hObject: THandle): BOOL; external 'CloseHandle#kernel32.dll stdcall';
procedure DoUnzip(source: String; targetdir: String);
var
unzipTool, unzipParams : String; { path to unzip util }
ReturnCode : Integer; { errorcode }
ExecInfo: TShellExecuteInfo;
begin
{ source might contain {tmp} or {app} constant, so expand/resolve it to path name }
source := ExpandConstant(source);
unzipTool := ExpandConstant('{tmp}\7za.exe');
unzipParams := ' x "' + source + '" -o"' + targetdir + '" -y';
ExecInfo.cbSize := SizeOf(ExecInfo);
ExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
ExecInfo.Wnd := 0;
ExecInfo.lpFile := unzipTool;
ExecInfo.lpParameters := unzipParams;
ExecInfo.nShow := SW_HIDE;
if not FileExists(unzipTool)
then MsgBox('UnzipTool not found: ' + unzipTool, mbError, MB_OK)
else if not FileExists(source)
then MsgBox('File was not found while trying to unzip: ' + source, mbError, MB_OK)
else begin
{ ShellExecuteEx combined with INFINITE WaitForSingleObject }
if ShellExecuteEx(ExecInfo) then
begin
while WaitForSingleObject(ExecInfo.hProcess, INFINITE) <> WAIT_OBJECT_0
do begin
InstallPage.Surface.Update;
{ BringToFrontAndRestore; }
WizardForm.Refresh();
end;
CloseHandle(ExecInfo.hProcess);
end;
end;
end;
Like I suspected using INFINITE with WaitForSingleObject still blocks the main-thread. Next I thought using a smaller timeout with WaitForSingleObject. But the problem is still that the main-thread stays in the while loop of WaitForSingleObject and doesn't respond to moving. WizardForm.Refresh does not make it movable. It just refreshes the form but doesn't process other messages (like WM_MOVE). You need something like Application.ProcessMessages to allow the windows to move. Since Inno Setup doesn't have a ProcessMessages we could create one ourselves.
Below is your code with a ProcessMessage implemented. It does a 100 millisecond wait for WaitForSingleObject and if it's still in the wait-state it executes the ProcessMessage and Refresh. This will allow you to move the window. You can play a little with the value 100.
Another way could be that you save the ExecInfo and go on with some other install-part. In the final page you could check if the process is finished. If it's not loop with the AppProcessMessage until it is.
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
const
WAIT_OBJECT_0 = $0;
WAIT_TIMEOUT = $00000102;
SEE_MASK_NOCLOSEPROCESS = $00000040;
INFINITE = $FFFFFFFF; { Infinite timeout }
type
TShellExecuteInfo = record
cbSize: DWORD;
fMask: Cardinal;
Wnd: HWND;
lpVerb: string;
lpFile: string;
lpParameters: string;
lpDirectory: string;
nShow: Integer;
hInstApp: THandle;
lpIDList: DWORD;
lpClass: string;
hkeyClass: THandle;
dwHotKey: DWORD;
hMonitor: THandle;
hProcess: THandle;
end;
function ShellExecuteEx(var lpExecInfo: TShellExecuteInfo): BOOL;
external 'ShellExecuteEx{#AW}#shell32.dll stdcall';
function WaitForSingleObject(hHandle: THandle; dwMilliseconds: DWORD): DWORD;
external 'WaitForSingleObject#kernel32.dll stdcall';
function CloseHandle(hObject: THandle): BOOL; external 'CloseHandle#kernel32.dll stdcall';
{ ----------------------- }
{ "Generic" code, some old "Application.ProcessMessages"-ish procedure }
{ ----------------------- }
type
TMsg = record
hwnd: HWND;
message: UINT;
wParam: Longint;
lParam: Longint;
time: DWORD;
pt: TPoint;
end;
const
PM_REMOVE = 1;
function PeekMessage(var lpMsg: TMsg; hWnd: HWND; wMsgFilterMin, wMsgFilterMax, wRemoveMsg: UINT): BOOL; external 'PeekMessageA#user32.dll stdcall';
function TranslateMessage(const lpMsg: TMsg): BOOL; external 'TranslateMessage#user32.dll stdcall';
function DispatchMessage(const lpMsg: TMsg): Longint; external 'DispatchMessageA#user32.dll stdcall';
procedure AppProcessMessage;
var
Msg: TMsg;
begin
while PeekMessage(Msg, WizardForm.Handle, 0, 0, PM_REMOVE) do begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end;
{ ----------------------- }
{ ----------------------- }
procedure DoUnzip(source: String; targetdir: String);
var
unzipTool, unzipParams : String; // path to unzip util
ReturnCode : Integer; // errorcode
ExecInfo: TShellExecuteInfo;
begin
{ source might contain {tmp} or {app} constant, so expand/resolve it to path name }
source := ExpandConstant(source);
unzipTool := ExpandConstant('{tmp}\7za.exe');
unzipParams := ' x "' + source + '" -o"' + targetdir + '" -y';
ExecInfo.cbSize := SizeOf(ExecInfo);
ExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
ExecInfo.Wnd := 0;
ExecInfo.lpFile := unzipTool;
ExecInfo.lpParameters := unzipParams;
ExecInfo.nShow := SW_HIDE;
if not FileExists(unzipTool)
then MsgBox('UnzipTool not found: ' + unzipTool, mbError, MB_OK)
else if not FileExists(source)
then MsgBox('File was not found while trying to unzip: ' + source, mbError, MB_OK)
else begin
{ ShellExecuteEx combined with INFINITE WaitForSingleObject }
if ShellExecuteEx(ExecInfo) then
begin
while WaitForSingleObject(ExecInfo.hProcess, 100) = WAIT_TIMEOUT { WAIT_OBJECT_0 }
do begin
AppProcessMessage;
{ InstallPage.Surface.Update; }
{ BringToFrontAndRestore; }
WizardForm.Refresh();
end;
CloseHandle(ExecInfo.hProcess);
end;
end;
end;
(This code is tested and works for me)

How to generate typescript interfaces/definitions for breeze entities

I’m new to SPA and I’m learning it with durandal and breeze. Recently I have switched my solution to Typescript and I’m wondering is there any good solution to generate typed breeze entities in TypeScript basing on EF model on the server. Only thing I have found is this post Breeze.js typed entities but this is only small piece of code and not even a real project. I’m wondering is there any better solution to this issue?
Below is a page you can drop in your site to generate typescript interface definitions. The page fetches the breeze metadata then iterates through all of the types and outputs a typescript interface declaration for each type. The output of this page can then be pasted in any typescript file (*.ts) or typescript definition file (*.d.ts). Enclose the results in a module declaration if you want to namespace the interfaces: declare module northwind { ... paste interfaces here... }.
Before using the page you'll need to make one edit: change the entity manager's controller url from "api/northwind" to whatever your breeze controller's url is.
The generated interfaces have a dependency on the Knockout.js typescript definitions which you can grab here: https://github.com/borisyankov/DefinitelyTyped/tree/master/knockout/
Using the northwind example from learn.breezejs.com, the output of this definitions generator page would be something like this:
export interface Employee extends breeze.Entity {
FirstName: KnockoutObservable<string>;
LastName: KnockoutObservable<string>;
}
you could then execute a query using breeze and cast the results to an array of employees like this:
var manager = new breeze.EntityManager('api/northwind');
var query = new breeze.EntityQuery()
.from("Employees");
manager.executeQuery(query).then(data => {
// ***cast the results to a strongly typed array of Employee***
var employees = <Employee[]>data.results;
}).fail(e => {
alert(e);
});
below is the definitions generator page- add a new html file to your project named "definitions.html", run the project and navigate to the page.
<html>
<head>
<title>Typescript Definition Generator</title>
<style>
code {
white-space: pre;
}
</style>
<script src="//code.jquery.com/jquery-2.1.0.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/knockout/knockout-3.0.0.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/q.js/1.0.0/q.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/breezejs/1.4.4/breeze.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
var entityManager = new breeze.EntityManager('api/northwind');
entityManager.fetchMetadata()
.then(function () {
var html = '',
types = entityManager.metadataStore.getEntityTypes(),
type,
i,
j,
property,
crlf = String.fromCharCode(13),
code = document.createElement('code'),
script = document.createElement('script');
function getJSType(metadataType) {
if (/(Int64)|(Int32)|(Int16)|(Byte)|(Decimal)|(Double)|(Single)|(number)/.test(metadataType))
return 'number';
else if (/(DateTime)|(DateTimeOffset)|(Time)|(Date)/.test(metadataType))
return 'Date';
else if (/(Boolean)/i.test(metadataType))
return 'boolean';
return 'string';
}
for (i = 0; i < types.length; i++) {
// type declaration
var type = types[i];
html += 'export interface ' + type.shortName;
// base type
html += ' extends ';
if (type.hasOwnProperty('baseEntityType')) {
html += type.baseEntityType.shortName;
} else {
html += 'breeze.Entity';
}
html += ' {' + crlf;
// data properties
for (j = 0; j < type.dataProperties.length; j++) {
property = type.dataProperties[j];
if (type.baseEntityType && type.baseEntityType.dataProperties.filter(function (p) { return p.name === property.name; }).length > 0)
continue;
html += ' ' + property.name;
//if (property.isNullable)
// html += '?';
html += ': KnockoutObservable<';
html += getJSType(property.dataType.name);
html += '>; //' + property.dataType.name + crlf;
}
// navigation properties
for (j = 0; j < type.navigationProperties.length; j++) {
property = type.navigationProperties[j];
if (type.baseEntityType && type.baseEntityType.navigationProperties.filter(function (p) { return p.name === property.name; }).length > 0)
continue;
html += ' ' + property.name;
//if (property.isNullable)
// html += '?';
if (property.isScalar)
html += ': KnockoutObservable<';
else
html += ': KnockoutObservableArray<';
html += property.entityType.shortName;
html += '>;' + crlf;
}
html += '}' + crlf + crlf;
}
code.innerHTML = html;
$(code).addClass('prettyprint');
document.body.appendChild(code);
script.setAttribute('src', '//google-code-prettify.googlecode.com/svn/loader/run_prettify.js');
document.body.appendChild(script);
})
.fail(function (reason) {
alert(reason);
});
});
</script>
</head>
<body>
</body>
</html>