├── resources ├── makeres.bat ├── Mvc.rc ├── Mvc.RES ├── Richtext.RES ├── richtext │ ├── kbd-back.png │ ├── richtext-icons.png │ ├── richtext.htm │ ├── richtext-utils.tis │ ├── richtext.css │ └── richtext.tis ├── Richtext.rc └── mvc │ ├── plus.css │ └── plus.tis ├── demo ├── scide.png ├── SciDeDemo.dof ├── SciDeDemo.res ├── SciDeDemo.tlb ├── SciDeDemo.cfg ├── SciDeDemo.dpr ├── SciDeDemo.ridl ├── NativeForm.pas ├── SciDeDemo_TLB.pas ├── DemoBehavior.pas ├── scide.htm ├── SciMainForm.pas ├── SciMainForm.dfm └── SciDeDemo.dproj ├── construction.swf ├── source ├── Sciter.dcr ├── Sciter.ico ├── TiScriptApi.pas └── SciterOle.pas ├── packages ├── SciDe_XE7 │ ├── SciDe.res │ ├── SciDe.dpk │ └── SciDe.dproj ├── SciDe_D7 │ ├── SciDe_D7.res │ ├── SciDe_D7.drc │ ├── SciDe_D7.cfg │ └── SciDe_D7.dpk ├── SciDe_D7.bpg └── SciDe_XE7.groupproj ├── .gitignore ├── clear.bat └── README.md /resources/makeres.bat: -------------------------------------------------------------------------------- 1 | brcc32 Richtext.rc 2 | brcc32 Mvc.rc 3 | pause -------------------------------------------------------------------------------- /demo/scide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/SciDe/HEAD/demo/scide.png -------------------------------------------------------------------------------- /resources/Mvc.rc: -------------------------------------------------------------------------------- 1 | plus_tis HTML "mvc\\plus.tis" 2 | plus_css HTML "mvc\\plus.css" -------------------------------------------------------------------------------- /construction.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/SciDe/HEAD/construction.swf -------------------------------------------------------------------------------- /demo/SciDeDemo.dof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/SciDe/HEAD/demo/SciDeDemo.dof -------------------------------------------------------------------------------- /demo/SciDeDemo.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/SciDe/HEAD/demo/SciDeDemo.res -------------------------------------------------------------------------------- /demo/SciDeDemo.tlb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/SciDe/HEAD/demo/SciDeDemo.tlb -------------------------------------------------------------------------------- /resources/Mvc.RES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/SciDe/HEAD/resources/Mvc.RES -------------------------------------------------------------------------------- /source/Sciter.dcr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/SciDe/HEAD/source/Sciter.dcr -------------------------------------------------------------------------------- /source/Sciter.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/SciDe/HEAD/source/Sciter.ico -------------------------------------------------------------------------------- /resources/Richtext.RES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/SciDe/HEAD/resources/Richtext.RES -------------------------------------------------------------------------------- /packages/SciDe_XE7/SciDe.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/SciDe/HEAD/packages/SciDe_XE7/SciDe.res -------------------------------------------------------------------------------- /packages/SciDe_D7/SciDe_D7.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/SciDe/HEAD/packages/SciDe_D7/SciDe_D7.res -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.identcache 2 | *.stat 3 | *.rsm 4 | *.drc 5 | *.dproj.local 6 | *.groupproj.local 7 | *.mes 8 | -------------------------------------------------------------------------------- /resources/richtext/kbd-back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/SciDe/HEAD/resources/richtext/kbd-back.png -------------------------------------------------------------------------------- /resources/richtext/richtext-icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/SciDe/HEAD/resources/richtext/richtext-icons.png -------------------------------------------------------------------------------- /resources/Richtext.rc: -------------------------------------------------------------------------------- 1 | kbd_back_png HTML "richtext\\kbd-back.png" 2 | richtext_icons_png HTML "richtext\\richtext-icons.png" 3 | richtext_css HTML "richtext\\richtext.css" 4 | richtext_tis HTML "richtext\\richtext.tis" 5 | richtext_utils HTML "richtext\\richtext-utils.tis" -------------------------------------------------------------------------------- /packages/SciDe_D7/SciDe_D7.drc: -------------------------------------------------------------------------------- 1 | /* VER150 2 | Generated by the Borland Delphi Pascal Compiler 3 | because -GD or --drc was supplied to the compiler. 4 | 5 | This file contains compiler-generated resources that 6 | were bound to the executable. 7 | If this file is empty, then no compiler-generated 8 | resources were bound to the produced executable. 9 | */ 10 | 11 | STRINGTABLE 12 | BEGIN 13 | END 14 | 15 | -------------------------------------------------------------------------------- /clear.bat: -------------------------------------------------------------------------------- 1 | FOR /r %%R IN (*.~*) DO IF EXIST %%R (del /s /q "%%R") 2 | FOR /r %%R IN (*.o) DO IF EXIST %%R (del /s /q "%%R") 3 | FOR /r %%R IN (*.identcache) DO IF EXIST %%R (del /s /q "%%R") 4 | FOR /r %%R IN (*.ddp) DO IF EXIST %%R (del /s /q "%%R") 5 | FOR /r %%R IN (*.ppu) DO IF EXIST %%R (del /s /q "%%R") 6 | FOR /r %%R IN (*.dcu) DO IF EXIST %%R (del /s /q "%%R") 7 | FOR /r %%R IN (*.bak) DO IF EXIST %%R (del /s /q "%%R") 8 | FOR /r %%R IN (*.hpp) DO IF EXIST %%R (del /s /q "%%R") 9 | FOR /r %%R IN (*.dtx) DO IF EXIST %%R (del /s /q "%%R") 10 | 11 | @IF EXIST "__history\*" rd /q /s __history\ 12 | -------------------------------------------------------------------------------- /packages/SciDe_D7/SciDe_D7.cfg: -------------------------------------------------------------------------------- 1 | -$A8 2 | -$B- 3 | -$C+ 4 | -$D+ 5 | -$E- 6 | -$F- 7 | -$G+ 8 | -$H+ 9 | -$I+ 10 | -$J- 11 | -$K- 12 | -$L+ 13 | -$M- 14 | -$N+ 15 | -$O- 16 | -$P+ 17 | -$Q+ 18 | -$R+ 19 | -$S- 20 | -$T- 21 | -$U- 22 | -$V+ 23 | -$W+ 24 | -$X+ 25 | -$YD 26 | -$Z1 27 | -GD 28 | -cg 29 | -vn 30 | -vr 31 | -AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; 32 | -H+ 33 | -W+ 34 | -M 35 | -$M16384,1048576 36 | -K$00400000 37 | -LE"c:\delphi7\Projects\Bpl" 38 | -LN"c:\delphi7\Projects\Bpl" 39 | -U"c:\delphi7\Lib\Debug" 40 | -O"c:\delphi7\Lib\Debug" 41 | -I"c:\delphi7\Lib\Debug" 42 | -R"c:\delphi7\Lib\Debug" 43 | -DWINDOWS 44 | -Z 45 | -w-UNSAFE_TYPE 46 | -w-UNSAFE_CODE 47 | -w-UNSAFE_CAST 48 | -------------------------------------------------------------------------------- /demo/SciDeDemo.cfg: -------------------------------------------------------------------------------- 1 | -$A8 2 | -$B- 3 | -$C+ 4 | -$D+ 5 | -$E- 6 | -$F- 7 | -$G+ 8 | -$H+ 9 | -$I+ 10 | -$J- 11 | -$K- 12 | -$L+ 13 | -$M- 14 | -$N+ 15 | -$O- 16 | -$P+ 17 | -$Q+ 18 | -$R+ 19 | -$S- 20 | -$T+ 21 | -$U- 22 | -$V+ 23 | -$W+ 24 | -$X+ 25 | -$YD 26 | -$Z1 27 | -GD 28 | -cg 29 | -vn 30 | -vr 31 | -AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; 32 | -H+ 33 | -W+ 34 | -M 35 | -$M16384,1048576 36 | -K$00400000 37 | -E".." 38 | -LE"c:\delphi7\Projects\Bpl" 39 | -LN"c:\delphi7\Projects\Bpl" 40 | -U"c:\delphi7\Lib\Debug;..\source" 41 | -O"c:\delphi7\Lib\Debug;..\source" 42 | -I"c:\delphi7\Lib\Debug;..\source" 43 | -R"c:\delphi7\Lib\Debug;..\source" 44 | -DWINDOWS 45 | -w-UNSAFE_TYPE 46 | -w-UNSAFE_CODE 47 | -w-UNSAFE_CAST 48 | -------------------------------------------------------------------------------- /resources/mvc/plus.css: -------------------------------------------------------------------------------- 1 | 2 | /* principal handlers */ 3 | [model] { aspect:"Plus.Model" url(plus.tis); } 4 | [model] [each] { aspect:"Plus.Repeater"; } /* note repeater shall come first before [model] [name] for

21 |

Note: Not finished, work in progress!

22 | 23 |
24 |   
25 | 26 | 27 | -------------------------------------------------------------------------------- /packages/SciDe_XE7/SciDe.dpk: -------------------------------------------------------------------------------- 1 | package SciDe; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO OFF} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS OFF} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION ON} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO OFF} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES OFF} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE RELEASE} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$IMPLICITBUILD ON} 29 | 30 | requires 31 | rtl, 32 | vcl; 33 | 34 | contains 35 | Sciter in '..\..\source\Sciter.pas', 36 | SciterApi in '..\..\source\SciterApi.pas', 37 | SciterNative in '..\..\source\SciterNative.pas', 38 | SciterOle in '..\..\source\SciterOle.pas', 39 | TiScriptApi in '..\..\source\TiScriptApi.pas'; 40 | 41 | end. 42 | -------------------------------------------------------------------------------- /packages/SciDe_D7/SciDe_D7.dpk: -------------------------------------------------------------------------------- 1 | // JCL_DEBUG_EXPERT_GENERATEJDBG OFF 2 | // JCL_DEBUG_EXPERT_INSERTJDBG OFF 3 | package SciDe_D7; 4 | 5 | {$R *.res} 6 | {$R '..\..\source\Sciter.dcr'} 7 | {$ALIGN 8} 8 | {$ASSERTIONS ON} 9 | {$BOOLEVAL OFF} 10 | {$DEBUGINFO ON} 11 | {$EXTENDEDSYNTAX ON} 12 | {$IMPORTEDDATA ON} 13 | {$IOCHECKS ON} 14 | {$LOCALSYMBOLS ON} 15 | {$LONGSTRINGS ON} 16 | {$OPENSTRINGS ON} 17 | {$OPTIMIZATION OFF} 18 | {$OVERFLOWCHECKS ON} 19 | {$RANGECHECKS ON} 20 | {$REFERENCEINFO ON} 21 | {$SAFEDIVIDE OFF} 22 | {$STACKFRAMES ON} 23 | {$TYPEDADDRESS OFF} 24 | {$VARSTRINGCHECKS ON} 25 | {$WRITEABLECONST OFF} 26 | {$MINENUMSIZE 1} 27 | {$IMAGEBASE $400000} 28 | {$DESCRIPTION 'Sciter for Delphi'} 29 | {$IMPLICITBUILD OFF} 30 | {$DEFINE WINDOWS} 31 | 32 | requires 33 | rtl, 34 | vcl; 35 | 36 | contains 37 | Sciter in '..\..\source\Sciter.pas', 38 | SciterApi in '..\..\source\SciterApi.pas', 39 | SciterNative in '..\..\source\SciterNative.pas', 40 | SciterOle in '..\..\source\SciterOle.pas', 41 | TiScriptApi in '..\..\source\TiScriptApi.pas', 42 | MLang in '..\..\source\MLang.pas'; 43 | 44 | end. 45 | -------------------------------------------------------------------------------- /demo/SciDeDemo.ridl: -------------------------------------------------------------------------------- 1 | // ************************************************************************ // 2 | // WARNING 3 | // ------- 4 | // This file is generated by the Type Library importer or Type Libary Editor. 5 | // Barring syntax errors, the Editor will parse modifications made to the file. 6 | // However, when applying changes via the Editor this file will be regenerated 7 | // and comments or formatting changes will be lost. 8 | // ************************************************************************ // 9 | // File generated on 18.02.2015 17:27:00 (- $Rev: 12980 $, 178915269). 10 | 11 | [ 12 | uuid(C7F57E73-1F11-4185-A28E-A7E2CF3CC3BB), 13 | version(1.0), 14 | helpstring("SciDeDemo Library") 15 | 16 | ] 17 | library SciDeDemo 18 | { 19 | 20 | importlib("stdole2.tlb"); 21 | 22 | interface ITest; 23 | 24 | 25 | [ 26 | uuid(F538C667-84DE-4F23-BD56-4C87D73F7AE9), 27 | version(1.0), 28 | dual, 29 | oleautomation 30 | ] 31 | interface ITest: IDispatch 32 | { 33 | [id(0x000000C9)] 34 | HRESULT _stdcall SayHello(void); 35 | }; 36 | 37 | }; -------------------------------------------------------------------------------- /packages/SciDe_XE7.groupproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {6D8014D7-5CB7-47AF-88FA-69D630C4CA10} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Default.Personality.12 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /demo/NativeForm.pas: -------------------------------------------------------------------------------- 1 | unit NativeForm; 2 | 3 | interface 4 | 5 | uses 6 | Windows, Forms, SciterNative, SciterApi, TiScriptApi; 7 | 8 | type 9 | TNativeForm = class(TSciterClassInfo) 10 | public 11 | constructor Create; override; 12 | destructor Destroy; override; 13 | end; 14 | 15 | implementation 16 | 17 | uses Controls; 18 | 19 | function _MethodHandler(vm: HVM; self: tiscript_value; tag: Pointer): tiscript_value; cdecl; 20 | var 21 | pForm: TForm; 22 | pInfo: ISciterMethodInfo; 23 | begin 24 | pForm := NI.get_instance_data(self); 25 | pInfo := ISciterMethodInfo(tag); 26 | 27 | if pInfo.Name = 'this' then 28 | begin 29 | // pForm := TForm.Create(Application) is dangerous because of 30 | // finalizer call followed by Application destructor call. 31 | // The form will be freed twice. 32 | pForm := TForm.CreateParented(GetDesktopWindow); 33 | 34 | pForm.Caption := 'Sciter'; 35 | pForm.ClientWidth := 400; 36 | pForm.ClientHeight := 200; 37 | pForm.Position := poScreenCenter; 38 | NI.set_instance_data(self, pForm); 39 | end 40 | 41 | else if pInfo.Name = 'Show' then 42 | begin 43 | if pForm <> nil then 44 | begin 45 | pForm.Show; 46 | pForm.BringToFront(); 47 | end; 48 | end 49 | 50 | else if pInfo.Name = 'Close' then 51 | begin 52 | pForm.Close; 53 | pForm.Free; 54 | NI.set_instance_data(self, nil); 55 | end; 56 | 57 | Result := self; 58 | end; 59 | 60 | procedure _FinalizerHandler(vm: HVM; this: tiscript_value); cdecl; 61 | var 62 | pForm: TForm; 63 | begin 64 | 65 | pForm := TObject(NI.get_instance_data(this)) as TForm; 66 | if pForm <> nil then 67 | begin 68 | pForm.Free; 69 | NI.set_instance_data(this, nil); 70 | end; 71 | end; 72 | 73 | { TNativeForm } 74 | 75 | 76 | constructor TNativeForm.Create; 77 | var 78 | pInfo: ISciterMethodInfo; 79 | begin 80 | inherited; 81 | TypeName := 'NativeForm'; 82 | 83 | Self.MethodHandler := _MethodHandler; 84 | Self.FinalizerHandler := _FinalizerHandler; 85 | 86 | pInfo := TSciterMethodInfo.Create; 87 | pInfo.Name := 'this'; 88 | Self.Methods.Add(pInfo); 89 | 90 | pInfo := TSciterMethodInfo.Create; 91 | pInfo.Name := 'Show'; 92 | Self.Methods.Add(pInfo); 93 | 94 | pInfo := TSciterMethodInfo.Create; 95 | pInfo.Name := 'Close'; 96 | Self.Methods.Add(pInfo); 97 | end; 98 | 99 | destructor TNativeForm.Destroy; 100 | begin 101 | inherited; 102 | end; 103 | 104 | end. 105 | -------------------------------------------------------------------------------- /resources/richtext/richtext-utils.tis: -------------------------------------------------------------------------------- 1 | 2 | 3 | class EditableImage: Behavior { 4 | 5 | function attached() { 6 | this.refresh(); 7 | this.paintOutline = this.renderActiveState; 8 | //stdout.println("attached"); 9 | } 10 | function detached() { 11 | this.refresh(); 12 | this.paintOutline = null; 13 | this.resizing = false; 14 | } 15 | 16 | function onMouse( evt ) { 17 | switch(evt.type) { 18 | case Event.MOUSE_UP: return this.onMouseUp(evt); 19 | case Event.MOUSE_DOWN: return this.onMouseDown(evt); 20 | case Event.MOUSE_MOVE: return this.onMouseMove(evt); 21 | } 22 | } 23 | 24 | property richtext(v) { 25 | for(var p = this.parent; p; p = p.parent) 26 | if( p.style#behavior && (p.style#behavior like "*richtext*")) 27 | return p; 28 | assert false; 29 | return null; 30 | } 31 | 32 | function isMouseOnCorner(evt) { 33 | var (w,h) = this.box(#dimension,#border); 34 | return evt.x > (w - 15) && evt.y > (h - 15); 35 | } 36 | 37 | function onMouseUp(evt) { 38 | 39 | if( this.resizing ) { 40 | this.capture(false); 41 | this.resizing = false; 42 | this.state.pressed = false; 43 | 44 | var img = this; 45 | 46 | // make undoable "change width" transaction: 47 | function changeWidth(transaction) { 48 | transaction.attr(img,"width",img.newWidth.toString()); 49 | img.style#width = undefined; 50 | img.newWidth = undefined; 51 | return true; 52 | } 53 | this.richtext.transact(changeWidth,"change width"); 54 | 55 | return true; 56 | } 57 | // else 58 | // return this.state.pressed ? this.activate(): false; 59 | } 60 | 61 | function onMouseDown(evt) { 62 | if(this.isMouseOnCorner(evt)) { 63 | var (x,y,w,h) = this.box(#rectw,#border,#view); 64 | this.ratio = w.toFloat() / h.toFloat(); 65 | this.xs = x; 66 | this.ys = y; 67 | this.dx = w - evt.x; 68 | this.dy = h - evt.y; 69 | this.resizing = true; 70 | this.capture(true); 71 | return true; 72 | } 73 | return false; 74 | } 75 | function onMouseMove(evt) { 76 | if(this.resizing) { 77 | var neww = (evt.xView - this.xs + this.dx).toInteger(); 78 | this.newWidth = neww; 79 | this.style#width = px(neww); 80 | return true; 81 | } 82 | else 83 | this.attributes.toggleClass("mouse-on-corner",this.isMouseOnCorner(evt)); 84 | return false; 85 | } 86 | 87 | function renderActiveState(gfx) { 88 | var (w,h) = this.box(#dimension,#border); 89 | gfx.lineWidth(1); 90 | gfx.fillColor(color("highlight")); 91 | gfx.lineColor(color("highlighttext")); 92 | gfx.rectangle(w-7.5,h-7.5,7,7); 93 | } 94 | 95 | } -------------------------------------------------------------------------------- /demo/SciDeDemo_TLB.pas: -------------------------------------------------------------------------------- 1 | unit SciDeDemo_TLB; 2 | 3 | // ************************************************************************ // 4 | // WARNING 5 | // ------- 6 | // The types declared in this file were generated from data read from a 7 | // Type Library. If this type library is explicitly or indirectly (via 8 | // another type library referring to this type library) re-imported, or the 9 | // 'Refresh' command of the Type Library Editor activated while editing the 10 | // Type Library, the contents of this file will be regenerated and all 11 | // manual modifications will be lost. 12 | // ************************************************************************ // 13 | 14 | // PASTLWTR : 1.2 15 | // File generated on 26.03.2015 11:34:38 from Type Library described below. 16 | 17 | // ************************************************************************ // 18 | // Type Lib: C:\git\SciDe\demo\SciDeDemo.tlb (1) 19 | // LIBID: {C7F57E73-1F11-4185-A28E-A7E2CF3CC3BB} 20 | // LCID: 0 21 | // Helpfile: 22 | // HelpString: SciDeDemo Library 23 | // DepndLst: 24 | // (1) v2.0 stdole, (C:\Windows\SysWOW64\stdole2.tlb) 25 | // ************************************************************************ // 26 | {$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers. 27 | {$WARN SYMBOL_PLATFORM OFF} 28 | {$WRITEABLECONST ON} 29 | {$VARPROPSETTER ON} 30 | interface 31 | 32 | uses Windows, ActiveX, Classes, Graphics, StdVCL, Variants; 33 | 34 | 35 | // *********************************************************************// 36 | // GUIDS declared in the TypeLibrary. Following prefixes are used: 37 | // Type Libraries : LIBID_xxxx 38 | // CoClasses : CLASS_xxxx 39 | // DISPInterfaces : DIID_xxxx 40 | // Non-DISP interfaces: IID_xxxx 41 | // *********************************************************************// 42 | const 43 | // TypeLibrary Major and minor versions 44 | SciDeDemoMajorVersion = 1; 45 | SciDeDemoMinorVersion = 0; 46 | 47 | LIBID_SciDeDemo: TGUID = '{C7F57E73-1F11-4185-A28E-A7E2CF3CC3BB}'; 48 | 49 | IID_ITest: TGUID = '{F538C667-84DE-4F23-BD56-4C87D73F7AE9}'; 50 | type 51 | 52 | // *********************************************************************// 53 | // Forward declaration of types defined in TypeLibrary 54 | // *********************************************************************// 55 | ITest = interface; 56 | ITestDisp = dispinterface; 57 | 58 | // *********************************************************************// 59 | // Interface: ITest 60 | // Flags: (4416) Dual OleAutomation Dispatchable 61 | // GUID: {F538C667-84DE-4F23-BD56-4C87D73F7AE9} 62 | // *********************************************************************// 63 | ITest = interface(IDispatch) 64 | ['{F538C667-84DE-4F23-BD56-4C87D73F7AE9}'] 65 | procedure SayHello; safecall; 66 | end; 67 | 68 | // *********************************************************************// 69 | // DispIntf: ITestDisp 70 | // Flags: (4416) Dual OleAutomation Dispatchable 71 | // GUID: {F538C667-84DE-4F23-BD56-4C87D73F7AE9} 72 | // *********************************************************************// 73 | ITestDisp = dispinterface 74 | ['{F538C667-84DE-4F23-BD56-4C87D73F7AE9}'] 75 | procedure SayHello; dispid 201; 76 | end; 77 | 78 | implementation 79 | 80 | uses ComObj; 81 | 82 | end. 83 | -------------------------------------------------------------------------------- /demo/DemoBehavior.pas: -------------------------------------------------------------------------------- 1 | unit DemoBehavior; 2 | 3 | interface 4 | 5 | uses 6 | Sciter, Messages, SysUtils, Classes, SciterAPI, Windows, Dialogs, 7 | ShockwaveFlashObjects_TLB, Forms, ExtCtrls; 8 | 9 | type 10 | TDemoBehavior = class(TElement) 11 | private 12 | FBodyIndex: IElement; 13 | FHeight: IElement; 14 | FHeightEvents: IElementEvents; 15 | FWeight: IElement; 16 | FWeightEvents: IElementEvents; 17 | procedure RecalcBMI; 18 | protected 19 | procedure DoBehaviorAttach(const Args: TElementOnBehaviorEventArgs); override; 20 | procedure DoBehaviorDetach(const Args: TElementOnBehaviorEventArgs); override; 21 | procedure DoControlEvents(const Args: TElementOnControlEventArgs); override; 22 | function GetText: WideString; override; 23 | function GetValue: Variant; override; 24 | procedure SetText(const Value: WideString); override; 25 | procedure SetValue(Value: Variant); override; 26 | public 27 | destructor Destroy; override; 28 | class function BehaviorName: AnsiString; override; 29 | end; 30 | 31 | TEventFilterBehavior = class(TElement) 32 | protected 33 | procedure DoBehaviorAttach(const Args: TElementOnBehaviorEventArgs); override; 34 | function QuerySubscriptionEvents: EVENT_GROUPS; override; 35 | procedure DoFocus(const Args: TElementOnFocusEventArgs); override; 36 | procedure DoMouse(const Args: TElementOnMouseEventArgs); override; 37 | public 38 | class function BehaviorName: AnsiString; override; 39 | end; 40 | 41 | TFlashBehavior = class(TElement) 42 | private 43 | FPanel: TPanel; 44 | FPlayer: TShockwaveFlash; 45 | protected 46 | procedure DoBehaviorAttach(const Args: TElementOnBehaviorEventArgs); override; 47 | procedure DoBehaviorDetach(const Args: TElementOnBehaviorEventArgs); override; 48 | procedure DoSize(const Args: TElementOnSizeEventArgs); override; 49 | procedure OnProgress(ASender: TObject; percentDone: Integer); 50 | public 51 | class function BehaviorName: AnsiString; override; 52 | end; 53 | 54 | implementation 55 | 56 | uses 57 | Variants, Controls; 58 | 59 | destructor TDemoBehavior.Destroy; 60 | begin 61 | FWeightEvents := nil; 62 | FHeightEvents := nil; 63 | FHeight := nil; 64 | FWeight := nil; 65 | inherited; 66 | end; 67 | 68 | { TDemoBehavior } 69 | 70 | class function TDemoBehavior.BehaviorName: AnsiString; 71 | begin 72 | Result := 'DemoBehavior'; 73 | end; 74 | 75 | procedure TDemoBehavior.DoBehaviorAttach(const Args: TElementOnBehaviorEventArgs); 76 | begin 77 | Attr['style'] := 'border: 1px dotted #666666; background-color: #FFCCCC; padding: 20px'; 78 | InnerHtml := '

Calculate your Body Mass Index (BMI)

' + 79 | '
' + 80 | '
' + 81 | '
' + 82 | '
' + 83 | '
'; 84 | FWeight := Self.Select('#txtWeight'); 85 | FWeightEvents := FWeight as IElementEvents; 86 | FHeight := Self.Select('#txtHeight'); 87 | FHeightEvents := FHeight as IElementEvents; 88 | FBodyIndex := Self.Select('#txtBodyIndex'); 89 | RecalcBMI; 90 | Args.Handled := True; 91 | end; 92 | 93 | procedure TDemoBehavior.DoBehaviorDetach(const Args: TElementOnBehaviorEventArgs); 94 | begin 95 | inherited; 96 | end; 97 | 98 | procedure TDemoBehavior.DoControlEvents(const Args: TElementOnControlEventArgs); 99 | begin 100 | if Args.EventType = EDIT_VALUE_CHANGED then 101 | RecalcBMI; 102 | inherited; 103 | end; 104 | 105 | function TDemoBehavior.GetText: WideString; 106 | begin 107 | Result := FBodyIndex.Text; 108 | end; 109 | 110 | function TDemoBehavior.GetValue: Variant; 111 | begin 112 | Result := FBodyIndex.Value; 113 | end; 114 | 115 | procedure TDemoBehavior.RecalcBMI; 116 | var 117 | w: Variant; 118 | h: Variant; 119 | begin 120 | try 121 | w := FWeight.Value; 122 | h := FHeight.Value; 123 | if VarIsNumeric(w) and VarIsNumeric(h) and (h <> 0) then 124 | FBodyIndex.Value := w / ((h / 100) * (h / 100)) 125 | else 126 | FBodyIndex.Value := Unassigned; 127 | except 128 | on E:Exception do 129 | begin 130 | FBodyIndex.Value := Unassigned; 131 | ThrowError(Sciter.VM, E.Message); 132 | end; 133 | end; 134 | end; 135 | 136 | procedure TDemoBehavior.SetText(const Value: WideString); 137 | begin 138 | end; 139 | 140 | procedure TDemoBehavior.SetValue(Value: Variant); 141 | begin 142 | end; 143 | 144 | { TEventFilterBehavior } 145 | 146 | class function TEventFilterBehavior.BehaviorName: AnsiString; 147 | begin 148 | Result := 'EventFilter'; 149 | end; 150 | 151 | procedure TEventFilterBehavior.DoBehaviorAttach( 152 | const Args: TElementOnBehaviorEventArgs); 153 | begin 154 | inherited; 155 | Args.Element.Text := 'This behavior handles focus events and ignores mouse events'; 156 | end; 157 | 158 | procedure TEventFilterBehavior.DoFocus( 159 | const Args: TElementOnFocusEventArgs); 160 | begin 161 | inherited; 162 | if Args.EventType = GOT_FOCUS then 163 | Args.Element.Text := 'GOT FOCUS' 164 | else 165 | Args.Element.Text := 'LOST_FOCUS'; 166 | end; 167 | 168 | procedure TEventFilterBehavior.DoMouse(const Args: TElementOnMouseEventArgs); 169 | begin 170 | Args.Element.Text := Format('OnMouseEvent %d:%d', [Args.X, Args.Y]); 171 | end; 172 | 173 | function TEventFilterBehavior.QuerySubscriptionEvents: EVENT_GROUPS; 174 | begin 175 | Result := HANDLE_FOCUS; // All other events will be rejected 176 | end; 177 | 178 | { TFlashBehavior } 179 | 180 | class function TFlashBehavior.BehaviorName: AnsiString; 181 | begin 182 | Result := 'FlashPlayer'; 183 | end; 184 | 185 | procedure TFlashBehavior.DoBehaviorAttach( 186 | const Args: TElementOnBehaviorEventArgs); 187 | var 188 | h: HWINDOW; 189 | sSrc: WideString; 190 | sSrc1: WideString; 191 | begin 192 | inherited; 193 | h := GetHWND; 194 | sSrc := Args.Element.Attr['src']; 195 | try 196 | FPanel := TPanel.CreateParented(h); 197 | FPanel.HandleNeeded; 198 | FPlayer := TShockwaveFlash.Create(FPanel); 199 | FPlayer.Parent := FPanel; 200 | FPlayer.Visible := True; 201 | if sSrc <> '' then 202 | begin 203 | sSrc1 := ExpandFileName(sSrc); 204 | if FileExists(sSrc1) then 205 | begin 206 | FPlayer.Movie := sSrc1; 207 | end 208 | else 209 | begin 210 | sSrc1 := Args.Element.CombineURL(sSrc); 211 | FPlayer.Movie := sSrc1; 212 | end; 213 | end; 214 | Self.AttachHwndToElement(FPanel.Handle); 215 | FPanel.Height := 400; 216 | FPanel.Width := 600; 217 | FPlayer.Width := 600; 218 | FPlayer.Height := 400; 219 | Self.Update; 220 | PostMessage(FPlayer.Handle, WM_ACTIVATE, 2, 0); // fix invalid startup size 221 | except 222 | on E:Exception do 223 | begin 224 | Self.Text := 'Failed to create ShockWave ActiveX control'; 225 | end; 226 | end; 227 | end; 228 | 229 | procedure TFlashBehavior.DoBehaviorDetach( 230 | const Args: TElementOnBehaviorEventArgs); 231 | begin 232 | if FPanel <> nil then 233 | FPanel.Free; 234 | inherited; 235 | end; 236 | 237 | procedure TFlashBehavior.DoSize(const Args: TElementOnSizeEventArgs); 238 | begin 239 | inherited; 240 | FPlayer.Height := 200; 241 | FPlayer.Width := 300; 242 | end; 243 | 244 | procedure TFlashBehavior.OnProgress(ASender: TObject; 245 | percentDone: Integer); 246 | begin 247 | Self.Update; 248 | end; 249 | 250 | initialization 251 | 252 | SciterRegisterBehavior(TDemoBehavior); 253 | SciterRegisterBehavior(TEventFilterBehavior); 254 | SciterRegisterBehavior(TFlashBehavior); 255 | 256 | end. 257 | -------------------------------------------------------------------------------- /resources/richtext/richtext.css: -------------------------------------------------------------------------------- 1 | @image-map tb-icons 2 | { 3 | src:url(res:richtext-icons.png); 4 | cells:15 2; /* 15 columns, 2 rows */ 5 | /* logical names of the parts, see toolbar-icons.png */ 6 | items: ulist, olist, 7 | unindent, indent, 8 | picture, table, link, 9 | align-left, align-center, align-right, align-justify, align, 10 | fullscreen, unfullscreen, 11 | props, 12 | bold, italic, underline, strikethrough, 13 | font-family, font-size, text-color, text-back-color, source, 14 | dlist; 15 | } 16 | 17 | popup[role="tooltip"] { padding:5px; font:system; /*background:infobackground; border:1px solid threedlight;*/ } 18 | 19 | kbd { 20 | display:inline-block; 21 | font-size:8.5pt; 22 | font-weight:bold; 23 | vertical-align:middle; 24 | padding:3px 6px; 25 | background-image:url(res:kbd-back.png); 26 | background-repeat:expand stretch-top stretch-bottom stretch-left stretch-right stretch-middle; 27 | background-position:4px 4px 4px 4px; 28 | } 29 | 30 | richtext { 31 | display:block; 32 | display-model:blocks-inside; 33 | style-set: std-richtext; 34 | prototype: Richtext url(res:richtext.tis); 35 | } 36 | 37 | @set std-richtext 38 | { 39 | :root { size:*; border: 1px solid #BBB; flow:vertical; 40 | /*font-rendering-mode: snap-pixel;*/ } 41 | 42 | :root > toolbar { 43 | display:block; 44 | display-model:block-inside; 45 | flow:horizontal-wrap; border-spacing:2px; 46 | padding:0; 47 | border-left: 1px solid #F4F4F4; 48 | border-bottom: 1px solid #BBB; 49 | background:linear-gradient(top, #F1F1F1, #DADADA); 50 | } 51 | :root > toolbar button { 52 | size:21px; 53 | padding:0; 54 | behavior:clickable; 55 | foreground:no-repeat 50% 50%; padding:3px; 56 | background-image:none; 57 | hit-margin: 2px; 58 | margin: 2px; 59 | transition:none; 60 | } 61 | :root > toolbar button[type=menu] { 62 | behavior:clickable popup-menu; 63 | } 64 | :root > toolbar button:hover { 65 | background-image:url(theme:toolbar-button-hover); 66 | } 67 | :root > toolbar button:active { 68 | background-image:url(theme:toolbar-button-pressed); 69 | foreground-position:57% 57%; 70 | } 71 | :root > toolbar button:checked { 72 | background-image:url(theme:toolbar-button-checked); 73 | } 74 | :root > toolbar button:checked:hover { 75 | background-image:url(theme:toolbar-button-checked-hover); 76 | } 77 | :root > toolbar button:disabled { 78 | background-image:none; 79 | opacity:0.25; 80 | } 81 | :root > toolbar > splitter { 82 | width:0; 83 | height:*; 84 | border-left: 1px solid #BBB; 85 | border-right: 1px solid #F4F4F4; 86 | } 87 | 88 | :root > toolbar > button.bold { foreground-image:image-map(tb-icons,bold); } 89 | :root > toolbar > button.italic { foreground-image:image-map(tb-icons,italic); } 90 | :root > toolbar > button.underline { foreground-image:image-map(tb-icons,underline); } 91 | :root > toolbar > button.strikethrough { foreground-image:image-map(tb-icons,strikethrough); } 92 | 93 | :root > toolbar > button.font-family { foreground-image:image-map(tb-icons,font-family); } 94 | :root > toolbar > button.font-size { foreground-image:image-map(tb-icons,font-size); } 95 | :root > toolbar > button.text-color { foreground-image:image-map(tb-icons,text-color); } 96 | :root > toolbar > button.text-back-color { foreground-image:image-map(tb-icons,text-back-color); } 97 | 98 | :root > toolbar > button.ulist { foreground-image:image-map(tb-icons,ulist); } 99 | :root > toolbar > button.olist { foreground-image:image-map(tb-icons,olist); } 100 | :root > toolbar > button.dlist { foreground-image:image-map(tb-icons,dlist); } 101 | :root > toolbar > button.unindent { foreground-image:image-map(tb-icons,unindent); } 102 | :root > toolbar > button.indent { foreground-image:image-map(tb-icons,indent); } 103 | :root > toolbar > button.align { foreground-image:image-map(tb-icons,align); } 104 | 105 | :root > toolbar > button.pre { foreground-image:image-map(tb-icons,props); } 106 | 107 | :root > toolbar > button.picture { foreground-image:image-map(tb-icons,picture); } 108 | :root > toolbar > button.table { foreground-image:image-map(tb-icons,table); } 109 | :root > toolbar > button.link { foreground-image:image-map(tb-icons,link); } 110 | 111 | :root > toolbar > button.fullscreen { foreground-image:image-map(tb-icons,fullscreen); margin-left:*; } 112 | :root > toolbar > button.fullscreen:checked { foreground-image:image-map(tb-icons,unfullscreen); } 113 | 114 | :root > toolbar > button > menu { padding:4dip; } 115 | :root > toolbar > button > menu > li { padding-left:32px; } 116 | :root > toolbar > button > menu > li:checked { foreground:url(stock:checkmark) 6px 50% no-repeat; } 117 | :root > toolbar > button.font-size > menu.popup { min-width:max-content; max-width:200px;} 118 | 119 | .align-left {foreground-image:image-map(tb-icons,align-left);} 120 | .align-right {foreground-image:image-map(tb-icons,align-right);} 121 | .align-center {foreground-image:image-map(tb-icons,align-center);} 122 | .align-justify {foreground-image:image-map(tb-icons,align-justify);} 123 | 124 | :root > textarea { size:*; background:window; padding:0; visibility:collapse;} 125 | 126 | :root > htmlarea { size:*; background:window; padding:0; padding-left:32px; overflow: scroll-indicator; font-rendering-mode:snap-pixel; } 127 | :root > htmlarea dt:content-editable { font-weight:bold; } 128 | :root > htmlarea br:content-editable { width:8px; background:url(res:br.png) no-repeat 1px 50%; } 129 | 130 | /*:root > htmlarea img { prototype:EditableImage url(richtext-utils.tis); cursor:pointer; } 131 | :root > htmlarea img:focus { outline:2px dotted highlight -2px; } 132 | :root > htmlarea img:focus.mouse-on-corner { cursor:nw-resize; } */ 133 | 134 | :root > htmlarea img:selected { prototype:EditableImage url(res:richtext-utils.tis); } 135 | :root > htmlarea img:selected.mouse-on-corner { cursor:se-resize; } 136 | :root > htmlarea img::selection { background:rgba(255,255,255,0.65); outline: 5px nesw-hatch highlight -5px; } 137 | 138 | :root > htmlarea input::selection, 139 | :root > htmlarea textarea::selection, 140 | :root > htmlarea button::selection, 141 | :root > htmlarea select::selection, 142 | :root > htmlarea th::selection, 143 | :root > htmlarea td::selection { background:rgba(highlight,0.25); outline: 3px nesw-hatch highlight -3px; } 144 | 145 | :root > htmlarea input, 146 | :root > htmlarea textarea, 147 | :root > htmlarea button, 148 | :root > htmlarea select { -disabled:true; } 149 | 150 | :root > htmlarea table td, 151 | :root > htmlarea table th { padding:2px 4px; } 152 | 153 | :root > htmlarea table:not([border]) td, 154 | :root > htmlarea table:not([border]) th { outline:1px dotted #ccc -1px; } 155 | 156 | :root[mode=source] > textarea { visibility:visible; } 157 | :root[mode=source] > htmlarea { visibility:collapse; } 158 | 159 | :root > toolbar > button.table > menu > table { size:*; border-spacing:-1px; } 160 | :root > toolbar > button.table > menu > table > tr { height:*; } 161 | :root > toolbar > button.table > menu > table > tr > td { size:1.6em; background:stretch; background-clip:padding-box; border:1px solid activecaption; -role:"menu-item"; } 162 | :root > toolbar > button.table > menu > table > tr > td[selected] { background-color:activecaption; border:1px solid threedface; } 163 | :root > toolbar > button.table > menu > table > tr > td:hover { background-image:url(theme:toolbar-button-hover); } 164 | :root > toolbar > button.table > menu > table > tr > td:active { background-image:url(theme:toolbar-button-pressed); } 165 | 166 | :root > toolbar > button.table > menu > header { behavior:form; text-align:center; } 167 | :root > toolbar > button.table > menu > header > button.radio { behavior:radio; width:max-content; height:auto; padding:4px 8px; } 168 | 169 | 170 | } 171 | -------------------------------------------------------------------------------- /source/TiScriptApi.pas: -------------------------------------------------------------------------------- 1 | {*******************************************************} 2 | { } 3 | { TIScript API } 4 | { Copyright (c) Dmitry Baranov } 5 | { } 6 | { This unit uses Sciter Engine, } 7 | { copyright Terra Informatica Software, Inc. } 8 | { (http://terrainformatica.com/). } 9 | { } 10 | {*******************************************************} 11 | 12 | unit TiScriptApi; 13 | 14 | interface 15 | 16 | uses 17 | Windows; 18 | 19 | type 20 | ptiscript_native_interface = ^tiscript_native_interface; 21 | HVM = ^tiscript_vm; 22 | 23 | { TIScript value } 24 | tiscript_value = type Int64; 25 | ptiscript_value = ^tiscript_value; 26 | 27 | { TIScript value handy synonyms } 28 | tiscript_class = type tiscript_value; 29 | tiscript_object = type tiscript_value; 30 | tiscript_string = type tiscript_value; 31 | 32 | { TIScript pinned value } 33 | tiscript_pvalue = record 34 | val: tiscript_value; 35 | vm: HVM; 36 | d1: Pointer; 37 | d2: Pointer; 38 | end; 39 | ptiscript_pvalue = ^tiscript_pvalue; 40 | 41 | { Sciter VM handle } 42 | tiscript_VM = record 43 | end; 44 | 45 | { TIScript iterator } 46 | tiscript_iterator = function(c: HVM; index: ptiscript_value; obj: tiscript_value): tiscript_value; cdecl; 47 | ptiscript_iterator = ^tiscript_iterator; 48 | 49 | { TIScript method callback } 50 | tiscript_method = function(c: HVM): tiscript_value; cdecl; 51 | ptiscript_method = ^tiscript_method; 52 | 53 | tiscript_tagged_method = function(vm: HVM; self: tiscript_value; tag: Pointer): tiscript_value; cdecl; 54 | ptiscript_tagged_method = ^tiscript_tagged_method; 55 | 56 | { TIScript method definition } 57 | tiscript_method_def = record 58 | dispatch: Pointer; 59 | name: PAnsiChar; 60 | handler: Pointer; // can be either tiscript_method or tiscript_tagged_method 61 | tag: Pointer; 62 | payload: tiscript_value; 63 | end; 64 | ptiscript_method_def = ^tiscript_method_def; 65 | 66 | tiscript_method_def_array = array of ptiscript_method_def; 67 | ptiscript_method_def_array = ^tiscript_method_def_array; 68 | 69 | tiscript_get_prop = function(c: HVM; this: tiscript_value): tiscript_value; cdecl; 70 | ptiscript_get_prop = ^tiscript_get_prop; 71 | 72 | tiscript_tagged_get_prop = function(c: HVM; this: tiscript_value; tag: Pointer): tiscript_value; cdecl; 73 | 74 | tiscript_set_prop = procedure(c: HVM; this: tiscript_value; value: tiscript_value ); cdecl; 75 | ptiscript_set_prop = ^tiscript_set_prop; 76 | 77 | tiscript_tagged_set_prop = procedure(c: HVM; this: tiscript_value; value: tiscript_value; tag: Pointer); cdecl; 78 | 79 | tiscript_finalizer = procedure(c: HVM; this: tiscript_value); cdecl; 80 | ptiscript_finalizer = ^tiscript_finalizer; 81 | 82 | tiscript_get_item = function(c: HVM; this: tiscript_value; key: tiscript_value): tiscript_value; cdecl; 83 | ptiscript_get_item = ^tiscript_get_item; 84 | 85 | tiscript_set_item = procedure(c: HVM; this: tiscript_value; key: tiscript_value; value: tiscript_value); cdecl; 86 | ptiscript_set_item = ^tiscript_set_item; 87 | 88 | tiscript_on_gc_copy = procedure(instance_data: Pointer; new_self: tiscript_value); cdecl; 89 | 90 | { TIScript property definition } 91 | tiscript_prop_def = record 92 | dispatch: Pointer; 93 | name: PAnsiChar; 94 | getter: ptiscript_get_prop; 95 | setter: ptiscript_set_prop; 96 | tag: Pointer; 97 | end; 98 | ptiscript_prop_def = ^tiscript_prop_def; 99 | 100 | { TOScript class definition } 101 | tiscript_class_def = record 102 | name: PAnsiChar; 103 | methods: ptiscript_method_def; 104 | props: ptiscript_prop_def; 105 | consts: Pointer; // ptiscript_const_def; 106 | get_item: tiscript_get_item; 107 | set_item: tiscript_set_item; 108 | finalizer: tiscript_finalizer; 109 | iterator: tiscript_iterator; 110 | on_gc_copy: tiscript_on_gc_copy; 111 | prototype: tiscript_value; 112 | 113 | // added by da-baranov to simplify memory management 114 | methodsc: UINT; // including null-terminated record 115 | propsc: UINT; // including null-terminated record 116 | end; 117 | ptiscript_class_def = ^tiscript_class_def; 118 | 119 | tiscript_native_interface = record 120 | create_vm: function(features: UINT; heap_size: UINT): HVM; cdecl; // 1 121 | destroy_vm: procedure(pvm: HVM); cdecl; 122 | invoke_gc: procedure(pvm: HVM); cdecl; 123 | set_std_streams: procedure; cdecl; 124 | get_current_vm: function: HVM; cdecl; // 5 125 | get_global_ns: function(pvm: HVM): tiscript_value; cdecl; 126 | get_current_ns: function(pvm: HVM): tiscript_value; cdecl; 127 | is_int: function(v: tiscript_value): Boolean; cdecl; 128 | is_float: function(v: tiscript_value): Boolean; cdecl; 129 | is_symbol: function(v: tiscript_value): Boolean; cdecl; // 10 130 | is_string: function(v: tiscript_value): Boolean; cdecl; 131 | is_array: function(v: tiscript_value): Boolean; cdecl; 132 | is_object: function(v: tiscript_value): BOOL; cdecl; 133 | is_native_object: function(v: tiscript_value): Boolean; cdecl; 134 | is_function: function(v: tiscript_value): Boolean; cdecl; // 15 135 | is_native_function: function(v: tiscript_value): Boolean; cdecl; 136 | is_instance_of : function(v: tiscript_value; cls: tiscript_value): Boolean; cdecl; 137 | is_undefined : function(v: tiscript_value): Boolean; cdecl; 138 | is_nothing : function(v: tiscript_value): Boolean; cdecl; 139 | is_null : function(v: tiscript_value): Boolean; cdecl; // 20 140 | is_true : function(v: tiscript_value): Boolean; cdecl; 141 | is_false : function(v: tiscript_value): Boolean; cdecl; 142 | is_class : function(pvm: HVM; v: tiscript_value): Boolean; cdecl; 143 | is_error : function(v: tiscript_value): Boolean; cdecl; 144 | is_bytes : function(v: tiscript_value): Boolean; cdecl; // 25 145 | is_datetime : function(pvm: HVM; v: tiscript_value): bool; cdecl; 146 | get_int_value : function(v: tiscript_value; var pi: Integer): bool; cdecl; 147 | get_float_value : function(v: tiscript_value; var pd: double): bool; cdecl; 148 | get_bool_value : function(v: tiscript_value; var pb: bool): bool; cdecl; 149 | get_symbol_value : function(v: tiscript_value; var psz: PWideChar): bool; cdecl; // 30 150 | get_string_value : function(v: tiscript_value; var pdata: PWideChar; var pLength: UINT): bool; cdecl; 151 | get_bytes : function(v: tiscript_value; var pb: PByte {* unsigned char** }; var pblen: UINT): BOOL; cdecl; 152 | get_datetime : function(pvm: HVM; v: tiscript_value; var dt: FILETIME): BOOL; cdecl; 153 | nothing_value : function: tiscript_value; cdecl; 154 | undefined_value : function: tiscript_value; cdecl; // 35 155 | null_value : function: tiscript_value; cdecl; 156 | bool_value : function(v: bool): tiscript_value; cdecl; 157 | int_value : function (v: integer): tiscript_value; cdecl; 158 | float_value : function(v: double): tiscript_value; cdecl; 159 | string_value : function (pvm: HVM; text: PWideChar; text_length: UINT): tiscript_value; cdecl; // 40 160 | symbol_value : function(zstr: PAnsiChar): tiscript_value; cdecl; 161 | bytes_value : function(pvm: HVM; data: PByte; data_length: UINT): tiscript_value; cdecl; 162 | datetime_value : function(pvm: HVM; ft: FILETIME): tiscript_value; cdecl; 163 | 164 | to_string : function(pvm: HVM; v: tiscript_value): tiscript_string; cdecl; 165 | 166 | define_class : function(pvm: HVM; cls: ptiscript_class_def; zns: tiscript_value): tiscript_class; cdecl; // 45 167 | create_object : function(pvm: HVM; cls: tiscript_class): tiscript_object; cdecl; 168 | set_prop : function(pvm: HVM; obj: tiscript_object; key: tiscript_value; value: tiscript_value): WordBool; cdecl; 169 | get_prop : function(pvm: HVM; obj: tiscript_object; key: tiscript_value): tiscript_value; cdecl; 170 | for_each_prop : function(pvm: HVM; obj: tiscript_value; cb: {tiscript_object_enum* cb} Pointer; tag: Pointer): BOOL; cdecl; 171 | get_instance_data : function(obj: tiscript_object): Pointer; cdecl; // 50 172 | set_instance_data : procedure(obj: tiscript_object; data: Pointer); cdecl; 173 | 174 | create_array : function(vm: HVM; of_size: UINT): tiscript_value; cdecl; 175 | set_elem : function(vm: HVM; arr: tiscript_value; idx: UINT; value: tiscript_value): BOOL; cdecl; 176 | get_elem : function(vm: HVM; arr: tiscript_value; idx: UINT): tiscript_value; cdecl; 177 | set_array_size : function(vm: HVM; arr: tiscript_value; of_size: UINT): tiscript_value; cdecl; // 55 178 | get_array_size : function(vm: HVM; arr: tiscript_value): UINT; cdecl; 179 | 180 | // eval 181 | eval : procedure; cdecl; 182 | eval_string : function(vm: HVM; ns: tiscript_value; script: PWideChar; script_length: UINT; var pretval: tiscript_value): boolean; cdecl; 183 | // call function (method) 184 | call : function(pvm: HVM; obj: tiscript_value; func: tiscript_value; argv: ptiscript_value; argn: UINT; var pretval: tiscript_value): BOOL; cdecl; 185 | 186 | // compiled bytecodes 187 | compile: procedure; cdecl; // 60 188 | loadbc: procedure; cdecl; 189 | 190 | throw_error: procedure(pvm: HVM; error: PWideChar); cdecl; 191 | 192 | get_arg_count: function(pvm: HVM): UINT; cdecl; 193 | get_arg_n: function(pvm: HVM; n: UINT): tiscript_value; cdecl; 194 | 195 | get_value_by_path: function(pvm: HVM; v: ptiscript_value; path: PAnsiChar): Boolean; cdecl; /// 65 196 | 197 | // pins 198 | pin: procedure(vm: HVM; value: ptiscript_pvalue); cdecl; 199 | unpin: procedure(value: ptiscript_pvalue); cdecl; 200 | 201 | native_function_value: function(pvm: HVM; const method: ptiscript_method_def): tiscript_value; cdecl; 202 | native_property_value: function(pvm: HVM; const prop: ptiscript_prop_def): tiscript_value; cdecl; 203 | 204 | post: procedure; cdecl; // 70 205 | 206 | set_remote_std_streams: procedure; cdecl; 207 | set_nth_retval: procedure; cdecl; 208 | get_length: procedure; cdecl; 209 | get_next: procedure; cdecl; 210 | get_next_key_value: procedure; cdecl; // 75 211 | 212 | set_extra_data: procedure; cdecl; 213 | get_extra_data: procedure; cdecl; // 77 214 | end; 215 | 216 | implementation 217 | 218 | end. 219 | -------------------------------------------------------------------------------- /resources/richtext/richtext.tis: -------------------------------------------------------------------------------- 1 | 2 | class Richtext: Behavior { 3 | 4 | const SELECTED = 0x01; 5 | const DISABLED = 0x02; 6 | 7 | function attached() { 8 | var nodes = this.nodes(); // store initial content 9 | this.clear(); // clear 10 | this.append(this.toolbar = new Element("toolbar")); 11 | this.append(this.htmlarea = new Element("htmlarea")); 12 | //this.append(this.textarea = new Element("textarea")); 13 | for( var node in nodes ) // assign content to htmlarea 14 | this.htmlarea.appendNode(node); 15 | this.observers = []; 16 | this.initToolbar(); 17 | this.setupKeyBindings(); 18 | } 19 | function detached() {} 20 | 21 | property value(v) 22 | { 23 | get { return this.htmlarea.html; } 24 | set { this.htmlarea.html = v; } 25 | } 26 | 27 | property text(v) 28 | { 29 | get { return this.htmlarea.text; } 30 | set { this.htmlarea.html = text; } 31 | } 32 | 33 | // binds UI thing (e.g. toolbar button) with command|function to be executed onClick 34 | function bind(selector, cmd, param = undefined) { 35 | var me = this; 36 | var uiel = this.select(selector); assert uiel; 37 | if(typeof cmd == #function) { 38 | uiel.onClick = :: cmd.call(me,#exec,param); 39 | this.observers.push( function() { 40 | var cmdState = cmd.call(me,#query,param) || 0; 41 | uiel.state.checked = (cmdState & SELECTED) != 0; 42 | uiel.state.disabled = (cmdState & DISABLED) != 0; 43 | }); 44 | } else if(typeof cmd == #string) { 45 | uiel.onClick = :: me.htmlarea.execCommand(cmd,param); 46 | this.observers.push( function() { 47 | var cmdState = me.htmlarea.queryCommand(cmd,param) || 0; 48 | uiel.state.checked = (cmdState & SELECTED) != 0; 49 | uiel.state.disabled = (cmdState & DISABLED) != 0; 50 | }); 51 | } else 52 | assert false: "Bad cmd type"; 53 | } 54 | 55 | function initToolbar() { 56 | 57 | // build toolbar 58 | this.toolbar.$content 59 | ( 76 | 96 | 97 | 99 | " 151 | "100%"; 152 | 153 | // initialization 154 | var tableGrid = ""; 155 | for( var r in DEF_TABLE_ROWS ) { 156 | tableGrid += ""; 157 | for( var c in DEF_TABLE_COLS ) 158 | tableGrid += ""; 160 | } 161 | tableGrid += "
"; 159 | tableGrid += "
"; 162 | 163 | menu.html = tableStyle + tableGrid; 164 | 165 | var table = button.$(:root>menu>table); 166 | 167 | function setSelection(R = -1,C = -1) { 168 | if( C == selTableCol && R == selTableRow ) 169 | return; 170 | for( var r in DEF_TABLE_ROWS ) 171 | for( var c in DEF_TABLE_COLS ) 172 | table[r][c].attributes["selected"] = r <= R && c <= C ? true : undefined; 173 | selTableCol = C; 174 | selTableRow = R; 175 | } 176 | 177 | table.onMouse = function(evt) 178 | { 179 | if( evt.type == Event.MOUSE_MOVE ) { 180 | var td = evt.target.$p(td); 181 | if( !td || !evt.target.belongsTo(table)) return; 182 | var C = td.index; 183 | var R = td.parent.index; 184 | setSelection(R,C); 185 | } else if( evt.type == Event.MOUSE_LEAVE ) 186 | setSelection(); 187 | } 188 | 189 | button.onControlEvent = function(evt) { 190 | if(evt.type == Event.POPUP_READY) 191 | setSelection(); 192 | else if(evt.type == Event.MENU_ITEM_CLICK) { 193 | var C = evt.target.index; 194 | var R = evt.target.parent.index; 195 | //stdout.printf("%V\n",menu.$(header).value); 196 | me.insertTable(R+1,C+1, menu.$(header).value.tablewidth); 197 | return true; // handled 198 | } 199 | } 200 | 201 | //this.htmlarea 202 | 203 | } 204 | 205 | function insertTable(rows, columns, width=undefined, border=undefined) 206 | { 207 | var html = ""; 208 | for( var r in rows ) { 209 | html += ""; 210 | for( var r in columns ) 211 | html += ""; 213 | } 214 | html += "
"; 212 | html += "
"; 215 | 216 | function insertIt(transaction) { 217 | // 'this' here is an htmlarea 218 | var pos = transaction.removeRange(); // delete selection if any 219 | var container = (this super).blockContainerOf(pos[0]); // get container that can hold the 220 | pos = transaction.split(pos,container); // split the pos until the container 221 | var insertedNodes = transaction.insertHtml(pos, html); // insert the html at pos 222 | assert insertedNodes.length && insertedNodes[0].tag == "table"; 223 | var table = insertedNodes[0]; 224 | var firstTextPos = table.$(td).firstCaretPos; 225 | this.state.focus = true; 226 | this.selection.select(firstTextPos); // move caret to pos 227 | return true; 228 | } 229 | this.htmlarea.transact(insertIt,"insert table"); // do the action inside undoable transaction. 230 | } 231 | 232 | // helper methods: 233 | function blockContainerOf(node) { 234 | var root = this.htmlarea; 235 | var c = node; 236 | while( c ) 237 | { 238 | if(c.contentModel == #block-inside) return c; 239 | if(c == root) return null; 240 | c = c.parent; 241 | } 242 | return null; 243 | } 244 | 245 | function setupKeyBindings() { 246 | 247 | const magickeys = 248 | [ 249 | { name: "B", code: Event.VK_B, cmd:"format:toggle-span:b|strong", desc: "apply span" }, 250 | { name: "I", code: Event.VK_I, cmd:"format:toggle-span:i|em", desc: "apply span" }, 251 | { name: "U", code: Event.VK_U, cmd:"format:toggle-span:u", desc: "apply (underline) span" }, 252 | { name: "T", code: Event.VK_T, cmd:"format:toggle-span:s|strike", desc: "apply span" }, 253 | { name: "D", code: Event.VK_D, cmd:"format:toggle-span:code", desc: "apply span" }, 254 | { name: "ENTER", code: Event.VK_RETURN, cmd:"edit:insert-block-break", desc: "break block element" }, 255 | { name: "NUMPAD+", code: Event.VK_ADD, cmd:"format:indent", desc: "indent selection" }, 256 | { name: "NUMPAD-", code: Event.VK_SUBTRACT, cmd:"format:unindent", desc: "unindent selection" }, 257 | { name: "NUMPAD1", code: Event.VK_NUMPAD1, cmd:"format:morph-block:h1", desc: "transform to

" }, 258 | { name: "NUMPAD2", code: Event.VK_NUMPAD2, cmd:"format:morph-block:h2", desc: "transform to

" }, 259 | { name: "NUMPAD3", code: Event.VK_NUMPAD3, cmd:"format:morph-block:h3", desc: "transform to

" }, 260 | { name: "NUMPAD4", code: Event.VK_NUMPAD4, cmd:"format:morph-block:h4", desc: "transform to

" }, 261 | { name: "NUMPAD5", code: Event.VK_NUMPAD5, cmd:"format:morph-block:h5", desc: "transform to

" }, 262 | { name: "NUMPAD6", code: Event.VK_NUMPAD6, cmd:"format:morph-block:h6", desc: "transform to
" }, 263 | { name: "NUMPAD*", code: Event.VK_MULTIPLY, cmd:"format:morph-block:p", desc: "transform to

" }, 264 | { name: "NUMPAD/", code: Event.VK_DIVIDE, cmd:"format:morph-block:div", desc: "transform to

" }, 265 | 266 | { name: "NUMPAD0", code: Event.VK_NUMPAD0, cmd:"format:toggle-list:ol", desc: "toggle ordered list
    /
  1. " }, 267 | { name: "NUMPAD.", code: Event.VK_DECIMAL, cmd:"format:toggle-list:ul", desc: "toggle unordered list
      /
    • " }, 268 | 269 | ]; 270 | 271 | this.htmlarea.onKey = function(evt) { 272 | if( evt.type != Event.KEY_DOWN ) return; 273 | if( !evt.ctrlKey ) return; 274 | for(var mk in magickeys) 275 | if( evt.keyCode == mk.code ) { 276 | return this.execCommand(mk.cmd,undefined); 277 | } 278 | } 279 | } 280 | } 281 | 282 | 283 | 284 | -------------------------------------------------------------------------------- /demo/scide.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SciDe examples 6 | 31 | 209 | 210 | 211 |

      SCIDE - Sciter for Delphi

      212 | 213 |
      214 |
      You can find more samples in the Sciter SDK (http://sciter.com)
      215 |
      216 | 217 | Table of Contents 218 | 221 | 222 | 223 |
      224 |

      Basic DOM manipulations

      225 | 226 | 227 | 228 | 229 | 230 |
      231 |     
      232 |     
      233 |
      234 | 235 | 236 |
      237 |

      Event handling using IElementEvents interface

      238 | 239 |
      240 | 241 | 242 |
      243 |

      Event handling using IElement.Subscribe* functions

      244 |
245 | 246 | 247 | 248 | 249 | 250 |
input|text:
input|checkbox:
textarea:
button
Type something here:
251 | 252 | 253 | 254 |
255 |

Event handlers assigned at design-time (see TSciter.EventMap collection)

256 |
257 | 258 | 259 | 260 | 261 |
262 |
263 | 264 | 265 | 266 |
267 |

OLE Example 1. Creating and manipulating XML document using MSXML

268 |
269 | var doc = CreateObject("MSXML2.DOMDocument");
270 | doc.loadXML("<div />");
271 | var root = doc.documentElement;  
272 | for (var i = 0; i < 10; i++)
273 | {
274 |   var heading = root.appendChild(doc.createElement("h"));
275 |   var textNode = heading.appendChild(doc.createTextNode("Heading " + i));
276 | }  
277 | var doc1 = doc;
278 | self.select("#oleOut1").text = doc1.xml;
279 | doc1 = null;
280 | doc = null;
281 |     
282 | 283 |
284 |     
285 |     
286 |
287 | 288 | 289 |
290 |

OLE Example 2. Parsing text with regular expressions

291 |
292 | var re = CreateObject("VBScript.RegExp");
293 | re.Pattern = "\\d+";
294 | re.Global = true;
295 | var arr = [];
296 | var matches = re.Execute(self#txtRegExpInp.text);
297 | for (var match in matches)
298 | {
299 |   arr.push(match.Value);
300 | }
301 | self.select("#oleOut2").text = "Found numeric values: " + arr.join(", ");
302 | matches = null;
303 | re = null;
304 |     
305 |
306 | 307 |
308 |
309 | 320 |
321 |
322 |     
323 |     
324 |
325 | 326 | 327 |
328 |

OLE Example 3. Call Microsoft Word

329 |
330 | var word = CreateObject("Word.Application");
331 | word.Visible = true;
332 | var doc = word.Documents.Add();
333 | doc.Paragraphs[doc.Paragraphs.Count].Range.Text = "Hello from Sciter!";
334 |     
335 | 336 | 337 |
338 | 339 |
340 |

OLE Example 4. Invoke externally passed COM object

341 |
342 | // Delphi code
343 | procedure TMainForm.FormCreate(Sender: TObject);
344 | var
345 |   pTest: ITest; // the ITest interface inherits from IDispatch
346 | begin
347 |   pTest := TTest.Create;
348 |   Sciter1.RegisterComObject('Test', pTest);
349 | end;
350 | 
351 | // TIScript code
352 | function self#cmd.onClick()
353 | {
354 |   Test.SayHello();
355 | }
356 |     
357 | 358 |
359 | 360 | 361 |
362 |

OLE Example 5. Invoke another externally passed COM object

363 |
364 | // Delphi code
365 | pXml := CreateOleObject('MSXML2.DOMDocument');
366 | pXml.LoadXML('...');
367 | Sciter1.RegisterComObject('XML', pXml);
368 | 
369 | // TIScript code
370 | function self#cmdXml.onClick()
371 | {
372 |   self#preXML.text = XML.xml; 
373 | }
374 |     
375 |
376 | 
377 |     
378 | 379 |
380 | 381 | 382 |
383 |

Intercept non-existing view methods calls

384 |
385 | // The Foo function does not exist in the view context, but you 
386 | // can intercept and handle that function call
387 | 
388 | procedure TMainForm.Sciter1MethodCall(ASender: TObject; const MethodName:
389 |     WideString; const Args: array of OLEVariant; var ReturnValue: OleVariant;
390 |     var Handled: Boolean);
391 | begin
392 |   if MethodName = 'Foo' then
393 |   begin
394 |     ShowMessage('Method ' + MethodName + ' is calling with argument ' + Args[0]);
395 |     Handled := True;
396 |   end;
397 |   // else Handled = False and Sciter will emit a warning message
398 | end;
399 |     
400 | 401 | 402 |
403 | 404 | 405 |
406 |

Intercept element methods calls

407 | 408 | 409 |
410 | 411 | 412 |
413 |

Call native function implemented in Delphi

414 |
415 | function SayHelloNative(c: HVM): tiscript_value; cdecl;
416 | begin
417 |   ShowMessage('Hello!');
418 |   Result := NI.int_value(0);
419 | end;
420 | ...
421 | Sciter1.RegisterNativeFunction('SayHello', @SayHelloNative);
422 |     
423 | 424 |
425 | 426 | 427 |
428 |

Call native class implemented in Delphi

429 | 430 | 431 |
432 | 433 | 434 |
435 |

Native Delphi Control inside Sciter

436 |
437 | procedure TMainForm.Sciter1DocumentComplete(ASender: TObject; const url:
438 |     WideString);
439 | var
440 |   pButton: TButton;
441 |   pDivContainer: TElement; 
442 | begin
443 |   pDivContainer := Sciter1.Root.Select('#divContainer');
444 |   if pDivContainer <> nil then
445 |   begin
446 |     pButton := TButton.Create(Self);
447 |     pButton.Parent := Sciter1;
448 |     pButton.Caption := 'Native button';
449 |     pButton.OnClick := OnNativeButtonClick;
450 |     pButton.Font.Color := clGreen;
451 |     pDivContainer.AttachHwndToElement(pButton.Handle);
452 |   end;
453 | end;
454 | 
455 |
456 | 457 |
458 |
459 | 460 | 461 |
462 |

Richtext behavior (embedded in Resources)

463 |
464 | 465 | 466 | 467 |

SciDe

468 | Sciter 469 |
470 |
471 |     
472 |       
473 |
474 |
475 | 476 | 477 |
478 |

Dump this Document DOM tree

479 | 480 |
481 |     
482 |     
483 |
484 | 485 | 486 |
487 |

Print something

488 | 489 | 490 | 491 |
492 | 493 | 494 |
495 |

Popups problem (resolved)

496 | 497 |
498 | 499 | 500 |
501 |

Native behavior demo

502 |
503 | <!-- HTML -->
504 | <div style="behavior: DemoBehavior" id="divDemoBehavior"/>
505 | 
506 | { Delphi code }
507 | TDemoBehavior = class(TElement)
508 | ...
509 | 
510 | class function TDemoBehavior.BehaviorName: AnsiString;
511 | begin
512 |   Result := 'DemoBehavior';
513 | end;
514 | 
515 | ...
516 | 
517 | initialization
518 |   SciterRegisterBehavior(TDemoBehavior);
519 | 
520 | 
521 | 522 | 523 |
524 | 525 |
526 | 527 |
528 | 529 | 530 |
531 |

Filtering behavior events

532 | 535 |
536 | 537 | 538 |
539 |

Embedded Flash player (experimental)

540 |
541 | 542 |
543 |
544 | 545 | 546 | 547 |
548 |

Timer demo

549 | 550 | 551 |
552 | 553 |
554 |
555 | 556 | 557 |
558 |

Request demo

559 | 560 |
561 |
562 |
563 | 564 | 565 |
566 |

Insert before/after

567 | 568 | 569 | |text| 570 |
571 | 572 | 573 |
574 |

Custom URL protocol handler

575 |
576 |       <img src="scide://scide.png" />
577 |     
578 | 579 |
580 | 581 | 582 | -------------------------------------------------------------------------------- /resources/mvc/plus.tis: -------------------------------------------------------------------------------- 1 | 2 | const Plus = function() { 3 | 4 | function parentModel(el) { 5 | for(var p = el.parent; p; p = p.parent) { 6 | //p.style.display; 7 | if(var dr = p.$model) return dr; 8 | } 9 | return null; 10 | } 11 | 12 | // setup model namespace binding, 'this' is the element 13 | function Model() 14 | { 15 | var me = this; 16 | var mo = this.@["model"]; 17 | this.$model = mo? eval(mo) : self.ns; 18 | if(!this.$model) throw "Model {" + mo + "} not found!"; 19 | } 20 | 21 | const reIsExpression=/ *[-()+*&:?|=!^"']+ */; 22 | //const reIsExpression=/ */; 23 | const reVarName = /[a-zA-Z_][a-zA-Z0-9_]*/; 24 | 25 | // 'changed()' gets called when coll[key] value has changed (updated or removed) 26 | function setupModelChangeHandler(coll,key,changed) 27 | { 28 | // data change event handler 29 | function on_model_change(changedef) { 30 | // changedef here is: 31 | //[0] - symbol, one of #add,#update,#delete,#add-range,#delete-range or #update-range 32 | //[1] - object or vector, its element(s) was changed; 33 | //[2] - symbol or string, property name - for objects 34 | // or start of changed range (index) in arrays 35 | //[3] - end of changed range (index, not inclusive) in arrays 36 | switch(changedef[0]) { 37 | case #update: if( key == changedef[2] ) changed(coll[key]); break; // object-property 38 | case #delete: if( key == changedef[2] ) changed(undefined); break; // object-property 39 | case #update-range: if( key >= changedef[2] && key < changedef[3] ) changed(coll[key]); break; // vector-index 40 | case #delete-range: if( key >= changedef[2] && key < changedef[3] ) changed(undefined); break; // vector-index 41 | } 42 | } 43 | // assign it as an observer 44 | Object.addObserver.call(coll,on_model_change); // subscribe to collection object changes 45 | } 46 | 47 | // 'added()' gets called for each new element added to coll 48 | function setupModelExpansionHandler(coll, added) 49 | { 50 | // setup data object change event handler 51 | function on_model_change(changedef) { 52 | switch(changedef[0]) { 53 | case #add: { added(coll,changedef[2]); } break; 54 | case #add-range: { var start = changedef[2]; var end = changedef[3]; for(var i = start; i < end; ++i) added(coll,i); } break; 55 | } 56 | } 57 | Object.addObserver.call(coll,on_model_change); // subscribe to collection object changes 58 | } 59 | 60 | // 'changed()' is called when coll.length has changed 61 | function setupModelLengthChangeHandler(coll, changed) 62 | { 63 | // setup data object change event handler 64 | function on_model_change(changedef) { 65 | switch(changedef[0]) { 66 | case #add: case #add-range: 67 | case #delete: case #delete-range: changed(coll.length); break; 68 | } 69 | } 70 | Object.addObserver.call(coll,on_model_change); // subscribe to collection object changes 71 | } 72 | 73 | // 'changed()' is called when coll changes 74 | function setupCollectionChangeHandler(coll, changed) 75 | { 76 | // setup data object change event handler 77 | function on_model_change(changedef) { changed(); } 78 | Object.addObserver.call(coll,on_model_change); // subscribe to collection object changes 79 | } 80 | 81 | 82 | // compile expression into function 83 | function compileExpr(model, expr) { 84 | var func = new Function("return " + expr); func.namespace = model; return func; 85 | } 86 | 87 | function setupTerminalBinding(model,thing,path,isInput,updater) 88 | { 89 | //stdout.printf("STB %s %V\n", path, path.match( reIsExpression ) ); 90 | if( typeof model != #object && typeof model != #namespace) 91 | return; 92 | 93 | if(reIsExpression.test(path)) { // looks like an expression, setup it as data observer 94 | var parts = path.split(reIsExpression); 95 | var expr = compileExpr(model,path); 96 | for( var part in parts) { 97 | if( part.match(reVarName) ) { 98 | var (coll,key) = Object.referenceOf(model, part); 99 | if(!key) continue; 100 | //stdout.printf("setupTerminalBinding, expr part key %s in coll %V\n", key, coll); 101 | if(key == #length) setupModelLengthChangeHandler( coll, function(length) { updater(thing, expr()); } ); 102 | else setupModelChangeHandler( coll, key, function(val) { updater(thing, expr()); } ); 103 | } 104 | } 105 | updater(thing,expr()); 106 | return; 107 | } 108 | 109 | assert model: "Model is null while binding " + path; 110 | 111 | //stdout.printf("STB %V %V\n", model, path ); 112 | 113 | var (coll,key) = Object.referenceOf(model, path); 114 | if( !key ) return; 115 | 116 | //stdout.printf("setupTerminalBinding: coll=%s key=%v\n", typeof coll, key); 117 | 118 | if( key == #length ) { // special treatment for length computale property 119 | setupModelLengthChangeHandler( coll, function(length) { updater(thing, length); } ); 120 | updater(thing,coll.length); // intial value 121 | } 122 | else { // subscribe to model change notifications: 123 | if( isInput ) { // setup DOM change event handler 124 | function on_ui_change() { coll[key] = thing.value; return false; } 125 | thing.subscribe("change.plus",on_ui_change); // subscribe to the element value change event 126 | } 127 | setupModelChangeHandler( coll, key, function(val) { updater(thing,val); } ); 128 | updater(thing,coll[key]); // assign intial value to it; 129 | } 130 | } 131 | 132 | function valueUpdater(thing,v) { 133 | //stdout.println("valueUpdater", thing,v); 134 | if(!thing.state.focus && v !== undefined) thing.value = v; 135 | } 136 | 137 | // setup terminal binding on 'this' 138 | function Terminal() { 139 | var path = this.@["name"]; 140 | var thing = this; // the DOM thing 141 | var model = /*this.$model ||*/ parentModel(thing); 142 | setupTerminalBinding(model,thing,path,thing.tag != #output, valueUpdater ); 143 | } 144 | 145 | const CLASS_RE = /(.*)\{\{(([-_a-z0-9]+) *\:)? *(.+)\}\}(.*)/i; 146 | //const CLASS_RE = /(.*)\{\{([-_a-z0-9]+)(\:)+(.+)\}\}(.*)/i; 147 | 148 | function ClassTerminal() { 149 | var model = this.$model || parentModel(this); 150 | var thing = this; // the DOM thing 151 | var classattr = this.@["class"]; 152 | assert model : "model shall exist" ; 153 | assert classattr : "it should not be empty"; 154 | 155 | var parts = classattr.match(CLASS_RE); 156 | 157 | if( parts[1] /*&& parts[5]*/ ) 158 | this.@["class"] = parts[1] + " " + (parts[5] || ""); 159 | else 160 | this.@["class"] = undefined; 161 | 162 | var expr = parts[4]; // expression 163 | var cname = parts[3]; // "cls1" if class="{{cls1:expr}}", A case, expr - boolean 164 | // "" if class="{{expr}}" , B case, expr - string 165 | var sname = null; // class name set by B case expr 166 | //stdout.printf("ClassTerminal %V\n", parts); 167 | 168 | function classUpdater(thing,v) { 169 | thing.post(function() { 170 | if( cname ) // case A 171 | thing.@.toggleClass(cname, v || false); 172 | else if( sname != v ) // case B 173 | thing.@.removeClass(sname); thing.@.addClass(sname = v); 174 | }, true); 175 | //stdout.println("classUpdater", thing, v); 176 | } 177 | setupTerminalBinding(model,thing,expr,false,classUpdater); 178 | } 179 | 180 | function AttrTerminal(attrname) { 181 | var model = this.$model || parentModel(this); 182 | var thing = this; // the DOM thing 183 | var attrval = this.@[attrname]; 184 | assert model : "model shall exist" ; 185 | assert attrval : "it should not be empty"; 186 | 187 | var prefix = attrval ~/ "{{"; 188 | var expr = attrval ~% "{{"; // expression part 189 | var suffix = expr %~ "}}"; // class name 190 | expr = expr /~ "}}"; // everything in between {{...}} 191 | //stdout.println("A:", prefix, expr, suffix); 192 | 193 | function attrUpdater(thing,v) { 194 | thing.post(function() { 195 | thing.@[attrname] = prefix + v + suffix; 196 | }, true); 197 | } 198 | setupTerminalBinding(model,thing,expr,false,attrUpdater); 199 | } 200 | 201 | function crackEachExpression(text) // parse iterator expression: each="[index,]item in collection[|extra]" 202 | { 203 | const RE = /(([a-z0-9]+)?\,?([a-z0-9]+)?) in ([^|]+)(\|(.+))?/i; 204 | var parts = text.match(RE); 205 | if( !parts ) 206 | throw "Unrecognized @each format:" + text; 207 | 208 | var nindex = parts[2]; // index var name 209 | var nitem = parts[3]; // 'item' var name 210 | if( !nitem ) 211 | (nitem,nindex) = (nindex,nitem); 212 | var ncoll = parts[4]; 213 | nitem = symbol(nitem); 214 | if(nindex) 215 | nindex = symbol(nindex); 216 | var filter = parts.length > 6? parts[6]:null; 217 | 218 | return (ncoll, nitem, nindex, filter); 219 | } 220 | 221 | function eachRecord(rec,filter) { return true; } 222 | 223 | 224 | function functionFilter(rec,idx,filter) { 225 | if( filter(rec, idx) ) 226 | return true; 227 | else 228 | return false; 229 | } 230 | 231 | function objectFilter(rec,idx,filter) { 232 | for(var (k,v) in filter) { 233 | var rv = rec[k]; 234 | if( typeof v == #string ) { if( rv.indexOf(v) < 0 ) return false; } 235 | else if( typeof v == #function ) { if( !v(rv) ) return false; } 236 | else if( rv != v ) return false; 237 | } 238 | return true; 239 | } 240 | function textFilter(rec,idx,filter) { 241 | for(var (k,v) in rec) { 242 | if( typeof v == #string && v.indexOf(filter) < 0 ) return false; 243 | } 244 | return true; 245 | } 246 | 247 | function Repeater() { 248 | var (ncoll, nitem, nindex, filter) = crackEachExpression(this.@["each"]); 249 | var root = parentModel(this); 250 | assert root; 251 | var isSelect = this.tag == "select"; 252 | var that = this; 253 | var thing = isSelect? that.options: that; 254 | var template = thing.first; 255 | thing.clear(); 256 | 257 | var renderList; // forward declaration 258 | 259 | var ff = eachRecord; // filter function 260 | var fs = null; // filter value 261 | 262 | function rqRenderList() { thing.post(renderList,true); } 263 | 264 | function appendRepeatableItem(cont, coll, idx, val, domItemIdx) 265 | { 266 | var domitem = cont[domItemIdx]; 267 | if( domitem && domitem.$model) { 268 | var elval = domitem.$model[nitem]; 269 | if( elval === val) 270 | return; // record already bound with the DOM 271 | domitem.remove(); 272 | Object.removeObserver.call(elval, rqRenderList); 273 | } 274 | //stdout.println("appendRepeatableItem", domItemIdx); 275 | domitem = template.clone(); 276 | var repeatable_root = {}; 277 | repeatable_root[nitem] = val; 278 | if(nindex) repeatable_root[nindex] = idx; 279 | repeatable_root.prototype = root; // repeatable root is derived from parent root 280 | domitem.$model = repeatable_root; // repeated element is holding local $model now for its descendannts. 281 | 282 | setupModelChangeHandler( coll, idx, 283 | function(val) { if(val) repeatable_root[nitem] = val; // this will propagate changes to record content 284 | else domitem.remove(); } ); 285 | 286 | cont.insert(domitem,domItemIdx); 287 | 288 | if( ff !== eachRecord && typeof val == #object ) // if something in the record has changed we need to rerender the list 289 | Object.addObserver.call(val, rqRenderList); 290 | } 291 | 292 | var (rcoll,rkey) = Object.referenceOf(root, ncoll); 293 | var coll = rcoll[rkey]; 294 | //eval(ncoll,root); 295 | assert(coll); 296 | 297 | this.$model = coll; 298 | 299 | renderList = function () { 300 | //debug stacktrace; 301 | var seqNo = 0; 302 | for(var (k,v) in coll) 303 | if( ff(v,k,fs) ) 304 | appendRepeatableItem(thing,coll,k,v,seqNo++); 305 | 306 | while( thing.length > seqNo ) { 307 | var domitem = thing.last; 308 | var elval = domitem.$model[nitem]; 309 | domitem.remove(); 310 | Object.removeObserver.call(elval, rqRenderList); 311 | } 312 | if(isSelect) // after rendering