source upload

This commit is contained in:
Razor12911
2022-01-17 22:16:47 +02:00
parent 12936d065b
commit 098e8c48de
1778 changed files with 1206749 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android = "http://schemas.android.com/apk/res/android"
android:versionCode = "1"
android:versionName = "1.0"
package = "com.mormot">
<uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name = "android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name = "android.permission.READ_PHONE_STATE" />
<supports-screens android:smallScreens = "true"
android:normalScreens = "true"
android:largeScreens = "true"
android:anyDensity = "true" />
<uses-sdk android:minSdkVersion = "11"
android:targetSdkVersion = "21"/>
<application android:label = "@string/app_name"
android:icon = "@drawable/icon"
android:hardwareAccelerated = "true"
android:debuggable = "true">
<activity android:name = "App"
android:largeHeap = "true"
android:label = "@string/app_name"
android:screenOrientation = "portrait"
android:configChanges = "orientation|screenSize|keyboardHidden">
<intent-filter>
<action android:name = "android.intent.action.MAIN" />
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,33 @@
# Description
A stand-alone *mORMot* application for Android, using its own *SQlite3* engine for ORM storage.
By alf - aka Alfred.
It is a very first draft version, uploaded as a showcase and informative-only code.
# Setup
It needs http://sourceforge.net/projects/laz4android for native GUI rendering.
Do not forget to put the latest *mORMot* framework sources (tested with 1.18.1018) into the `mORMot` sub-folder.
# Technical background
See also http://blog.naver.com/simonsayz/220287473497 for some good ideas about FPC on Android (including threading and 3D with OpenGL).
# Compiled example
You can download a compiled version from http://synopse.info/files/samples/mORMotSample.apk
# Forum Thread
See http://synopse.info/forum/viewtopic.php?id=2393
# Blog Article
See http://blog.synopse.info/post/2015/03/01/ShowCase%3A-mORMot-with-FPC-on-Android
# Disclaimer
It is currently a working proof-of-concept, with no warranty, without even for any merchantability or fitness for a particular purpose.

View File

@@ -0,0 +1,4 @@
key.store=my-release-key.keystore
key.alias=alias_name
key.store.password=likjes69
key.alias.password=likjes69

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -0,0 +1,3 @@
set path=C:\Users\Public\Documents\Embarcadero\Studio\15.0\PlatformSDKs\apache-ant-1.9.4\bin;C:\Users\Public\Documents\Embarcadero\Studio\15.0\PlatformSDKs\adt-bundle-windows-x86-20131030\sdk\platform-tools;
set JAVA_HOME=C:\Progra~1\Java\jdk1.7.0_25
ant debug

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="mORMot" default="help">
<property name="sdk.dir" location = "C:\Users\Public\Documents\Embarcadero\Studio\15.0/PlatformSDKs\adt-bundle-windows-x86-20131030\sdk\" />
<property name="target" value = "android-19" />
<property file="ant.properties" />
<fail
message="sdk.dir is missing."
unless="sdk.dir"
/>
<import file="${sdk.dir}\tools\ant\build.xml" />
</project>

View File

@@ -0,0 +1,3 @@
set path=C:\Users\Public\Documents\Embarcadero\Studio\15.0\PlatformSDKs\apache-ant-1.9.4\bin;C:\Users\Public\Documents\Embarcadero\Studio\15.0\PlatformSDKs\adt-bundle-windows-x86-20131030\sdk\platform-tools;
set JAVA_HOME=C:\Progra~1\Java\jdk1.7.0_25
ant release

View File

@@ -0,0 +1,19 @@
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\gen\com\mormot\R.java \
: C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\res\drawable\ic_menu_preferences.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\res\drawable\ic_menu_recent_history.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\res\drawable\ic_menu_search.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\res\drawable-hdpi\icon.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\res\drawable-ldpi\icon.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\res\drawable-mdpi\icon.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\res\drawable-xhdpi\icon.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\res\drawable-xxhdpi\icon.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\res\values\strings.xml \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\bin\res\drawable\ic_menu_preferences.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\bin\res\drawable\ic_menu_recent_history.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\bin\res\drawable\ic_menu_search.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\bin\res\drawable-hdpi\icon.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\bin\res\drawable-ldpi\icon.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\bin\res\drawable-mdpi\icon.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\bin\res\drawable-xhdpi\icon.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\bin\res\drawable-xxhdpi\icon.png \
C:\Users\Alfred\Documents\GitHub\mOMRotOnAndroid\bin\AndroidManifest.xml \

View File

@@ -0,0 +1,6 @@
/** Automatically generated file. DO NOT MODIFY */
package com.kredix;
public final class BuildConfig {
public final static boolean DEBUG = true;
}

View File

@@ -0,0 +1,19 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.kredix;
public final class R {
public static final class attr {
}
public static final class drawable {
public static final int icon=0x7f020000;
}
public static final class string {
public static final int app_name=0x7f030000;
}
}

View File

@@ -0,0 +1,3 @@
set path=C:\Users\Public\Documents\Embarcadero\Studio\15.0\PlatformSDKs\adt-bundle-windows-x86-20131030\sdk\platform-tools;
adb.exe install bin\mORMot-debug.apk

View File

@@ -0,0 +1,455 @@
//
// And_Controls Base Type & Constant
//
// simonsayz@naver.com / 최원식옹
//
// 2015.02.24 Started
//
unit And_Controls_Types;
{$IFDef FPC} {$mode delphi} {$packrecords c} {$EndIF}
interface
uses
SysUtils, Types, Classes,
And_Jni;
Const
// standard colors
clBlack = $FF000000;
clMaroon = $FF800000;
clGreen = $FF008000;
clOlive = $FF808000;
clNavy = $FF000080;
clPurple = $FF800080;
clTeal = $FF008080;
clGray = $FF808080;
clSilver = $FFC0C0C0;
clRed = $FFFF0000;
clLime = $FF00FF00;
clYellow = $FFFFFF00;
clBlue = $FF0000FF;
clFuchsia = $FFFF00FF;
clAqua = $FF00FFFF;
clWhite = $FFFFFFFF;
clLtGray = clSilver;
clDkGray = clGray;
// extended colors
clMoneyGreen = $FFC0DCC0;
clSkyBlue = $FFA6CAF0;
clCream = $FFFFFBF0;
clMedGray = $FFA0A0A4;
clCyan = clAqua;
clMagenta = clFuchsia;
clTransparent = $00000000;
// Max
cMaxTouch = 10; // Max Touch
cMaxForm = 40; // Max Form Stack Count
//
cLogModeOn = True;
cLogModeOff = False;
Type
//----------------------------------------------------------------------------
// Base Types
//----------------------------------------------------------------------------
cInt = Int32;
PInt32 = PjInt;
PSingle = PjFloat;
{$IfDef DCC}
pAnsiChar = MarshaledAString;
{$EndIf}
//----------------------------------------------------------------------------
// General Types
//----------------------------------------------------------------------------
TOnAppCreate = Procedure;
TOnNotify = Procedure(Sender: TObject) of object;
//
TLangType = (ltNone,
ltPascal,
ltJava,
ltAll);
//
TBytes = Array[0..0] of Byte;
pBytes = ^TBytes;
//
TRGB = Packed Record
R,G,B : Byte;
End;
pRGB = ^TRGB;
TRGBs = Packed Array[0..0] of TRGB;
pRGBs = ^TRGBs;
TImgRGB = Record
Width : Integer;
Height : Integer;
pRGBs_ : pRGBs;
End;
//
TXYi = Record
X,Y : Integer;
end;
TXYf = Record
X,Y : Single;
end;
TWH = Record
Width : Integer;
Height : Integer;
End;
TWidthHeight = TWH;
TXYWH = Record
X, Y, W, H: Integer;
End;
TColor = DWord;
TChangeType = (ctChangeBefore,
ctChange,
ctChangeAfter);
TFormState = (fsFormCreate, // Initializing
fsFormWork, // Working
fsFormClose); // Closing
//----------------------------------------------------------------------------
// Java - And_Controls Types (And_Controls Const )
// XRef. Controls.java - Const
//----------------------------------------------------------------------------
//
TDirectory_Type = ( DIRECTORY_ALARMS = 0,
DIRECTORY_DCIM = 1,
DIRECTORY_DOCUMENTS = 2,
DIRECTORY_DOWNLOADS = 3,
DIRECTORY_MOVIES = 4,
DIRECTORY_MUSIC = 5,
DIRECTORY_NOTIFICATIONS = 6,
DIRECTORY_PICTURES = 7,
DIRECTORY_PODCASTS = 8,
DIRECTORY_RINGTONES = 9,
DIRECTORY_App = 10001,
DIRECTORY_Files = 10002,
DIRECTORY_SDCard = 10003,
DIRECTORY_DataBase = 10004,
DIRECTORY_Shared_Prefs = 10005);
//
TScreen_Style = ( Screen_Style_Normal = 0,
Screen_Style_Full = 1);
//
TNetwork_Type = ( Network_Type_None = 0,
Network_Type_Wifi = 1,
Network_Type_Mobile = 2);
//
TPaint_Style = ( Paint_Style_Fill = 0,
Paint_Style_Fill_And_Stroke = 1,
Paint_Style_Stroke = 2);
//
TCompress_Format = ( Compress_Format_PNG = 0,
Compress_Format_JPEG = 1);
//
TTouch_Type = ( Touch_Down = 0,
Touch_Move = 1,
Touch_Up = 2);
//
TClick = ( Click_Default = 0,
Click_Yes = -1,
Click_No = -2);
// Animation
TAnimation_Effect = ( Animation_Effect_None = $00000000,
Animation_Effect_iR2L = $00000001,
Animation_Effect_oR2L = $00000002,
Animation_Effect_iL2R = $00000004,
Animation_Effect_oL2R = $00000008,
Animation_Effect_FadeIn = $00000010,
Animation_Effect_FadeOut = $00000020);
//
TGLView_State = ( GLView_State_SurfaceCreated = 0,
GLView_State_SurfaceChanged = 1,
GLView_State_DrawFrame = 2,
GLView_State_SurfaceDestroyed = 3,
GLView_State_SurfaceThread = 4);
//
TWebView_Act = ( WebView_Act_Continue = 0,
WebView_Act_Break = 1);
//
TWebView_State = ( WebView_State_Unknown = 0,
WebView_State_Before = 1,
WebView_State_Finish = 2,
WebView_State_Error = 3);
//
TAsyncTask_State = ( AsyncTask_State_PreExecute = 0,
AsyncTask_State_Update = 1,
AsyncTask_State_PostExecute = 2,
AsyncTask_State_BackGround = 3);
//
TEdit_Style = ( Edit_Style_SingleLine = 0,
Edit_Style_MultiLine = 1);
//
TEdit_Type = ( Edit_Type_Number = 0,
Edit_Type_Text = 1,
Edit_Type_Phone = 2,
Edit_Type_PassNumber = 3,
Edit_Type_PassText = 4);
//
THttp_Act = ( Http_Act_Text = 0,
Http_Act_Download = 1,
Http_Act_Upload = 2);
//
THttp_State = ( Http_State_Xfer = 0,
Http_State_Done = 1,
Http_State_Error = 2);
//----------------------------------------------------------------------------
// Java - Android Native Types
//----------------------------------------------------------------------------
TText_Alignment = ( Text_Alignment_INHERIT = 0,
Text_Alignment_GRAVITY = 1,
Text_Alignment_TEXT_START = 2,
Text_Alignment_TEXT_END = 3,
Text_Alignment_CENTER = 4,
Text_Alignment_VIEW_START = 5,
Text_Alignment_VIEW_END = 6);
TAndroid_Log = ( Android_Log_UNKNOWN = 0,
Android_Log_DEFAULT = 1,
Android_Log_VERBOSE = 2,
Android_Log_DEBUG = 3,
Android_Log_INFO = 4,
Android_Log_WARN = 5,
Android_Log_ERROR = 6,
Android_Log_FATAL = 7,
Android_Log_SILENT = 8);
//
TActivity_Result = ( Activity_Result_OK = -1,
Activity_Result_CANCELED = 0);
//
TScreen_Rotate = ( Screen_Rotate_UNDEFINED = 0,
Screen_Rotate_PORTRAIT = 1,
Screen_Rotate_LANDSCAPE = 2,
Screen_Rotate_SQUARE = 3); // Deprecated API 16
//
TScreen_Orientation = ( Screen_Orientation_UNSPECIFIED = -1,
Screen_Orientation_LANDSCAPE = 0,
Screen_Orientation_PORTRAIT = 1,
Screen_Orientation_USER = 2,
Screen_Orientation_BEHIND = 3,
Screen_Orientation_SENSOR = 4,
Screen_Orientation_NOSENSOR = 5,
Screen_Orientation_SENSOR_LANDSCAPE = 6,
Screen_Orientation_SENSOR_PORTRAIT = 7,
Screen_Orientation_REVERSE_LANDSCAPE = 8,
Screen_Orientation_REVERSE_PORTRAIT = 9,
Screen_Orientation_FULL_SENSOR = 10,
Screen_Orientation_USER_LANDSCAPE = 11,
Screen_Orientation_USER_PORTRAIT = 12,
Screen_Orientation_FULL_USER = 13,
Screen_Orientation_LOCKED = 14);
//
TGLES_Version = ( GLES_v1 = 1,
GLES_v2 = 2);
//
TProgressBarStyle = ( ProgressBarStyle_Horizontal = $01010078,
ProgressBarStyle_Large = $0101007a);
// jnigraphics
TAndroid_Bitmap_Result = ( Android_Bitmap_Result_SUCCESS = 0,
Android_Bitmap_Result_BAD_PARAMETER = -1,
Android_Bitmap_Result_JNI_EXCEPTION = -2,
Android_Bitmap_Result_ALLOCATION_FAILED = -3);
TAndroid_Bitmap_Format = ( Android_Bitmap_Format_NONE = 0,
Android_Bitmap_Format_RGBA_8888 = 1,
Android_Bitmap_Format_RGB_565 = 4,
Android_Bitmap_Format_RGBA_4444 = 7,
Android_Bitmap_Format_A_8 = 8);
TAndroid_Bitmap_Info = Record
width : Cardinal; // uint32_t;
height : Cardinal; // uint32_t
stride : Cardinal; // uint32_t
format : Integer; // int32_t
flags : Cardinal; // uint32_t - 0 for now
End;
PAndroid_Bitmap_Info = ^TAndroid_Bitmap_Info;
//----------------------------------------------------------------------------
// Mouch = Mouse + Touch
//----------------------------------------------------------------------------
TMouch = Record // Ref. iOS_Controls.pas TiOSMTouch
// Result
Active : Boolean;
Pt : TXYf;
Zoom : Single;
Angle : Single;
Start : Boolean; // Multi Touch start Event
End;
TMouches = Record
// Input
Cnt : Integer;
XYs : Array[0..cMaxTouch-1] of TXYf;
// Status Save
sLen : Single;
sAngle : Single;
sPt : TXYf;
sPt1 : TXYf;
sPt2 : TXYf;
sCount : Integer; // Total Event Count
Mouch : TMouch; // MultiTouch Result (Pt,Zoom,Angle)
End;
// Java Env Info.
TEnv = Record
//
AppName : String; // [Global] AppName ex. "com.kredix"
//
jVM : PJavaVM; // [Global] App
jEnv : PJNIEnv; // [Not Global] Env per Thread
//
jClass : jClass; // [Global] Java I/F Controls - Class
jControls : jObject; // [Global] Java I/F Controls - Object
jLayout : jObject; // [Global] Java App - Base Layout
End;
TPaths = Record
//
ALARMS : String;
DCIM : String;
DOCUMENTS : String;
DOWNLOADS : String;
MOVIES : String;
MUSIC : String;
NOTIFICATIONS : String;
PICTURES : String;
PODCASTS : String;
RINGTONES : String;
//
App : String;
Files : String;
SDCard : String;
DataBase : String;
Shared_Prefs : String;
End;
// Device Info.
TDevice = Record
ScreenStyle : TScreen_Style;
ScreenOrientation : TScreen_Orientation;
ScreenWH : TWH; // ex.
//
Model : String; // ex. Nexus 7
Version : String; // ex. 5.0.3
PhoneNumber : String; // ex.
ID : String; // ex.
Network : TNetwork_Type; // None,Wifi,Mobile
End;
TAnimation = Record
AniIn : TAnimation_Effect;
AniOut : TAnimation_Effect;
end;
// Form Stack
TCallBack = Record
Event : TOnNotify;
Sender : TObject;
End;
TFormCallBack = Record
jForm : jObject;
CloseCB : TCallBack; // Close Call Back Event
End;
TForms = Record
Index : Integer;
Stack : Array[0..cMaxForm-1] of TFormCallBack;
end;
//
TOnClickEx = Procedure(Sender: TObject; Value: integer) of object;
TOnClickYN = Procedure(Sender: TObject; Click : TClick ) of object;
TOnClickItem = Procedure(Sender: TObject; Item : Integer ) of object;
//
TOnChange = Procedure(Sender: TObject; EventType : TChangeType) of object;
TOnTouch = Procedure(Sender: TObject; ID: integer; X, Y: single) of object;
TOnTouchEvent = Procedure(Sender: TObject; Touch : TMouch ) of Object;
TOnCloseQuery = Procedure(Sender: TObject; var CanClose: boolean) of object;
TOnRotate = Procedure(Sender: TObject; rotate : TScreen_Rotate; Var rstRotate : TScreen_Rotate) of Object;
TOnActivityRst = Procedure(Sender: TObject; requestCode : Integer; resultCode : TActivity_Result; jData : jObject) of Object;
// State Event
TOnGLViewSize = Procedure(Sender: TObject; W, H : integer) of object;
TOnWebViewState = Procedure(Sender: TObject; State : TWebView_State ; URL : String; Var CanNavi : Boolean) of object;
TOnAsyncTaskState= Procedure(Sender: TObject; State : TAsyncTask_State; Progress : Integer) of object;
TOnHttpState = Procedure(Sender: TObject; Act : THttp_Act; State : THttp_State; Progress : Integer;Const Msg : String) of object;
// Camera Preview Event
TOnCameraFrame = Procedure(Sender: TObject; W,H,Fmt : Integer; Data : Pointer) of Object;
// Type To String
Function strWH ( WH : TWH ) : String;
Function strScreenStyle ( ScreenStyle : TScreen_Style ) : String;
Function strScreenOrientation( ScreenOrientation : TScreen_Orientation ) : String;
Function strNetworkType ( NetworkType : TNetwork_Type ) : String;
Function strEditType ( EditType : TEdit_Type ) : String;
Var
gLog : Boolean = True; // Log Write On/Off
implementation
Function strWH ( WH : TWH ) : String;
begin
Result := IntToStr(WH.Width) + 'x' + IntToStr(WH.Height);
end;
Function strScreenStyle ( ScreenStyle : TScreen_Style ) : String;
begin
Case ScreenStyle of
Screen_Style_Normal : Result := 'Normal';
Screen_Style_Full : Result := 'Full';
else Result := 'Unknown';
end;
end;
Function strScreenOrientation( ScreenOrientation : TScreen_Orientation ) : String;
begin
Case ScreenOrientation of
Screen_Orientation_UNSPECIFIED : Result := 'Unspecified';
Screen_Orientation_LANDSCAPE : Result := 'LANDSCAPE';
Screen_Orientation_PORTRAIT : Result := 'PORTRAIT';
Screen_Orientation_USER : Result := 'USER';
Screen_Orientation_BEHIND : Result := 'BEHIND';
Screen_Orientation_SENSOR : Result := 'SENSOR';
Screen_Orientation_NOSENSOR : Result := 'NOSENSOR';
Screen_Orientation_SENSOR_LANDSCAPE : Result := 'SENSOR_LANDSCAPE';
Screen_Orientation_SENSOR_PORTRAIT : Result := 'SENSOR_PORTRAIT';
Screen_Orientation_REVERSE_LANDSCAPE : Result := 'REVERSE_LANDSCAPE';
Screen_Orientation_REVERSE_PORTRAIT : Result := 'REVERSE_PORTRAIT';
Screen_Orientation_FULL_SENSOR : Result := 'FULL_SENSOR';
Screen_Orientation_USER_LANDSCAPE : Result := 'USER_LANDSCAPE';
Screen_Orientation_USER_PORTRAIT : Result := 'USER_PORTRAIT';
Screen_Orientation_FULL_USER : Result := 'FULL_USER';
Screen_Orientation_LOCKED : Result := 'LOCKED';
else Result := 'Unknown';
end;
end;
Function strNetworkType ( NetworkType : TNetwork_Type ) : String;
begin
Case NetworkType of
Network_Type_None : Result := 'None';
Network_Type_Wifi : Result := 'Wifi';
Network_Type_Mobile : Result := 'Mobile';
End;
end;
Function strEditType ( EditType : TEdit_Type ) : String;
begin
Case EditType of
Edit_Type_Text : Result := 'TEXT';
Edit_Type_Number : Result := 'NUMBER';
Edit_Type_Phone : Result := 'PHONE';
Edit_Type_PassNumber : Result := 'PASSNUMBER';
Edit_Type_PassText : Result := 'PASSTEXT';
else Result := 'Unknown';
end;
end;
end.

View File

@@ -0,0 +1,552 @@
//
//
// Jni for Pascal
//
// Original Source Code : /fpc/2.7.1/packages/jni/src/jni.pas
//
//
//
//
//
//
unit And_jni;
{$ifdef fpc} {$mode delphi} {$packrecords c} {$endif}
interface
(*
* Manifest constants.
*)
const JNI_FALSE=0;
JNI_TRUE=1;
JNI_VERSION_1_1=$00010001;
JNI_VERSION_1_2=$00010002;
JNI_VERSION_1_4=$00010004;
JNI_VERSION_1_6=$00010006;
JNI_OK=0; // no error
JNI_ERR=-1; // generic error
JNI_EDETACHED=-2; // thread detached from the VM
JNI_EVERSION=-3; // JNI version error
JNI_COMMIT=1; // copy content, do not free buffer
JNI_ABORT=2; // free buffer w/o copying back
{$IfDef DCC}
type
pChar = MarshaledAString;
{$EndIf}
(*
* Type definitions.
*)
type va_list=pointer;
jboolean=byte; // unsigned 8 bits
jbyte=shortint; // signed 8 bits
jchar=word; // unsigned 16 bits
jshort=smallint; // signed 16 bits
jint=longint; // signed 32 bits
jlong=int64; // signed 64 bits
jfloat=single; // 32-bit IEEE 754
jdouble=double; // 64-bit IEEE 754
jsize=jint; // "cardinal indices and sizes"
Pjboolean=^jboolean;
Pjbyte=^jbyte;
Pjchar=^jchar;
Pjshort=^jshort;
Pjint=^jint;
Pjlong=^jlong;
Pjfloat=^jfloat;
Pjdouble=^jdouble;
Pjsize=^jsize;
// Reference type
jobject=pointer;
jclass=jobject;
jstring=jobject;
jarray=jobject;
jobjectArray=jarray;
jbooleanArray=jarray;
jbyteArray=jarray;
jcharArray=jarray;
jshortArray=jarray;
jintArray=jarray;
jlongArray=jarray;
jfloatArray=jarray;
jdoubleArray=jarray;
jthrowable=jobject;
jweak=jobject;
jref=jobject;
PPointer=^pointer;
Pjobject=^jobject;
Pjclass=^jclass;
Pjstring=^jstring;
Pjarray=^jarray;
PjobjectArray=^jobjectArray;
PjbooleanArray=^jbooleanArray;
PjbyteArray=^jbyteArray;
PjcharArray=^jcharArray;
PjshortArray=^jshortArray;
PjintArray=^jintArray;
PjlongArray=^jlongArray;
PjfloatArray=^jfloatArray;
PjdoubleArray=^jdoubleArray;
Pjthrowable=^jthrowable;
Pjweak=^jweak;
Pjref=^jref;
_jfieldID=record // opaque structure
end;
jfieldID=^_jfieldID;// field IDs
PjfieldID=^jfieldID;
_jmethodID=record // opaque structure
end;
jmethodID=^_jmethodID;// method IDs
PjmethodID=^jmethodID;
PJNIInvokeInterface=^JNIInvokeInterface;
Pjvalue=^jvalue;
jvalue={$ifdef packedrecords}packed{$endif} record
case integer of
0:(z:jboolean);
1:(b:jbyte);
2:(c:jchar);
3:(s:jshort);
4:(i:jint);
5:(j:jlong);
6:(f:jfloat);
7:(d:jdouble);
8:(l:jobject);
end;
jobjectRefType=(
JNIInvalidRefType=0,
JNILocalRefType=1,
JNIGlobalRefType=2,
JNIWeakGlobalRefType=3);
PJNINativeMethod=^JNINativeMethod;
JNINativeMethod={$ifdef packedrecords}packed{$endif} record
name:pchar;
signature:pchar;
fnPtr:pointer;
end;
PJNINativeInterface=^JNINativeInterface;
_JNIEnv={$ifdef packedrecords}packed{$endif} record
functions:PJNINativeInterface;
end;
_JavaVM={$ifdef packedrecords}packed{$endif} record
functions:PJNIInvokeInterface;
end;
C_JNIEnv=^JNINativeInterface;
JNIEnv=^JNINativeInterface;
JavaVM=^JNIInvokeInterface;
PPJNIEnv=^PJNIEnv;
PJNIEnv=^JNIEnv;
PPJavaVM=^PJavaVM;
PJavaVM=^JavaVM;
JNINativeInterface={$ifdef packedrecords}packed{$endif} record
reserved0:pointer;
reserved1:pointer;
reserved2:pointer;
reserved3:pointer;
GetVersion:function(Env:PJNIEnv):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
DefineClass:function(Env:PJNIEnv;const Name:pchar;Loader:JObject;const Buf:PJByte;Len:JSize):JClass;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
FindClass:function(Env:PJNIEnv;const Name:pchar):JClass;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
// Reflection Support
FromReflectedMethod:function(Env:PJNIEnv;Method:JObject):JMethodID;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
FromReflectedField:function(Env:PJNIEnv;Field:JObject):JFieldID;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ToReflectedMethod:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;IsStatic:JBoolean):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetSuperclass:function(Env:PJNIEnv;Sub:JClass):JClass;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
IsAssignableFrom:function(Env:PJNIEnv;Sub:JClass;Sup:JClass):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
// Reflection Support
ToReflectedField:function(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID;IsStatic:JBoolean):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
Throw:function(Env:PJNIEnv;Obj:JThrowable):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ThrowNew:function(Env:PJNIEnv;AClass:JClass;const Msg:pchar):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ExceptionOccurred:function(Env:PJNIEnv):JThrowable;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ExceptionDescribe:procedure(Env:PJNIEnv);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ExceptionClear:procedure(Env:PJNIEnv);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
FatalError:procedure(Env:PJNIEnv;const Msg:pchar);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
// Local Reference Management
PushLocalFrame:function(Env:PJNIEnv;Capacity:JInt):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
PopLocalFrame:function(Env:PJNIEnv;Result:JObject):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewGlobalRef:function(Env:PJNIEnv;LObj:JObject):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
DeleteGlobalRef:procedure(Env:PJNIEnv;GRef:JObject);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
DeleteLocalRef:procedure(Env:PJNIEnv;Obj:JObject);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
IsSameObject:function(Env:PJNIEnv;Obj1:JObject;Obj2:JObject):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
// Local Reference Management
NewLocalRef:function(Env:PJNIEnv;Ref:JObject):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
EnsureLocalCapacity:function(Env:PJNIEnv;Capacity:JInt):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
AllocObject:function(Env:PJNIEnv;AClass:JClass):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewObject:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewObjectV:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:va_list):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewObjectA:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:PJValue):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetObjectClass:function(Env:PJNIEnv;Obj:JObject):JClass;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
IsInstanceOf:function(Env:PJNIEnv;Obj:JObject;AClass:JClass):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetMethodID:function(Env:PJNIEnv;AClass:JClass;const Name:pchar;const Sig:pchar):JMethodID;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallObjectMethod:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallObjectMethodV:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:va_list):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallObjectMethodA:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:PJValue):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallBooleanMethod:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallBooleanMethodV:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:va_list):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallBooleanMethodA:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:PJValue):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallByteMethod:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID):JByte;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallByteMethodV:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:va_list):JByte;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallByteMethodA:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:PJValue):JByte;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallCharMethod:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID):JChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallCharMethodV:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:va_list):JChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallCharMethodA:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:PJValue):JChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallShortMethod:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID):JShort;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallShortMethodV:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:va_list):JShort;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallShortMethodA:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:PJValue):JShort;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallIntMethod:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallIntMethodV:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:va_list):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallIntMethodA:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:PJValue):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallLongMethod:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID):JLong;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallLongMethodV:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:va_list):JLong;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallLongMethodA:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:PJValue):JLong;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallFloatMethod:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID):JFloat;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallFloatMethodV:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:va_list):JFloat;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallFloatMethodA:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:PJValue):JFloat;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallDoubleMethod:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID):JDouble;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallDoubleMethodV:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:va_list):JDouble;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallDoubleMethodA:function(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:PJValue):JDouble;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallVoidMethod:procedure(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallVoidMethodV:procedure(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:va_list);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallVoidMethodA:procedure(Env:PJNIEnv;Obj:JObject;MethodID:JMethodID;Args:PJValue);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualObjectMethod:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualObjectMethodV:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:va_list):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualObjectMethodA:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:PJValue):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualBooleanMethod:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualBooleanMethodV:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:va_list):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualBooleanMethodA:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:PJValue):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualByteMethod:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID):JByte;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualByteMethodV:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:va_list):JByte;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualByteMethodA:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:PJValue):JByte;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualCharMethod:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID):JChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualCharMethodV:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:va_list):JChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualCharMethodA:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:PJValue):JChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualShortMethod:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID):JShort;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualShortMethodV:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:va_list):JShort;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualShortMethodA:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:PJValue):JShort;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualIntMethod:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualIntMethodV:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:va_list):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualIntMethodA:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:PJValue):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualLongMethod:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID):JLong;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualLongMethodV:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:va_list):JLong;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualLongMethodA:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:PJValue):JLong;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualFloatMethod:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID):JFloat;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualFloatMethodV:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:va_list):JFloat;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualFloatMethodA:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:PJValue):JFloat;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualDoubleMethod:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID):JDouble;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualDoubleMethodV:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:va_list):JDouble;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualDoubleMethodA:function(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:PJValue):JDouble;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualVoidMethod:procedure(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualVoidMethodV:procedure(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:va_list);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallNonvirtualVoidMethodA:procedure(Env:PJNIEnv;Obj:JObject;AClass:JClass;MethodID:JMethodID;Args:PJValue);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetFieldID:function(Env:PJNIEnv;AClass:JClass;const Name:pchar;const Sig:pchar):JFieldID;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetObjectField:function(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetBooleanField:function(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetByteField:function(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID):JByte;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetCharField:function(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID):JChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetShortField:function(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID):JShort;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetIntField:function(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetLongField:function(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID):JLong;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetFloatField:function(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID):JFloat;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetDoubleField:function(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID):JDouble;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetObjectField:procedure(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID;Val:JObject);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetBooleanField:procedure(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID;Val:JBoolean);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetByteField:procedure(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID;Val:JByte);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetCharField:procedure(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID;Val:JChar);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetShortField:procedure(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID;Val:JShort);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetIntField:procedure(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID;Val:JInt);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetLongField:procedure(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID;Val:JLong);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetFloatField:procedure(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID;Val:JFloat);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetDoubleField:procedure(Env:PJNIEnv;Obj:JObject;FieldID:JFieldID;Val:JDouble);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStaticMethodID:function(Env:PJNIEnv;AClass:JClass;const Name:pchar;const Sig:pchar):JMethodID;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticObjectMethod:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticObjectMethodV:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:va_list):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticObjectMethodA:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:PJValue):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticBooleanMethod:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticBooleanMethodV:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:va_list):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticBooleanMethodA:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:PJValue):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticByteMethod:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID):JByte;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticByteMethodV:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:va_list):JByte;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticByteMethodA:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:PJValue):JByte;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticCharMethod:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID):JChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticCharMethodV:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:va_list):JChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticCharMethodA:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:PJValue):JChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticShortMethod:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID):JShort;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticShortMethodV:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:va_list):JShort;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticShortMethodA:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:PJValue):JShort;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticIntMethod:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticIntMethodV:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:va_list):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticIntMethodA:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:PJValue):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticLongMethod:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID):JLong;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticLongMethodV:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:va_list):JLong;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticLongMethodA:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:PJValue):JLong;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticFloatMethod:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID):JFloat;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticFloatMethodV:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:va_list):JFloat;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticFloatMethodA:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:PJValue):JFloat;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticDoubleMethod:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID):JDouble;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticDoubleMethodV:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:va_list):JDouble;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticDoubleMethodA:function(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:PJValue):JDouble;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticVoidMethod:procedure(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticVoidMethodV:procedure(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:va_list);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
CallStaticVoidMethodA:procedure(Env:PJNIEnv;AClass:JClass;MethodID:JMethodID;Args:PJValue);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStaticFieldID:function(Env:PJNIEnv;AClass:JClass;const Name:pchar;const Sig:pchar):JFieldID;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStaticObjectField:function(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStaticBooleanField:function(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStaticByteField:function(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID):JByte;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStaticCharField:function(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID):JChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStaticShortField:function(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID):JShort;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStaticIntField:function(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStaticLongField:function(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID):JLong;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStaticFloatField:function(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID):JFloat;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStaticDoubleField:function(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID):JDouble;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetStaticObjectField:procedure(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID;Val:JObject);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetStaticBooleanField:procedure(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID;Val:JBoolean);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetStaticByteField:procedure(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID;Val:JByte);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetStaticCharField:procedure(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID;Val:JChar);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetStaticShortField:procedure(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID;Val:JShort);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetStaticIntField:procedure(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID;Val:JInt);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetStaticLongField:procedure(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID;Val:JLong);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetStaticFloatField:procedure(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID;Val:JFloat);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetStaticDoubleField:procedure(Env:PJNIEnv;AClass:JClass;FieldID:JFieldID;Val:JDouble);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewString:function(Env:PJNIEnv;const Unicode:PJChar;Len:JSize):JString;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStringLength:function(Env:PJNIEnv;Str:JString):JSize;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStringChars:function(Env:PJNIEnv;Str:JString;var IsCopy:JBoolean):PJChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ReleaseStringChars:procedure(Env:PJNIEnv;Str:JString;const Chars:PJChar);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewStringUTF:function(Env:PJNIEnv;const UTF:pchar):JString;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStringUTFLength:function(Env:PJNIEnv;Str:JString):JSize;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStringUTFChars:function(Env:PJNIEnv;Str:JString; IsCopy:PJBoolean):pchar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ReleaseStringUTFChars:procedure(Env:PJNIEnv;Str:JString;const Chars:pchar);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetArrayLength:function(Env:PJNIEnv;AArray:JArray):JSize;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewObjectArray:function(Env:PJNIEnv;Len:JSize;AClass:JClass;Init:JObject):JObjectArray;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetObjectArrayElement:function(Env:PJNIEnv;AArray:JObjectArray;Index:JSize):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetObjectArrayElement:procedure(Env:PJNIEnv;AArray:JObjectArray;Index:JSize;Val:JObject);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewBooleanArray:function(Env:PJNIEnv;Len:JSize):JBooleanArray;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewByteArray:function(Env:PJNIEnv;Len:JSize):JByteArray;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewCharArray:function(Env:PJNIEnv;Len:JSize):JCharArray;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewShortArray:function(Env:PJNIEnv;Len:JSize):JShortArray;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewIntArray:function(Env:PJNIEnv;Len:JSize):JIntArray;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewLongArray:function(Env:PJNIEnv;Len:JSize):JLongArray;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewFloatArray:function(Env:PJNIEnv;Len:JSize):JFloatArray;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
NewDoubleArray:function(Env:PJNIEnv;Len:JSize):JDoubleArray;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetBooleanArrayElements:function(Env:PJNIEnv;AArray:JBooleanArray;var IsCopy:JBoolean):PJBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetByteArrayElements:function(Env:PJNIEnv;AArray:JByteArray;var IsCopy:JBoolean):PJByte;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetCharArrayElements:function(Env:PJNIEnv;AArray:JCharArray;var IsCopy:JBoolean):PJChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetShortArrayElements:function(Env:PJNIEnv;AArray:JShortArray;var IsCopy:JBoolean):PJShort;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetIntArrayElements:function(Env:PJNIEnv;AArray:JIntArray;var IsCopy:JBoolean):PJInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetLongArrayElements:function(Env:PJNIEnv;AArray:JLongArray;var IsCopy:JBoolean):PJLong;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetFloatArrayElements:function(Env:PJNIEnv;AArray:JFloatArray;var IsCopy:JBoolean):PJFloat;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetDoubleArrayElements:function(Env:PJNIEnv;AArray:JDoubleArray;var IsCopy:JBoolean):PJDouble;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ReleaseBooleanArrayElements:procedure(Env:PJNIEnv;AArray:JBooleanArray;Elems:PJBoolean;Mode:JInt);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ReleaseByteArrayElements:procedure(Env:PJNIEnv;AArray:JByteArray;Elems:PJByte;Mode:JInt);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ReleaseCharArrayElements:procedure(Env:PJNIEnv;AArray:JCharArray;Elems:PJChar;Mode:JInt);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ReleaseShortArrayElements:procedure(Env:PJNIEnv;AArray:JShortArray;Elems:PJShort;Mode:JInt);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ReleaseIntArrayElements:procedure(Env:PJNIEnv;AArray:JIntArray;Elems:PJInt;Mode:JInt);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ReleaseLongArrayElements:procedure(Env:PJNIEnv;AArray:JLongArray;Elems:PJLong;Mode:JInt);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ReleaseFloatArrayElements:procedure(Env:PJNIEnv;AArray:JFloatArray;Elems:PJFloat;Mode:JInt);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ReleaseDoubleArrayElements:procedure(Env:PJNIEnv;AArray:JDoubleArray;Elems:PJDouble;Mode:JInt);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetBooleanArrayRegion:procedure(Env:PJNIEnv;AArray:JBooleanArray;Start:JSize;Len:JSize;Buf:PJBoolean);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetByteArrayRegion:procedure(Env:PJNIEnv;AArray:JByteArray;Start:JSize;Len:JSize;Buf:PJByte);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetCharArrayRegion:procedure(Env:PJNIEnv;AArray:JCharArray;Start:JSize;Len:JSize;Buf:PJChar);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetShortArrayRegion:procedure(Env:PJNIEnv;AArray:JShortArray;Start:JSize;Len:JSize;Buf:PJShort);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetIntArrayRegion:procedure(Env:PJNIEnv;AArray:JIntArray;Start:JSize;Len:JSize;Buf:PJInt);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetLongArrayRegion:procedure(Env:PJNIEnv;AArray:JLongArray;Start:JSize;Len:JSize;Buf:PJLong);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetFloatArrayRegion:procedure(Env:PJNIEnv;AArray:JFloatArray;Start:JSize;Len:JSize;Buf:PJFloat);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetDoubleArrayRegion:procedure(Env:PJNIEnv;AArray:JDoubleArray;Start:JSize;Len:JSize;Buf:PJDouble);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetBooleanArrayRegion:procedure(Env:PJNIEnv;AArray:JBooleanArray;Start:JSize;Len:JSize;Buf:PJBoolean);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetByteArrayRegion:procedure(Env:PJNIEnv;AArray:JByteArray;Start:JSize;Len:JSize;Buf:PJByte);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetCharArrayRegion:procedure(Env:PJNIEnv;AArray:JCharArray;Start:JSize;Len:JSize;Buf:PJChar);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetShortArrayRegion:procedure(Env:PJNIEnv;AArray:JShortArray;Start:JSize;Len:JSize;Buf:PJShort);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetIntArrayRegion:procedure(Env:PJNIEnv;AArray:JIntArray;Start:JSize;Len:JSize;Buf:PJInt);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetLongArrayRegion:procedure(Env:PJNIEnv;AArray:JLongArray;Start:JSize;Len:JSize;Buf:PJLong);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetFloatArrayRegion:procedure(Env:PJNIEnv;AArray:JFloatArray;Start:JSize;Len:JSize;Buf:PJFloat);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
SetDoubleArrayRegion:procedure(Env:PJNIEnv;AArray:JDoubleArray;Start:JSize;Len:JSize;Buf:PJDouble);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
RegisterNatives:function(Env:PJNIEnv;AClass:JClass;const Methods:PJNINativeMethod;NMethods:JInt):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
UnregisterNatives:function(Env:PJNIEnv;AClass:JClass):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
MonitorEnter:function(Env:PJNIEnv;Obj:JObject):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
MonitorExit:function(Env:PJNIEnv;Obj:JObject):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetJavaVM:function(Env:PJNIEnv;var VM:JavaVM):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
// String Operations
GetStringRegion:procedure(Env:PJNIEnv;Str:JString;Start:JSize;Len:JSize;Buf:PJChar);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetStringUTFRegion:procedure(Env:PJNIEnv;Str:JString;Start:JSize;Len:JSize;Buf:pchar);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
// Array Operations
GetPrimitiveArrayCritical:function(Env:PJNIEnv;AArray:JArray;var IsCopy:JBoolean):pointer;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ReleasePrimitiveArrayCritical:procedure(Env:PJNIEnv;AArray:JArray;CArray:pointer;Mode:JInt);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
// String Operations
GetStringCritical:function(Env:PJNIEnv;Str:JString;var IsCopy:JBoolean):PJChar;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
ReleaseStringCritical:procedure(Env:PJNIEnv;Str:JString;CString:PJChar);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
// Weak Global References
NewWeakGlobalRef:function(Env:PJNIEnv;Obj:JObject):JWeak;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
DeleteWeakGlobalRef:procedure(Env:PJNIEnv;Ref:JWeak);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
// Exceptions
ExceptionCheck:function(Env:PJNIEnv):JBoolean;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
// J2SDK1_4
NewDirectByteBuffer:function(Env:PJNIEnv;Address:pointer;Capacity:JLong):JObject;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetDirectBufferAddress:function(Env:PJNIEnv;Buf:JObject):pointer;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetDirectBufferCapacity:function(Env:PJNIEnv;Buf:JObject):JLong;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
// added in JNI 1.6
GetObjectRefType:function(Env:PJNIEnv;AObject:JObject):jobjectRefType;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
end;
JNIInvokeInterface={$ifdef packedrecords}packed{$endif} record
reserved0:pointer;
reserved1:pointer;
reserved2:pointer;
DestroyJavaVM:function(PVM:PJavaVM):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
AttachCurrentThread:function(PVM:PJavaVM;PEnv:PPJNIEnv;Args:pointer):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
DetachCurrentThread:function(PVM:PJavaVM):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
GetEnv:function(PVM:PJavaVM;PEnv:Ppointer;Version:JInt):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
AttachCurrentThreadAsDaemon:function(PVM:PJavaVM;PEnv:PPJNIEnv;Args:pointer):JInt;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
end;
JavaVMAttachArgs={$ifdef packedrecords}packed{$endif} record
version:jint; // must be >= JNI_VERSION_1_2
name:pchar; // NULL or name of thread as modified UTF-8 str
group:jobject; // global ref of a ThreadGroup object, or NULL
end;
(**
* JNI 1.2+ initialization. (As of 1.6, the pre-1.2 structures are no
* longer supported.)
*)
PJavaVMOption=^JavaVMOption;
JavaVMOption={$ifdef packedrecords}packed{$endif} record
optionString:pchar;
extraInfo:pointer;
end;
JavaVMInitArgs={$ifdef packedrecords}packed{$endif} record
version:jint; // use JNI_VERSION_1_2 or later
nOptions:jint;
options:PJavaVMOption;
ignoreUnrecognized:Pjboolean;
end;
(*
* VM initialization functions.
*
* Note these are the only symbols exported for JNI by the VM.
*)
{$ifdef jniexternals}
function JNI_GetDefaultJavaVMInitArgs(p:pointer):jint;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}external 'jni' name 'JNI_GetDefaultJavaVMInitArgs';
function JNI_CreateJavaVM(vm:PPJavaVM;AEnv:PPJNIEnv;p:pointer):jint;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}external 'jni' name 'JNI_CreateJavaVM';
function JNI_GetCreatedJavaVMs(vm:PPJavaVM;ASize:jsize;p:Pjsize):jint;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}external 'jni' name 'JNI_GetCreatedJavaVMs';
{$endif}
(*
* Prototypes for functions exported by loadable shared libs. These are
* called by JNI, not provided by JNI.
*)
const curVM : PJavaVM = nil;
curEnv : PJNIEnv = nil;
(*
function JNI_OnLoad(vm:PJavaVM;reserved:pointer):jint;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
procedure JNI_OnUnload(vm:PJavaVM;reserved:pointer);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
*)
implementation
//function JNI_OnLoad(vm:PJavaVM;reserved:pointer):jint;{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
//begin
// curVM := vm;
// result := JNI_VERSION_1_6;
//end;
//procedure JNI_OnUnload(vm:PJavaVM;reserved:pointer);{$ifdef mswindows}stdcall;{$else}cdecl;{$endif}
//begin
//end;
end.

View File

@@ -0,0 +1,117 @@
Unit Form_Splash;
{$mode delphi}
interface
uses
SysUtils,Classes,math,
And_jni,And_jni_Bridge,
And_Controls_Types,And_Controls;
Type
jForm_Splash = class(jForm)
private
tvLabel : jTextView;
ivImageBG : jImageView; // Image - BackGround
ivImageIcon : jImageView; // Image - Cube
Timer : jTimer;
//
protected
Procedure Form_OnActive (Sender : TObject);
Procedure Form_OnCloseQuery(Sender : TObject; Var CanClose : Boolean);
Procedure Form_OnClose (Sender : TObject);
//
Procedure Timer_OnTimer (Sender : TObject);
public
Cnt_Timer : Integer;
Constructor Create(Owner : jForm) ; override;
Destructor Destroy; override;
end;
implementation
//
Constructor jForm_Splash.Create(Owner : jForm);
begin
inherited;
dbg('SplashForm.OnCreate');
// Resource Extract
Asset_SaveToFile('mormot.jpg' ,App.Paths.Files+'/mormot.jpg');
Asset_SaveToFile('Synopse.png',App.Paths.Files+'/Synopse.png');
// Create Controls ----------------------------------------------------------
ivImageBG := jImageView.Create(Self);
ivImageBG.xyWH := xyWH( 0,0,App.Device.ScreenWH.width,App.Device.ScreenWH.height); // x,y,w,h
ivImageBG.Parent := Self.View;
ivImageBG.ImageName := App.Paths.Files+'/mormot.jpg';
//
ivImageIcon := jImageView.Create(Self);
ivImageIcon.xyWH := xyWH(100,80,550,190); // x,y,w,h
ivImageIcon.Parent := Self.View;
ivImageIcon.ImageName := App.Paths.Files+'/Synopse.png';
//
tvLabel := jTextView.Create (Self);
tvLabel.xyWH := xyWH(60,100,600,60);
tvLabel.Parent := Self.View;
tvLabel.Text := utf8encode('Please wait ... initializing the mORMot');
tvLabel.FontColor := clWhite;
tvLabel.FontSize := 35;
//
Timer := jTimer.Create(Self);
Timer.OnTimer := Timer_OnTimer;
Timer.Interval := 20;
Timer.Enabled := True;
Cnt_Timer := 0;
//
Self.Name := 'Form_Splash';
Self.Color := clBlack;
Self.OnActive := Form_OnActive;
Self.OnClose := Form_OnClose;
Self.OnCloseQuery := Form_OnCloseQuery;
App.SetTitleBar(False);
App.SetScreenStyle(Screen_Style_Full);
//
end;
Destructor jForm_Splash.Destroy;
begin
ivImageBG.Free;
ivImageIcon.Free;
tvLabel.Free;
Timer.Free;
inherited;
end;
//
Procedure jForm_Splash.Form_OnActive(Sender : TObject);
begin
dbg('Form_Splash OnActive');
end;
//
Procedure jForm_Splash.Form_OnCloseQuery(Sender : TObject; Var CanClose : Boolean);
begin
dbg('Form_Splash OnCloseQuery');
CanClose := True;
end;
//
Procedure jForm_Splash.Form_OnClose (Sender : TObject);
begin
dbg('Form_Splash OnClose');
Free;
App.SetTitleBar(True);
App.SetScreenStyle(Screen_Style_Normal);
end;
//
Procedure jForm_Splash.Timer_OnTimer(Sender : TObject);
begin
Inc(Cnt_Timer,3);
If Cnt_timer < ((App.Device.ScreenWH.height DIV 2)-200) then ivImageIcon.xyWH := xyWH(100,80+Cnt_Timer,550,190);
If Cnt_timer < (App.Device.ScreenWH.height DIV 2) then Exit;
Timer.Enabled := False;
Close;
end;
end.

View File

@@ -0,0 +1,245 @@
Unit Form_Main;
{$mode delphi}
interface
uses
SysUtils,Classes,math,
And_jni,And_jni_Bridge,And_Controls_Types,And_Controls,
Form_Splash
,SynCommons
,mORMot
,mORMotSQLite3, SynSQLite3Static
,SampleData
;
Type
jForm_Main = class(jForm)
private
ivImageBG : jImageView; // Image - BackGround
lblTitle : jTextView;
lblName : jTextView;
lblMessage : jTextView;
AddBtn : jButton;
FindBtn : jButton;
cbInput : jCheckBox;
cbInput2 : jCheckBox;
NameInput : jEditText;
MessageInput : jEditText;
private
Database: TSQLRest;
Model: TSQLModel;
protected
Procedure Form_OnActive (Sender : TObject);
Procedure Form_OnCloseQuery(Sender : TObject; Var CanClose : Boolean);
Procedure Form_OnClose (Sender : TObject);
Procedure Form_OnRotate (Sender : TObject; rotate : TScreen_Rotate; var rstRotate : TScreen_Rotate);
//
Procedure AddBtn_OnClick (Sender : TObject);
Procedure FindBtn_OnClick (Sender : TObject);
Procedure cbInput_OnClick (Sender : TObject);
Procedure cbInput2_OnClick (Sender : TObject);
public
Form_Splash : jForm;
Constructor Create(Owner : jForm) ; override;
end;
implementation
//
Constructor jForm_Main.Create(Owner : jForm) ;
begin
inherited;
Dbg('MainForm.OnCreate');
Self.Color := clBlack;
// Resource Extract
Asset_SaveToFile('mormotbw.jpg' ,App.Paths.Files+'/mormotbw.jpg');
// Create Controls ----------------------------------------------------------
ivImageBG := jImageView.Create(Self);
ivImageBG.xyWH := xyWH( 0,0,App.Device.ScreenWH.width,App.Device.ScreenWH.height); // x,y,w,h
ivImageBG.Parent := Self.View;
ivImageBG.ImageName := App.Paths.Files+'/mormotbw.jpg';
lblTitle := jTextView.Create (Self);
lblTitle.xyWH := xyWH(30,10,600,80,1.4);
lblTitle.Parent := Self.View;
lblTitle.Text := 'mORMot for Android';
lblTitle.FontSize := 60;
lblTitle.FontColor := clBlue;
lblTitle.Enabled := True;
//
lblName := jTextView.Create (Self);
lblName.xyWH := xyWH(30,90,200,40,1.2);
lblName.Parent := Self.View;
lblName.Text := 'Your name' ;
lblName.FontColor := clBlack;
lblName.FontSize := 30;
NameInput := jEditText.Create (Self);
NameInput.xyWH := xyWH( 30,150,350, 80);
NameInput.Parent := Self.View;
NameInput.FontColor := clWhite; // ARGB , Black
NameInput.FontSize := 40; // Pixel
NameInput.EditType := Edit_Type_Text; //
//NameInput.OnEnter := edInput_OnEnter;
//NameInput.OnChange := edInput_OnChange;
NameInput.Text := '';
NameInput.Hint := 'Enter Name';
FindBtn := jButton.Create(Self);
FindBtn.xyWH := xyWH( 400,150,220,80); // x,y,w,h
FindBtn.Parent := Self.View;
FindBtn.Text := 'Find';
FindBtn.FontColor := clWhite;
FindBtn.FontSize := 40;
FindBtn.OnClick := FindBtn_OnClick;
lblMessage := jTextView.Create (Self);
lblMessage.xyWH := xyWH(30,200,200,40,1.2);
lblMessage.Parent := Self.View;
lblMessage.Text := 'Your message' ;
lblMessage.FontColor := clBlack;
lblMessage.FontSize := 30;
MessageInput := jEditText.Create(Self);
MessageInput.xyWH := xyWH( 30, 280, 600, 400);
MessageInput.Parent := Self.View;
MessageInput.FontColor := clWhite; // ARGB , Black
MessageInput.FontSize := 40; // Pixel
MessageInput.EditType := Edit_Type_Text; //
MessageInput.EditStyle := Edit_Style_MultiLine; //
//MessageInput.OnEnter := edInput_OnEnter;
//MessageInput.OnChange := edInput_OnChange;
MessageInput.Text := '';
MessageInput.Hint := 'Enter Message';
AddBtn := jButton.Create(Self);
AddBtn.xyWH := xyWH(30,700,600,80); // x,y,w,h
AddBtn.Parent := Self.View;
AddBtn.Text := 'Add the message';
AddBtn.OnClick := AddBtn_OnClick;
AddBtn.FontSize := 40;
AddBtn.FontColor := clWhite;
cbInput := jCheckBox.Create(Self);
cbInput.xyWH := xyWH( 30,800,400, 50); // x,y,w,h
cbInput.Parent := Self.View;
cbInput.Text := 'Full screen';
cbInput.Checked := False;
cbInput.FontColor := clWhite;
cbInput.FontSize := 40; // Pixel
cbInput.OnClick := cbInput_OnClick;
cbInput2 := jCheckBox.Create(Self);
cbInput2.xyWH := xyWH( 30,900,400, 50); // x,y,w,h
cbInput2.Parent := Self.View;
cbInput2.Text := 'Title / action bar';
cbInput2.Checked := True;
cbInput2.FontColor := clWhite;
cbInput2.FontSize := 40; // Pixel
cbInput2.OnClick := cbInput2_OnClick;
Self.Name := 'Form_Main';
Self.OnActive := Form_OnActive;
Self.OnCloseQuery := Form_OnCloseQuery;
Self.OnClose := Form_OnClose;
//Self.OnRotate := Form_OnRotate; // rotate not enabled now ... fixed portrait ... see also AndroidManifest.xml
App.SetTitleBar(True);
App.SetScreenStyle(Screen_Style_Normal);
// the mORMot
Model := CreateSampleModel; // from SampleData unit
Database := TSQLRestServerDB.Create(Model,App.Paths.DOWNLOADS+'/mORMot.db3');
TSQLRestServerDB(Database).CreateMissingTables;
Form_Splash := jForm_Splash.Create(Self);
end;
Procedure jForm_Main.Form_OnActive(Sender : TObject);
begin
Dbg('OnActive Event');
Form_Splash.Show;
end;
Procedure jForm_Main.Form_OnCloseQuery(Sender : TObject; Var CanClose : Boolean);
begin
Dbg('CanClose:Main');
CanClose := True;
if Assigned(Form_Splash.View) then Form_Splash.Visible := False;
end;
Procedure jForm_Main.Form_OnClose(Sender : TObject);
begin
Dbg('OnClose Event:Main');
Database.Free;
Model.Free;
Self.Free;
App.Finish;
end;
Procedure jForm_Main.Form_OnRotate(Sender : TObject; rotate : TScreen_Rotate; var rstRotate : TScreen_Rotate);
begin
MessageInput.Text := 'Rotating';
case rotate of
Screen_Rotate_PORTRAIT:MessageInput.Text := 'Rotating: Portrait';
Screen_Rotate_LANDSCAPE:MessageInput.Text := 'Rotating: Landscape';
end;
end;
Procedure jForm_Main.cbInput_OnClick(Sender : TObject);
begin
Case cbInput.Checked of
True : begin
App.setScreenStyle(Screen_Style_Full);
end;
False : begin
App.setScreenStyle(Screen_Style_Normal);
end;
end;
end;
Procedure jForm_Main.cbInput2_OnClick(Sender : TObject);
begin
App.SetTitleBar(cbInput2.Checked);
end;
Procedure jForm_Main.AddBtn_OnClick (Sender : TObject);
var Rec: TSQLSampleRecord;
begin
Rec := TSQLSampleRecord.Create;
try
// we use explicit StringToUTF8() for conversion below
// a real application should use TLanguageFile.StringToUTF8() in mORMoti18n
Rec.Name := StringToUTF8(NameInput.Text);
Rec.Question := StringToUTF8(MessageInput.Text);
if Database.Add(Rec,true)=0 then
ShowMessage('Error adding the data') else begin
NameInput.Text := '';
MessageInput.Text := '';
NameInput.SetFocus;
end;
finally
Rec.Free;
end;
end;
Procedure jForm_Main.FindBtn_OnClick (Sender : TObject);
var Rec: TSQLSampleRecord;
begin
Rec := TSQLSampleRecord.Create(Database,'Name=?',[StringToUTF8(NameInput.Text)]);
try
if Rec.ID=0 then
MessageInput.Text := 'Not found' else
MessageInput.Text := UTF8ToString(Rec.Question);
finally
Rec.Free;
end;
end;
end.

View File

@@ -0,0 +1,39 @@
/// it's a good practice to put all data definition into a stand-alone unit
// - this unit will be shared between client and server
unit SampleData;
interface
uses
SynCommons,
mORMot;
type
/// here we declare the class containing the data
// - it just has to inherits from TSQLRecord, and the published
// properties will be used for the ORM (and all SQL creation)
// - the beginning of the class name must be 'TSQL' for proper table naming
// in client/server environnment
TSQLSampleRecord = class(TSQLRecord)
private
fQuestion: RawUTF8;
fName: RawUTF8;
fTime: TModTime;
published
property Time: TModTime read fTime write fTime;
property Name: RawUTF8 read fName write fName;
property Question: RawUTF8 read fQuestion write fQuestion;
end;
/// an easy way to create a database model for client and server
function CreateSampleModel: TSQLModel;
implementation
function CreateSampleModel: TSQLModel;
begin
result := TSQLModel.Create([TSQLSampleRecord]);
end;
end.

View File

@@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="9"/>
<General>
<Flags>
<SaveOnlyProjectUnits Value="True"/>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="mORMotDemoOnAndroid"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
<Icon Value="-1"/>
</General>
<i18n>
<EnableI18N LFM="False"/>
</i18n>
<VersionInfo>
<UseVersionInfo Value="True"/>
<AutoIncrementBuild Value="True"/>
<BuildNr Value="2986"/>
<StringTable ProductVersion=""/>
</VersionInfo>
<BuildModes Count="1">
<Item1 Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
<ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
</local>
</RunParams>
<Units Count="5">
<Unit0>
<Filename Value="mORMotOnAndroid.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="mORMotOnAndroid"/>
</Unit0>
<Unit1>
<Filename Value="Form_main.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="Form_Main"/>
</Unit1>
<Unit2>
<Filename Value="And_Controls/And_Jni_Bridge.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="And_Jni_Bridge"/>
</Unit2>
<Unit3>
<Filename Value="../src/Controls.java"/>
<IsPartOfProject Value="True"/>
</Unit3>
<Unit4>
<Filename Value="../src/App.java"/>
<IsPartOfProject Value="True"/>
</Unit4>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<Target>
<Filename ApplyConventions="False"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir);../mORMot"/>
<Libraries Value="C:/Users/Public/Documents/Embarcadero/Studio/15.0/PlatformSDKs/android-ndk-r9c/platforms/android-18/arch-arm/usr/lib/;C:/Users/Public/Documents/Embarcadero/Studio/15.0/PlatformSDKs/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/lib/gcc/arm-linux-androideabi/4.6/"/>
<OtherUnitFiles Value="And_Controls;../mORMot;../mORMot/SQLite3"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<SyntaxMode Value="Delphi"/>
<CStyleOperator Value="False"/>
<AllowLabel Value="False"/>
<CPPInline Value="False"/>
<UseAnsiStrings Value="False"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<TargetCPU Value="arm"/>
<TargetOS Value="android"/>
<Optimizations>
<OptimizationLevel Value="3"/>
</Optimizations>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
<UseLineInfoUnit Value="False"/>
</Debugging>
<Options>
<ExecutableType Value="Library"/>
</Options>
</Linking>
<Other>
<Verbosity>
<ShowNotes Value="False"/>
<ShowHints Value="False"/>
<ShowGenInfo Value="False"/>
</Verbosity>
<WriteFPCLogo Value="False"/>
<CustomOptions Value="-MObjFPC -Scghi -CX
-Tandroid
-Parm
-O3
-XsdX
-vew
-FuAnd_Controls
-FUoutput
-XParm-linux-androideabi-
-o..\libs\armeabi-v7a\libmain.so"/>
<ExecuteBefore>
<CompileReasons Compile="False" Build="False" Run="False"/>
</ExecuteBefore>
<ExecuteAfter>
<ShowAllMessages Value="True"/>
<CompileReasons Compile="False" Run="False"/>
</ExecuteAfter>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

View File

@@ -0,0 +1,115 @@
//------------------------------------------------------------------------------
//
// Free Pascal for Android
//
//------------------------------------------------------------------------------
library mORMotOnAndroidTyphon;
{$mode delphi}
{$packrecords c}
uses
And_jni,And_jni_Bridge,
And_Controls_Types,And_Controls,
Form_Main;
//------------------------------------------------------------------------------
// Application Define
//
// XRef.
// App.java : package com.kredix;
// Controls.java : package com.kredix;
//
// AndroidManifest.xml : package = "com.kredix"
// uninstall.bat : adb.exe uninstall com.kredix
//------------------------------------------------------------------------------
Const
cAppName = 'com.mormot.mORMotDemoOnAndroid'; // ! Use your app name
cAppJ = 'com_mormot_Controls'; // ! Pascal Lib. Export name
// JNI - Java->Pas
function JNI_OnLoad (vm:PJavaVM;reserved:pointer):jint; cdecl; forward;
Procedure JNI_OnUnload (vm:PJavaVM;reserved:pointer); cdecl; forward;
//-----------------------------------------------------------------------------
// Java Interface
//-----------------------------------------------------------------------------
exports
// JNI
JNI_OnLoad name 'JNI_OnLoad',
JNI_OnUnload name 'JNI_OnUnload',
// App Event
Java_Event_pOnAppCreate name 'Java_' + cAppJ + '_pOnAppCreate' ,
Java_Event_pOnAppScreenStyle name 'Java_' + cAppJ + '_pOnAppScreenStyle' ,
Java_Event_pOnAppScreenOrientation name 'Java_' + cAppJ + '_pOnAppScreenOrientation' ,
Java_Event_pOnAppNewIntent name 'Java_' + cAppJ + '_pOnAppNewIntent' ,
Java_Event_pOnAppDestroy name 'Java_' + cAppJ + '_pOnAppDestroy' ,
Java_Event_pOnAppPause name 'Java_' + cAppJ + '_pOnAppPause' ,
Java_Event_pOnAppRestart name 'Java_' + cAppJ + '_pOnAppRestart' ,
Java_Event_pOnAppResume name 'Java_' + cAppJ + '_pOnAppResume' ,
Java_Event_pOnAppActive name 'Java_' + cAppJ + '_pOnAppActive' ,
Java_Event_pOnAppStop name 'Java_' + cAppJ + '_pOnAppStop' ,
Java_Event_pOnAppBackPressed name 'Java_' + cAppJ + '_pOnAppBackPressed' ,
Java_Event_pOnAppRotate name 'Java_' + cAppJ + '_pOnAppRotate' ,
Java_Event_pOnAppConfigurationChanged name 'Java_' + cAppJ + '_pOnAppConfigurationChanged',
Java_Event_pOnAppActivityResult name 'Java_' + cAppJ + '_pOnAppActivityResult' ,
// Control Event
Java_Event_pOnChange name 'Java_' + cAppJ + '_pOnChange',
Java_Event_pOnClick name 'Java_' + cAppJ + '_pOnClick' ,
Java_Event_pOnDraw name 'Java_' + cAppJ + '_pOnDraw' ,
Java_Event_pOnEnter name 'Java_' + cAppJ + '_pOnEnter' ,
Java_Event_pOnTimer name 'Java_' + cAppJ + '_pOnTimer' ,
Java_Event_pOnTouch name 'Java_' + cAppJ + '_pOnTouch' ,
// Form Event
Java_Event_pOnClose name 'Java_' + cAppJ + '_pOnClose' ,
// State Event
Java_Event_pOnGLViewState name 'Java_' + cAppJ + '_pOnGLViewState' ,
Java_Event_pOnWebViewState name 'Java_' + cAppJ + '_pOnWebViewState' ,
Java_Event_pOnAsyncTaskState name 'Java_' + cAppJ + '_pOnAsyncTaskState',
Java_Event_pOnHttpState name 'Java_' + cAppJ + '_pOnHttpState' ,
// Camera Preview Event
Java_Event_pOnCameraFrame name 'Java_' + cAppJ + '_pOnCameraFrame';
//-----------------------------------------------------------------------------
// Application StartUp
//-----------------------------------------------------------------------------
Procedure OnAppCreate;
begin
App.Form := jForm_Main.Create(nil);
App.Form.Show;
end;
//------------------------------------------------------------------------------
// JNI_OnLoad, Unload
//------------------------------------------------------------------------------
Function JNI_OnLoad(vm:PJavaVM;reserved:pointer):jint; cdecl;
begin
jLog('JNI_OnLoad');
Result := JNI_VERSION_1_6;
//
jAppInit(App, // App Object Create & Init
Vm, // Java VM
cAppName, // App Name
Screen_Style_Normal, // Screen Style [Normal,Full]
Screen_Orientation_Portrait, // Screen Orientation [Portrait,Landscape]
// Screen_Orientation_SENSOR,
cLogModeOn, // Log Mode (Default : On)
OnAppCreate); // App Create Event
end;
Procedure JNI_OnUnload(vm:PJavaVM;reserved:pointer); cdecl;
begin
jLog('JNI_OnUnload');
//
end;
end.

View File

@@ -0,0 +1,93 @@
//------------------------------------------------------------------------------
//
// Free Pascal for Android
//
//------------------------------------------------------------------------------
library main;
{$mode delphi}
{$packrecords c}
uses
And_jni,
And_Controls_Types,And_Controls,
Form_Main;
//------------------------------------------------------------------------------
// Application Define
//
// XRef.
// App.java : package com.kredix;
// Controls.java : package com.kredix;
//
// AndroidManifest.xml : package = "com.kredix"
// uninstall.bat : adb.exe uninstall com.kredix
//------------------------------------------------------------------------------
Const
cAppName = 'com.kredix'; // ! Use your app name
cAppJ = 'com_kredix_Controls'; // ! Pascal Lib. Export name
//-----------------------------------------------------------------------------
// Java Interface
//-----------------------------------------------------------------------------
exports
// JNI
JNI_OnLoad name 'JNI_OnLoad',
JNI_OnUnload name 'JNI_OnUnload',
// App Event
Java_Event_pOnAppCreate name 'Java_' + cAppJ + '_pOnAppCreate' ,
Java_Event_pOnAppScreenStyle name 'Java_' + cAppJ + '_pOnAppScreenStyle' ,
Java_Event_pOnAppScreenOrientation name 'Java_' + cAppJ + '_pOnAppScreenOrientation' ,
Java_Event_pOnAppNewIntent name 'Java_' + cAppJ + '_pOnAppNewIntent' ,
Java_Event_pOnAppDestroy name 'Java_' + cAppJ + '_pOnAppDestroy' ,
Java_Event_pOnAppPause name 'Java_' + cAppJ + '_pOnAppPause' ,
Java_Event_pOnAppRestart name 'Java_' + cAppJ + '_pOnAppRestart' ,
Java_Event_pOnAppResume name 'Java_' + cAppJ + '_pOnAppResume' ,
Java_Event_pOnAppActive name 'Java_' + cAppJ + '_pOnAppActive' ,
Java_Event_pOnAppStop name 'Java_' + cAppJ + '_pOnAppStop' ,
Java_Event_pOnAppBackPressed name 'Java_' + cAppJ + '_pOnAppBackPressed' ,
Java_Event_pOnAppRotate name 'Java_' + cAppJ + '_pOnAppRotate' ,
Java_Event_pOnAppConfigurationChanged name 'Java_' + cAppJ + '_pOnAppConfigurationChanged',
Java_Event_pOnAppActivityResult name 'Java_' + cAppJ + '_pOnAppActivityResult' ,
// Control Event
Java_Event_pOnChange name 'Java_' + cAppJ + '_pOnChange',
Java_Event_pOnClick name 'Java_' + cAppJ + '_pOnClick' ,
Java_Event_pOnDraw name 'Java_' + cAppJ + '_pOnDraw' ,
Java_Event_pOnEnter name 'Java_' + cAppJ + '_pOnEnter' ,
Java_Event_pOnTimer name 'Java_' + cAppJ + '_pOnTimer' ,
Java_Event_pOnTouch name 'Java_' + cAppJ + '_pOnTouch' ,
// Form Event
Java_Event_pOnClose name 'Java_' + cAppJ + '_pOnClose' ,
// State Event
Java_Event_pOnGLViewState name 'Java_' + cAppJ + '_pOnGLViewState' ,
Java_Event_pOnWebViewState name 'Java_' + cAppJ + '_pOnWebViewState' ,
Java_Event_pOnAsyncTaskState name 'Java_' + cAppJ + '_pOnAsyncTaskState',
Java_Event_pOnHttpState name 'Java_' + cAppJ + '_pOnHttpState' ,
// Camera Preview Event
Java_Event_pOnCameraFrame name 'Java_' + cAppJ + '_pOnCameraFrame';
//-----------------------------------------------------------------------------
// Application StartUp
//-----------------------------------------------------------------------------
Procedure OnAppCreate;
begin
App.Form := jForm_Main.Create(nil);
App.Form.Show;
end;
begin
Dbg('Lib Start');
jAppInit(App, // App Object Create & Init
cAppName, // App Name
Screen_Style_Normal, // Screen Style [Normal,Full]
Screen_Orientation_Portrait, // Screen Orientation [Portrait,Landscape]
cLogModeOn, // Log Mode (Default : On)
OnAppCreate); // App Create Event
end.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">mORMot</string>
</resources>

View File

@@ -0,0 +1,124 @@
//
// Java Activity for Pascal
//
// http://blog.naver.com/simonsayz
// Author : Simon,Choi
//
//
package com.mormot;
//
import java.lang.Override;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.pm.ActivityInfo;
import android.widget.RelativeLayout;
import android.view.WindowManager;
import android.view.Window;
import android.view.View;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
// http://stackoverflow.com/questions/16282294/show-title-bar-from-code
public class App extends Activity {
private Controls controls;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//
Log.d(Const.LogHeader,"onCreate");
controls = new Controls(); // process Load Lib, Lib main , Jni_OnLoad
Log.d(Const.LogHeader,"Controls created");
controls.activity = this;
controls.appLayout = new RelativeLayout(this);
controls.appLayout.getRootView().setBackgroundColor (0x00000000);
// Event : Java -> Pascal : Get ScreenStyle,ScreenOrient
controls.screenStyle = controls.jOnAppScreenStyle(); // Normal,Full
controls.screenOrientation = controls.jOnAppScreenOrientation(); // Portrait,...
// Set ScreenStyle,ScreenOrientation
controls.systemSetScreenStyle (controls.screenStyle );
controls.systemSetScreenOrientation(controls.screenOrientation);
this.setContentView(controls.appLayout);
this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
// Event : Java -> Pascal
controls.jOnAppCreate(controls.appLayout);
}
@Override
protected void onNewIntent(Intent intent) { super.onNewIntent(intent);
controls.jOnAppNewIntent(); }
@Override
protected void onDestroy() { super.onDestroy();
controls.jOnAppDestroy(); }
@Override
protected void onPause() { super.onPause();
controls.jOnAppPause(); }
@Override
protected void onRestart() { super.onRestart();
controls.jOnAppRestart(); }
@Override
protected void onResume() { super.onResume();
controls.jOnAppResume(); }
@Override
protected void onStart() { super.onStart();
controls.jOnAppActive(); }
@Override
protected void onStop() { super.onStop();
controls.jOnAppStop(); }
@Override
public void onBackPressed() { controls.jOnAppBackPressed(); }
@Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
controls.jOnAppRotate(newConfig.orientation);
controls.jOnAppConfigurationChanged();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
controls.jOnAppActivityResult(requestCode,resultCode,data);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
menu.add(Menu.NONE, 0, Menu.NONE, "History").setIcon(R.drawable.ic_menu_recent_history)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.add(Menu.NONE, 1, Menu.NONE, "Quit").setIcon(R.drawable.ic_menu_search)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_WITH_TEXT);
//return true;
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
//check selected menu item
if(item.getItemId() == 1)
{
//close the Activity
this.finish();
return true;
}
return false;
}
}

View File

@@ -0,0 +1,3 @@
set path=C:\Users\Public\Documents\Embarcadero\Studio\15.0\PlatformSDKs\adt-bundle-windows-x86-20131030\sdk\platform-tools;
adb.exe uninstall com.kredix

View File

@@ -0,0 +1,15 @@
program CSV2ORM;
uses
MidasLib,
Vcl.Forms,
MAinFormU in 'MAinFormU.pas' {MainForm};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.

View File

@@ -0,0 +1,16 @@
Desc,RawUTF8,Edit,50
Make,RawUTF8,ComboBox,30
Model,RawUTF8,ComboBox,30
Highsite,Integer,ComboBox
IP,RawUTF8,Edit,15
Software,RawUTF8,Edit,30
Username,RawUTF8,Edit,30
SkipMap,Boolean,Checkbox
Created,TDateTime,DateEdit
LastLogin,TDateTime,DateEdit
GPSlat,Double,Edit
GPSLon,Double,Edit
Active,Boolean,Checkbox
SiteType,Integer,RadioGroup
CapUsed,Int64,Edit
Throttle,RawUTF8,Edit,30
1 Desc,RawUTF8,Edit,50
2 Make,RawUTF8,ComboBox,30
3 Model,RawUTF8,ComboBox,30
4 Highsite,Integer,ComboBox
5 IP,RawUTF8,Edit,15
6 Software,RawUTF8,Edit,30
7 Username,RawUTF8,Edit,30
8 SkipMap,Boolean,Checkbox
9 Created,TDateTime,DateEdit
10 LastLogin,TDateTime,DateEdit
11 GPSlat,Double,Edit
12 GPSLon,Double,Edit
13 Active,Boolean,Checkbox
14 SiteType,Integer,RadioGroup
15 CapUsed,Int64,Edit
16 Throttle,RawUTF8,Edit,30

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,426 @@
unit MAinFormU;
interface
{*****************************************}
{*** Please see ReadMe file ***}
{*** No copyright/license ***}
{*** No guarantees ***)
{*** Free to use/modify/distribute ***)
(*** Created by Anton Ekermans ***)
(*** antone@true.co.za ***)
(*** Original : ***)
(*** ftp://ftp.true.co.za/CSV2ORM.zip ***)
{*****************************************}
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.DBCtrls, Data.DB,
Vcl.Grids, Vcl.DBGrids, JvExDBGrids, JvDBGrid, JvDBUltimGrid,
Datasnap.DBClient, Vcl.StdCtrls, Vcl.Buttons, Vcl.Menus, Vcl.ComCtrls,
JvExExtCtrls, JvExtComponent, JvCaptionPanel, JvExControls, JvDBLookup;
type
TMainForm = class(TForm)
CDS: TClientDataSet;
CDSName: TStringField;
CDSTipe: TStringField;
CDSControl: TStringField;
DS: TDataSource;
FileOpenDialog1: TFileOpenDialog;
FileSaveDialog1: TFileSaveDialog;
PopupMenu1: TPopupMenu;
ImportthisasNameType1: TMenuItem;
CDSOrde: TIntegerField;
CDSSize: TIntegerField;
CDSField: TStringField;
CDSControlName: TStringField;
CDSFieldAs: TStringField;
PageMain: TPageControl;
TSProject: TTabSheet;
TSTemplates: TTabSheet;
Panel2: TPanel;
JvDBUltimGrid1: TJvDBUltimGrid;
DBMemo1: TDBMemo;
Memo1: TMemo;
Splitter1: TSplitter;
Panel1: TPanel;
BitBtn1: TBitBtn;
DBNavigator1: TDBNavigator;
Templates: TClientDataSet;
DSTemplates: TDataSource;
TemplatesName: TStringField;
TemplatesFiles: TDataSetField;
Files: TClientDataSet;
FilesFileName: TStringField;
FilesSource: TBlobField;
DSFiles: TDataSource;
Panel3: TPanel;
BtnTemplSave: TBitBtn;
PanelLeft: TPanel;
PanelFiles: TJvCaptionPanel;
PanelTemplates: TJvCaptionPanel;
Splitter2: TSplitter;
JvDBUltimGrid2: TJvDBUltimGrid;
JvDBUltimGrid3: TJvDBUltimGrid;
MemoSource: TDBMemo;
BtnGenerate: TBitBtn;
ComboTempl: TJvDBLookupCombo;
CDSDBControl: TStringField;
procedure BitBtn1Click(Sender: TObject);
procedure ImportthisasNameType1Click(Sender: TObject);
procedure BtnTemplSaveClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure BtnGenerateClick(Sender: TObject);
private
{ Private declarations }
procedure AnalyseData;
public
{ Public declarations }
ObjName:String;
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
uses idGlobal;
procedure TMainForm.BitBtn1Click(Sender: TObject);
begin
if FileOpenDialog1.Execute
then {CDS.LoadFromFile(FileSaveDialog1.FileName);}
ImportthisasNameType1Click(nil);
BtnGenerate.Enabled:=True;
end;
procedure TMainForm.BtnGenerateClick(Sender: TObject);
var SS,
SD,
ST : TStringList;
FileName : String;
I,K,T : Integer;
S1,S2,S3 : String;
MyTop : Integer;
MyTabOrder : Integer;
begin
if CDS.RecordCount=0
then begin
ShowMessage('Import a CSV file first with MetaData.');
exit;
end;
if ComboTempl.Text=''
then begin
ShowMEssage('Select a template first.');
exit;
end;
SS:=TStringList.Create;
SD:=TStringList.Create;
ST:=TStringList.Create;
Files.First;
while not Files.EOF do
begin
FileName:=FilesFileName.AsString;
FileName:=StringReplace(FileName,'MyObj',ObjName,[rfReplaceAll]);
SS.Clear;
SD.Clear;
SS.Text:=MemoSource.Lines.Text;
I:=0;
while I<SS.Count do
begin
S1:=SS[I];
if Pos('[Fields]',S1)>0
then begin
ST.Clear;
ST.Add(S1);
K:=I;
Inc(I);
while Pos('[/Fields]',S1)<=0 do
begin
try
S1:=SS[I];
except
ShowMessage('Unresolved [Fields] loop on line '+IntToStr(K)+' in '+FilesFileName.AsString);
break;
end;
ST.Add(S1);
Inc(I);
end;
CDS.First;
while not CDS.EOF do
begin
for t := 0 to Pred(ST.Count) do
begin
S1:=ST[T];
if (Pos('[Size]',S1)>0)and (CDSSize.AsInteger=0)
then continue;
if (Pos('[!Size]',S1)>0)and (CDSSize.AsInteger>0)
then continue;
S2:=StringReplace(S1,'[Fields]','',[rfReplaceAll]);
S2:=StringReplace(S2,'[/Fields]','',[rfReplaceAll]);
S2:=StringReplace(S2,'[Size]','',[rfReplaceAll]);
S2:=StringReplace(S2,'[!Size]','',[rfReplaceAll]);
S2:=StringReplace(S2,'MyObj',ObjName,[rfReplaceAll]);
S2:=StringReplace(S2,'MyType',CDSTipe.AsString,[rfReplaceAll]);
S2:=StringReplace(S2,'MyName',CDSName.AsString,[rfReplaceAll]);
S2:=StringReplace(S2,'MyFieldAs',CDSFieldAs.AsString,[rfReplaceAll]);
S2:=StringReplace(S2,'MyField',CDSField.AsString,[rfReplaceAll]);
S2:=StringReplace(S2,'MySize',CDSSize.AsString,[rfReplaceAll]);
SD.Add(S2);
end;
CDS.Next;
end;
Continue;
end;
if Pos('[Controls]',S1)>0
then begin
ST.Clear;
ST.Add(S1);
K:=I;
Inc(I);
while Pos('[/Controls]',S1)<=0 do
begin
try
S1:=SS[I];
except
ShowMessage('Unresolved [Controls] loop on line '+IntToStr(K)+' in '+FilesFileName.AsString);
break;
end;
ST.Add(S1);
Inc(I);
end;
MyTop:=21;
MyTabOrder:=0;
CDS.First;
while not CDS.EOF do
begin
if CDSControl.AsString=''
then begin
CDS.Next;
continue;
end;
for t := 0 to Pred(ST.Count) do
begin
S1:=ST[T];
if (Pos('[Size]',S1)>0)and (CDSSize.AsInteger=0)
then continue;
if (Pos('[!Size]',S1)>0)and (CDSSize.AsInteger>0)
then continue;
S2:=StringReplace(S1,'[Controls]','',[rfReplaceAll]);
S2:=StringReplace(S2,'[/Controls]','',[rfReplaceAll]);
S2:=StringReplace(S2,'[Size]','',[rfReplaceAll]);
S2:=StringReplace(S2,'[!Size]','',[rfReplaceAll]);
S2:=StringReplace(S2,'MyObj',ObjName,[rfReplaceAll]);
S2:=StringReplace(S2,'MyType',CDSTipe.AsString,[rfReplaceAll]);
S2:=StringReplace(S2,'MyName',CDSName.AsString,[rfReplaceAll]);
S2:=StringReplace(S2,'MyFieldAs',CDSFieldAs.AsString,[rfReplaceAll]);
S2:=StringReplace(S2,'MyField',CDSField.AsString,[rfReplaceAll]);
S2:=StringReplace(S2,'MyControlName',CDSControlName.AsString,[rfReplaceAll]);
S2:=StringReplace(S2,'MyControl',CDSControl.AsString,[rfReplaceAll]);
S2:=StringReplace(S2,'MyDBControl',CDSDBControl.AsString,[rfReplaceAll]);
S2:=StringReplace(S2,'MyTop',IntToStr(MyTop),[rfReplaceAll]);
S2:=StringReplace(S2,'MyTabOrder',IntToStr(MyTabORder),[rfReplaceAll]);
S2:=StringReplace(S2,'MySize',CDSSize.AsString,[rfReplaceAll]);
SD.Add(S2);
end;
Inc(MyTop,21);
Inc(MyTabOrder);
CDS.Next;
end;
Continue;
end;
S1:=StringReplace(S1,'MyObj',ObjName,[rfReplaceAll]);
S1:=StringReplace(S1,'MyType',CDSTipe.AsString,[rfReplaceAll]);
SD.Add(S1);
Inc(I);
end;
SD.SaveToFile(FileName);
Files.Next;
end;
end;
procedure TMainForm.AnalyseData;
var S1 : String;
begin
CDS.First;
while not CDS.EOF do
begin
(*CDS fields*)
CDS.Edit;
S1:='';
CDSField.Clear;
if CompareText(CDSTipe.AsString,'Integer')=0
then begin
CDSField.AsString:='TIntegerField';
CDSFieldAs.AsString:='AsInteger';
end;
if CompareText(CDSTipe.AsString,'Int64')=0
then begin
CDSField.AsString:='TLargeIntField';
CDSFieldAs.AsString:='AsLargeInt';
end;
if CompareText(CDSTipe.AsString,'RawUTF8')=0
then begin
CDSField.AsString:='TStringField';
CDSFieldAs.AsString:='AsString';
end;
if CompareText(CDSTipe.AsString,'Boolean')=0
then begin
CDSField.AsString:='TBooleanField';
CDSFieldAs.AsString:='AsBoolean';
end;
if CompareText(CDSTipe.AsString,'TDateTime')=0
then begin
CDSField.AsString:='TDateTimeField';
CDSFieldAs.AsString:='AsDateTime';
end;
if CompareText(CDSTipe.AsString,'Double')=0
then begin
CDSField.AsString:='TFloatField';
CDSFieldAs.AsString:='AsFloat';
end;
if CompareText(CDSTipe.AsString,'Currency')=0
then begin
CDSField.AsString:='TCurrencyField';
CDSFieldAs.AsString:='AsCurrency';
end;
if CDSField.AsString=''
then raise Exception.Create('Error Message 141 - Unknown type : '+CDSTipe.AsString);
(*PAS UI controls*)
CDSControlName.Clear;
if (CDSControl.AsString='')or
(CDSControl.AsString='-none-')
then begin
CDSControl.Clear;
CDS.Post;
CDS.Next;
continue;
end;
S1:='';
if CompareText(CDSControl.AsString,'Edit')=0
then begin
CDSControl .AsString:='TEdit';
CDSDBControl.AsString:='TDBEdit';
CDSControlName.AsString:='Edit'+CDSName.AsString;
end;
if CompareText(CDSControl.AsString,'Combo')=0
then begin
CDSControl.AsString:='TComboBox';
CDSDBControl.AsString:='TDBComboBox';
CDSControlName.AsString:='Combo'+CDSName.AsString;
end;
if CompareText(CDSControl.AsString,'ComboBox')=0
then begin
CDSControl.AsString:='TComboBox';
CDSDBControl.AsString:='TDBComboBox';
CDSControlName.AsString:='Combo'+CDSName.AsString;
end;
if CompareText(CDSControl.AsString,'Radio')=0
then begin
CDSControl.AsString:='TRadioGroup';
CDSDBControl.AsString:='TDBRadioGroup';
CDSControlName.AsString:='Radio'+CDSName.AsString;
end;
if CompareText(CDSControl.AsString,'RadioGroup')=0
then begin
CDSControl.AsString:='TRadioGroup';
CDSDBControl.AsString:='TDBRadioGroup';
CDSControlName.AsString:='Radio'+CDSName.AsString;
end;
if CompareText(CDSControl.AsString,'RadioButton')=0
then begin
CDSControl.AsString:='TDBRadioGroup';
CDSDBControl.AsString:='TRadioGroup';
CDSControlName.AsString:='Radio'+CDSName.AsString;
end;
if CompareText(CDSControl.AsString,'Check')=0
then begin
CDSControl.AsString:='TCheckBox';
CDSDBControl.AsString:='TDBCheckBox';
CDSControlName.AsString:='Check'+CDSName.AsString;
end;
if CompareText(CDSControl.AsString,'CheckBox')=0
then begin
CDSControl.AsString:='TCheckBox';
CDSDBControl.AsString:='TDBCheckBox';
CDSControlName.AsString:='Check'+CDSName.AsString;
end;
if CompareText(CDSControl.AsString,'DateEdit')=0
then begin
CDSControl.AsString:='TJvDateEdit';
CDSDBControl.AsString:='TJvDBDateEdit';
CDSControlName.AsString:='Edit'+CDSName.AsString;
end;
if CDSControlName.AsString=''
then raise Exception.Create('Error Message 170 - Unknown control : '+CDSControl.AsString);
CDS.Post;
CDS.Next;
end;
end;
procedure TMainForm.BtnTemplSaveClick(Sender: TObject);
begin
Templates.SaveToFile;
end;
procedure TMainForm.FormCreate(Sender: TObject);
var I : Integer;
begin
try
Templates.LoadFromFile;
except
I:=0;
end;
end;
procedure TMainForm.ImportthisasNameType1Click(Sender: TObject);
var SL,SL2 : TStringList;
S1,
S2,
S3,
S4 : String;
I : Integer;
begin
CDS.EmptyDataSet;
ObjName:=ExtractFileName(FileOpenDialog1.FileName);
ObjName:=Fetch(ObjName,'.',True);
SL:=TStringList.Create;
SL2:=TStringList.Create;
SL.LoadFromFile(FileOpenDialog1.FileName);
I:=0;
while SL.Count>0 do
begin
SL2.CommaText:=Trim(SL[0]);
S1:=Trim(SL2[0]);
S2:=Trim(SL2[1]);
S3:=Trim(SL2[2]);
if SL2.Count>3
then S4:=Trim(SL2[3])
else S4:='0';
SL.Delete(0);
if S1=''
then break;
CDS.Insert;
CDSOrde .AsInteger:=I;
CDSName .AsString :=S1;
CDSTipe .AsString :=S2;
CDSControl.AsString :=S3;
CDSSize .AsString :=S4;
CDS.Post;
Inc(I);
end;
SL2.Free;
SL .Free;
AnalyseData;
end;
end.

View File

@@ -0,0 +1,87 @@
# Description
This tool takes a CSV file with basic metadata and expand it into a source file(s) for use in Delphi based on pre-defined templates.
Using single and multi-file templates you can make almost any unit or form. Included example includes generating a *mORMot* `TSQLRecord` descendant as well as a CDS-based form for editing a single record/object.
It is not intended as a full-fledged RAD tool but rather to generate the bulk of repetitive code so you can copy to your project and edit from there on.
# Forum Thread
See http://synopse.info/forum/viewtopic.php?id=1911
# Usage
Create CSV file
e.g. `SampleObj.csv`:
Code,RawUTF8,Edit,30
Desc,RawUTF8,Edit,512
ItemType,RawUTF8,ComboBox,30
Cost,Currency,Edit
LastCostD,TDateTime,DateEdit
VatCat,Integer,RadioGroup
Active,Boolean,CheckBox
# Format
<Property/Field name>, DataType, Control[, Size]
Save with `FileName` of class name, e.g. `SampleObj.csv` would create e.g. classes:
DataSampleObj.pas (class TSQLSampleObj)
SampleObjFormU.pas (Class TSampleObjForm)
SampleObjFormU.dfm
When creating template, keep in mind the following, there are few magic-cookies that get replaced with your text and some tags.
Some magic-cookies:
* MyObj = ClassName, e.g. SampleObj (Determined by filename)
* MyName = property name e.g. BirthDate
* MyType = property type, e.g. `RawUTF8`
* MyField = property CDS Field type `TStringField`
* MyFieldAs = CDS field get/setter str, e.g. `AsString`
* MyControl = If assigned, expanded control type, e.g. `TEdit`
* MyDBControl = If assigned, expanded DB control type, e.g. `TDBEdit`
* MyControlName = If assigned, control name, e.g. `EditBirthDate`
* MyTop = Value that start at 21 and get incremented by 21 on each control, to space controls underneath each other.
* MySize = Size of CDS string field, see 'Tags' below.
# Tags
There are 3 tags:
* `[Fields]...[/Fields]` Cause a loop, passing all properties
* `[Controls] ..[/Controls]` Cause a loop, passing all properties that have a control assigned.
* `[Size]` Only include this line (tag can be anywhere on the line) if the current field have a size>0, used for TStringField size.
* `[!Size]` Only onclude this line if current filed have `Size=0` (i.o.w. not a String field)
E.g.:
[Fields][Size]Obj.MyName :=StringToUTF8(CDSMyName .MyFieldAs);
[!Size]Obj.MyName := CDSMyName .MyFieldAs;[/Fields]
This would create a line for each field/property. String fields will get 1st line `[Size]` with `StringToRawUTF8`, other fields will be rendered with 2nd line `[!Size]`, e.g.:
Obj.Code :=StringToRAWUTF8(CDSCode.AsString);
Obj.Cost := CDSCost.AsInteger;
Templates for generated files can be edited/saved. It is saved in `TClientdataset` binary format, so make backups as upgrades might make it useless.
# Future needed changes
* Make magic-cookies customizable.
* Use syntax-highlighter for code editing.
* Better tags or scripting to make more versatile.
* Support for more data-types and control types. (In meantime, use `Integer`/`RawUTF8` or `TEdit` for unsupported types and edit code afterwards)
* Way to indent code - prettyfy.
* Save templates in separate text files that can be edited in external editor.
# Changelog
* 2014/07/28 - ver 1.1
- Added Templates and non-DB controls.
- Added Tags for Field/Control loops and [Size]/[!Size] to make conditional render of string fields. (Fields with a size limit)

View File

@@ -0,0 +1,35 @@
object DataMod: TDataMod
OldCreateOrder = False
Height = 150
Width = 215
object cdsPerson: TClientDataSet
Aggregates = <>
Params = <>
Left = 32
Top = 16
object cdsPersonID: TLargeintField
FieldName = 'ID'
end
object cdsPersonName: TStringField
FieldName = 'Name'
Size = 50
end
object cdsPersonInt: TIntegerField
FieldName = 'Int'
end
object cdsPersonPhones: TDataSetField
FieldName = 'Phones'
end
object cdsPersonGender: TIntegerField
FieldName = 'Gender'
end
object cdsPersonChildren: TDataSetField
FieldName = 'Children'
end
end
object DSPerson: TDataSource
DataSet = cdsPerson
Left = 32
Top = 72
end
end

View File

@@ -0,0 +1,56 @@
object MainForm: TMainForm
Left = 0
Top = 0
Caption = 'mORMot into Nested TClientdatasets 1.1'
ClientHeight = 287
ClientWidth = 489
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
Position = poScreenCenter
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 8
Top = 70
Width = 473
Height = 187
Alignment = taCenter
AutoSize = False
Caption =
'This will demo ORMCDS routines that convert mORMot TSQLRecord cl' +
'asses into nested TClientdatasets for easy UI handlng.'#13#10'It will ' +
'also apply delta updates, i.e. only update fields in records tha' +
't have changed in UI, giving field-level isolation when multiple' +
' users edit the same record in UI.'#13#10#13#10'Dynamic arrays of records ' +
'are created as nested CDS as well as linked TSQLRecord tables.'#13#10 +
#13#10'Simple reconcilliation is done to handle deleted, inserted rec' +
'ords, array re-ordering, etc.'#13#10#13#10'First verion with many untested' +
' scenarios... Use at own risk!'
WordWrap = True
end
object BtnSample1: TButton
Left = 88
Top = 8
Width = 305
Height = 25
Caption = 'Sample 1 - Static TClientdataset+Fields'
TabOrder = 0
OnClick = BtnSample1Click
end
object BtnSample2: TButton
Left = 88
Top = 39
Width = 305
Height = 25
Caption = 'Sample 2 - Dynamic TClientdataset+Fields'
TabOrder = 1
OnClick = BtnSample2Click
end
end

View File

@@ -0,0 +1,163 @@
unit MAinFormU;
interface
uses
Winapi.Windows, Winapi.Messages, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs,mORMot,mORMotSQLite3, SynSQLite3Static,SynCommons,
Vcl.StdCtrls, Data.DB, Datasnap.DBClient,Contnrs, Vcl.Grids, Vcl.DBGrids,
Xml.xmldom, Datasnap.Provider,
Xmlxform;
type
TMainForm = class(TForm)
BtnSample1: TButton;
BtnSample2: TButton;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure BtnSample1Click(Sender: TObject);
procedure BtnSample2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
Model : TSQLModel;
DB : TSQLRestServerDB;
procedure CreateDefaults;
end;
type TPhoneType = (ptWork, ptHome,ptFax,ptSMS);
TPhoneTypeSet = set of TPhoneType;
type TPhone = packed record
Number : RawUTF8;
PType : TPhoneTypeSet;
end;
TPhoneArr = Array of TPhone;
type TGender = (gnUnknown,gnMale,gnFemale);
type TSQLPerson = class(TSQLRecord)
private
fName : RawUTF8;
fInt : Integer;
fGender : TGender;
fPhones : TPhoneArr;
public
protected
published
property Name : RawUTF8 read fName write fName;
property Int : Integer read fInt write fInt;
property Phones : TPhoneArr read fPhones write fPhones;
property Gender : TGender read fGender write fGender;
end;
type TSQLChild = class(TSQLRecord)
private
fParent : TID;
fChildName : RawUTF8;
fChildGender : TGender;
published
property Parent : TID read fParent write fParent;
property ChildName : RawUTF8 read fChildName write fChildName;
property ChildGender : TGender read fChildGender write fChildGender;
end;
var MainForm: TMainForm;
implementation
{$R *.dfm}
uses SysUtils,RTTI, TypInfo, ORMCDS, SampleForm1U, SampleForm2U;
procedure TMainForm.BtnSample1Click(Sender: TObject);
begin
Application.CreateForm(TSampleForm1,SampleForm1);
SampleForm1.ShowModal;
SampleForm1.Release;
end;
procedure TMainForm.BtnSample2Click(Sender: TObject);
begin
Application.CreateForm(TSampleForm1,SampleForm1);
SampleForm1.ShowModal;
SampleForm1.Release;
end;
procedure TMainForm.CreateDefaults;
var Person : TSQLPerson;
DA : TDynArray;
Ph : TPhone;
Ch : TSQLChild;
begin
Person:=TSQLPerson.Create;
Person.Name:='Guy';
Person.Int :=1;
DA:=Person.DynArray('Phones');
Ph.Number:='1234';
Ph.PType :=[ptWork];
DA.Add(Ph);
Ph.Number:='5678';
Ph.PType :=[ptHome,ptSMS];
DA.Add(Ph);
DB.Add(Person,True);
Ch:=TSQLChild.Create;
Ch.Parent :=Person.ID;
Ch.ChildName:='Boy1';
Ch.ChildGender:=gnMale;
DB.Add(Ch,True);
Ch.ChildName:='Boy2';
Ch.ChildGender:=gnMale;
DB.Add(Ch,True);
Person.Free;
Ch.Free;
Person:=TSQLPerson.Create;
Person.Name:='Gal';
Person.Int :=1;
DA:=Person.DynArray('Phones');
Ph.Number:='AA1234';
Ph.PType :=[ptHome];
DA.Add(Ph);
Ph.Number:='BB5678';
Ph.PType :=[ptSMS];
DA.Add(Ph);
DB.Add(Person,True);
Ch:=TSQLChild.Create;
Ch.Parent :=Person.ID;
Ch.ChildName:='GirlA';
Ch.ChildGender:=gnFeMale;
DB.Add(Ch,True);
Ch.ChildName:='ChildB';
Ch.ChildGender:=gnUnknown;
DB.Add(Ch,True);
Person.Free;
Ch.Free;
end;
procedure TMainForm.FormCreate(Sender: TObject);
var FN : String;
IsNew : Boolean;
begin
FN:=ChangeFileExt(paramstr(0),'.db3');
IsNew:=not FileExists(FN);
{ DeleteFile(FN);}
Model := TSQLModel.Create([TSQLChild,TSQLPerson]);
DB := TSQLRestServerDB.Create(Model,FN);
TSQLRestServerDB(DB).CreateMissingTables(0);
if IsNew
then CreateDefaults;
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
DB.Free;
Model.Free;
end;
end.

View File

@@ -0,0 +1,785 @@
unit ORMCDS;
interface
uses Data.DB,DBClient,mORMot,SynCommons,RTTI,TypInfo,Classes;
(*2014/12/01 - Version 1
TODO:
Ordered/(multi?)-Indexed or Ordered Arrays with TIDs
TADTFields for SETs?
*)
(*This is Info record that will be attached to root CDS .Tag and to each nested dataset (array or sub-TSQLRecord list) to
BOTH the TDatasetField.Tag and it's detail TClientdataset.Tag.
*)
type TORMCDSinfo = class(TObject)
public
CDS : TClientdataset; (*Nested TClientdataset*)
SQLRecordClass : TSQLRecordClass;(*IF it's SubList (not array), contain type*)
RecordTypeInfo : PTypeInfo; (*IF it';s array (not sublist, contain DynArray PTypeInfo*)
DatasetField : TDatasetField; (*Master CDS.TDatasetField*)
LinkField : RawUTF8; (*If it's SubList (not array), contain link field name that will be =MasterSQLRecord.ID*)
{ArrayKeyFields : RawUTF8;
ArrayOrdered : Boolean;}
(*Implement array comparing routines to handle key-fields in arrays and ordering
for finer-grained 'not touching' array elements when applying updates.
At the moment, when SAVEing, all array items are directly compared and overwritten if different from CDS*)
function IsArrayLink:Boolean;
end;
(*Attempt to create TField descentdants and nested Fields (for arrays) in the CDS*)
procedure ORM_CreateCDSFields(CDS:TClientdataset;AName:RawUTF8;ATypeInfo:PTypeInfo);
(*Add a TSQLRecord sub-class that is linked via DetailSQLrecord.ALinkField=MasterSQLRecord.ID*)
procedure ORM_AddSubField (CDS:TClientdataset;AFieldName,ALinkField:RawUTF8;AClass:TSQLRecordClass);overload;
(*Add a Dynamic Arrray nested field*)
procedure ORM_AddSubField (CDS:TClientdataset;AFieldName:RawUTF8;ADynArrayType:PTypeInfo);overload;
procedure ORM_LoadCDSFields (DB:TSQLRest;CDS:TClientdataset;AName:RawUTF8;AValue:TValue);
function ORM_SaveCDSFields (DB:TSQLRest;CDS:TClientdataset;AName:RawUTF8;var AValue:TValue;AForceUpdate:Boolean):Integer;
(*Link existing TClientdataset by creating TORMCDSinfo record.*)
procedure ORM_LinkCDS(ASourceCDS:TClientDataset;ATypeInfo:PTypeInfo;ALinkField:RawUTF8);
(*Free TORMCDSinfo record info, alternatively free dynamically created TClientdatasets*)
procedure ORM_FreeCDSInfo(CDS:TClientdataset;AFreeCDS:Boolean);
procedure ORM_LoadData(CDS:TClientdataset;aClient: TSQLRest;FormatSQLWhere: PUTF8Char;const BoundsSQLWhere: array of const;const aCustomFieldsCSV: RawUTF8='');
procedure ClearCDS(CDS:TClientDataset);
implementation
uses SysUtils,Datasnap.Provider;
procedure ClearCDS(CDS:TClientDataset);
begin;
if CDS.Active
then begin
CDS.EmptyDataSet;
CDS.Close;
end;
CDS.DataSetField:=nil;
CDS.Fields.Clear;
CDS.FieldDefs.Clear;
CDS.IndexDefs.Clear;
CDS.Params.Clear;
CDS.Aggregates.Clear;
CDS.IndexName := '';
CDS.IndexFieldNames := '';
end;
procedure ORM_LinkCDS(ASourceCDS:TClientDataset;ATypeInfo:PTypeInfo;ALinkField:RawUTF8);
var OInfo : TORMCDSinfo;
Field : TField;
I : Integer;
Cln : TClientdataset;
begin
OInfo:=TORMCDSinfo.Create;
OInfo.CDS:=ASourceCDS;
case ATypeInfo.Kind of
tkClass : begin
{$IFDEF DEBUG}
if not GetTypeData(ATypeInfo).ClassType.InheritsFrom(TSQLRecord)
then raise Exception.Create('ErrorMessage22');
{$ENDIF DEBUG}
OInfo.SQLRecordClass:=TSQLRecordClass(GetTypeData(ATypeInfo).ClassType);
OInfo.DatasetField :=ASourceCDS.DataSetField;
if ASourceCDS.DataSetField<>nil
then OInfo.LinkField:=ALinkField;
end;
tkDynArray:begin
if (ATypeInfo^.Kind<>tkDynArray)
then raise Exception.Create('ErrorMessage65');
OInfo.RecordTypeInfo:=ATypeInfo;
end
end;
ASourceCDS.Tag:=Integer(OInfo);
if ASourceCDS.DataSetField<>nil
then begin
ASourceCDS.DataSetField.Tag:=Integer(OInfo);
end;
end;
procedure ORM_FreeCDSInfo(CDS:TClientdataset;AFreeCDS:Boolean);
var Field : TField;
OInfo : TORMCDSinfo;
begin
if (TObject(CDS.Tag) is TORMCDSinfo)
then (TObject(CDS.Tag) as TORMCDSinfo).Free;
CDS.Tag:=0;
for Field in CDS.Fields do
begin
if (Field is TDatasetField)
then begin
OInfo:=TORMCDSinfo(Field.Tag);
if Assigned(OInfo)
then ORM_FreeCDSInfo(OInfo.CDS,AFreeCDS);
Field.Tag:=0;
end;
end;
if AFreeCDS
then CDS.Free;
end;
procedure ORM_LoadData(CDS:TClientdataset;aClient: TSQLRest;
FormatSQLWhere: PUTF8Char;
const BoundsSQLWhere: array of const;
const aCustomFieldsCSV: RawUTF8='');
var qRec : TSQLRecord;
OInfo:TORMCDSinfo;
OldDisabled : Boolean;
begin
OldDisabled:=CDS.ControlsDisabled;
if not OldDisabled
then CDS.DisableControls;
CDS.LogChanges:=False;
{$IFDEF DEBUG}
if not (TObject(CDS.Tag) is TORMCDSinfo)
then raise Exception.Create('ErrorMessage118');
{$ENDIF DEBUG}
OInfo:=TORMCDSinfo(CDS.Tag);
qRec:=OInfo.SQLRecordClass.CreateAndFillPrepare(aClient,FormatSQLWhere,BoundsSQLWhere,aCustomFieldsCSV);
while qRec.FillOne do
begin
ORM_LoadCDSFields(aClient,CDS,'root',qRec);
end;
qRec.Free;
CDS.MergeChangeLog;
CDS.LogChanges:=True;
if not OldDisabled
then CDS.EnableControls;
end;
procedure ORM_CreateCDSFields(CDS:TClientdataset;AName:RawUTF8;ATypeInfo:PTypeInfo);
var Ctx : TRttiContext;
Typ : TRttiType;
Fld : TField;
Cln : TClientDataset;
I : Integer;
S : String;
RField:TRttiField;
RProp :TRttiProperty;
OInfo :TORMCDSinfo;
begin
Ctx:=TRttiContext.Create;
Typ:=Ctx.GetType(ATypeInfo);
Fld:=CDS.FindField(AName);
case Typ.TypeKind of
tkString,
tkUString,
tkLString : begin
if Fld<>nil
then exit;
Fld:=TWideStringField.Create(CDS);
Fld.Name :=CDS.Name+AName;
Fld.FieldName:=AName;
Fld.DataSet:=CDS;
end;
tkInteger : begin
if Fld<>nil
then exit;
Fld:=TIntegerField.Create(CDS);
Fld.Name :=CDS.Name+AName;
Fld.FieldName:=AName;
Fld.DataSet:=CDS;
end;
tkEnumeration: begin
{???}{Maybe create a lookupfield?}
if Fld<>nil
then exit;
Fld:=TIntegerField.Create(CDS);
Fld.Name :=CDS.Name+AName;
Fld.FieldName:=AName;
Fld.DataSet:=CDS;
end;
tkSet : begin
case TRttiSetType(typ).ElementType.TypeKind of
tkEnumeration : begin
for I := TRttiEnumerationType(TRttiSetType(Typ).ElementType).MinValue to TRttiEnumerationType(TRttiSetType(Typ).ElementType).MaxValue do
begin
S:=GetEnumName(TRttiSetType(Typ).ElementType.Handle,I);
Fld:=CDS.FindField(AName+'_'+S);
if Fld<>nil
then exit;
Fld:=TBooleanField.Create(CDS);
Fld.Name :=CDS.Name+AName+'_'+S;
Fld.FieldName:=AName+'_'+S;
Fld.DataSet:=CDS;
end;
end
else raise Exception.Create('Error Message')
end;
end;
tkFloat : begin
if Fld<>nil
then exit;
Fld:=TFloatField.Create(CDS);
Fld.Name :=CDS.Name+AName;
Fld.FieldName:=AName;
Fld.DataSet:=CDS;
end;
tkInt64 : begin
if Fld<>nil
then exit;
Fld:=TLargeintField.Create(CDS);
Fld.Name :=CDS.Name+AName;
Fld.FieldName:=AName;
Fld.DataSet:=CDS;
end;
tkDynArray : begin
ORM_AddSubField (CDS,AName,TRttiDynamicArrayType(Typ).ElementType.Handle);
end;
tkRecord : begin
for RField in Typ.GetFields do
ORM_CreateCDSFields(CDS,RField.Name,RField.FieldType.Handle);
end;
tkClass : begin
if CDS.Tag=0
then begin(*Root CDS, create Info*)
OInfo:=TORMCDSinfo.Create;
OInfo.CDS:=CDS;
OInfo.SQLRecordClass:=TSQLRecordClass(TRttiInstanceType(Typ).MetaclassType);
CDS.Tag:=Integer(OInfo);
end;
for RProp in Typ.GetProperties do
begin
if RProp.IsWritable
then ORM_CreateCDSFields(CDS,RProp.Name,RProp.PropertyType.Handle);
end;
end
else raise Exception.Create('Error Message');
end;
Ctx.Free;
end;
procedure ORM_AddSubField (CDS:TClientdataset;AFieldName,ALinkField:RawUTF8;AClass:TSQLRecordClass);
var OInfo : TORMCDSinfo;
begin
OInfo:=TORMCDSinfo.Create;
OInfo.DatasetField:=TDatasetField.Create(CDS);
OInfo.DatasetField.Name :=CDS.Name+AFieldName;
OInfo.DatasetField.FieldName:=AFieldName;
OInfo.DatasetField.DataSet :=CDS;
OInfo.CDS :=TClientDataset.Create(CDS.Owner);
OInfo.CDS.Name:=AFieldName;
OInfo.CDS.DataSetField :=TDatasetField(OInfo.DatasetField);
OInfo.LinkField :=ALinkField;
OInfo.SQLRecordClass :=AClass;
OInfo.DatasetField.Tag:=Integer(OInfo);
OInfo.CDS .Tag:=Integer(OInfo);
ORM_CreateCDSFields(OInfo.CDS,AFieldName,AClass.ClassInfo);
end;
procedure ORM_AddSubField (CDS:TClientdataset;AFieldName:RawUTF8;ADynArrayType:PTypeInfo);
var OInfo:TORMCDSinfo;
begin
OInfo:=TORMCDSinfo.Create;
OInfo.DatasetField:=TDatasetField.Create(CDS);
OInfo.DatasetField.Name :=CDS.Name+AFieldName;
OInfo.DatasetField.FieldName:=AFieldName;
OInfo.DatasetField.DataSet :=CDS;
OInfo.CDS :=TClientDataset.Create(CDS.Owner);
OInfo.CDS.Name:=AFieldName;
OInfo.CDS.DataSetField :=TDatasetField(OInfo.DatasetField);
OInfo.RecordTypeInfo :=ADynArrayType;
ORM_CreateCDSFields(OInfo.CDS,AFieldName,ADynArrayType);
OInfo.DatasetField.Tag:=Integer(OInfo);
OInfo.CDS .Tag:=Integer(OInfo);
end;
procedure ORM_LoadCDSFields(DB:TSQLRest;CDS:TClientdataset;AName:RawUTF8;AValue:TValue);
var Ctx : TRttiContext;
Typ : TRttiType;
Fld : TField;
I : Integer;
S : String;
RField:TRttiField;
RProp :TRttiProperty;
BValue: TValue;
Obj : TObject;
DA : TDynArray;
Rec : TSQLRecord;
I64 : TID;
RSTR : PUTF8Char;
OInfo : TORMCDSinfo;
begin
Fld:=CDS.FindField(AName);
{ if Fld=nil
then exit;}
Ctx:=TRttiContext.Create;
Typ:=Ctx.GetType(AValue.TypeInfo);
case Typ.TypeKind of
tkString,
tkUString,
tkLString : begin
Fld.AsString:=AValue.AsString;
end;
tkInteger : begin
Fld.AsInteger:=AValue.AsInteger;
end;
tkEnumeration: begin
Fld.AsVariant:=Integer(AValue.GetReferenceToRawData^);
end;
tkSet : begin
case TRttiSetType(typ).ElementType.TypeKind of
tkEnumeration : begin
I:=Integer(AValue.GetReferenceToRawData^);
for I := TRttiEnumerationType(TRttiSetType(Typ).ElementType).MinValue to TRttiEnumerationType(TRttiSetType(Typ).ElementType).MaxValue do
begin
S:=GetEnumName(TRttiSetType(Typ).ElementType.Handle,I);
Fld:=CDS.FindField(AName+'_'+S);
if Fld<>nil
then begin
if ((1 shl I) and Integer(AValue.GetReferenceToRawData^))=(1 shl I)
then Fld.AsBoolean:=True
else Fld.AsBoolean:=False;
end;
end;
end
else raise Exception.Create('Error Message')
end;
end;
tkFloat : begin
Fld.AsFloat:=AValue.AsExtended;
end;
tkInt64 : begin
Fld.AsLargeInt:=AValue.AsInt64;
end;
tkDynArray : begin
if Fld<>nil
then begin
{$IFDEF DEBUG}
if not (TObject(Fld.Tag) is TORMCDSinfo)
then raise Exception.Create('ErrorMessage256');
{$ENDIF DEBUG}
OInfo:=TORMCDSinfo(Fld.Tag);
end;
{BValue.Make(nil,TRttiDynamicArrayType(Typ).ElementType.Handle,BValue);}
for I := 0 to Pred(AValue.GetArrayLength) do
begin
BValue:=AValue.GetArrayElement(I);
OInfo.CDS.Insert;
ORM_LoadCDSFields(DB,OInfo.CDS,'Value',BValue);
{ Cln.Post;}
end;
end;
tkRecord : begin
CDS.Insert;
for RField in Typ.GetFields do
begin
BValue:=RField.GetValue(AValue.GetReferenceToRawData);
ORM_LoadCDSFields(DB,CDS,RField.Name,BValue);
end;
{ CDS.Post;}
end;
tkClass : begin
Obj:=AValue.AsObject;
CDS.Insert;
for I := 0 to Pred(CDS.Fields.Count) do
begin
if (CDS.Fields[I] is TDataSetField)
then begin
{$IFDEF DEBUG}
if not(TObject(CDS.Fields[I].Tag) is TORMCDSinfo)
then raise Exception.Create('ErrorMessage286');
{$ENDIF DEBUG}
OInfo:=TORMCDSinfo(CDS.Fields[I].Tag);
if OInfo.IsArrayLink
then begin(*Array link*)
end
else begin(*Dataset link*)
RStr:=PUTF8Char(OInfo.LinkField+' = ?');
I64 :=TSQLRecord(Obj).ID;
Rec:=OInfo.SQLRecordClass.CreateAndFillPrepare(DB,RStr,[I64]);
while Rec.FillOne do
begin
ORM_LoadCDSFields(DB,OInfo.CDS,CDS.Fields[I].FieldName,Rec);
end;
Rec.Free;
continue;
end;
end;
RProp:=Typ.GetProperty(CDS.Fields[I].FieldName);
if RProp<>nil
then begin
(*BValue.Make(nil,RProp.PropertyType.Handle,BValue);*)
BValue:=RProp.GetValue(AValue.AsObject);
ORM_LoadCDSFields(DB,CDS,RProp.Name,BValue);
end;
end;
end
else raise Exception.Create('Error Message');
end;
Ctx.Free;
end;
function ORM_SaveCDSFields(DB:TSQLRest;CDS:TClientdataset;AName:RawUTF8;var AValue:TValue;AForceUpdate:Boolean):Integer;
(*AForceUpdate introduced to force update on usInserted record as TClientdataset does not always reflect OldValue=null on newly inserted record but rather OldValue=NewValue*)
var Ctx : TRttiContext;
Typ : TRttiType;
Fld : TField;
I,I2: Integer;
S : String;
RField:TRttiField;
RProp :TRttiProperty;
BValue: TValue;
Obj : TObject;
DA : TDynArray;
Rec : TSQLRecord;
I64 : TID;
RSTR : PUTF8Char;
PDS : TPacketDataSet;
Changed:Integer;
OInfo,
BInfo : TORMCDSinfo;
ArrLen : NativeInt;
P,PP : Pointer;
US : TUpdateStatus;
begin
Result:=0;
Fld:=CDS.FindField(AName);
{ if Fld=nil
then exit;}
Ctx:=TRttiContext.Create;
Typ:=Ctx.GetType(AValue.TypeInfo);
case Typ.TypeKind of
tkString,
tkLString : begin
if not AForceUpdate and (Fld.OldValue=Fld.NewValue)
then exit;
Inc(Result);
AValue:=Fld.AsString;
end;
tkInteger : begin
if not AForceUpdate and (Fld.OldValue=Fld.NewValue)
then exit;
Inc(Result);
AValue:=Fld.AsInteger;
end;
tkEnumeration: begin
if not AForceUpdate and (Fld.OldValue=Fld.NewValue)
then exit;
Inc(Result);
case Fld.DataType of
ftInteger: Integer(AValue.GetReferenceToRawData^):=Fld.AsInteger;
ftBoolean: Boolean(AValue.GetReferenceToRawData^):=Fld.AsBoolean
else raise Exception.Create('ErrorMessage429');
end;
end;
tkSet : begin
Inc(Result);
I:=Integer(AValue.GetReferenceToRawData^);
case TRttiSetType(typ).ElementType.TypeKind of
tkEnumeration : begin
I2:=0;
for I := TRttiEnumerationType(TRttiSetType(Typ).ElementType).MinValue to TRttiEnumerationType(TRttiSetType(Typ).ElementType).MaxValue do
begin
S:=GetEnumName(TRttiSetType(Typ).ElementType.Handle,I);
Fld:=CDS.FindField(AName+'_'+S);
if Fld<>nil
then begin
if Fld.AsBoolean
then I2:=I2 or (1 shl I);
end;
end;
if AForceUpdate or (I2<>Integer(AValue.GetReferenceToRawData^))
then begin
Inc(Result);
Integer(AValue.GetReferenceToRawData^):=I2;
end;
end
else raise Exception.Create('Error Message')
end;
end;
tkFloat : begin
if not AForceUpdate and (Fld.OldValue=Fld.NewValue)
then exit;
Inc(Result);
AValue:=Fld.AsFloat;
end;
tkInt64 : begin
if not AForceUpdate and (Fld.OldValue=Fld.NewValue)
then exit;
Inc(Result);
AValue:=Fld.AsLargeInt;
end;
tkDynArray : begin
if Fld=nil
then exit;
BInfo:=TORMCDSinfo(Fld.Tag);
BValue.Make(nil,TRttiDynamicArrayType(Typ).ElementType.Handle,BValue);
I:=AValue.GetArrayLength;
P :=PPointer(AValue.GetReferenceToRawData)^;
if I<>BInfo.CDS.RecordCount
then begin
Inc(Result);
{ ArrLen:=0;
DynArraySetLength(P,Typ.Handle,1,@ArrLen);}
(***************METHOD A *************************)
DA.Init(Typ.Handle,P);
I:=DA.Count;
DA.Count:=I+1;
I:=DA.Count;
(*************************************************)
(***************METHOD B *************************)
{ ArrLen:=BInfo.CDS.RecordCount;
DynArraySetLength(P,Typ.Handle,1,@ArrLen);}
(*************************************************)
AValue.Make(@P,Typ.Handle,AValue);(*Seems here old array in AValue is not dereferenced, causing memory leaks*)
I:=AValue.GetArrayLength;
(*I:=DA.Count;*)
end;
BInfo.CDS.First;
while not BInfo.CDS.Eof do
begin
US:=BInfo.CDS.UpdateStatus;
{TValue.Make(nil,TRttiDynamicArrayType(Typ).ElementType.Handle,BValue);}
BValue:=AValue.GetArrayElement(Pred(BInfo.CDS.RecNo));
if ORM_SaveCDSFields(DB,BInfo.CDS,(*Fld.FieldName*)BInfo.CDS.RecNo.ToString,BValue,True{(US=usInserted)}{AForceUpdate})>0
then begin
AValue.SetArrayElement(Pred(BInfo.CDS.RecNo),BValue);
Inc(Result);
end;
BInfo.CDS.Next;
end;
end;
tkRecord : begin
{$IFDEF DEBUG}
if not (TObject(CDS.Tag) is TORMCDSinfo)
then raise Exception.Create('ErrorMessage428');
{$ENDIF DEBUG}
OInfo:=TORMCDSinfo(CDS.Tag);
for Fld in CDS.Fields do
begin
RField:=Typ.GetField(Fld.FieldName);
{???}{Set/ENum fields!!!}
if RField=nil
then continue;
BInfo:=TORMCDSinfo(CDS.Fields[I].Tag);
if Assigned(BInfo) and not BInfo.IsArrayLink (*Skip sublists, do them separate later*)
then continue;
BValue.MakeWithoutCopy(nil,RField.FieldType.Handle,BValue);
BValue:=RField.GetValue(AValue.GetReferenceToRawData);
if ORM_SaveCDSFields(DB,OInfo.CDS,Fld.FieldName,BValue,AForceUpdate)>0
then begin
Inc(Result);
RField.SetValue(AValue.GetReferenceToRawData,BValue);
end;
end;
(*Check special-case SET fields*)
for RField in Typ.GetFields do
begin
case RField.FieldType.TypeKind of
tkSet : begin
BValue.From(RField.GetValue(AValue.GetReferenceToRawData));
BValue:=RField.GetValue(AValue.GetReferenceToRawData);
if ORM_SaveCDSFields(DB,CDS,RField.Name,BValue,AForceUpdate)>0
then begin
RField.SetValue(AValue.GetReferenceToRawData,BValue);
Inc(Result);
end;
end;
end;
end;
end;
tkClass : begin
{$IFDEF DEBUG}
if not (TObject(CDS.Tag) is TORMCDSinfo)
then raise Exception.Create('ErrorMessage428');
{$ENDIF DEBUG}
OInfo:=TORMCDSinfo(CDS.Tag);
Rec:=TSQLRecord(AValue.AsObject);
(*Update local fields*)
for I := 0 to Pred(CDS.Fields.Count) do
begin
Fld:=CDS.Fields[I];
RProp:=Typ.GetProperty(Fld.FieldName);
if RProp=nil
then continue;
BInfo:=TORMCDSinfo(CDS.Fields[I].Tag);
if Assigned(BInfo) and not BInfo.IsArrayLink (*Skip sublists, do them separate later*)
then continue;
BValue.MakeWithoutCopy(nil,RProp.PropertyType.Handle,BValue);
BValue:=RProp.GetValue(Rec);
if ORM_SaveCDSFields(DB,CDS,Fld.FieldName,BValue,AForceUpdate)>0
then begin
Changed:=Changed+1;
RProp.SetValue(Rec,BValue);
end;
end;
if Changed>0
then begin
if Rec.ID=0
then begin
I64:=DB.Add(Rec,True);
OInfo.CDS.Edit;
OInfo.CDS.FieldByName('ID').AsLargeInt:=I64;
end
else begin
I64:=Rec.ID;
DB.Update(Rec);
end;
end;
(*Update SubLists*)
for I := 0 to Pred(CDS.Fields.Count) do
begin
if not(TObject(CDS.Fields[I].Tag) is TORMCDSinfo) or ((TObject(CDS.Fields[I].Tag) as TORMCDSinfo).IsArrayLink)
then continue;
BInfo:=TORMCDSinfo(CDS.Fields[I].Tag);
{$IFDEF DEBUG}
if BInfo.LinkField=''
then raise Exception.Create('ErrorMessage457');
{$ENDIF}
BValue.MakeWithoutCopy(nil,TypeInfo(TSQLRecordClass),BValue);
BValue:=BInfo.SQLRecordClass;
BInfo.CDS.First;
while not BInfo.CDS.EOF do
begin
if (BInfo.CDS.FieldByName(BInfo.LinkField).AsLargeInt<>I64)
then begin
BInfo.CDS.Edit;
BInfo.CDS.FieldByName(BInfo.LinkField).AsLargeInt:=I64;
end;
BInfo.CDS.Next;
end;
Changed:=Changed+ORM_SaveCDSFields(DB,BInfo.CDS,CDS.Fields[I].FieldName,BValue,AForceUpdate);
BInfo.CDS.EnableControls;
end;
Result:=Changed;
end;
tkClassRef : begin
{$IFDEF DEBUG}
if not (TObject(CDS.Tag) is TORMCDSinfo)
then raise Exception.Create('ErrorMessage427');
{$ENDIF DEBUG}
CDS.DisableControls;
if CDS.State<>dsBrowse
then try
CDS.Post;
except
CDS.EnableControls;
exit;
end;
CDS.First;(*Fix uplinks before TPacketDataset fix*)
PDS := TPacketDataSet.Create(nil);
PDS.Data:=CDS.Data;
PDS.InitAltRecBuffers(True);
PDS.Free;
OInfo:=TORMCDSinfo(CDS.Tag);
CDS.First;(*Fix uplinks before TPacketDataset fix*)
if OInfo.LinkField<>''
then begin
while not CDS.EOF do
begin
if CDS.FieldByName(OInfo.LinkField).AsLargeInt=0
then begin
CDS.Edit;
CDS.FieldByName(OInfo.LinkField).AsLargeInt:=TClientDataset(OInfo.DatasetField.DataSet).FieldByNAme('ID').AsLargeint;
Inc(Changed);
end;
CDS.Next;
end;
end;
CDS.First;
CDS.StatusFilter:=[usDeleted];
CDS.First;
while not CDS.EOF do
begin
I64:=CDS.FieldByName('ID').AsLargeInt;
(*Delete all child records*)
for I := 0 to Pred(CDS.Fields.Count) do
begin
if not(TObject(CDS.Fields[I].Tag) is TORMCDSinfo) or ((TObject(CDS.Fields[I].Tag) as TORMCDSinfo).IsArrayLink)
then continue;
(*Delete all children tables*)
RStr:=PUTF8Char(TORMCDSinfo(CDS.Fields[I].Tag).LinkField+' = ?');
DB.Delete(TORMCDSinfo(CDS.Fields[I].Tag).SQLRecordClass,RStr^,[I64]);
end;
DB.Delete(OInfo.SQLRecordClass,I64);
CDS.Next;
Inc(Changed);
end;
CDS.StatusFilter:=[];
Rec:=OInfo.SQLRecordClass.Create;
CDS.First;
while not CDS.EOF do
begin
(*Check all fields for changes. Arrays must update as well.*)
US:=CDS.UpdateStatus;
{ if (CDS.UpdateStatus=usModified)or(CDS.UpdateStatus=usInserted)
then begin}
(*Update all fields+Arrays*)
I64:=CDS.FieldByName('ID').AsLargeInt;
{$IFDEF DEBUG}
{ US:=CDS.UpdateStatus;
if (I64=0)and (US=usModified)
then raise Exception.Create('ErrorMessage506');}
{$ENDIF DEBUG}
if I64=0
then begin
Rec.ClearProperties;
Changed:=Changed+1;
end
else DB.Retrieve(I64,Rec,True);
BValue:=Rec;
Changed:=Changed+ORM_SaveCDSFields(DB,CDS,CDS.Fields[I].FieldName,BValue,(I64=0));
if I64<>0
then DB.Unlock(Rec);
{end;}
CDS.Next;
end;
CDS.EnableControls;
Rec.Free;
Result:=Changed;
end
else raise Exception.Create('Error Message');
end;
Ctx.Free;
end;
{ TORMCDSinfo }
function TORMCDSinfo.IsArrayLink: Boolean;
begin
Result:=LinkField='';
end;
end.

View File

@@ -0,0 +1,18 @@
program ORMCDS_Test;
uses
FastMM4,
Vcl.Forms,
MAinFormU in 'MAinFormU.pas' {MainForm},
ORMCDS in 'ORMCDS.pas',
SampleForm1U in 'SampleForm1U.pas' {SampleForm1},
SampleForm2U in 'SampleForm2U.pas' {SampleForm2};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.

View File

@@ -0,0 +1,32 @@
# Description
Unit to convert `TSQLRecord` and it's sub-arrays/records to Nested `TClientdataset`.
Some key features:
* Create `TClientdataset` hierarchy dynamically based on data.
* Also work with static `TClientDataset`+Static fields.
* Handle sub-`TSQLRecord` lists. (See sample)
* Convert Set of ENUM to/from multiple `Boolean` fields for grid checkboxes
* Most importantly: Apply delta-changes back to *mORMot*. i.e. only changed fields.
* (With RTTI adjustments), should work on any platform that support `TClientdataset`, e.g. Intraweb
It is very first version so not tested on insert/delete yet nor many types of data, guaranteed to be buggy & lacking at this stage, but working, with the latest versions of Delphi only (this first version uses the new Rtti.pas unit, and not *mORMot*'s RTTI).
# Forum Thread
See http://synopse.info/forum/viewtopic.php?id=1911
# Supplied Demo project
Choose Static or Dynamic demo, select 'Load' to load data, edit any field or nested data, click 'Apply'.
This Demo would need the JVCL Grid to compile - see http://wiki.delphi-jedi.org/wiki/JVCL_Help:TJvDBUltimGrid
Best is to see code to get more info.
# Disclaimer
My first try with RTTI and new at *mORMot* so I'm sure it could have been done more elegantly with mORMot's RTTI built-support.
Also not optimized for speed but should be pretty fast.

View File

@@ -0,0 +1,259 @@
object SampleForm1: TSampleForm1
Left = 0
Top = 0
Caption = 'Static CDS+Fields'
ClientHeight = 404
ClientWidth = 630
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
Position = poScreenCenter
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 334
Top = 8
Width = 288
Height = 388
Alignment = taCenter
AutoSize = False
Caption =
'Core work is done by creating a TORMCDSinfo object for every nes' +
'ted TClientdataset.'#13#10'This is then linked to the TORMCDSinfo(TDat' +
'asetField.Tag) as well as the nested-child TClientdataset.Tag.'#13#10 +
'These TORMCDSinfo objects are referenced by the routines to esta' +
'blish relations and supply type info.'#13#10#13#10'When TClientdatasets ex' +
'ist, just run ORM_LinkCDS '
WordWrap = True
end
object Button2: TButton
Left = 8
Top = 8
Width = 75
Height = 25
Caption = 'Load'
TabOrder = 0
OnClick = Button2Click
end
object JvDBUltimGrid1: TJvDBUltimGrid
Left = 8
Top = 39
Width = 320
Height = 120
DataSource = DSPerson
TabOrder = 1
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'Tahoma'
TitleFont.Style = []
OnGetCellParams = JvDBUltimGrid1GetCellParams
SelectColumnsDialogStrings.Caption = 'Select columns'
SelectColumnsDialogStrings.OK = '&OK'
SelectColumnsDialogStrings.NoSelectionWarning = 'At least one column must be visible!'
EditControls = <>
RowsHeight = 17
TitleRowHeight = 17
Columns = <
item
Expanded = False
FieldName = 'Name'
Width = 150
Visible = True
end
item
Expanded = False
FieldName = 'Int'
Visible = True
end
item
Expanded = False
FieldName = 'Gender'
Visible = True
end>
end
object JvDBUltimGrid2: TJvDBUltimGrid
Left = 8
Top = 165
Width = 320
Height = 120
DataSource = DSPhones
TabOrder = 2
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'Tahoma'
TitleFont.Style = []
OnGetCellParams = JvDBUltimGrid1GetCellParams
SelectColumnsDialogStrings.Caption = 'Select columns'
SelectColumnsDialogStrings.OK = '&OK'
SelectColumnsDialogStrings.NoSelectionWarning = 'At least one column must be visible!'
EditControls = <>
RowsHeight = 17
TitleRowHeight = 17
Columns = <
item
Expanded = False
FieldName = 'Number'
Width = 98
Visible = True
end
item
Expanded = False
FieldName = 'PType_ptWork'
Title.Caption = 'Work'
Width = 37
Visible = True
end
item
Expanded = False
FieldName = 'PType_ptHome'
Title.Caption = 'Home'
Width = 37
Visible = True
end
item
Expanded = False
FieldName = 'PType_ptFax'
Title.Caption = 'Fax'
Width = 37
Visible = True
end
item
Expanded = False
FieldName = 'PType_ptSMS'
Title.Caption = 'SMS'
Visible = True
end>
end
object JvDBUltimGrid3: TJvDBUltimGrid
Left = 8
Top = 278
Width = 320
Height = 120
DataSource = DSChildren
TabOrder = 3
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'Tahoma'
TitleFont.Style = []
OnGetCellParams = JvDBUltimGrid1GetCellParams
SelectColumnsDialogStrings.Caption = 'Select columns'
SelectColumnsDialogStrings.OK = '&OK'
SelectColumnsDialogStrings.NoSelectionWarning = 'At least one column must be visible!'
EditControls = <>
RowsHeight = 17
TitleRowHeight = 17
Columns = <
item
Expanded = False
FieldName = 'ChildName'
Width = 187
Visible = True
end
item
Expanded = False
FieldName = 'ChildGender'
Width = 74
Visible = True
end>
end
object BtnApply: TButton
Left = 253
Top = 8
Width = 75
Height = 25
Caption = 'Apply'
TabOrder = 4
OnClick = BtnApplyClick
end
object DSPerson: TDataSource
DataSet = cdsPerson
Left = 168
Top = 112
end
object DSPhones: TDataSource
DataSet = cdsPhones
Left = 232
Top = 112
end
object DSChildren: TDataSource
DataSet = cdsChildren
Left = 296
Top = 112
end
object cdsChildren: TClientDataSet
Aggregates = <>
DataSetField = cdsPersonChildren
Params = <>
Left = 296
Top = 56
object cdsChildrenID: TLargeintField
FieldName = 'ID'
end
object cdsChildrenParent: TLargeintField
FieldName = 'Parent'
end
object cdsChildrenChildName: TStringField
FieldName = 'ChildName'
Size = 50
end
object cdsChildrenChildGender: TIntegerField
FieldName = 'ChildGender'
end
end
object cdsPhones: TClientDataSet
Aggregates = <>
DataSetField = cdsPersonPhones
Params = <>
Left = 232
Top = 56
object cdsPhonesNumber: TStringField
FieldName = 'Number'
Size = 30
end
object cdsPhonesPType_ptWork: TBooleanField
FieldName = 'PType_ptWork'
end
object cdsPhonesPType_ptHome: TBooleanField
FieldName = 'PType_ptHome'
end
object cdsPhonesPType_ptFax: TBooleanField
FieldName = 'PType_ptFax'
end
object cdsPhonesPType_ptSMS: TBooleanField
FieldName = 'PType_ptSMS'
end
end
object cdsPerson: TClientDataSet
Aggregates = <>
Params = <>
Left = 168
Top = 56
object cdsPersonID: TLargeintField
FieldName = 'ID'
end
object cdsPersonName: TStringField
FieldName = 'Name'
Size = 50
end
object cdsPersonInt: TIntegerField
FieldName = 'Int'
end
object cdsPersonPhones: TDataSetField
FieldName = 'Phones'
end
object cdsPersonGender: TIntegerField
FieldName = 'Gender'
end
object cdsPersonChildren: TDataSetField
FieldName = 'Children'
end
end
end

View File

@@ -0,0 +1,107 @@
unit SampleForm1U;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Grids, Vcl.DBGrids, JvExDBGrids,
JvDBGrid, JvDBUltimGrid, Vcl.StdCtrls, Data.DB, Datasnap.DBClient;
type
TSampleForm1 = class(TForm)
DSPerson: TDataSource;
DSPhones: TDataSource;
DSChildren: TDataSource;
cdsChildren: TClientDataSet;
cdsChildrenID: TLargeintField;
cdsChildrenParent: TLargeintField;
cdsChildrenChildName: TStringField;
cdsChildrenChildGender: TIntegerField;
cdsPhones: TClientDataSet;
cdsPhonesNumber: TStringField;
cdsPhonesPType_ptWork: TBooleanField;
cdsPhonesPType_ptHome: TBooleanField;
cdsPhonesPType_ptFax: TBooleanField;
cdsPhonesPType_ptSMS: TBooleanField;
cdsPerson: TClientDataSet;
cdsPersonID: TLargeintField;
cdsPersonName: TStringField;
cdsPersonInt: TIntegerField;
cdsPersonPhones: TDataSetField;
cdsPersonGender: TIntegerField;
cdsPersonChildren: TDataSetField;
Button2: TButton;
JvDBUltimGrid1: TJvDBUltimGrid;
JvDBUltimGrid2: TJvDBUltimGrid;
JvDBUltimGrid3: TJvDBUltimGrid;
BtnApply: TButton;
Label1: TLabel;
procedure Button2Click(Sender: TObject);
procedure BtnApplyClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure JvDBUltimGrid1GetCellParams(Sender: TObject; Field: TField;
AFont: TFont; var Background: TColor; Highlight: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
SampleForm1: TSampleForm1;
implementation
{$R *.dfm}
uses MainFormU,ORMCDS,mORMot,RTTI,Provider;
procedure TSampleForm1.BtnApplyClick(Sender: TObject);
var Value : TValue;
begin
Value.From(TSQLRecord);
Value:=TSQLRecord;
ORM_SaveCDSFields(MainForm.DB,cdsPerson,'Person',Value,False);
Close;
end;
procedure TSampleForm1.Button2Click(Sender: TObject);
var Person : TSQLPerson;
begin
ORM_LinkCDS(cdsPerson ,TypeInfo(TSQLPerson),'');
ORM_LinkCDS(cdsPhones ,TypeInfo(TPhoneArr ),'');
ORM_LinkCDS(cdsChildren,TypeInfo(TSQLChild ),'Parent');
cdsPerson.CreateDataSet;
cdsPerson.LogChanges:=False;
cdsPerson.SaveToFile('FileX.xml');
Person:=TSQLPerson.Create;
MAinForm.DB.Retrieve(1,Person);
ORM_LoadCDSFields(MainForm.DB,cdsPerson,'Person',Person);
MainForm.DB.Retrieve(2,Person);
ORM_LoadCDSFields(MainForm.DB,cdsPerson,'Person',Person);
Person.Free;
cdsPerson.MergeChangeLog;
cdsPerson.LogChanges:=True;
cdsPerson.SaveToFile('FileY.xml');
end;
procedure TSampleForm1.FormDestroy(Sender: TObject);
begin
ORM_FreeCDSInfo(cdsPerson,False);
end;
procedure TSampleForm1.JvDBUltimGrid1GetCellParams(Sender: TObject;
Field: TField; AFont: TFont; var Background: TColor; Highlight: Boolean);
begin
case TClientDataset(Field.DataSet).UpdateStatus of
usUnmodified : Background:=clWhite;
usModified : BAckground:=clMoneyGreen;
usInserted : Background:=clSkyBlue;
usDeleted : Background:=clRed
else raise Exception.Create('Error Message');
end;
end;
end.

View File

@@ -0,0 +1,169 @@
object SampleForm2: TSampleForm2
Left = 0
Top = 0
Caption = 'Dynamic CDS+Fields'
ClientHeight = 404
ClientWidth = 334
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
Position = poScreenCenter
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object Button2: TButton
Left = 8
Top = 8
Width = 75
Height = 25
Caption = 'Load'
TabOrder = 0
OnClick = Button2Click
end
object BtnApply: TButton
Left = 253
Top = 8
Width = 75
Height = 25
Caption = 'Apply'
TabOrder = 1
OnClick = BtnApplyClick
end
object JvDBUltimGrid1: TJvDBUltimGrid
Left = 8
Top = 39
Width = 320
Height = 120
DataSource = DSPerson
TabOrder = 2
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'Tahoma'
TitleFont.Style = []
SelectColumnsDialogStrings.Caption = 'Select columns'
SelectColumnsDialogStrings.OK = '&OK'
SelectColumnsDialogStrings.NoSelectionWarning = 'At least one column must be visible!'
EditControls = <>
RowsHeight = 17
TitleRowHeight = 17
Columns = <
item
Expanded = False
FieldName = 'Name'
Width = 150
Visible = True
end
item
Expanded = False
FieldName = 'Int'
Visible = True
end
item
Expanded = False
FieldName = 'Gender'
Visible = True
end>
end
object JvDBUltimGrid3: TJvDBUltimGrid
Left = 8
Top = 278
Width = 320
Height = 120
DataSource = DSChildren
TabOrder = 3
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'Tahoma'
TitleFont.Style = []
SelectColumnsDialogStrings.Caption = 'Select columns'
SelectColumnsDialogStrings.OK = '&OK'
SelectColumnsDialogStrings.NoSelectionWarning = 'At least one column must be visible!'
EditControls = <>
RowsHeight = 17
TitleRowHeight = 17
Columns = <
item
Expanded = False
FieldName = 'ChildName'
Width = 187
Visible = True
end
item
Expanded = False
FieldName = 'ChildGender'
Width = 74
Visible = True
end>
end
object JvDBUltimGrid2: TJvDBUltimGrid
Left = 8
Top = 159
Width = 320
Height = 120
DataSource = DSPhones
TabOrder = 4
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'Tahoma'
TitleFont.Style = []
SelectColumnsDialogStrings.Caption = 'Select columns'
SelectColumnsDialogStrings.OK = '&OK'
SelectColumnsDialogStrings.NoSelectionWarning = 'At least one column must be visible!'
EditControls = <>
RowsHeight = 17
TitleRowHeight = 17
Columns = <
item
Expanded = False
FieldName = 'Number'
Width = 98
Visible = True
end
item
Expanded = False
FieldName = 'PType_ptWork'
Title.Caption = 'Work'
Width = 37
Visible = True
end
item
Expanded = False
FieldName = 'PType_ptHome'
Title.Caption = 'Home'
Width = 37
Visible = True
end
item
Expanded = False
FieldName = 'PType_ptFax'
Title.Caption = 'Fax'
Width = 37
Visible = True
end
item
Expanded = False
FieldName = 'PType_ptSMS'
Title.Caption = 'SMS'
Visible = True
end>
end
object DSPerson: TDataSource
Left = 168
Top = 112
end
object DSPhones: TDataSource
Left = 232
Top = 112
end
object DSChildren: TDataSource
Left = 296
Top = 112
end
end

View File

@@ -0,0 +1,86 @@
unit SampleForm2U;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Grids, Vcl.DBGrids, JvExDBGrids,
JvDBGrid, JvDBUltimGrid, Vcl.StdCtrls,DBClient, Data.DB;
type
TSampleForm2 = class(TForm)
Button2: TButton;
BtnApply: TButton;
JvDBUltimGrid1: TJvDBUltimGrid;
JvDBUltimGrid3: TJvDBUltimGrid;
DSPerson: TDataSource;
DSPhones: TDataSource;
DSChildren: TDataSource;
JvDBUltimGrid2: TJvDBUltimGrid;
procedure Button2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure BtnApplyClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
TmpCDS:TClientdataset;
end;
var
SampleForm2: TSampleForm2;
implementation
{$R *.dfm}
uses RTTI,mORMot,MAinFormU,ORMCDS;
procedure TSampleForm2.BtnApplyClick(Sender: TObject);
var Value : TValue;
begin
Value.From(TSQLRecord);
Value:=TSQLRecord;
ORM_SaveCDSFields(MAinForm.DB,TmpCDS,'Person',Value,False);
Close;
end;
procedure TSampleForm2.Button2Click(Sender: TObject);
var Person : TSQLPerson;
Ctx : TRttiContext;
begin
TmpCDS:=TClientdataset.Create(self);
Ctx:=TRttiContext.Create;
ORM_CreateCDSFields(TmpCDS ,'Person' ,Ctx.GetType(TSQLPerson).Handle);
ORM_AddSubField (TmpCDS ,'Children','Parent',TSQLChild);
TmpCDS.CreateDataSet;
TmpCDS.LogChanges:=False;
TmpCDS.SaveToFile('FileX.xml');
Person:=TSQLPerson.Create;
MainForm.DB.Retrieve(1,Person);
ORM_LoadCDSFields(MainForm.DB,TmpCDS,'Person',Person);
MainForm.DB.Retrieve(2,Person);
ORM_LoadCDSFields(MainForm.DB,TmpCDS,'Person',Person);
Person.Free;
TmpCDS.LogChanges:=True;
TmpCDS.MergeChangeLog;
TmpCDS.SaveToFile('FileY.xml');
(*Link Datasources to Tmp TClientdatasets*)
DSPerson.DataSet:=TmpCDS;
DSPhones.DataSet:=TORMCDSinfo(TmpCDS.FieldByName('Phones').Tag).CDS;
DSPhones .DataSet:=TORMCDSinfo(TmpCDS.FieldByName('Phones' ).Tag).CDS;
DSChildren.DataSet:=TORMCDSinfo(TmpCDS.FieldByName('Children').Tag).CDS;
end;
procedure TSampleForm2.FormDestroy(Sender: TObject);
begin
if Assigned(TmpCDS)
then ORM_FreeCDSInfo(TmpCDS,True);
end;
end.

View File

@@ -0,0 +1,11 @@
SSPI / Windows Authentication Test App for *mORMot*
===================================================
*by Chaa*
This is some code shared in our forum, at http://synopse.info/forum/viewtopic.php?pid=17358#p17358
Could be used to validate that the SSPI authentication works as expected on your platform.
Thanks Chaa for sharing!

View File

@@ -0,0 +1,53 @@
program WindowsAuth;
{$APPTYPE CONSOLE}
uses
{$I SynDprUses.inc}
SysUtils,
SynSSPI,
SynLZ in 'SynLZ.pas',
SynCommons in 'SynCommons.pas',
SynSSPIAuth in 'SynSSPIAuth.pas';
procedure Test;
var
ClientSecContext: TSecContext;
ServerSecContext: TSecContext;
InData, OutData: RawByteString;
UserName: RawUTF8;
begin
try
InvalidateSecContext(ClientSecContext, 0);
InvalidateSecContext(ServerSecContext, 0);
ClientSSPIAuth(ClientSecContext, InData, '', OutData);
InData := OutData;
ServerSSPIAuth(ServerSecContext, InData, OutData);
InData := OutData;
ClientSSPIAuth(ClientSecContext, InData, '', OutData);
InData := OutData;
ServerSSPIAuth(ServerSecContext, InData, OutData);
ServerSSPIAuthUser(ServerSecContext, UserName);
FreeSecContext(ClientSecContext);
FreeSecContext(ServerSecContext);
Writeln('Authentified as: "',UserName,'"');
writeln('Press [Enter] to continue');
readln;
except
on E: Exception do
ConsoleShowFatalException(E);
end;
end;
begin
Test;
end.

View File

@@ -0,0 +1,13 @@
Android Java Client for *mORMot*
================================
*by ChinaPeng*
This is some code shared in our forum, at http://synopse.info/forum/viewtopic.php?pid=13115#p13115
Could be used as reference or start point for accessing a *mORMot* server from a Java client - especially an Android client.
Any further input (e.g. writing a simple Java library and a mustache template) is welcome, to allow easy Java client code wrappers generation, just as we do for Cross-Platform Delphi, FPC and SmartMobileStudio.
Thanks ChinaPeng for sharing!

View File

@@ -0,0 +1,355 @@
package com.core;
import android.util.Log;
import android.util.Xml;
import org.apache.http.util.EncodingUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.LineNumberReader;
import java.security.MessageDigest;
import java.security.spec.EncodedKeySpec;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.zip.CRC32;
/**
* Created by PSM on 2014-10-20
* 用户验证.
*/
public class SynAuth {
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getRoot() {
return root;
}
public void setRoot(String root) {
this.root = root;
}
public long getSessionID() {
return sessionID;
}
public void setSessionID(long sessionID) {
this.sessionID = sessionID;
}
public String getSessionIDHexa8() {
return sessionIDHexa8;
}
public void setSessionIDHexa8(String sessionIDHexa8) {
this.sessionIDHexa8 = sessionIDHexa8;
}
public long getSessionPrivateKey() {
return sessionPrivateKey;
}
public void setSessionPrivateKey(int sessionPrivateKey) {
this.sessionPrivateKey = sessionPrivateKey;
}
public long getSessionTickCountOffset() {
return sessionTickCountOffset;
}
public void setSessionTickCountOffset(long sessionTickCountOffset) {
this.sessionTickCountOffset = sessionTickCountOffset;
}
public long getLastSessionTickCount() {
return lastSessionTickCount;
}
public void setLastSessionTickCount(int lastSessionTickCount) {
this.lastSessionTickCount = lastSessionTickCount;
}
public String getPasswordHashHexa() {
return passwordHashHexa;
}
public void setPasswordHashHexa(String passwordHashHexa) {
this.passwordHashHexa = passwordHashHexa;
}
public long getServerTimeStampOffset() {
return serverTimeStampOffset;
}
public void setServerTimeStampOffset(long serverTimeStampOffset) {
this.serverTimeStampOffset = serverTimeStampOffset;
}
private long sessionID = 0;
private String sessionIDHexa8 = "";
private long sessionPrivateKey = 0;
private long sessionTickCountOffset = 0;
private long lastSessionTickCount = 0;
private String passwordHashHexa = "";
private long serverTimeStampOffset = 0;
private String user = "";
private String root = "";
/*
字节转换为二进制
*/
private String byteToHex(byte[] bts) {
String des = "";
String tmp = null;
for (int i = 0; i < bts.length; i++) {
tmp = (Integer.toHexString(bts[i] & 0xFF));
if (tmp.length() == 1) {
des += "0";
}
des += tmp;
}
return des;
}
/**
* 获取客户端随机值进行 SHA-256编码
* @return
*/
private String SHA256(String aNonce) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
//将字符串转换为byte类型
byte[] bytes = aNonce.getBytes();
//编码加密
md.update(bytes);
return byteToHex(md.digest());
}catch (java.security.NoSuchAlgorithmException err) {
Log.e("警告", "SHA-256编码算法为实现");
}
return "";
}
public String gotTimestamp(String timestamp) {
long _timestamp = Long.parseLong(timestamp);
String clientTime = "";
String s = "";
Calendar cal = Calendar.getInstance();
int _temp = cal.get(cal.YEAR);
s = Integer.toBinaryString(_temp);
if(s.length() < 13 )
s += "0" + s;
clientTime = s;
_temp = cal.get(cal.MONTH);
s = Integer.toBinaryString(_temp);
while(s.length() < 4) {
s += "0" + s;
}
clientTime += s;
s = Integer.toBinaryString(cal.get(cal.DAY_OF_MONTH) - 1);
while(s.length() < 5) {
s += "0" + s;
}
clientTime += s;
s = Integer.toBinaryString(cal.get(cal.HOUR_OF_DAY));
while(s.length() < 5) { s = '0'+s; }
clientTime = clientTime +s;
s = Integer.toBinaryString(cal.get(cal.MINUTE));
while(s.length() < 6) { s = '0'+s;}
clientTime = clientTime +s;
s = s = Integer.toBinaryString(cal.get(cal.SECOND));
while(s.length() < 6) { s = '0'+s;}
clientTime = clientTime +s;
setServerTimeStampOffset(_timestamp - Long.valueOf(clientTime, 2));
return String.valueOf(serverTimeStampOffset);
}
public SynAuth(String root, String username, String password){
setRoot(root);
setUser(username);
setPasswordHashHexa(SHA256( "salt" + password));
}
public String doAuth(String serverUrl) throws Exception{
HttpUtils http = new HttpUtils(serverUrl + "/" + this.root +"/");
String timeStamp = http.doGet("TimeStamp", null);
Log.i("gotTimestamp", gotTimestamp(timeStamp));
HashMap<String, String> userInfo = new HashMap<String, String>(1);
userInfo.put("UserName", this.user);
return http.doGet("auth", userInfo);
}
/**
* 获取一个客户端时间随机值
* @return
*/
public String gotClientNonce () {
//create client nonce
String aClientNonce = "", s = "";
Calendar calendar =Calendar.getInstance();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
aClientNonce = df.format(calendar.getTime());
aClientNonce = SHA256(aClientNonce);
return aClientNonce;
}
public boolean doLogin(String serviceUrl) {
JSONObject tokenObject = null;
String token = "";
try {
tokenObject = new JSONObject(doAuth(serviceUrl));
if(tokenObject.get("result") == null)
return false;
token = tokenObject.getString("result");
}catch (Exception err) {
err.printStackTrace();
}
if(token == "")
return false;
String aNonce = gotClientNonce();
HttpUtils http = new HttpUtils(serviceUrl + "/");
HashMap params = new HashMap<String, String>();
params.put("UserName", user);
//二次编码
params.put("Password", SHA256(root + token + aNonce + user +passwordHashHexa));
params.put("ClientNonce", aNonce);
//认证 如果成功返回SessionKey ,失败403
String result = http.doGet("root/auth", params);
try {
JSONObject session = new JSONObject(result);
//如果成功 返回SessionKey
Log.i("result", session.getString("result"));
gotSession(session.getString("result"));
}catch (JSONException err) {
err.printStackTrace();
}
//TEST
result = http.doGet(sessionSign("root/Test"), null);
Log.i("Response", result);
return false;
}
private String gotSession(String sessionKey) {
int i = sessionKey.indexOf('+');
sessionID = Long.valueOf(sessionKey.substring(0, i));
sessionIDHexa8 = Long.toHexString(sessionID);
//小于8位补齐
while(sessionIDHexa8.length() < 8) {
sessionIDHexa8 = "0" + sessionIDHexa8;
}
long r = getCRC32(sessionKey, 0);
sessionPrivateKey =
getCRC32(passwordHashHexa, r);
return String.valueOf(sessionPrivateKey);
//私有密匙
}
public String sessionSign(String url) {
long Tix;
Date d = new Date();
Tix = d.getTime();
if(lastSessionTickCount == Tix)
Tix += 1;
lastSessionTickCount = Tix;
String aNonce = Long.toHexString(Tix);
while(aNonce.length() < 8)
aNonce = '0' +aNonce;
if (aNonce.length() > 8)
aNonce = aNonce.substring(aNonce.length() - 8, aNonce.length());
String ss = Long.toHexString(getCRC32(url,
getCRC32(aNonce, sessionPrivateKey)));
while(ss.length() < 8) { ss = '0'+ss; }
String s = url.indexOf("?") == -1 ? url+ "?session_signature=" : url+ "&session_signature=";
return s + sessionIDHexa8 + aNonce + ss;
}
public long Crc32Add(long crc, int c) {
int[] table = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
return table[(int)((crc^c) & 0xFF) ]^((crc>>8)&0xFFFFFF) ;
}
public long getCRC32(String str, long crc){
byte[] bytes = str.getBytes();
crc = crc^0xFFFFFFFF;
if (crc < 0) {
crc = (4294967296L + crc);
}
for (int n=0; n< str.length(); n++)
{
crc= Crc32Add(crc, str.codePointAt(n));
}
crc = crc^0xFFFFFFFF;
if (crc < 0) {
crc = (4294967296L + crc);
}
return crc;
}
}

View File

@@ -0,0 +1,18 @@
# Scope
Some part of an *AngularJS* client to a *mORMot* server.
It features login, with full authentication via a pure JavaScript / AngularJS client.
It is not a working demo, just some sources to get implementation ideas, and working code for authentication on a *mORMot* server.
To understand how it works is better to download Software (*G-Lock EasyMail*) as presented in topic http://synopse.info/forum/viewtopic.php?id=1954
# Forum Thread
See http://synopse.info/forum/viewtopic.php?pid=12547#p12547
**enjoy!**
DigDiver

View File

@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html lang="en" ng-app="em7frontend">
<head>
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<!-- Bootstrap -->
<link href="bower_components/bootstrap/dist/css/bootstrap.css" rel="stylesheet" media="screen">
<link href="css/signin.css" rel="stylesheet">
<script src="bower_components/jquery/jquery.min.js"></script>
<script src="bower_components/angular/angular.js"></script>
<!-- remove me --><script xrc="bower_components/angular/build/angular-route.js"></script>
<script src="bower_components/angular-ui-router/release/angular-ui-router.js"></script>
<script src="bower_components/angular-bootstrap/ui-bootstrap.js"></script>
<script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>
<script src="js/lib/emmi.min.js"></script>
<script src="js/lib/ckeditor/ckeditor.js"></script>
<script src="js/lib/ng-infinite-scroll.js"></script>
<script src="js/lib/multiselect/multiselect.js"></script>
<script src="js/lib/long.js"></script>
<script src="js/lib/gt-select/gt-select.js"></script>
<link href="js/lib/gt-select/gt-select.css" rel="stylesheet">
<script src="js/lib/gt-dropdown/gt-dropdown.js"></script>
<link href="js/lib/gt-dropdown/gt-dropdown.css" rel="stylesheet">
<!--
<script src="js/lib/jquery.ui/jquery.ui.core.min.js"></script>
<script src="js/lib/jquery.ui/jquery.ui.widget.min.js"></script>
-->
<script src="js/lib/grf-uploader.js"></script>
<script src="js/em-utils.js"></script>
<script src="js/syn-auth.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/controllers/emails.js"></script>
<script src="js/controllers/drafts.js"></script>
<script src="js/controllers/templates.js"></script>
<script src="js/controllers/editor.js"></script>
<script src="js/controllers/contacts.js"></script>
</head>
<body ng-controller="MainCtrl" class="{{section}}">
<div emd-loadingbar></div>
<div id="head">
<div ng-show="fullUserName" class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button" ng-click="toggleCollaped()" class="navbar-toggle">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">G-Lock EasyMail 7</a>
</div>
<div collapse="isCollapsed" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li ng-hide="workplace"><a>{{fullUserName}}</a></li>
<li ng-show="workplace" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">{{fullUserName}} @ {{workplace.WPName}} <b class="caret"></b></a>
<ul class="dropdown-menu">
<li ng-repeat="wp in workplaces"><a href="#/workplaces/{{wp.ID}}/outbox">{{wp.WPName}}</a></li>
<li class="divider"></li>
<li><a href="#/logout">Logout</a></li>
</ul>
</li>
<li ng-if="!workplace"><a href="#/logout">Logout</a></li>
<!-- <span class="show-xxs-only-inline"> -->
<li class="divider"></li>
<li class="show-xs-only"><a ng-show="emlCanBeSent" ng-click="" href="#">Start sending</a></li>
<li class="show-xs-only"><a ng-show="emlCanBeStopped" ng-click="" href="#">Stop</a></li>
<li ng-show="item" class="divider"></li>
<li ng-if="section.length && section !== 'contacts'" class="show-xs-only"><a href="#" ng-click="compose()">Compose</a></li>
<li ng-if="section.length && section !== 'contacts'" ng-class="{ 'active':showPreview }" class="show-xs-only">
<a ng-click="togglePreview()">Preview</a>
</li>
<li ng-if="section == 'contacts'" ng-class="{'active': showExclusionList}" class="show-xs-only">
<a ng-click="toggleExclusionList()">Show Exclusion List</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div ui-view="root"></div>
<div id="foot" class="footer hide-xs-only">
<div class="container">
<p>&copy; G-Lock Software</p>
</div>
</div></body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,476 @@
function MainCtrl($rootScope, $scope, synConn, emAuth, $timeout, EmDrafts, $location, EmEml) {
$scope.workplace = null;
$scope.fullUserName = null;
$scope.authenticated = false;
$scope.email = null;
$scope.template = null;
$scope.draft = null;
$scope.sub = null;
$scope.itemParams = null;
$scope.toggleCollaped = function(){
$rootScope.isCollapsed = !$rootScope.isCollapsed;
};
$scope.item = null;
$scope.setItem = function(item) {
$scope.item = item;
window.item = item;
};
$scope.emlCanBeSent = false;
$scope.emlCanBeStopped = false;
$scope.$watch('item.Status', function(itms){
if ( itms ) {
$scope.emlCanBeSent = EmEml.canBeSent(itms);
$scope.emlCanBeStopped = EmEml.canBeStopped(itms);
}
});
$scope.startSending = function() {
if ( $scope.item ) {
$scope.item.startSending();
}
}
$scope.stopSending = function(){
if ( $scope.item ) {
$scope.item.stopSending();
}
};
$scope.alerts = [];
$scope.alert = function(a) {
$scope.alerts.push(a);
var idx = $scope.alerts.length - 1;
$timeout(function() {
$scope.alerts.splice(idx, 1);
}, 3000);
};
if ( emAuth.get('userName') ) {
$scope.fullUserName = emAuth.get('userName');
}
$scope.setUserName = function(userName) {
emAuth.set('userName', userName);
$scope.fullUserName = userName;
};
$scope.setWorkplace = function(wp) {
$scope.workplace = wp;
emAuth.set('workplace', wp);
};
$scope.setEmail = function(eml) {
$scope.email = eml;
};
$scope.setTemplate = function(tpl) {
$scope.template = tpl;
}
$scope.setDraft = function(drf) {
$scope.draft = drf;
};
$scope.setWPS = function(wps) {
$scope.workplaces = wps;
};
$scope.setItemParams = function(params) {
$scope.itemParams = params;
};
$scope.setSub = function(s) {
$scope.sub = s;
}
$scope.compose = function() {
(new EmDrafts()).createDraft(function(drf){
window.location.hash = '#/workplaces/'+emAuth.get('workplace').ID+'/drafts/'+drf.ID+'/edit';
});
};
// preview for mobile devices
$scope.showPreview = false;
$scope.togglePreview = function() {
$scope.showPreview = !$scope.showPreview;
};
$scope.showExclusionList = false;
$scope.toggleExclusionList = function() {
$scope.showExclusionList = !$scope.showExclusionList;
};
}
var LS = (function(){
var l = window.localStorage;
return {
get: function(key) {
var v = l.getItem(key);
if ( v && v.indexOf('__JSON__') === 0 ) {
var vObj = null;
try {
vObj = JSON.parse(v.substr(8))
v = vObj;
} catch(e) {
console.error('cannot parse localStorage value '+v);
}
}
return v;
},
set: function(key, value) {
if ( typeof value !== 'string' ) {
value = '__JSON__'+JSON.stringify(value);
}
l.setItem(key, value);
}
}
})();
function LoginCtrl($window, $scope, $http, emAuth, synConn) {
var u = (window.location+'').match(/http(s|)\:\/\/([^\/]+)(?:\:(\d+)|)/);
var port = u[3] || null,
secure = (u[1] == 's');
if ( !port ) {
port = secure ? '443' : '50888';
} else if ( port == '443' ) {
secure = true;
}
$scope.conn = {
host: u[2]+':'+port,
email: '',
password: '',
secure: secure
};
$scope.remember = false;
$scope.savedHosts = LS.get('savedHosts') || [];
var lastUsedHostID = LS.get('lastUsedHostID');
if ( lastUsedHostID !== null ) {
$scope.conn = angular.extend({}, $scope.savedHosts[lastUsedHostID]);
if ( typeof $scope.conn.secure === 'undefined' ) {
$scope.conn.secure = !!$scope.conn.host.match(/\:443$/);
}
}
$scope.loadHost = function(idx){
var h = $scope.savedHosts[idx];
if ( h ) {
$scope.conn = angular.extend({}, h);
lastUsedHostID = idx;
} else {
console.error('cannot load host data with index '+idx);
}
};
function isHostSaved(hostData) {
var saved = false;
angular.forEach($scope.savedHosts, function(conn, i){
if (
conn.host == hostData.host &&
conn.email == hostData.email &&
conn.password == hostData.password
) {
saved = i;
return false; // breaking the loop
}
});
return saved;
}
$scope.signIn = function() {
var hostData = {
host: $scope.conn.host.trim(),
email: $scope.conn.email.trim(),
password: $scope.conn.password.trim()
};
var hostSaved = isHostSaved(hostData);
if ( $scope.remember ) {
if ( hostSaved === false ) {
$scope.savedHosts.push(hostData);
LS.set('savedHosts', $scope.savedHosts);
lastUsedHostID = $scope.savedHosts.length-1;
} else {
lastUsedHostID = hostSaved;
}
}
if ( lastUsedHostID !== null ) {
LS.set('lastUsedHostID', lastUsedHostID);
}
var arr = $scope.conn.host.split(':'),
host = arr[0],
port = arr[1] || '50888';
emAuth
.set('host', host)
.set('port', port)
.set('email', $scope.conn.email)
.set('password', $scope.conn.password)
.set('secure', $scope.conn.secure);
synConn.setOpts({
host: host,
port: port,
email: $scope.conn.email,
password: $scope.conn.password,
secure: $scope.conn.secure
});
synConn.touch('wps', function(err, sa){
if ( err ) {
$scope.error = err;
} else {
emAuth.setAuthenticated(true);
$scope.setUserName(sa.User);
$window.location.hash = '#/workplaces';
}
});
};
}
function WorkplacesCtrl($scope, $stateParams, wps) {
//var wps = $route.current.locals.wps;
$scope.setWPS(wps);
}
WorkplacesCtrl.resolve = {
wps: function($q, $http, synConn) {
var defer = $q.defer();
synConn
.http({ uri: 'wps/GetUserWorkplaces?UserName={email}' })
.success(function(data){
defer.resolve(data);
})
.error(function(data, status, headers, config){
defer.reject(data);
});
return defer.promise;
}
}
app.controller('TopToolbarCtrl', function($scope){
//console.log('TopToolbarCtrl section: '+$scope.section);
//$scope.itemPath
});
app.controller('SidebarMenuCtrl', function($scope, emCategories){
var cats = emCategories.getAll();
if ( cats.then ) {
cats.then(function(c){
$scope.templateCats = c;
});
} else {
$scope.templateCats = cats;
}
});
function openPreview(item) {
// // var zoomStyle = ['<style>',
// // 'html { ',
// // '-ms-zoom: 0.30;',
// // '-moz-transform:scale(0.30);',
// // '-moz-tansform-origin: 0 0;',
// // '-o-transform: scale(0.30);',
// // '-o-transform-origin: 0 0;',
// // '-webkit-transform: scale(0.30);',
// // '-webkit-transform-origin: 0 0;',
// // '}</style>'].join('');
// // zoomStyle = []; console.warn('zoom style disabled');
// // data.EmailSource = data.EmailSource.replace(/(<\/head>)/i, zoomStyle+'$1');
// // data.EmailSource = emUtils.expandAssetURLs(data.EmailSource, data.BaseURL);
if ( item.then ) {
item.then(
function(itm){
openPreview(itm);
},
function(err){
console.error(err);
}
);
return;
}
var body = item.getBody();
if ( body.then ) {
body.then(
function(b){
setIFrameContent(b);
},
function(err){
if ( err instanceof URIError || (err+'').match(/URI\s+malformed/i) ) {
err = 'cannot unpack EmailSource';
}
setIFrameContent('An error occured: '+err);
}
);
} else {
setIFrameContent(body);
}
}
function setIFrameContent(data) {
var iframeId = 'preview-container-iframe',
container = document.getElementById('preview-container'),
iframe = document.getElementById(iframeId);
if ( !container ) { return; }
if ( !iframe ) {
var iframe = document.createElement('iframe');
container.appendChild(iframe);
iframe.id = iframeId;
}
var doc = iframe.document;
if ( iframe.contentDocument ) {
doc = iframe.contentDocument; // For NS6
} else if(iframe.contentWindow) {
doc = iframe.contentWindow.document; // For IE5.5 and IE6
}
// Put the content in the iframe
doc.open();
doc.writeln(data);
doc.close();
}
function CtrlConsole($scope, synConn) {
$scope.params = [];
$scope.headers = [];
$scope.method = 'GET';
$scope.uri = '/wp/1/settings/Drafts?Select=*&where=deleted=0&STARTINDEX=0&RESULTS=10';
$scope.contentType = '';
$scope.response = '';
$scope.useRawBody = false;
$scope.rawBodyBtn = 'Use raw body';
$scope.rawBody = '';
$scope.$watch('useRawBody', function(use){
$scope.rawBodyBtn = $scope.useRawBody ? 'Don\'t use raw body' : 'Use raw body';
});
$scope.addParam = function() {
$scope.useRawBody = false;
$scope.params.push({
name: '',
value: ''
})
};
$scope.toggleRawBody = function(){
$scope.useRawBody = !$scope.useRawBody;
if ( $scope.useRawBody ) {
$scope.params = [];
}
};
$scope.delParam = function(idx) {
$scope.params.splice(idx, 1);
};
$scope.addHeader = function() {
$scope.headers.push({
name: '',
value: ''
})
};
$scope.delHeader = function(idx) {
$scope.headers.splice(idx, 1);
};
$scope.sendRequest = function() {
var uri = $scope.uri;
if ( uri[0] === '/' ) {
uri = uri.substr(1);
}
var params = $scope.params.length ? {} : null;
angular.forEach($scope.params, function(p){
params[p.name] = p.value;
});
var headers = {};
if ( $scope.contentType ) {
headers['Content-Type'] = $scope.contentType;
}
angular.forEach($scope.headers, function(h){
headers[h.name] = h.value;
});
var opts = {
method: $scope.method,
uri: uri,
headers: headers,
synReq: true
};
if ( params ) {
opts[ ( opts.method === 'GET' ) ? 'params' : 'data' ] = params;
}
if ( $scope.useRawBody ) {
opts.data = $scope.rawBody;
}
synConn
.http(opts)
.success(function(data){
if ( typeof data !== 'string' ) {
data = JSON.stringify(data, null, '\t');
}
$scope.response = data;
})
.error(function(err){
$scope.$apply(function(){
$scope.response = err.status+' : '+err.message;
});
});
};
}

View File

@@ -0,0 +1,309 @@
app.controller('ContactsCtrl', function($scope, $stateParams, EmContacts, EmContactsEL){
if ( $stateParams.gid ) {
$scope.contacts = new EmContacts({
groupId: parseInt($stateParams.gid, 10),
placement: $stateParams.placement
});
}
if ( $stateParams.gid ) {
$scope.contactsExcList = new EmContactsEL({
groupId: parseInt($stateParams.gid, 10)
});
}
if ( $scope.contacts ) {
$scope.contacts.nextPage();
}
if ( $scope.contactsExcList ) {
$scope.contactsExcList.nextPage();
}
});
app.factory('EmContacts', function($http, $q, emAuth, synConn, emGroups, emAccounts, EmDrf) {
var EmContacts = function(opts) {
opts = opts || {};
this.items = [];
this.busy = false;
this.after = '';
this.options = {
groupId: null
};
this.noMoreData = false;
angular.extend(this.options, opts);
};
function resolveGroups(drafts, done) {
var draftsToProcess = drafts.length;
for (var i = 0; i < drafts.length; i++) {
emGroups.resolve(drafts[i].GroupList, function(err, resolved){
if (err) {
return console.log(err);
}
try {
drafts[this.i].GroupList = JSON.parse(drafts[this.i].GroupList);
} catch (e) {
drafts[this.i].GroupList = [];
}
drafts[this.i].GroupListResolved = resolved;
//drafts[this.i].GroupList = resolved;
emAccounts.resolve(drafts[this.i].AccountList, function(err, resolvedAccounts){
if (err) { return console.log(err); }
try {
drafts[this.i].AccountList = JSON.parse(drafts[this.i].AccountList) || [];
} catch (e) {
drafts[this.i].AccountList = [];
}
drafts[this.i].AccountListResolved = resolvedAccounts;
//drafts[this.i].AccountList = resolvedAccounts;
draftsToProcess -= 1;
if ( draftsToProcess === 0 ) {
done(drafts);
}
}.bind({ i: this.i }));
}.bind({ i: i }));
}
}
function parseFields(fields) {
if ( typeof fields === 'string' ) {
try {
fields = JSON.parse(fields);
} catch(e) {
return fields;
}
}
var res = {};
angular.forEach(fields, function(fd){
res[fd.Name] = fd.Value;
});
return res;
}
function reformatResponseObj(o) {
var res = {
Fields: {}
};
var directMappingFields = [
'Email',
'First_Name',
'Last_Name',
'Recipient_Name',
'Subscribed',
'Subscribe_Date'
];
function createRX(fieldName) {
var rxStr = '^'+fieldName.replace(/W+/, '.*?').toLowerCase()+'$';
return new RegExp(rxStr, 'i');
}
angular.forEach(directMappingFields, function(dmf){
var rx = createRX(dmf);
for ( var p in o ) {
if ( rx.exec(p) ) {
res[dmf] = o[p];
delete o[p];
break;
}
}
});
res.Fields = o;
return res;
}
EmContacts.prototype.getExclusionList = function(done) {
done = done || function(){};
if ( this._exclusionList ) {
return done(null, this._exclusionList);
} else {
var start = 0;
var uri = 'wp/{wpId}/group/ExclusionList?SELECT=*&WHERE=GroupID='+this.options.groupId+'&STARTINDEX='+start+'&RESULTS=25';
//var uri = 'Select Email, Date_Added from ExclusionList WHERE GROUPID=ID LIMIT 25 OFFSET 0"';
synConn
.http({ uri: uri })
.success(function(data){
done(null, data);
})
.error(function(err){
console.error(err);
done(err);
});
}
};
EmContacts.prototype.nextPage = function() {
var that = this,
defer = $q.defer();
if ( that.busy ) return;
that.busy = true;
var start = this.items.length;
var groupWhere = (typeof this.options.groupId !== 'undefined' && this.options.groupId !== null)
? '&where=GroupID='+this.options.groupId
: '';
var uri,
isLocalGroup = this.options.placement == 'local';
if ( groupWhere ) {
this.getExclusionList();
}
if ( isLocalGroup ) {
uri = 'wp/{wpId}/group/Emails?SELECT=*'+groupWhere+'&STARTINDEX='+start+'&RESULTS=25';
} else { // remote
uri = 'wp/{wpId}/settings/ConnectToDB?ID='+this.options.groupId+'&STARTINDEX='+start+'&RESULTS=25';
}
synConn
.http({ uri: uri })
.success(function(data){
// console.warn('Got data: '+data.length);
// console.log(data);
// no more emails
if ( typeof data.fieldCount !== 'undefined' ) {
that.busy = false;
that.noMoreData = true;
} else {
for (var i = 0; i < data.length; i++) {
if ( isLocalGroup ) {
if ( data[i].Fields ) {
data[i].Fields = parseFields(data[i].Fields);
}
} else { // remote group
data[i] = reformatResponseObj(data[i]);
}
that.items.push(data[i]);
}
that.busy = false;
defer.resolve();
}
})
.error(function(err){
defer.reject(err);
console.error(err)
});
return defer.promise;
};
return EmContacts;
});
app.factory('EmContactsEL', function($http, $q, emAuth, synConn, emGroups, emAccounts, EmDrf) {
var EmContactsEL = function(opts) {
opts = opts || {};
this.items = [];
this.busy = false;
this.after = '';
this.options = {
groupId: null
};
this.noMoreData = false;
angular.extend(this.options, opts);
};
EmContactsEL.prototype.nextPage = function() {
var that = this,
defer = $q.defer();
if ( that.busy ) return;
that.busy = true;
var start = this.items.length;
var uri = 'wp/{wpId}/group/ExclusionList?SELECT=*&WHERE=GroupID='+this.options.groupId+'&STARTINDEX='+start+'&RESULTS=25';
synConn
.http({ uri: uri })
.success(function(data){
// console.warn('Got data: '+data.length);
// console.log(data);
// no more items
if ( typeof data.fieldCount !== 'undefined' ) {
that.busy = false;
that.noMoreData = true;
} else {
for (var i = 0; i < data.length; i++) {
that.items.push(data[i]);
}
that.busy = false;
defer.resolve();
}
})
.error(function(err){
console.error(err);
defer.reject(err);
});
return defer.promise;
};
return EmContactsEL;
});
app.controller('ContactsSidebarMenuCtrl', function($scope, $stateParams, groups){
var sortedGroups = {
local: [],
db: []
};
$scope.wpid = $stateParams.wpid;
angular.forEach(groups, function(g){
sortedGroups[ (g.GroupKind == 1) ? 'local':'db' ].push(g);
});
$scope.groups = sortedGroups;
});
var ContactsSidebarMenuCtrlResolve = {
groups: function($q, synConn) {
var defer = $q.defer();
synConn
.http({
uri: 'wp/{wpId}/settings/Groups?Select=ID,GroupName,GroupKind&WHERE=Hidden=0'
})
.success(function(data){
angular.forEach(data, function(g){
console.log(g.GroupKind);
switch ( g.GroupKind ) {
case 1: // internal
g.type = 'My Groups';
g.placement = 'local';
break;
case 0: // external
case 2: //wpnewsman
g.type = 'My Databases';
g.placement = 'remote';
break;
}
});
defer.resolve(data);
})
.error(function(err){
console.error(err);
defer.reject(err);
});
return defer.promise;
}
};

View File

@@ -0,0 +1,549 @@
function DraftsCtrl($scope, $http, $stateParams, EmDrafts, emAuth, synConn, emUtils) {
$scope.drafts = new EmDrafts({ showDeleted: $scope.subSection === 'trash' });
$scope.drfClick = function(drf) {
$scope.drafts.activeItem = drf.ID;
$scope.setEmail(drf);
openPreview(drf);
};
$scope.drfDelete = function(ev, drf){
ev.preventDefault();
ev.stopPropagation();
var delFromTrash = ($scope.subSection === 'trash');
if ( delFromTrash && !confirm('Are sure you want to delete this draft?') ) { return; }
drf.del(function(err){
if ( !err ) {
$scope.drafts.del(drf);
}
}, delFromTrash);
};
$scope.drfRestore = function(ev, drf){
ev.preventDefault();
ev.stopPropagation();
drf.restore(function(err){
if ( !err ) {
$scope.drafts.del(drf);
}
});
};
}
app.controller('DraftEditorCtrl', function($scope, $controller, $modal, $stateParams, emAuth, synConn, emUtils, emCategories, EmTemplates, EmDrafts, accounts, groups){
$controller('CommonEditorController', { $scope: $scope });
$scope.stateParams = $stateParams;
var gotScopeItem;
$scope.itemType = '';
$scope.accounts = accounts;
$scope.account = [];
$scope.$watch('account', function(newVal){
if ( $scope.item ) {
var nv = parseInt(newVal, 10);
$scope.item.AccountList = !isNaN(nv) ? [nv] : [];
}
});
$scope.groups = groups;
$scope.to = [];
$scope.$watch('item', function(newVal){
if ( typeof newVal !== 'undefined' && !newVal.then ) {
$scope.to = $scope.item.GroupList;
}
});
$scope.$watch('to', function(newVal){
if ( $scope.item ) {
$scope.item.GroupList = newVal
}
});
$scope.enableTracking = false;
$scope.$watch('item', function(item){
if ( typeof item !== 'undefined' && !item.then ) {
$scope.enableTracking = item.TrackMethod > 0;
}
});
if ( $stateParams.draft ) {
$scope.itemType = 'draft';
$scope.setItem( (new EmDrafts()).getDraft($stateParams.draft) );
var p = { root: 'drafts' };
gotScopeItem = function(drf) {
//p.name = drf.Subject;
p.item = drf;
$scope.setItemParams(p);
//$scope.item = drf;
$scope.setItem(drf);
$scope.account = drf.AccountList[0];
window.drf = drf;
};
}
// ----------
if ( $scope.item.then ) {
$scope.item.then(
gotScopeItem,
function(err){
console.error(err+'');
}
);
} else {
gotScopeItem($scope.item);
}
$scope.save = function() {
$scope.item.save(function(err){
console.log(arguments);
if ( !err ) {
$scope.alert({ type:'success', msg: 'Successfully saved' });
} else {
$scope.alert({ type:'danger', msg: err+'' });
}
});
};
$scope.sendNow = function(){
$scope.item.save(function(err){
if ( !err ) {
$scope.item.startSending(function(err, outboxEmlID){
if ( !err ) {
window.location.hash = '#/workplaces/'+emAuth.get('workplace').ID+'/outbox/'+outboxEmlID+'/preview';
} else {
$scope.alert({
type:'danger',
msg: err+''
});
}
});
} else {
$scope.alert({
type:'danger',
msg: 'Error while saving draft: '+err
});
}
});
};
$scope.removeAttachment = function(fileName) {
$scope.item.removeAttachment(fileName, function(err){
if ( err ) { return console.error(err); }
for (var i = $scope.item.AttachList.length - 1; i >= 0; i--) {
if ( $scope.item.AttachList[i] == fileName ) {
$scope.item.AttachList.splice(i, 1);
break;
}
}
$scope.item.save();
});
};
});
var DraftEditorResolve = {
accounts: function($q, synConn) {
var defer = $q.defer();
synConn
.http({
uri: 'wp/{wpId}/settings/Account?Select=AccountName,ID'
})
.success(function(data){
defer.resolve(data);
})
.error(function(err){
console.error(err);
defer.reject(err);
});
return defer.promise;
},
groups: function($q, synConn) {
var defer = $q.defer();
synConn
.http({
uri: 'wp/{wpId}/settings/Groups?Select=ID,GroupName,GroupKind&WHERE=Hidden=0'
})
.success(function(data){
angular.forEach(data, function(g){
g.type = (g.GroupKind == 1) ? 'My Groups' : 'My Databases';
});
defer.resolve(data);
})
.error(function(err){
console.error(err);
defer.reject(err);
});
return defer.promise;
}
};
app.factory('EmDrf', function($http, $q, synConn, emUtils, emAuth){
var EmDrf = function(data){
var defaults = {
AccountList: [],
PersonalAttachList: [],
CID: 0,
CName: "",
CharSet: "UTF-8",
ConfirmRead: 0,
Deleted: 0,
GroupList: [],
Guid: '{'+emUtils.UUID()+'}',
ID: 0,
MailTo: "",
MessageFormat: 0, // 1 - html, 0 - plain
ModTime: (new Date()).getTime(),
Priority: 3,
Subject: "Please Enter Subject Here",
TrackMethod: 0,
TrackName: "",
UseAnalytics: 0,
};
angular.extend(this, defaults);
if ( typeof data !== 'undefined' ) {
angular.extend(this, data);
}
this.ModTime = emUtils.timeLogToDate(this.ModTime);
this.GroupList = this._map(this.GroupList, function(itm){ return parseInt(itm, 10); });
this.AccountList = this._map(this.AccountList, function(itm){ return parseInt(itm, 10); });
};
var p = EmDrf.prototype;
p.getBaseURL = function() {
return '/wps/drafts/'+emAuth.get('workplace').ID+'/'+this.Guid+'/';
};
p._map = function(arr, mapper) {
for (var i = 0; i < arr.length; i++) {
arr[i] = mapper(arr[i], i);
}
return arr;
};
p.del = function(done, forever) {
var req;
if ( forever ) {
req = {
method: 'DELETE',
uri: 'wp/{wpId}/settings/drafts/'+this.ID
};
} else {
req = {
method: 'PUT',
uri: 'wp/{wpId}/settings/drafts/'+this.ID,
data: {
deleted: 1
}
};
}
synConn
.http(req)
.success(function(data){
done(null);
})
.error(function(err){
console.error(err);
done(err);
});
}
p.restore = function(done) {
synConn
.http({
method: 'PUT',
uri: 'wp/{wpId}/settings/drafts/'+this.ID,
data: {
deleted: 0
}
})
.success(function(data){
done(null);
})
.error(function(err){
console.error(err);
done(err);
});
}
p.save = function(done) {
var _this = this;
done = done || function(){};
var obj = {
'ID': this.ID,
'CharSet': 'UTF-8',
'Subject': this.Subject,
'MessageFormat': 0, // 0 - html, 1 - plain
'Guid': this.Guid,
'EmailSource': emUtils.shrinkAssetURLs(this.EmailSource, this.getBaseURL()),
'Name': this.TemplateName,
'TrackMethod': parseInt(this.TrackMethod, 10), // - numeric, values (0: not used; 1: google; 2: piwik)
'TrackName': this.TrackName, // - string, tracking campaign name
'AccountList': this._map(this.AccountList, function(itm){ return itm+''; }), // converting array of nums into arr of strings
'GroupList': this._map(this.GroupList, function(itm){ return itm+''; }), // ~
'AttachList': this.AttachList,
'PersonalAttachList': this.PersonalAttachList
};
synConn
.http({
method: 'POST',
uri: 'wp/{wpId}/settings/SetDraftMessage',
data: obj
})
.success(function(data){
_this.ID = data.ID;
done(null);
})
.error(function(err){
console.error(err);
done(err);
});
};
p.setBody = function(body) {
this.EmailSource = body;
}
p.getBody = function() {
var _this = this;
if ( typeof this._data !== 'undefined' ) {
return this.EmailSource;
}
var defer = $q.defer();
synConn
.http({ uri: 'wp/{wpId}/settings/GetDraftMessage?ID='+this.ID })
.success(function(data){
_this._data = data;
data.EmailSource = emUtils.unpackEmailSource(data.EmailSource);
//data.BaseURL = emUtils.supplant('/wps/drafts/{wpid}/{guid}/',{ guid: data.Guid, wpid: emAuth.get('workplace').ID });
_this.EmailSource = emUtils.expandAssetURLs(data.EmailSource, _this.getBaseURL());
defer.resolve(_this.EmailSource);
})
.error(function(err){
console.error(err);
defer.reject(err);
});
return defer.promise;
};
p.startSending = function(done) {
done = done || function(){};
synConn
.http({ uri: 'wp/{wpId}/settings/SendDraftMessage?ID='+this.ID })
.success(function(data){
console.warn('SendDraftMessage');
console.log(data);
done(null, data.ID);
})
.error(function(err){
console.error(err);
done(err);
});
// SendDraftMessage
// param - ID
// StopSending - ID
// SendMessage - ID
};
p.removeAttachment = function(fileName, done) {
synConn
.http({ uri: 'wp/{wpId}/settings/RemoveContent?GUID='+this.Guid+'&type=drafts&Folder=attachment&FileName='+fileName })
.success(function(data){
done(null);
})
.error(function(err){
done(err);
});
};
p.addAttachment = function(fileName) {
var idx = this.AttachList.indexOf(fileName);
if ( idx === -1 ) {
this.AttachList.push(fileName);
this.save();
}
}
return EmDrf;
});
app.factory('EmDrafts', function($http, $q, emAuth, synConn, emGroups, emAccounts, EmDrf) {
var EmDrafts = function(opts) {
opts = opts || {};
this.items = [];
this.busy = false;
this.after = '';
this.options = {
showDeleted: false
};
this.noMoreData = false;
angular.extend(this.options, opts);
};
function resolveGroups(drafts, done) {
var draftsToProcess = drafts.length;
for (var i = 0; i < drafts.length; i++) {
emGroups.resolve(drafts[i].GroupList, function(err, resolved){
if (err) {
return console.log(err);
}
try {
drafts[this.i].GroupList = JSON.parse(drafts[this.i].GroupList);
} catch (e) {
drafts[this.i].GroupList = [];
}
drafts[this.i].GroupListResolved = resolved;
//drafts[this.i].GroupList = resolved;
emAccounts.resolve(drafts[this.i].AccountList, function(err, resolvedAccounts){
if (err) { return console.log(err); }
try {
drafts[this.i].AccountList = JSON.parse(drafts[this.i].AccountList) || [];
} catch (e) {
drafts[this.i].AccountList = [];
}
drafts[this.i].AccountListResolved = resolvedAccounts;
//drafts[this.i].AccountList = resolvedAccounts;
draftsToProcess -= 1;
if ( draftsToProcess === 0 ) {
done(drafts);
}
}.bind({ i: this.i }));
}.bind({ i: i }));
}
}
EmDrafts.prototype.nextPage = function() {
var that = this,
defer = $q.defer();
if ( that.busy ) return;
that.busy = true;
//var sql = 'ID, Subject, MailTo, Total, Processed, Sent, Excluded, Failed, Status, StatusMessage, CreateTime, UseAnalytics, CID, AccountList, GroupList, Deleted, Log From Outbox Order by CreateTime DESC LIMIT 10';
var sql = '*';
var start = this.items.length;
synConn
.http({ uri: 'wp/{wpId}/settings/Drafts?Select=*&where=deleted='+(this.options.showDeleted ? '1' : '0')+'&STARTINDEX='+start+'&RESULTS=10&SORT=ModTime&DIR=DESC' })
.success(function(data){
// no more emails
if ( typeof data.fieldCount !== 'undefined' ) {
that.busy = false;
that.noMoreData = true;
} else {
resolveGroups(data, function(drafts){
for (var i = 0; i < drafts.length; i++) {
that.items.push(new EmDrf(drafts[i]));
}
that.busy = false;
defer.resolve();
});
}
})
.error(function(err){
defer.reject(err);
console.error(err)
});
return defer.promise;
};
EmDrafts.prototype.getDraft = function(id) {
var tpl;
if ( this.items ) {
angular.forEach(this.items, function(t, i){
if ( t.ID == id ) {
tpl = t;
return false;
}
});
if ( tpl ) {
return tpl;
}
}
var defer = $q.defer();
synConn
//.http({ uri: 'wp/{wpId}/settings/Drafts?Select=*&where=ID='+id+'&RESULTS=1' })
.http({ uri: 'wp/{wpId}/settings/GetDraftMessage?ID='+id })
.success(function(data){
defer.resolve( new EmDrf(data) );
})
.error(function(err){
defer.reject(err);
});
return defer.promise;
};
EmDrafts.prototype.createDraft = function(done) {
var _this = this;
synConn
.http({
method: 'GET',
uri: 'wp/{wpId}/settings/CreateNewMessage'
})
.success(function(draft){
console.log('createDraft results:');
console.log(draft);
var drf = new EmDrf(draft)
_this.items.push(drf);
done(drf);
})
.error(function(err){
console.error(err);
done(err);
});
};
EmDrafts.prototype.del = function(drf) {
for (var i = 0; i < this.items.length; i++) {
if ( this.items[i] === drf ) {
this.items.splice(i, 1);
break;
}
}
};
return EmDrafts;
});

View File

@@ -0,0 +1,109 @@
app.controller('ModalUploadAttachmentCtrl', function($scope, $modalInstance, emAuth, grfFiles, editItem, itemType, synConn){
$scope.files = grfFiles.items;
var uploadType;
switch ( itemType ) {
case 'template':
uploadType = 'templates';
break;
case 'draft':
uploadType = 'drafts';
break;
};
grfFiles.attrs.action = synConn.getBaseURL()+'wp/'+emAuth.get('workplace').ID+'/settings/UploadContent?'+[
'GUID='+editItem.Guid,
'type='+uploadType,
'folder=attachment'
].join('&');
$scope.close = function () {
var fileNames = [];
angular.forEach($scope.files, function(f){
fileNames.push(f.fileName);
})
$modalInstance.dismiss(fileNames);
};
$scope.setFiles = function(element) {
$scope.$apply(function($scope) {
// Turn the FileList object into Array
$scope.files = [];
for (var i = 0; i < element.files.length; i++) {
$scope.files.push(element.files[i])
}
$scope.progressVisible = false
});
};
$scope.uploadFile = function() {
var fd = new FormData()
for (var i in $scope.files) {
fd.append("uploadedFile", $scope.files[i])
}
fd.append('path', $scope.upload.path);
var xhr = new XMLHttpRequest()
xhr.upload.addEventListener("progress", uploadProgress, false)
xhr.addEventListener("load", uploadComplete, false)
xhr.addEventListener("error", uploadFailed, false)
xhr.addEventListener("abort", uploadCanceled, false)
xhr.open('PUT', '/wp/'+emAuth.workplace.ID+'/settings/UploadContent')
$scope.progressVisible = true
xhr.send(fd)
}
function uploadProgress(evt) {
$scope.$apply(function(){
if (evt.lengthComputable) {
$scope.progress = Math.round(evt.loaded * 100 / evt.total)
} else {
$scope.progress = 'unable to compute'
}
})
}
function uploadComplete(evt) {
/* This event is raised when the server send back a response */
$modalInstance.close(evt.target.responseText);
}
function uploadFailed(evt) {
alert("There was an error attempting to upload the file.")
}
function uploadCanceled(evt) {
$scope.$apply(function(){
$scope.progressVisible = false
})
alert("The upload has been canceled by the user or the browser dropped the connection.")
}
});
app.controller('CommonEditorController', function($scope, $modal){
$scope.addCommonAtt = function() {
var modalInstance = $modal.open({
templateUrl: 'partials/modal-upload-attachment.html',
controller: 'ModalUploadAttachmentCtrl',
resolve: {
itemType: function(){
return $scope.itemType;
},
editItem: function(){
return $scope.item;
}
}
});
modalInstance.result.then(function (rel) {
var r = angular.copy(rel);
}, function (uploadedFiles) {
angular.forEach(uploadedFiles, function(fn){
$scope.item.addAttachment(fn);
});
});
}
});

View File

@@ -0,0 +1,678 @@
/*
Setn log
/wp/1/settings/GetSentItems?MessageID=6&SQL=Select+*+from+SentItems&LIMIT=10
Plain Log
/wp/1/settings/Outbox/6/Log
*/
function EmailsCtrl($scope, $http, $stateParams, EmEmails, emAuth, synConn, emUtils, EmSentLog) {
$scope.emails = new EmEmails($scope, {
showDeleted: $scope.subSection === 'trash'
});
$scope.log = null;
$scope.activateEmail = function(eml) {
$scope.log = null;
$scope.emails.activeItem = eml.ID;
$scope.setEmail(eml);
if ( $scope.item && $scope.item.stopPolling ) {
$scope.item.stopPolling();
}
$scope.setItem(eml);
if ( eml.Status != 2 && eml.startPolling ) {
eml.startPolling();
}
openPreview(eml);
};
$scope.emlClick = function(eml) {
window.location.hash = '#/workplaces/'+$scope.wpid+'/outbox/'+eml.ID+'/preview';
};
$scope.startSending = function($scope, $http) {
$http({ method: 'GET', url: '' })
};
$scope.setPreview = function(){
$scope.log = null;
$http({ method: 'GET', url: 'http://blog.dev/wp-admin/admin.php?page=newsman-templates&action=edit&id=16&tpl-source=1' })
.success(function(data, status, headers, config) {
var zoomStyle = ['<style>',
'html { ',
'-ms-zoom: 0.65;',
'-moz-transform:scale(0.65);',
'-moz-tansform-origin: 0 0;',
'-o-transform: scale(0.65);',
'-o-transform-origin: 0 0;',
'-webkit-transform: scale(0.65);',
'-webkit-transform-origin: 0 0;',
'}</style>'].join('');
data = data.replace('</head>', zoomStyle+'</head>');
openPreview(data);
// this callback will be called asynchronously
// when the response is available
})
.error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
};
$scope.viewLog = function(emailId) {
$scope.log = null;
var htmlWrapper = [
'<html><head><style>',
'pre {',
'font-size: 12px;',
'font-family: sans-serif;',
'}',
'</style></head><body><pre>{body}</pre></body></html>'].join('');
synConn
.http({
method: 'GET',
uri: 'wp/{wpId}/settings/Outbox/'+emailId+'/Log'
})
.success(function(data){
setIFrameContent(emUtils.supplant(htmlWrapper, { body: data }));
})
.error(function(err){
console.error(err);
});
}
$scope.emDelete = function(eml) {
var delFromTrash = $scope.subSection === 'trash';
if ( delFromTrash && !confirm('Are you sure you want to delete this email?') ) { return; }
eml.del(function(err){
if ( err ) { console.log(err); return; }
$scope.emails.del(eml);
}, delFromTrash);
};
$scope.viewSentLog = function(emailId, type) {
$scope.log = new EmSentLog($scope, emailId, type);
$scope.log.nextPage();
}
}
app.controller('EmailsItemDetailsCtrl', function($scope, $stateParams){
var subView = ( typeof $stateParams.subview === 'undefined' ) ? 'preview' : $stateParams.subview;
switch ( subView ) {
case 'preview':
$scope.emails.getEmail($stateParams.id, function(err, eml){
if ( err ) { return console.error(err); }
$scope.activateEmail(eml);
});
break;
case 'log':
$scope.viewLog($stateParams.id);
break;
case 'processed':
$scope.viewSentLog($stateParams.id, 'processed');
break;
case 'sent':
$scope.viewSentLog($stateParams.id, 'sent');
break;
case 'failed':
$scope.viewSentLog($stateParams.id, 'failed');
break;
}
});
app.factory('EmEml', function($http, $q, synConn, emUtils, emAuth, $timeout, $interval){
var EmEml = function(data){
var defaults = {
AccountList: [],
AttachList: [],
Attempt: 0,
Bounced: 0,
CID: 0,
CName: "",
CharSet: "WINDOWS-1252",
Complaint: 0,
ConfirmRead: 0,
CreateTime: 135125718208,
Deleted: 0,
Excluded: 0,
Failed: 0,
FinishTime: "",
GroupList: [],
Guid: '{'+emUtils.UUID()+'}',
ID: 0,
MailTo: "",
MessageFormat: 0,
Priority: 3,
Processed: 2,
ResumeTime: "",
SendMode: 0,
Sent: 2,
StartTime: "",
Status: 2, // 0- RedyForSent; 1 - InSent; 2- Sending Finished; 3 - Pending
StatusMessage: "Finished [View Log]",
Subject: "Pure Papers",
Total: 0,
Total_Clicks: 0,
Total_Opens: 0,
TrackMethod: 0,
TrackName: "",
Unique_Clicks: 0,
Unique_Opens: 0,
Unsubscribed: 0,
UseAnalytics: 0,
User: null
};
angular.extend(this, defaults);
if ( typeof data !== 'undefined' ) {
angular.extend(this, data);
}
this.CreateTime = emUtils.timeLogToDate(this.CreateTime);
};
EmEml.status = {
READY_FOR_SENT: 0,
SENDING: 1,
FINISHED: 2,
PENDING: 3
//0: RedyForSent; 1 - InSent; 2- Sending Finished; 3 - Pending
};
EmEml.canBeSent = function(o) {
var st = (typeof o === 'number') ? o : o.Status;
var x =
st == EmEml.status.FINISHED ||
st == EmEml.status.READY_FOR_SENT;
return x;
};
EmEml.canBeStopped = function(o) {
var st = (typeof o === 'number') ? o : o.Status;
var x =
st == EmEml.status.PENDING ||
st == EmEml.status.SENDING;
return x;
};
var p = EmEml.prototype;
p.getBaseURL = function() {
return '/wps/outbox/'+emAuth.get('workplace').ID+'/'+this.Guid+'/';
};
p.save = function(done) {
var _this = this;
done = done || function(){};
/*
'/wp/1/settings/Drafts?session_signature=004888DF0000838811DF13D9',
'POST',
'Content-Type: application/json; charset=UTF-8'
{
"CharSet":"UTF-8",
"Subject":"Test",
"MailTo":"",
"ModTime":135135803300,"UseAnalytics":false,"CID":0,"CName":"",
"TrackMethod":0,"TrackName":"",
"Priority":1,
"ConfirmRead":false,"Deleted":false,"MessageFormat":0,"AttachList":"[]",
"AccountList":"[\"1\"]",
"GroupList":"[\"1\"]",
"Guid":""
}
//*/
//'id', 'MessageFormat', 'Guid', 'EmailSource', 'Name', 'Subject', 'AccountList', 'GroupList'
var obj = {
'id': this.ID,
'MessageFormat': 0, // 0 - html, 1 - plain
'Guid': item.Guid,
'EmailSource': emUtils.shrinkAssetURLs(this.EmailSource, this.getBaseURL()),
'Subject': this.Subject,
'AccountList': [],
'GroupList': []
};
synConn
.http({
method: 'POST',
uri: 'wp/{wpId}/settings/SetOutboxMessage',
data: obj
})
.success(function(data){
_this.ID = data.ID;
done(null);
})
.error(function(err){
console.error(err);
done(err);
});
};
p.setBody = function(body) {
this.EmailSource = body;
}
p.getBody = function() {
var _this = this;
if ( typeof this._data !== 'undefined' ) {
return this.EmailSource;
}
var defer = $q.defer();
synConn
.http({ uri: 'wp/{wpId}/settings/GetOutboxMessage?ID='+this.ID })
.success(function(data){
_this._data = data;
try {
data.EmailSource = emUtils.unpackEmailSource(data.EmailSource);
} catch(e) {
data.EmailSource = 'error';
defer.reject(e);
}
//data.BaseURL = emUtils.supplant('/wps/outbox/{wpid}/{guid}/',{ guid: data.Guid, wpid: emAuth.get('workplace').ID });
_this.EmailSource = emUtils.expandAssetURLs(data.EmailSource, _this.getBaseURL());
defer.resolve(_this.EmailSource);
//this.CreateTime = emUtils.timeLogToDate(this.CreateTime);
})
.error(function(err){
console.error(err);
defer.reject(err);
});
return defer.promise;
};
p.reloadData = function(done) {
done = done || function(){};
var _this = this;
synConn
.http({ uri: 'wp/{wpId}/settings/GetOutboxMessage?ID='+this.ID })
.success(function(data){
_this._data = data;
try {
data.EmailSource = emUtils.unpackEmailSource(data.EmailSource);
} catch(e) {
data.EmailSource = 'error';
}
//data.BaseURL = emUtils.supplant('/wps/outbox/{wpid}/{guid}/',{ guid: data.Guid, wpid: emAuth.get('workplace').ID });
_this.EmailSource = emUtils.expandAssetURLs(data.EmailSource, _this.getBaseURL());
// refreshing the rest of data
if ( typeof data !== 'undefined' ) {
angular.extend(_this, data);
}
done(null, data);
//this.CreateTime = emUtils.timeLogToDate(this.CreateTime);
})
.error(function(err){
console.error(err);
done(err);
});
};
p.del = function(done, forever) {
var req;
if ( forever ) {
req = {
method: 'DELETE',
uri: 'wp/{wpId}/settings/outbox/'+this.ID
};
} else {
req = {
method: 'PUT',
uri: 'wp/{wpId}/settings/outbox/'+this.ID,
data: {
deleted: 1
}
};
}
synConn
.http(req)
.success(function(data){
done(null);
})
.error(function(err){
console.error(err);
done(err);
});
}
p.startPolling = function() {
var _this = this;
this.pollForUpdates();
};
p.stopPolling = function() {
if ( this.pollTO ) {
$timeout.cancel(this.pollTO);
}
};
p.pollForUpdates = function(){
var _this = this;
_this.reloadData(function(err, data){
if ( !err && data && typeof _this._oldStatus !== 'undefined' && _this._oldStatus !== data.Status ) {
// if status changed - stop the polling
delete _this._oldStatus;
return;
}
_this.pollTO = $timeout(function(){
_this.pollForUpdates();
}, 3000);
});
};
p.startSending = function() {
var _this = this;
synConn
.http({ uri: 'wp/{wpId}/settings/SendMessage?ID='+this.ID })
.success(function(data){
_this.startPolling();
})
.error(function(err){
console.error(data);
});
};
p.stopSending = function() {
var _this = this;
this._oldStatus = this.Status;
// saving old status, then check in poll function for changes and stop
synConn
.http({ uri: 'wp/{wpId}/settings/StopSending?ID='+this.ID })
.success(function(data){
$timeout(function(){
_this.reloadData();
}, 3000);
// if ( typeof data !== 'undefined' ) {
// angular.extend(this, data);
// }
// this.CreateTime = emUtils.timeLogToDate(this.CreateTime);
})
.error(function(err){
console.error(err);
});
// SendDraftMessage
// param - ID
// StopSending - ID
// SendMessage - ID
};
return EmEml;
});
// Reddit constructor function to encapsulate HTTP and pagination logic
app.factory('EmEmails', function($http, $q, emAuth, synConn, emGroups, emAccounts, EmEml) {
var EmEmails = function($scope, opts) {
opts = opts || {};
this.$scope = $scope;
this.items = [];
this.busy = false;
this.after = '';
this.noMoreData = false;
this.options = {
showDeleted: false
};
angular.extend(this.options, opts);
this.m = new Emmi();
};
EmEmails.prototype.getEmail = function(id, done) {
var _this = this;
if ( !this.items.length ) {
this.m.once('data', function(){
_this.getEmail(id, done);
});
return;
}
var found = false;
angular.forEach(this.items, function(eml){
if ( eml.ID == id ) {
done(null, eml);
found = true;
return false; // breaking the loop
}
});
if ( !found ) {
done(new Error('Email with id '+id+' is not found.'));
}
};
EmEmails.prototype.nextPage = function() {
var that = this,
defer = $q.defer();
if ( that.noMoreData ) { return; }
if ( that.busy ) return;
that.busy = true;
var sql = '*';
function resolveGroups(emails, done) {
var emailsToProcess = emails.length;
for (var i = 0; i < emails.length; i++) {
emGroups.resolve(emails[i].GroupList, function(err, resolved){
if (err) { return console.log(err); }
emails[this.i].resGroupList = resolved;
emAccounts.resolve(emails[this.i].AccountList, function(err, resolvedAccounts){
if (err) { return console.log(err); }
emails[this.i].resAccountList = resolvedAccounts;
emailsToProcess -= 1;
if ( emailsToProcess === 0 ) {
done(emails);
}
}.bind({ i: this.i }));
}.bind({ i: i }));
}
}
var start = this.items.length;
synConn
.http({ uri: 'wp/{wpId}/settings/Outbox?Select=*&where=deleted='+(this.options.showDeleted ? '1' : '0')+'&STARTINDEX='+start+'&RESULTS=10&SORT=CreateTime&DIR=DESC' })
.success(function(data){
// no more emails
if ( typeof data.fieldCount !== 'undefined' ) {
that.busy = false;
that.noMoreData = true;
} else {
resolveGroups(data, function(emails){
for (var i = 0; i < emails.length; i++) {
that.items.push(new EmEml(emails[i]));
}
that.busy = false;
that.m.emit('data');
defer.resolve();
});
}
})
.error(function(err){
defer.reject(err);
console.error(err)
});
return defer.promise;
};
EmEmails.prototype.del = function(eml) {
for (var i = 0; i < this.items.length; i++) {
if ( this.items[i] === eml ) {
this.items.splice(i, 1);
break;
}
}
};
return EmEmails;
});
app.factory('EmSentLog', function($http, $q, emAuth, synConn, emGroups, emAccounts, EmEml) {
var EmSentLog = function($scope, msgId, type) {
this.$scope = $scope;
this.type = type;
this.msgId = msgId;
this.items = [];
this.busy = false;
this.noMoreData = false;
this.after = '';
};
EmSentLog.prototype.nextPage = function() {
var that = this,
defer = $q.defer();
if ( that.busy || that.noMoreData ) return;
that.busy = true;
function resolveGroups(emails, done) {
var emailsToProcess = emails.length;
for (var i = 0; i < emails.length; i++) {
emGroups.resolve(emails[i].GroupList, function(err, resolved){
if (err) { throw err; }
emails[this.i].GroupList = resolved;
emAccounts.resolve(emails[this.i].AccountList, function(err, resolvedAccounts){
if (err) { throw err; }
emails[this.i].AccountList = resolvedAccounts;
emailsToProcess -= 1;
if ( emailsToProcess === 0 ) {
done(emails);
}
}.bind({ i: this.i }));
}.bind({ i: i }));
}
}
var start = this.items.length;
/*
$$hashKey: "01Q"
Clicked: 0
Email: "sales@cartridgecare.com"
GroupName: "Import From SQL Server EasyMail"
ID: 1
LastResponse: "63"
Log: "PFNlbmRSYXdFbWFpbFJlc3BvbnNlIHhtbG5zPSJodHRwOi8vc2VzLmFtYXpvbmF3cy5jb20vZG9jLzIwMTAtMTItMDEvIj4KICA8U2VuZFJhd0VtYWlsUmVzdWx0PgogICAgPE1lc3NhZ2VJZD4wMDAwMDE0MTNiN2RjY2E2LWExMTdhMjllLWIwYzAtNGI0NS05ZTRlLTQ2ZmE1MTlhMThkYy0wMDAwMDA8L01lc3NhZ2VJZD4KICA8L1NlbmRSYXdFbWFpbFJlc3VsdD4KICA8UmVzcG9uc2VNZXRhZGF0YT4KICAgIDxSZXF1ZXN0SWQ+ZjU4NzBmMmItMjFmNS0xMWUzLWEwNWEtMjc4Y2Q5NmI3ZGFmPC9SZXF1ZXN0SWQ+CiAgPC9SZXNwb25zZU1ldGFkYXRhPgo8L1NlbmRSYXdFbWFpbFJlc3BvbnNlPgoNCg0KODg5"
Opened: 0
RecipientName: "cartridgecare"
SendDate: "2013-09-20T13:10:44"
Status: 1
*/
var ipp = 25,
sql = '';
switch (this.type) {
case 'processed':
sql = 'Select * from SentItems LIMIT '+start+','+ipp;
break;
case 'sent':
sql = 'Select * from SentItems where Status = 1 LIMIT '+start+','+ipp;
break;
case 'failed':
sql = 'Select * from SentItems where Status != 1 LIMIT '+start+','+ipp;
break;
}
synConn
.http({ uri: 'wp/{wpId}/settings/GetSentItems?MessageID='+this.msgId+'&SQL='+sql.replace(/\s+/g, '+') })
.success(function(data){
if ( typeof data.fieldCount !== 'undefined' ) {
that.busy = false;
that.noMoreData = true;
return;
}
for (var i = 0; i < data.length; i++) {
data[i].SendDate = new Date(data[i].SendDate);
switch ( data[i].Status ) {
case 1:
data[i].StatusText = 'Successfully delivered';
break;
case 2:
data[i].StatusText = 'Temporary error. Sending attempt will be repeted in a minute';
break;
case 3:
data[i].StatusText = 'Error';
break;
}
that.items.push(data[i]);
}
that.busy = false;
defer.resolve();
})
.error(function(err){
console.error(err);
defer.reject(err);
});
return defer.promise;
};
return EmSentLog;
});

View File

@@ -0,0 +1,454 @@
function TemplatesCtrl($scope, $http, $location, $stateParams, $state, EmTemplates, emAuth, synConn, emUtils) {
var sub = $stateParams.folder || $scope.subSection;
$scope.setSub(sub);
$scope.templates = new EmTemplates($scope, sub);
function expandAssetURLs(src, baseURL) {
function replacer(match, p1, p2, p3, p4) {
var url = p3;
if ( url.match(/^\w+:\/\//) ) {
return p1+url+p4;
}
if ( baseURL[baseURL.length-1] !== '/' && url[0] !== '/' ) { baseURL += '/'; }
url = baseURL+url;
return p1+url+p4;
}
return src
.replace(/(\b(?:src|url|background)=(\\\'|"))(.*?)(\2)/ig, replacer)
.replace(/(\burl\(([\\\'"]{0,1}))(.*?)(\2\))/ig, replacer);
}
$scope.tplClick = function(tpl) {
$scope.templates.activeItem = tpl.ID;
$scope.item = tpl;
var tpl = $scope.templates.getTemplate(tpl.ID);
openPreview(tpl);
};
$scope.tplDelete = function(e, tpl) {
e.stopPropagation();
e.preventDefault();
var delfromTrash = $scope.subSection === 'trash';
if ( delfromTrash && !confirm('Are you sure you want to delete this template?') ) { return; }
tpl.del(function(err){
if ( err ) { console.log(err); return; }
$scope.templates.del(tpl);
}, delfromTrash);
};
$scope.tplRestore = function(e, tpl) {
e.stopPropagation();
e.preventDefault();
tpl.restore(function(err){
if ( err ) { console.log(err); return; }
$scope.templates.del(tpl);
});
};
$scope.tplCreateMsg = function(e, tpl) {
e.preventDefault();
e.stopPropagation();
synConn
.http({
method: 'PUT',
uri: 'wp/{wpId}/settings/NewMessageFromTemplate?ID='+tpl.ID
})
.success(function(data){
$location.path('/workplaces/'+emAuth.get('workplace').ID+'/drafts/'+data.ID+'/edit');
})
.error(function(err){
console.error(err);
});
};
$scope.startSending = function($scope, $http) {
$http({ method: 'GET', url: '' })
};
$scope.setPreview = function(){
$http({ method: 'GET', url: 'http://blog.dev/wp-admin/admin.php?page=newsman-templates&action=edit&id=16&tpl-source=1' })
.success(function(data, status, headers, config) {
var zoomStyle = ['<style>',
'html { ',
'-ms-zoom: 0.65;',
'-moz-transform:scale(0.65);',
'-moz-tansform-origin: 0 0;',
'-o-transform: scale(0.65);',
'-o-transform-origin: 0 0;',
'-webkit-transform: scale(0.65);',
'-webkit-transform-origin: 0 0;',
'}</style>'].join('');
data = data.replace('</head>', zoomStyle+'</head>');
openPreview(data);
// this callback will be called asynchronously
// when the response is available
})
.error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
};
}
app.controller('TemplateEditorCtrl', function($scope, $controller, $modal, $stateParams, emAuth, synConn, emUtils, emCategories, EmTemplates, groups){
$controller('CommonEditorController', { $scope: $scope });
$scope.stateParams = $stateParams;
var gotScopeItem;
$scope.itemType = '';
$scope.groups = groups;
$scope.to = [];
$scope.$watch('item', function(newVal){
if ( typeof newVal !== 'undefined' && !newVal.then ) {
$scope.to = $scope.item.GroupList;
}
});
$scope.$watch('to', function(newVal){
if ( $scope.item ) {
$scope.item.GroupList = newVal
}
});
$scope.enableTracking = false;
$scope.$watch('item', function(item){
if ( typeof item !== 'undefined' && !item.then ) {
$scope.enableTracking = item.TrackMethod > 0;
}
});
if ( $stateParams.template ) {
$scope.itemType = 'template';
$scope.setItem( (new EmTemplates()).getTemplate($stateParams.template) );
var p = { root: 'templates' };
gotScopeItem = function(tpl) {
//p.name = drf.Subject;
p.item = tpl;
$scope.setItemParams(p);
//$scope.item = tpl;
$scope.setItem(tpl);
window.tpl = tpl;
};
}
// ----------
if ( $scope.item.then ) {
$scope.item.then(
gotScopeItem,
function(err){
console.error(err);
}
);
} else {
gotScopeItem($scope.item);
}
$scope.save = function() {
$scope.item.save(function(err){
$scope.alert({
type:'success',
msg: 'Successfully saved'
});
});
};
});
var TemplateEditorResolve = {
groups: function($q, synConn) {
var defer = $q.defer();
synConn
.http({
uri: 'wp/{wpId}/settings/Groups?Select=ID,GroupName,GroupKind&WHERE=Hidden=0'
})
.success(function(data){
angular.forEach(data, function(g){
g.type = (g.GroupKind == 1) ? 'My Groups' : 'My Databases';
});
defer.resolve(data);
})
.error(function(err){
console.error(err);
defer.reject(err);
});
return defer.promise;
}
};
app.factory('EmTpl', function($http, $q, synConn, emUtils, emAuth){
var EmTpl = function(data){
var defaults = {
AttachList: "[]",
CategoryID: 0,
CharSet: "UTF-8",
GroupList: [],
Guid: "{"+emUtils.UUID()+"}",
//ID: 17,
MessageFormat: 0,
ModTime: (new Date()).getTime(),
//StoreID: 6,
Subject: "No Subject",
TemplateName: "Unnamed",
};
angular.extend(this, defaults);
if ( typeof data !== 'undefined' ) {
angular.extend(this, data);
}
this.ModTime = emUtils.timeLogToDate(this.ModTime);
this.GroupList = this._map(this.GroupList, function(itm){ return (typeof itm === 'string') ? parseInt(itm, 10) : itm; });
};
var p = EmTpl.prototype;
p.getBaseURL = function() {
return '/wps/templates/'+emAuth.get('workplace').ID+'/'+this.Guid+'/';
};
p._map = function(arr, mapper) {
for (var i = 0; i < arr.length; i++) {
arr[i] = mapper(arr[i], i);
}
return arr;
};
p.save = function(done) {
done = done || function(){};
var obj = {
ID: this.ID,
CharSet : 'UTF-8',
CategoryID: 0,
TemplateName: this.TemplateName,
Subject: this.Subject,
MessageFormat: 0, // 0 - html, 1 - plain
GroupList: this._map(this.GroupList, function(itm){ return itm+''; }), // ~
AttachList: this.AttachList,
Guid: item.Guid
};
if ( typeof this._data !== 'undefined' ) {
obj.EmailSource = emUtils.shrinkAssetURLs(this.EmailSource, this.getBaseURL());
}
synConn
.http({
method: 'PUT',
uri: 'wp/{wpId}/settings/SetTemplateMessage',
data: obj
})
.success(function(data){
done(null);
})
.error(function(err){
console.error(err);
done(err);
});
};
p.setBody = function(body) {
this.EmailSource = body;
}
p.getBody = function() {
var _this = this;
if ( typeof this._data !== 'undefined' ) {
return this.EmailSource;
}
var defer = $q.defer();
synConn
.http({ uri: 'wp/{wpId}/settings/GetTemplateMessage?ID='+this.ID })
.success(function(data){
_this._data = data;
_this.Guid = data.Guid;
data.EmailSource = emUtils.unpackEmailSource(data.EmailSource);
_this.EmailSource = emUtils.expandAssetURLs(data.EmailSource, _this.getBaseURL());
defer.resolve(_this.EmailSource);
})
.error(function(err){
defer.reject(err);
});
return defer.promise;
};
p.del = function(done, forever) {
var req;
if ( forever ) {
req = {
method: 'DELETE',
uri: 'wp/{wpId}/settings/templates/'+this.ID
};
} else {
req = {
method: 'PUT',
uri: 'wp/{wpId}/settings/templates/'+this.ID,
data: {
CategoryID: -1
}
};
}
synConn
.http(req)
.success(function(data){
done(null);
})
.error(function(err){
console.error(err);
done(err);
});
}
p.restore = function(done) {
synConn
.http({
method: 'PUT',
uri: 'wp/{wpId}/settings/templates/'+this.ID,
data: {
CategoryID: 0
}
})
.success(function(data){
done(null);
})
.error(function(err){
console.error(err);
done(err);
});
};
return EmTpl;
});
app.factory('EmTemplates', function($http, $q, emAuth, synConn, emGroups, emAccounts, EmTpl) {
var EmTemplates = function($scope, cat) {
this.$scope = $scope;
this.items = [];
this.busy = false;
this.noMoreData = false;
this.after = '';
this.category = cat ? cat : 0;
if ( this.category === 'trash' ) {
this.category = -1;
}
};
function resolveGroups(templates, done) {
var templatesToProcess = templates.length;
for (var i = 0; i < templates.length; i++) {
emGroups.resolve(templates[i].GroupList, function(err, resolved){
if (err) { throw err; }
templates[this.i].GroupList = resolved;
templatesToProcess -= 1;
if ( templatesToProcess === 0 ) {
done(templates);
}
}.bind({ i: i }));
}
}
EmTemplates.prototype.getTemplate = function(id) {
var tpl;
if ( this.items ) {
angular.forEach(this.items, function(t, i){
if ( t.ID == id ) {
tpl = t;
return false;
}
});
if ( tpl ) {
return tpl;
}
}
var defer = $q.defer();
synConn
.http({ uri: 'wp/{wpId}/settings/GetTemplateMessage?ID='+id })
.success(function(data){
defer.resolve(new EmTpl(data));
})
.error(function(err){
defer.reject(err);
});
return defer.promise;
};
EmTemplates.prototype.nextPage = function() {
var that = this,
defer = $q.defer();
if ( that.busy ) return;
that.busy = true;
var sql = '*';
var start = this.items.length;
synConn
.http({ uri: 'wp/{wpId}/settings/Templates?Select=*&where=CategoryID='+that.category+'&STARTINDEX='+start+'&RESULTS=10&SORT=ModTime&DIR=DESC' })
.success(function(data){
if ( typeof data.fieldCount !== 'undefined' ) {
// no more templates
that.busy = false;
that.noMoreData = true;
} else {
resolveGroups(data, function(templates){
for (var i = 0; i < templates.length; i++) {
that.items.push(new EmTpl(templates[i]));
}
that.busy = false;
defer.resolve(data);
});
}
})
.error(function(err){
defer.reject(err);
console.error(err)
});
return defer.promise;
};
EmTemplates.prototype.del = function(tpl) {
for (var i = 0; i < this.items.length; i++) {
if ( this.items[i].id == tpl.id ) {
this.items.splice(i, 1);
break;
}
}
};
return EmTemplates;
});

View File

@@ -0,0 +1,64 @@
var ckeditorBasePath = CKEDITOR.basePath.substr(0, CKEDITOR.basePath.indexOf('ckeditor/'));
var customPluginsRoot = ckeditorBasePath + 'custom_plugins/';
CKEDITOR.plugins.addExternal('resizewithwindow', customPluginsRoot+'resizewithwindow/plugin.js', '');
CKEDITOR.plugins.addExternal('iframedialog', customPluginsRoot+'iframedialog/plugin.js', '');
CKEDITOR.plugins.addExternal('em_image_gallery', customPluginsRoot+'em_image_gallery/plugin.js', '');
CKEDITOR.editorConfig = function( config ) {
// Define changes to default configuration here.
// For the complete reference:
// http://docs.ckeditor.com/#!/api/CKEDITOR.config
// %REMOVE_START%
//The configuration options below are needed when running CKEditor from source files.
//config.plugins = 'dialogui,dialog,about,a11yhelp,basicstyles,blockquote,clipboard,panel,floatpanel,menu,contextmenu,resize,button,toolbar,elementspath,list,indent,enterkey,entities,popup,filebrowser,floatingspace,listblock,richcombo,format,htmlwriter,horizontalrule,wysiwygarea,image,fakeobjects,link,magicline,maximize,pastetext,pastefromword,removeformat,sourcearea,specialchar,menubutton,scayt,stylescombo,tab,table,tabletools,undo,wsc,panelbutton,colorbutton,font,justify,liststyle';
//config.skin = 'moono';
// %REMOVE_END%
config.fullPage = true;
config.allowedContent = true;
config.entities = false;
config.basicEntities = true;
//config.entities_latin = false;
config.resize_enabled = false;
config.extraPlugins = 'resizewithwindow,iframedialog,em_image_gallery';
config.enterMode = CKEDITOR.ENTER_BR;
config.shiftEnterMode = CKEDITOR.ENTER_P;
config.fillEmptyBlocks = false;
config.codemirror = {
// showSearchButton: true,
showCommentButton: false,
showUncommentButton: false
};
// The toolbar groups arrangement, optimized for two toolbar rows.
config.toolbarGroups = [
{ name: 'document', groups: [ 'mode', 'document' ] },
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
//'/',
{ name: 'styles' },
{ name: 'links' },
'/',
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align' ] },
{ name: 'colors' },
{ name: 'tools' },
{ name: 'document', groups: [ 'document', 'doctools' ] },
{ name: 'emBar' },
{ name: 'insert' },
{ name: 'about' },
{ name: 'others' }
];
// Remove some buttons, provided by the standard plugins, which we don't
// need to have in the Standard(s) toolbar.
config.removeButtons = 'Subscript,Superscript,Save,Styles';
};

View File

@@ -0,0 +1,210 @@
angular.module('em-utils', [], function($provide) {
var makeCRCTable = function(){
var c;
var crcTable = [];
for(var n =0; n < 256; n++){
c = n;
for(var k =0; k < 8; k++){
c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
}
crcTable[n] = c;
}
return crcTable;
}
var crcTable = makeCRCTable();
var crc32 = function(str, init) {
var crc = (typeof init === 'undefined') ? 0 ^ (-1) : init^0xFFFFFFFF;
//var crc = 0 ^ (-1);
for (var i = 0; i < str.length; i++ ) {
crc = (crc >>> 8) ^ crcTable[(crc ^ str.charCodeAt(i)) & 0xFF];
}
return (crc ^ (-1)) >>> 0;
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* SHA-256 implementation in JavaScript | (c) Chris Veness 2002-2010 | www.movable-type.co.uk */
/* - see http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html */
/* http://csrc.nist.gov/groups/ST/toolkit/examples.html */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
var Sha256 = {}; // Sha256 namespace
/**
* Generates SHA-256 hash of string
*
* @param {String} msg String to be hashed
* @param {Boolean} [utf8encode=true] Encode msg as UTF-8 before generating hash
* @returns {String} Hash of msg as hex character string
*/
Sha256.hash = function(msg, utf8encode) {
utf8encode = (typeof utf8encode == 'undefined') ? true : utf8encode;
// convert string to UTF-8, as SHA only deals with byte-streams
if (utf8encode) msg = Utf8.encode(msg);
// constants [§4.2.2]
var K = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
// initial hash value [§5.3.1]
var H = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19];
// PREPROCESSING
msg += String.fromCharCode(0x80); // add trailing '1' bit (+ 0's padding) to string [§5.1.1]
// convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1]
var l = msg.length/4 + 2; // length (in 32-bit integers) of msg + '1' + appended length
var N = Math.ceil(l/16); // number of 16-integer-blocks required to hold 'l' ints
var M = new Array(N);
for (var i=0; i<N; i++) {
M[i] = new Array(16);
for (var j=0; j<16; j++) { // encode 4 chars per integer, big-endian encoding
M[i][j] = (msg.charCodeAt(i*64+j*4)<<24) | (msg.charCodeAt(i*64+j*4+1)<<16) |
(msg.charCodeAt(i*64+j*4+2)<<8) | (msg.charCodeAt(i*64+j*4+3));
} // note running off the end of msg is ok 'cos bitwise ops on NaN return 0
}
// add length (in bits) into final pair of 32-bit integers (big-endian) [§5.1.1]
// note: most significant word would be (len-1)*8 >>> 32, but since JS converts
// bitwise-op args to 32 bits, we need to simulate this by arithmetic operators
M[N-1][14] = ((msg.length-1)*8) / Math.pow(2, 32); M[N-1][14] = Math.floor(M[N-1][14])
M[N-1][15] = ((msg.length-1)*8) & 0xffffffff;
// HASH COMPUTATION [§6.1.2]
var W = new Array(64); var a, b, c, d, e, f, g, h;
for (var i=0; i<N; i++) {
// 1 - prepare message schedule 'W'
for (var t=0; t<16; t++) W[t] = M[i][t];
for (var t=16; t<64; t++) W[t] = (Sha256.sigma1(W[t-2]) + W[t-7] + Sha256.sigma0(W[t-15]) + W[t-16]) & 0xffffffff;
// 2 - initialise working variables a, b, c, d, e, f, g, h with previous hash value
a = H[0]; b = H[1]; c = H[2]; d = H[3]; e = H[4]; f = H[5]; g = H[6]; h = H[7];
// 3 - main loop (note 'addition modulo 2^32')
for (var t=0; t<64; t++) {
var T1 = h + Sha256.Sigma1(e) + Sha256.Ch(e, f, g) + K[t] + W[t];
var T2 = Sha256.Sigma0(a) + Sha256.Maj(a, b, c);
h = g;
g = f;
f = e;
e = (d + T1) & 0xffffffff;
d = c;
c = b;
b = a;
a = (T1 + T2) & 0xffffffff;
}
// 4 - compute the new intermediate hash value (note 'addition modulo 2^32')
H[0] = (H[0]+a) & 0xffffffff;
H[1] = (H[1]+b) & 0xffffffff;
H[2] = (H[2]+c) & 0xffffffff;
H[3] = (H[3]+d) & 0xffffffff;
H[4] = (H[4]+e) & 0xffffffff;
H[5] = (H[5]+f) & 0xffffffff;
H[6] = (H[6]+g) & 0xffffffff;
H[7] = (H[7]+h) & 0xffffffff;
}
return Sha256.toHexStr(H[0]) + Sha256.toHexStr(H[1]) + Sha256.toHexStr(H[2]) + Sha256.toHexStr(H[3]) +
Sha256.toHexStr(H[4]) + Sha256.toHexStr(H[5]) + Sha256.toHexStr(H[6]) + Sha256.toHexStr(H[7]);
}
Sha256.ROTR = function(n, x) { return (x >>> n) | (x << (32-n)); }
Sha256.Sigma0 = function(x) { return Sha256.ROTR(2, x) ^ Sha256.ROTR(13, x) ^ Sha256.ROTR(22, x); }
Sha256.Sigma1 = function(x) { return Sha256.ROTR(6, x) ^ Sha256.ROTR(11, x) ^ Sha256.ROTR(25, x); }
Sha256.sigma0 = function(x) { return Sha256.ROTR(7, x) ^ Sha256.ROTR(18, x) ^ (x>>>3); }
Sha256.sigma1 = function(x) { return Sha256.ROTR(17, x) ^ Sha256.ROTR(19, x) ^ (x>>>10); }
Sha256.Ch = function(x, y, z) { return (x & y) ^ (~x & z); }
Sha256.Maj = function(x, y, z) { return (x & y) ^ (x & z) ^ (y & z); }
//
// hexadecimal representation of a number
// (note toString(16) is implementation-dependant, and
// in IE returns signed numbers when used on full words)
//
Sha256.toHexStr = function(n) {
var s="", v;
for (var i=7; i>=0; i--) { v = (n>>>(i*4)) & 0xf; s += v.toString(16); }
return s;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Utf8 class: encode / decode between multi-byte Unicode characters and UTF-8 multiple */
/* single-byte character encoding (c) Chris Veness 2002-2010 */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
var Utf8 = {}; // Utf8 namespace
/**
* Encode multi-byte Unicode string into utf-8 multiple single-byte characters
* (BMP / basic multilingual plane only)
*
* Chars in range U+0080 - U+07FF are encoded in 2 chars, U+0800 - U+FFFF in 3 chars
*
* @param {String} strUni Unicode string to be encoded as UTF-8
* @returns {String} encoded string
*/
Utf8.encode = function(strUni) {
// use regular expressions & String.replace callback function for better efficiency
// than procedural approaches
var strUtf = strUni.replace(
/[\u0080-\u07ff]/g, // U+0080 - U+07FF => 2 bytes 110yyyyy, 10zzzzzz
function(c) {
var cc = c.charCodeAt(0);
return String.fromCharCode(0xc0 | cc>>6, 0x80 | cc&0x3f); }
);
strUtf = strUtf.replace(
/[\u0800-\uffff]/g, // U+0800 - U+FFFF => 3 bytes 1110xxxx, 10yyyyyy, 10zzzzzz
function(c) {
var cc = c.charCodeAt(0);
return String.fromCharCode(0xe0 | cc>>12, 0x80 | cc>>6&0x3F, 0x80 | cc&0x3f); }
);
return strUtf;
}
/**
* Decode utf-8 encoded string back into multi-byte Unicode characters
*
* @param {String} strUtf UTF-8 string to be decoded back to Unicode
* @returns {String} decoded string
*/
Utf8.decode = function(strUtf) {
// note: decode 3-byte chars first as decoded 2-byte strings could appear to be 3-byte char!
var strUni = strUtf.replace(
/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars
function(c) { // (note parentheses for precence)
var cc = ((c.charCodeAt(0)&0x0f)<<12) | ((c.charCodeAt(1)&0x3f)<<6) | ( c.charCodeAt(2)&0x3f);
return String.fromCharCode(cc); }
);
strUni = strUni.replace(
/[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars
function(c) { // (note parentheses for precence)
var cc = (c.charCodeAt(0)&0x1f)<<6 | c.charCodeAt(1)&0x3f;
return String.fromCharCode(cc); }
);
return strUni;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
$provide.factory('crc32', function() {
return crc32;
});
$provide.factory('sha256', function() {
return Sha256;
});
});

View File

@@ -0,0 +1,492 @@
angular.module('syn-auth', ['em-utils'], function($provide) {
// the number of login retries on 403 before logout
var MAX_RECONNECT_COUNT = 5;
$provide.factory('SynAuth', function(crc32, sha256) {
function SynAuth(host, port) {
var defaults = {
host: '',
defaultPort: '888',
User : "",
fRoot : "",
fSessionID : 0,
fSessionIDHexa8 : "",
fSessionPrivateKey : 0,
fSessionTickCountOffset : 0,
fLastSessionTickCount : 0,
PasswordHashHexa : "",
fServerTimeStampOffset : 0,
fcallBack : null,
ffailCallBack : null
}; // SynAuth namespace
this.connectionReady = false;
this.readyCallbacks = [];
for ( var p in defaults ) {
this[p] = defaults[p];
}
if ( host ) {
this.setHost(host, port);
}
}
var sp = SynAuth.prototype;
sp.ready = function(cb) {
if ( this.connectionReady ) {
cb(this);
} else {
this.readyCallbacks.push(cb);
}
};
sp.fireReadyCbs = function() {
var _this = this;
angular.forEach(this.readyCallbacks, function(cb){
cb(_this);
});
};
sp.wrap = function(method){
var that = this;
return function(){
method.apply(that, arguments);
};
};
sp.setHost = function(host, port) {
if ( !host.match(/\:\d+$/) ) {
host += ':'+(port || this.defaultPort);
}
this.host = host;
};
sp.LogIn = function (root, username, password, callback, failCallback){
this.fRoot = root;
this.User = username;
this.PasswordHashHexa = sha256.hash("salt"+password);
if (callback) {this.fcallBack = callback;}
if (failCallback) {this.ffailCallback = failCallback;}
$.get(this.host+"/"+root+"/TimeStamp", this.wrap(this.gotTimeStamp));
}
sp.LogInAgain = function(callback){ //after timeout error for silent re-login
this.fSessionID = 0;
this.fSessionIDHexa8 = "";
this.fSessionPrivateKey = 0;
if (callback) {this.fcallBack = callback;} else {this.fcallBack = null;}
$.get(this.host+"/"+this.fRoot+"/TimeStamp", this.wrap(this.gotTimeStamp));
}
sp.gotTimeStamp = function (timestamp) {
var s = '', d = new Date(), clientTime = '';
timestamp = parseInt(timestamp, 10);
s = d.getFullYear().toString(2);
while(s.length < 13) { s = '0'+s;}
clientTime = s;
s = d.getMonth().toString(2);
while(s.length < 4) { s = '0'+s;}
clientTime = clientTime +s;
s = (d.getDate()-1).toString(2);
while(s.length < 5) { s = '0'+s;}
clientTime = clientTime +s;
s = d.getHours().toString(2);
while(s.length < 5) { s = '0'+s;}
clientTime = clientTime +s;
s = d.getMinutes().toString(2);
while(s.length < 6) { s = '0'+s;}
clientTime = clientTime +s;
s = d.getSeconds().toString(2);
while(s.length < 6) { s = '0'+s;}
clientTime = clientTime +s;
this.fServerTimeStampOffset = (timestamp - Math.floor(d.getTime()/10));
$.get(this.host+"/"+this.fRoot+"/auth?UserName="+this.User, this.wrap(this.gotNonce));
}
sp.gotNonce = function (aNonce){
var that = this;
//create client nonce
var aClientNonce = "", s = "", d = new Date();
aClientNonce = d.getFullYear().toString();
s = d.getMonth().toString();
if (s.length === 1) { s = '0'+s;}
aClientNonce = aClientNonce + '-' + s;
s = d.getDate().toString();
if (s.length === 1) { s = '0'+s;}
aClientNonce = aClientNonce + '-' + s + ' ';
s = d.getHours().toString();
if (s.length === 1) { s = '0'+s;}
aClientNonce = aClientNonce + s;
s = d.getMinutes().toString();
if (s.length === 1) { s = '0'+s;}
aClientNonce = aClientNonce + ':' + s;
s = d.getSeconds().toString();
if (s.length === 1) { s = '0'+s;}
aClientNonce = aClientNonce + ':' + s;
aClientNonce = sha256.hash(aClientNonce);
s = this.host+"/"+ this.fRoot+"/auth?UserName="+this.User+"&Password=" +
sha256.hash(this.fRoot+aNonce.result+aClientNonce+this.User+this.PasswordHashHexa )+
"&ClientNonce="+aClientNonce;
$.ajax({
type: "GET",
dataType: "json",
url: s,
success: function(){ that.gotSession.apply(that, arguments); },
error: function(){ that.ffailCallback.apply(that, arguments); }
});
};
sp.gotSession = function (aSessionKey){
var sessArr = aSessionKey.result.split('+');
this.fSessionID = parseInt(sessArr[0], 10);
this.fSessionIDHexa8 = this.fSessionID.toString(16);
while ( this.fSessionIDHexa8.length < 8 ) { this.fSessionIDHexa8 = '0'+this.fSessionIDHexa8; }
this.fSessionPrivateKey = crc32(this.PasswordHashHexa, crc32(aSessionKey.result, 0));
if (this.fcallBack != null) {
this.connectionReady = true;
this.fireReadyCbs();
this.fcallBack();
}
}
sp.SessionSign = function (url) {
var Tix, Nonce, s, ss;
Tix = Date.now(); // # of ms since Epoch
if ( Tix <= this.fLastSessionTickCount ) {
this.fLastSessionTickCount += 1;
} else {
this.fLastSessionTickCount = Tix;
}
Nonce = Tix.toString(16);
while ( Nonce.length < 8 ) { Nonce = '0'+Nonce; }
if ( Nonce.length > 8 ) { Nonce = Nonce.slice(Nonce.length-8) }
ss = crc32(url, crc32(Nonce, this.fSessionPrivateKey)).toString(16);
while ( ss.length < 8 ) { ss = '0'+ss; }
s = url.indexOf("?") == -1 ? url+'?session_signature=' : url+'&session_signature=';
return s + this.fSessionIDHexa8 + Nonce + ss;
}
sp.getURL = function(uri) {
return this.host+'/'+this.SessionSign(uri);
}
sp.Logout = function (callback) {
if (this.fSessionID == 0) {if (callback){callback();}} else {
$.get(this.host+"/"+this.fRoot+"/auth?UserName="+this.User+"&Session="+this.fSessionID, callback);
this.fRoot = '';
this.User = '';
this.fSessionID = 0;
this.fSessionIDHexa8 = "";
this.fSessionPrivateKey = 0;
}
}
return SynAuth;
});
// wps
// wp/%/settings
// wp/%/group
// wp/%/bounce
// infinitypropertycomau
// garethinfinitypropertycomau
// bernieinfinitypropertycomau
var forEach = angular.forEach;
function isArray(value) {
return Object.prototype.toString.apply(value) == '[object Array]';
}
function isObject(value){return value != null && typeof value == 'object';}
function sortedKeys(obj) {
var keys = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
keys.push(key);
}
}
return keys.sort();
}
function forEachSorted(obj, iterator, context) {
var keys = sortedKeys(obj);
for ( var i = 0; i < keys.length; i++) {
iterator.call(context, obj[keys[i]], keys[i]);
}
return keys;
}
function encodeUriQuery(val, pctEncodeSpaces) {
return encodeURIComponent(val).
replace(/%40/gi, '@').
replace(/%3A/gi, ':').
replace(/%24/g, '$').
replace(/%2C/gi, ',').
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
}
function buildQueryString(params) {
var parts = [];
forEachSorted(params, function(value, key) {
if (value == null || value == undefined) return;
if (!isArray(value)) value = [value];
forEach(value, function(v) {
if (isObject(v)) {
v = toJson(v);
}
parts.push(encodeUriQuery(key) + '=' +
encodeUriQuery(v));
});
});
return parts.join('&');
}
function buildUrl(url, params) {
if (!params) return url;
var qs = buildQueryString(params);
return url + ((url.indexOf('?') == -1) ? '?' : '&') + qs;
}
$provide.factory('synConn', function(SynAuth, emAuth, $http, $q, emsLoadingBar) {
var synConn = {
opts: {
host: emAuth.get('host'),
port: emAuth.get('port'),
email: emAuth.get('email'),
password: emAuth.get('password'),
secure: emAuth.get('secure')
}
};
var roots = [
'wps',
'wp/\\d+/settings',
'wp/\\d+/group',
'wp/\\d+/bounce'
];
var connCache = {};
function setOpts(o) {
synConn.opts = o;
if ( !o.host ) { throw new Exception('[SynConn] setOpts. "host" option is not defined.'); }
if ( !o.email ) { throw new Exception('[SynConn] setOpts. "email" option is not defined.'); }
if ( !o.password ) { throw new Exception('[SynConn] setOpts. "password" option is not defined.'); }
o.port = o.port || '888';
}
function supplant (str, o) {
return str.replace(
/\{([^{}]*)\}/g,
function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
}
function getBaseURL() {
var pr = synConn.opts.secure ? 'https' : 'http';
return pr+'://'+synConn.opts.host+':'+synConn.opts.port+'/';
}
function createNewSynAuth(root, done) {
var pr = synConn.opts.secure ? 'https' : 'http';
//return { SynAuth: 'dummy'+(new Date()).getTime() };
var sa = new SynAuth(pr+'://'+synConn.opts.host, synConn.opts.port);
sa.LogIn(root, synConn.opts.email, synConn.opts.password, function(){
done(null, sa);
}, function(xhr, status, msg){
// failback
var err = new Error(msg);
err.status = xhr.status;
done(err);
});
return sa;
}
function getConnectionFromURi(uri, done) {
var found = false;
// looking for cached connection
for ( var root in connCache ) {
if ( uri.indexOf(root) === 0 ) {
return connCache[root].ready(function(conn){
done(null, conn);
});
}
}
// creating new connection
for (var r, res, i = 0; i < roots.length; i++) {
if ( res = (new RegExp(roots[i],'i')).exec(uri) ) {
r = res[0]; // matched root uri, like wp/1/settings
found = true;
connCache[r] = createNewSynAuth(r, function(err, sa){
if ( err ) {
delete connCache[r];
return done(err);
}
return done(null, sa);
});
}
}
if ( !found ) {
done(new Error('getConnectionFromURi: Cannot get rootURi for '+uri));
}
}
function removeCachedConnection(sa) {
var found = false;
// looking for cached connection
for ( var root in connCache ) {
if ( connCache[root] === sa) {
delete connCache[root];
break;
}
}
}
function http(o) {
var that = {
sa: null,
err: null,
errorCb: null,
successCb: null
};
if ( !o.headers ) {
o.headers = {};
}
var reconnect = 0;
var wp = emAuth.get('workplace');
if ( wp ) {
synConn.opts.wpId = emAuth.get('workplace').ID;
}
o.uri = supplant(o.uri, synConn.opts);
function connect() {
getConnectionFromURi(o.uri, function(err, sa){
if ( err ) { that.err = err; }
that.sa = sa;
setTimeout(function() {
if ( err ) { return that.errorCb(err); }
runRequest();
}, 1);
});
}
connect();
function runRequest() {
var url;
if ( o.params ) {
url = that.sa.getURL( buildUrl(o.uri, o.params) );
delete o.params;
} else {
url = that.sa.getURL(o.uri);
}
if ( o.data ) {
if ( o.headers['Content-Type'] === 'application/x-www-form-urlencoded' ) {
o.data = buildQueryString(o.data);
}
}
var opts = angular.extend({ url : url }, o);
delete opts.uri;
opts.method = opts.method || 'GET';
$http(opts).success(function(){
that.successCb.apply(this, arguments);
emsLoadingBar.stop();
reconnect = 0;
}).error(function(data){
var err = new Error(data.ErrorText);
err.ErrorCode = data.ErrorCode;
if ( err && err.ErrorCode == 403 ) {
if ( reconnect == MAX_RECONNECT_COUNT ) {
alert('Authentication failure. You will be logged out now. Shall this error repeat, contact your server administrator.');
window.location.hash = '#/logout';
return;
}
removeCachedConnection(that.sa);
reconnect += 1;
connect();
} else {
var args = Array.prototype.slice.call(arguments);
args.unshift(err);
that.errorCb.apply(this, args);
emsLoadingBar.stop();
}
});
emsLoadingBar.start();
}
return {
success: function(cb){
that.successCb = cb;
return this;
},
error: function(cb){
that.errorCb = cb;
return this;
}
};
}
function touch(uri, done) {
getConnectionFromURi(uri, done);
}
synConn.logout = function() {
connCache = {};
};
//getConnectionFromURi('wp/1/settings/GetTemplateMessage?ID=');
synConn.setOpts = setOpts;
synConn.http = http;
synConn.touch = touch;
synConn.getBaseURL = getBaseURL;
return synConn;
});
});

View File

@@ -0,0 +1,67 @@
<div class="container" style="padding-top: 70px;">
<div class="col-md-4 col-sm-4">
<div class="form-group">
<select class="form-control" ng-model="method">
<option value="GET">GET</option>
<option value="POST">POST</option>
<option value="PUT">PUT</option>
<option value="DELETE">DELETE</option>
</select>
<br>
<label for="control-label">Query Params: <button class="btn btn-xs btn-default" ng-click="addParam()"><span class="glyphicon glyphicon-plus"></span></button> <button class="btn btn-xs btn-default" ng-click="toggleRawBody()">{{rawBodyBtn}}</button> </label>
<table class="table table-fixed" ng-show="!useRawBody">
<tbody>
<tr ng-repeat="p in params">
<td><input type="text" class="form-control input-sm" ng-model="p.name" placeholder="Name"></td>
<td><input type="text" class="form-control input-sm" ng-model="p.value" placeholder="Value"></td>
<td style="width: 30px;"><button class="btn btn-default" ng-click="delParam($index)"><span class="glyphicon glyphicon-trash"></span></button></td>
</tr>
</tbody>
</table>
<textarea class="form-control" ng-show="useRawBody" ng-model="rawBody"></textarea>
<hr>
<label for="control-label">Headers: <button class="btn btn-xs btn-default" ng-click="addHeader()"><span class="glyphicon glyphicon-plus"></span></button></label>
<div class="control-group">
<label class="control-label">Content-Type: </label>
<select ng-model="contentType">
<option value=""></option>
<option value="application/json">application/json</option>
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
</select>
</div>
<table class="table table-fixed">
<tbody>
<tr ng-repeat="h in headers">
<td><input type="text" class="form-control input-sm" ng-model="h.name" placeholder="Name"></td>
<td><input type="text" class="form-control input-sm" ng-model="h.value" placeholder="Value"></td>
<td style="width: 30px;"><button class="btn btn-default" ng-click="delHeader($index)"><span class="glyphicon glyphicon-trash"></span></button></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-md-8 col-sm-8">
<div class="row">
<div class="col-md-9 col-sm-9">
<div class="form-group">
<input type="text" class="form-control" placeholder="URI" ng-model="uri">
</div>
</div>
<div class="col-md-3 col-sm-3">
<button class="btn btn-primary" ng-click="sendRequest()">Send Request</button>
</div>
</div>
<hr>
<label class="control-label">Response</label>
<textarea ng-model="response" class="form-control" style="width: 100%; height: 300px;"></textarea>
</div>
</div>

View File

@@ -0,0 +1,21 @@
<div ng-controller="ContactsCtrl" class="contacts-view">
<div class="row">
<div class="col-xs-12 hide-xs-only" style="text-align: center;" >Please select group from the menu.</div>
<!--- mobile menu -->
<ul class="contacts-group-menu show-xs-only">
<li>
<h5>My Databases</h5>
<ul class="nav">
<li ng-class="{'active': g.ID == gid}" ng-repeat="g in groups.db"><a href="#/workplaces/{{wpid}}/contacts/{{g.placement}}/{{g.ID}}">{{g.GroupName}}</a></li>
</ul>
</li>
<li>
<h5>My Groups</h5>
<ul class="nav">
<li ng-class="{'active': g.ID == gid}" ng-repeat="g in groups.local"><a href="#/workplaces/{{wpid}}/contacts/{{g.placement}}/{{g.ID}}">{{g.GroupName}}</a></li>
</ul>
</li>
</ul>
<!--- /mobile menu -->
</div>
</div>

View File

@@ -0,0 +1,14 @@
<ul class="nav">
<li class="open">
<a href="#">My Databases</a>
<ul class="nav">
<li ng-class="{'active': g.ID == gid}" ng-repeat="g in groups.db"><a href="#/workplaces/{{wpid}}/contacts/{{g.placement}}/{{g.ID}}">{{g.GroupName}}</a></li>
</ul>
</li>
<li class="open">
<a href="#">My Groups</a>
<ul class="nav">
<li ng-class="{'active': g.ID == gid}" ng-repeat="g in groups.local"><a href="#/workplaces/{{wpid}}/contacts/{{g.placement}}/{{g.ID}}">{{g.GroupName}}</a></li>
</ul>
</li>
</ul>

View File

@@ -0,0 +1,32 @@
<div ng-controller="ContactsCtrl" class="contacts-view">
<div class="row split-view">
<div class="col-sm-6" ng-if="contacts" id="contacts-list">
<div infinite-scroll='contacts.nextPage()' infinite-scroll-disabled='contacts.busy' infinite-scroll-distance='20' infinite-scroll-box="contacts-list">
<div class="contact" ng-repeat="c in contacts.items" ng-class="{'unsubscribed': !c.Subscribed}">
<span class="name">{{c.First_Name}} {{c.Last_Name}} {{c.Recipient_Name}}</span>
<span class="email">&lt;{{c.Email}}&gt;</span>
<span class="subscribed-date">{{c.Subscribe_Date | date:'MM/dd/yyyy @ h:mm a'}}</span>
<span ng-show="!c.Subscribed" class="label label-default unsubscribed">unsubscrubed</span>
<span ng-show="c.Fields" class="fields">
<table>
<tr ng-repeat="(key, val) in c.Fields">
<td>{{key}}</td>
<td>{{val}}</td>
</tr>
</table>
</span>
</div>
</div>
</div>
<div class="col-sm-6 exclusion-list-pane" id="exclusion-list-container" ng-class="{'show': showExclusionList}">
<div class="title">
<h4>Exclusion list</h4>
</div>
<div id="exclusion-list">
<ul ng-if="contactsExcList" class="list-unstyled" infinite-scroll='contactsExcList.nextPage()' infinite-scroll-disabled='contactsExcList.busy' infinite-scroll-distance='20' infinite-scroll-box="exclusion-list">
<li ng-repeat="e in contactsExcList.items">{{e.Email}}</li>
</ul>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,22 @@
<ul class="nav gs-sidenav">
<li ng-class="{'active': section == 'templates'}">
<a href="#/workplaces/{{workplace.ID}}/templates">Templates</a>
<ul class="nav">
<li ng-class="{'active': sub == catId}" ng-repeat="(catId, cat) in templateCats"><a href="#/workplaces/{{workplace.ID}}/templates/folder/{{catId}}"><span class="glyphicon glyphicon-folder-close"></span> {{cat}}</a></li>
<li ng-class="{'active': sub == 'trash'}" sub="trash"><a href="#/workplaces/{{workplace.ID}}/templates/trash"><span class="glyphicon glyphicon-trash"></span> Trash</a></li>
</ul>
</li>
<li ng-class="{'active': section == 'drafts'}">
<a href="#/workplaces/{{workplace.ID}}/drafts">Drafts</a>
<ul class="nav">
<li ng-class="{'active': subSection == 'trash'}"><a href="#/workplaces/{{workplace.ID}}/drafts/trash"><span class="glyphicon glyphicon-trash"></span> Trash</a></li>
</ul>
</li>
<li ng-class="{'active': section == 'outbox'}">
<a href="#/workplaces/{{workplace.ID}}/outbox">Outbox</a>
<ul class="nav">
<li ng-class="{'active': subSection == 'trash'}"><a href="#/workplaces/{{workplace.ID}}/outbox/trash"><span class="glyphicon glyphicon-trash"></span> Trash</a></li>
</ul>
</li>
</ul>

View File

@@ -0,0 +1,30 @@
<div ng-controller="DraftsCtrl">
<div class="row split-view">
<div class="col-md-6 col-sm-6" id="messages-list-wrap">
<ul class="messages-list" infinite-scroll='drafts.nextPage()' infinite-scroll-disabled='drafts.busy' infinite-scroll-distance='1' infinite-scroll-box="messages-list-wrap">
<li ng-repeat="drf in drafts.items" ng-click="drfClick(drf)" ng-class="{'active': drf.ID == drafts.activeItem}">
<table>
<tr>
<td><span class="message-subject">{{drf.Subject}}</span></td>
<td><span class="message-date">{{drf.ModTime | date:'MM/dd/yyyy @ h:mm a'}}</span></td>
</tr>
<tr>
<td ng-repeat="g in drf.GroupList">
<span class="message-template">{{g.GroupName}}</span>
</td>
<td ng-repeat="a in drf.AccountList">
<span class="message-group">{{a.AccountName}}</span>
</td>
</tr>
</table>
<span class="message-links" ng-if="subSection !== 'trash'"><a href="#/workplaces/{{workplace.ID}}/drafts/{{drf.ID}}/edit">Edit Message</a> | <a href="#" ng-click="drfDelete($event, drf)">Delete</a></span>
<span class="message-links" ng-if="subSection == 'trash'"><a ng-click="drfRestore($event, drf)">Restore</a> | <a class="text-danger" href="#" ng-click="drfDelete($event, drf)">Delete</a></span>
</li>
<li class="message-list-info" ng-show="drafts.busy">Loading data...</li>
<li class="message-list-info" ng-show="!drafts.items.length && drafts.noMoreData">No drafts here yet</li>
</ul>
</div>
<div class="col-md-6 col-sm-6" ng-class="{ 'show': showPreview }" id="preview-container"></div>
</div>
</div>

View File

@@ -0,0 +1,71 @@
<div class="container">
<div class="row split-view editor">
<div class="col-md-9 col-sm-9">
<form class="form-horizontal" role="form">
<div class="form-group">
<label for="subject" class="col-xs-2 control-label">Subject:</label>
<div class="col-xs-10">
<input type="text" class="form-control" ng-model="item.Subject" id="subject" placeholder="Subject">
</div>
</div>
</form>
<div class="editor-wrap">
<textarea class="col" id="editor" data-ck-source="item" data-ck-editor></textarea>
</div>
</div>
<div class="col-md-3 col-sm-3">
<form class="form-horizontal" role="form">
<button ng-click="sendNow()" class="btn btn-primary btn-md btn-margin">Send Now</button>
<button class="btn btn-default btn-md btn-margin" ng-click="save()">Save</button>
<div class="form-group">
<label for="account" class="col-xs-1 control-label">From:</label>
<div class="col-xs-11">
<!-- <select name="from" id="from" class="form-control" ng-model="account">
<option value="">Select Account</option>
<option ng-selected="account == acc.ID" ng-repeat="acc in accounts" value="{{acc.ID}}">{{acc.AccountName}}</option>
</select>
-->
<gt-select gt-model="account" options="acc.ID as acc.AccountName for acc in accounts"></gt-select>
</div>
</div>
<div class="form-group">
<label for="to" class="col-xs-1 control-label">To:</label>
<div class="col-xs-11">
<gt-select multiple="true" gt-model="to" options="g.ID as g.GroupName for g in groups group by g.type" plural="groups"></gt-select>
</div>
</div>
<label>
<input type="checkbox" ng-model="enableTracking"> Track recipients' actions
</label>
<input ng-disabled="!enableTracking" type="text" class="form-control" placeholder="Campaign Name" ng-model="item.TrackName">
<div class="radio">
<label>
<input ng-disabled="!enableTracking" type="radio" ng-model="item.TrackMethod" name="analytics" id="analytics-google" value="1" checked>
Google analytics
</label>
</div>
<div class="radio">
<label>
<input ng-disabled="!enableTracking" type="radio" ng-model="item.TrackMethod" name="analytics" id="analytics-piwik" value="2" checked>
Piwik
</label>
</div>
<hr>
<label>Attachments <button ng-click="addCommonAtt()" class="btn btn-default btn-xs"><span class="glyphicon glyphicon-plus"></span></button> </label>
<ul class="list-unstyled em-file-list">
<li ng-repeat="itm in item.AttachList"><i class="glyphicon glyphicon-file"></i><span>{{itm}}</span><span class="em-btn-remove"><i class="glyphicon glyphicon-trash" ng-click="removeAttachment(itm)"></i></span></li>
</ul>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,40 @@
<div class="container">
<div class="row split-view editor">
<div class="col-md-9 col-sm-9">
<form class="form-horizontal" role="form">
<div class="form-group">
<label for="subject" class="col-xs-2 control-label">Subject:</label>
<div class="col-xs-10">
<input type="text" class="form-control" ng-model="item.Subject" id="subject" placeholder="Subject">
</div>
</div>
</form>
<div class="editor-wrap">
<textarea class="col" id="editor" data-ck-source="item" data-ck-editor></textarea>
</div>
</div>
<div class="col-md-3 col-sm-3">
<form class="form-horizontal" role="form">
<button class="btn btn-primary btn-md" ng-click="save()">Save</button>
<div class="form-group">
<label for="to" class="col-xs-1 control-label">To:</label>
<div class="col-xs-11">
<gt-select multiple="true" gt-model="to" options="g.ID as g.GroupName for g in groups group by g.type" plural="groups"></gt-select>
</div>
</div>
<label>Attachments <button ng-click="addCommonAtt()" class="btn btn-default btn-xs"><span class="glyphicon glyphicon-plus"></span></button> </label>
<ul class="list-unstyled em-file-list">
<li ng-repeat="itm in item.AttachList"><i class="glyphicon glyphicon-file"></i> {{itm}} <span class="em-btn-remove"><i class="glyphicon glyphicon-trash"></i></span></li>
</ul>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,83 @@
<div class="container">
<div class="row split-view editor">
<div class="col-md-9 col-sm-9">
<form class="form-horizontal" role="form">
<div class="form-group">
<label for="subject" class="col-xs-2 control-label">Subject:</label>
<div class="col-xs-10">
<input type="text" class="form-control" ng-model="item.Subject" id="subject" placeholder="Subject">
</div>
</div>
</form>
<div class="editor-wrap">
<textarea class="col" id="editor" data-ck-source="item" data-ck-editor></textarea>
</div>
</div>
<div class="col-md-3 col-sm-3">
<form class="form-horizontal" role="form">
<div ng-if="itemType=='template'">
<button class="btn btn-primary btn-md" ng-click="save()">Save</button>
<div class="form-group">
<label for="to" class="col-xs-1 control-label">To:</label>
<div class="col-xs-11">
<gt-select multiple="true" gt-model="$parent.to" options="g.ID as g.GroupName for g in groups group by g.type" plural="groups"></gt-select>
</div>
</div>
</div>
<div ng-if="itemType=='draft'">
<button ng-click="sendNow()" class="btn btn-primary btn-md btn-margin">Send Now</button>
<button class="btn btn-default btn-md btn-margin" ng-click="save()">Save</button>
</div>
<div ng-if="itemType=='draft'">
<div class="form-group">
<label for="account" class="col-xs-1 control-label">From:</label>
<div class="col-xs-11">
<select name="from" id="from" class="form-control">
<option value="">Select Account</option>
</select>
</div>
</div>
<div class="form-group">
<label for="to" class="col-xs-1 control-label">To:</label>
<div class="col-xs-11">
<select class="form-control" id="to">
<option value="">Select Group</option>
</select>
</div>
</div>
<label>
<input type="checkbox"> Track recipients' actions
</label>
<input type="text" class="form-control" placeholder="Campaign Name">
<div class="radio">
<label>
<input type="radio" name="analytics" id="analytics-google" value="google" checked>
Google analytics
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="analytics" id="analytics-piwik" value="piwik" checked>
Piwik
</label>
</div>
<hr>
<a href="#" ng-click="addAttachment()">Add Attachment</a>
</div>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,11 @@
<div ng-class="{ 'show': $parent.showPreview }" id="preview-container" ng-show="!log"></div>
<div id="sentlog" ng-show="log">
<ul class="list-unstyled" infinite-scroll="log.nextPage()" infinite-scroll-disabled="log.busy" infinite-scroll-distance="1" infinite-scroll-box="sentlog">
<li title="{{itm.StatusText}}" ng-repeat="itm in log.items" class="sentlog-item" ng-class="{ 'sentlog-item-success': itm.Status === 1, 'sentlog-item-temperror': itm.Status === 2, 'sentlog-item-error': itm.Status === 3}">
<div class="sentlog-item-groupname">{{itm.GroupName}}<span class="sentlog-item-date">{{itm.SendDate | date:'MM/dd/yyyy @ h:mm a'}}</span></div>
<div class="sentlog-item-recipient">{{itm.RecipientName}} &lt;{{itm.Email}}&gt;</div>
<div class="sentlog-item-response"><span>{{itm.LastResponse}}</span></div>
</li>
<li class="message-list-info" ng-show="log.busy">Loading data...</li>
</ul>
</div>

View File

@@ -0,0 +1,46 @@
<div class="dropdown gt-dropdown">
<button class="btn btn-default gtms-dropdown-toggle form-control" type="button">
<span>{{buttonTitle}}</span>
<span class="caret"></span>
</button>
<ul class="gt-dropdown dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<li ng-if="multiple" role="presentation">
<a ng-click="aCheckAllClick($event)">
<input type="checkbox" ng-model="$parent.allChecked" ng-click="iClick($event)"> {{ allChecked ? 'Uncheck All' : 'Check All' }}
</a>
</li>
<li ng-if="multiple" role="presentation" class="divider"></li>
<!-- multiple mode -->
<li ng-if="multiple && groupedItems" role="presentation" class="dropdown-header" ng-repeat-start="(optGroup, opts) in groupedItems">{{optGroup}}</li>
<li ng-if="multiple && groupedItems" role="presentation" ng-repeat-end ng-repeat="itm in opts">
<a role="menuitem" tabindex="-1" ng-click="aClick($event, itm)">
<input value="{{itm.value}}" ng-model="itm.checked" type="checkbox" name="{{inpName}}" ng-click="iClick($event)"> {{itm.label}}</a>
</li>
<li ng-if="multiple && items" role="presentation" ng-repeat="itm in items">
<a role="menuitem" tabindex="-1" ng-click="aClick($event, itm)">
<input value="{{itm.value}}" ng-model="itm.checked" type="checkbox" name="{{inpName}}" ng-click="iClick($event)"> {{itm.label}}</a>
</li>
<!-- single -->
<li ng-if="!multiple">
<a role="menuitem" tabindex="-1" ng-click="raNullClick($event)">
<input value="" ng-model="$parent.singleResult" type="radio"> {{defaultButtonTitle}}</a>
</li>
<li ng-if="!multiple && groupedItems" role="presentation" class="dropdown-header" ng-repeat-start="(optGroup, opts) in groupedItems">{{optGroup}}</li>
<li ng-if="!multiple && groupedItems" ng-repeat-end ng-repeat="itm in opts">
<a role="menuitem" tabindex="-1" ng-click="raClick($event, itm)">
<input value="{{itm.value}}" ng-model="$parent.$parent.singleResult" ng-click="raInpClick($event)" type="radio"> {{itm.label}}</a>
</li>
<li ng-if="!multiple && items" role="presentation" ng-repeat="itm in items">
<a role="menuitem" tabindex="-1" ng-click="raClick($event, itm)">
<input value="{{itm.value}}" ng-model="$parent.$parent.singleResult" ng-click="raInpClick($event)" type="radio"> {{itm.label}}</a>
</li>
</ul>
</div>

View File

@@ -0,0 +1,46 @@
<div class="dropdown gt-select">
<button class="btn btn-default gtms-dropdown-toggle form-control" type="button">
<span>{{buttonTitle}}</span>
<span class="caret"></span>
</button>
<ul class="gt-select dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<li ng-if="multiple" role="presentation">
<a ng-click="aCheckAllClick($event)">
<input type="checkbox" ng-model="$parent.allChecked" ng-click="iClick($event)"> {{ allChecked ? 'Uncheck All' : 'Check All' }}
</a>
</li>
<li ng-if="multiple" role="presentation" class="divider"></li>
<!-- multiple mode -->
<li ng-if="multiple && groupedItems" role="presentation" class="dropdown-header" ng-repeat-start="(optGroup, opts) in groupedItems">{{optGroup}}</li>
<li ng-if="multiple && groupedItems" role="presentation" ng-repeat-end ng-repeat="itm in opts">
<a role="menuitem" tabindex="-1" ng-click="aClick($event, itm)">
<input value="{{itm.value}}" ng-model="itm.checked" type="checkbox" name="{{inpName}}" ng-click="iClick($event)"> {{itm.label}}</a>
</li>
<li ng-if="multiple && items" role="presentation" ng-repeat="itm in items">
<a role="menuitem" tabindex="-1" ng-click="aClick($event, itm)">
<input value="{{itm.value}}" ng-model="itm.checked" type="checkbox" name="{{inpName}}" ng-click="iClick($event)"> {{itm.label}}</a>
</li>
<!-- single -->
<li ng-if="!multiple">
<a role="menuitem" tabindex="-1" ng-click="raNullClick($event)">
<input value="" ng-model="$parent.singleResult" type="radio"> {{defaultButtonTitle}}</a>
</li>
<li ng-if="!multiple && groupedItems" role="presentation" class="dropdown-header" ng-repeat-start="(optGroup, opts) in groupedItems">{{optGroup}}</li>
<li ng-if="!multiple && groupedItems" ng-repeat-end ng-repeat="itm in opts">
<a role="menuitem" tabindex="-1" ng-click="raClick($event, itm)">
<input value="{{itm.value}}" ng-model="$parent.$parent.singleResult" ng-click="raInpClick($event)" type="radio"> {{itm.label}}</a>
</li>
<li ng-if="!multiple && items" role="presentation" ng-repeat="itm in items">
<a role="menuitem" tabindex="-1" ng-click="raClick($event, itm)">
<input value="{{itm.value}}" ng-model="$parent.$parent.singleResult" ng-click="raInpClick($event)" type="radio"> {{itm.label}}</a>
</li>
</ul>
</div>

View File

@@ -0,0 +1,34 @@
<div class="container" ng-controller="LoginCtrl">
<form class="form-signin">
<h2 class="form-signin-heading">G-Lock EasyMail 7</h2>
<div ng-show="selectServer">
<div class="input-group">
<input type="text" class="form-control" placeholder="localhost" ng-model="conn.host">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" tabindex="-1">
<span class="caret"></span>
</button>
<ul class="dropdown-menu pull-right" role="menu">
<li ng-repeat="h in savedHosts"><a ng-click="loadHost($index)"><strong>{{h.email}}</strong> @ {{h.host}}</a></li>
</ul>
</div>
</div>
<hr class="hr">
</div>
<input type="text" class="form-control top-el" placeholder="Username" value="" autofocus ng-model="conn.email">
<input type="password" class="form-control bottom-el" placeholder="Password" value="" ng-model="conn.password">
<label class="checkbox">
<input type="checkbox" ng-model="remember"> Remember me
</label>
<div ng-show="error" class="alert alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<strong>Error!</strong> {{error}}
</div>
<button class="btn btn-md btn-primary btn-block" type="button" ng-click="signIn()">Sign in</button>
</form>
</div>

View File

@@ -0,0 +1,30 @@
<div class="modal-header">
<button type="button" class="close" ng-click="close()" aria-hidden="true">&times;</button>
<h4 class="modal-title">Select a File to Upload</h4>
</div>
<div class="modal-body">
<table class="em-table-fixed em-table-upload">
<tbody>
<tr ng-repeat="f in files">
<td>{{f.fileName}}</td>
<td>
<div class="progress progress-striped" ng-class="{'em-progress-bar-fallback': (!f.progressEnabled && f.status == 'uploading'), 'em-progress-bar-fallback-done': (!f.progressEnabled && f.status == 'done'), 'active': (f.progressEnabled && f.status == 'uploading') }">
<div class="progress-bar" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100" style="width: {{f.uploadedPct}}%">
<span class="sr-only">{{f.uploadedPct}}% Complete</span>
</div>
</div>
</td>
<td>{{f.status}}</td>
</tr>
</tbody>
</table>
<div class="file-upload-dropzone">
Drop Files here or <div grf-upload-button="1" class="btn btn-default" id="choose-files">Click to Add</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="close()">Done</button>
</div>

View File

@@ -0,0 +1,18 @@
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" ng-click="toggleSelect()" ng-disabled="disabled" ng-class="{'error': !valid()}">
{{header}} <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li>
<input class="form-control input-sm" type="text" ng-model="searchText.label" autofocus="autofocus" placeholder="Filter" />
</li>
<li ng-show="multiple" role="presentation" class="">
<button class="btn btn-link btn-xs" ng-click="checkAll()" type="button"><i class="glyphicon glyphicon-ok"></i> Check all</button>
<button class="btn btn-link btn-xs" ng-click="uncheckAll()" type="button"><i class="glyphicon glyphicon-remove"></i> Uncheck all</button>
</li>
<li ng-repeat="i in items | filter:searchText">
<a ng-click="select(i); focus()">
<i class='glyphicon' ng-class="{'glyphicon-ok': i.checked, 'empty': !i.checked}"></i> {{i.label}}</a>
</li>
</ul>
</div>

View File

@@ -0,0 +1,29 @@
<div ng-controller="EmailsCtrl">
<div class="row split-view">
<div class="col-sm-6" id="messages-list-wrap">
<ul class="messages-list" infinite-scroll='emails.nextPage()' infinite-scroll-disabled='emails.busy' infinite-scroll-distance='1' infinite-scroll-box="messages-list-wrap">
<li ng-repeat="eml in emails.items" ng-click="emlClick(eml)" eml-id="{{eml.ID}}" ng-class="{'active': eml.ID == emails.activeItem}">
<table>
<tr>
<td><span class="message-subject">{{eml.Subject}}</span></td>
<td><span class="message-date">{{eml.CreateTime | date:'MM/dd/yyyy @ h:mm a'}}</span></td>
</tr>
<tr>
<td>
<span ng-repeat="g in eml.resGroupList" class="message-template">{{g.GroupName}}</span>
</td>
<td ng-repeat="a in eml.resAccountList">
<span class="message-group">{{a.AccountName}}</span>
</td>
</tr>
</table>
<span class="message-links"><a href="#/workplaces/{{wpid}}/outbox/{{eml.ID}}/log" em-nobubble>{{eml.StatusMessage}}</a> | <a href="#" class="text-danger" ng-click="emDelete(eml)" em-nobubble>Delete</a></span>
<span class="message-links pull-right"><a href="#/workplaces/{{wpid}}/outbox/{{eml.ID}}/processed" em-nobubble>Processed: {{eml.Processed}}</a> | <a href="#/workplaces/{{wpid}}/outbox/{{eml.ID}}/sent" em-nobubble>Sent: {{eml.Sent}}</a> | <a href="#/workplaces/{{wpid}}/outbox/{{eml.ID}}/failed" em-nobubble>Failed: {{eml.Failed}}</a></span>
</li>
<li class="message-list-info" ng-show="emails.busy">Loading data...</li>
<li class="message-list-info" ng-show="!emails.items.length && emails.noMoreData">No emails here yet</li>
</ul>
</div>
<div class="col-sm-6" id="item-details" ui-view="itemdetails"></div>
</div>
</div>

View File

@@ -0,0 +1,8 @@
<div class="container">
<div id="contentsidebar" class="col-sm-2 gl-sidebar hide-xs-only" ui-view="contentsidebar">
</div>
<div id="contentmain" class="col-xs-12 col-sm-10" ui-view="contentmain">
</div>
</div>

View File

@@ -0,0 +1,29 @@
<div ng-controller="TemplatesCtrl">
<div class="row split-view">
<div class="col-md-6 col-sm-6" id="messages-list-wrap">
<ul class="messages-list" infinite-scroll='templates.nextPage()' infinite-scroll-disabled='templates.busy' infinite-scroll-distance='1' infinite-scroll-box="messages-list-wrap">
<li ng-repeat="tpl in templates.items" ng-click="tplClick(tpl)" ng-class="{'active': tpl.ID == templates.activeItem}">
<table>
<tr>
<td><span class="message-subject">{{tpl.Subject}}</span></td>
<td><span class="message-date">{{tpl.ModTime | date:'MM/dd/yyyy @ h:mm a'}}</span></td>
</tr>
<tr>
<td ng-repeat="g in tpl.GroupList">
<span class="message-template">{{g.GroupName}}</span>
</td>
<td ng-repeat="a in tpl.AccountList">
<span class="message-group">{{a.AccountName}}</span>
</td>
</tr>
</table>
<span class="message-links" ng-if="sub !== 'trash'"><a href="#/workplaces/{{workplace.ID}}/templates/{{tpl.ID}}/edit" em-nobubble>Edit Template</a> | <a ng-click="tplCreateMsg($event, tpl)">Create New Message</a> | <a class="text-danger" ng-click="tplDelete($event, tpl)">Delete</a></span>
<span class="message-links" ng-if="sub == 'trash'"><a ng-click="tplRestore($event, tpl)">Restore</a> | <a class="text-danger" ng-click="tplDelete($event, tpl)">Delete</a></span>
</li>
<li class="message-list-info" ng-show="templates.busy">Loading data...</li>
<li class="message-list-info" ng-show="!templates.items.length && templates.noMoreData">No templates here yet</li>
</ul>
</div>
<div class="col-md-6 col-sm-6" ng-class="{ 'show': showPreview }" id="preview-container"></div>
</div>
</div>

View File

@@ -0,0 +1,19 @@
<div class="container" ng-controller="TopToolbarCtrl">
<div class="top-toolbar row">
<div class="col-md-2 col-sm-2 col-sm-2">
<div class="btn-group btn-page-main">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
Console <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="#/wp/1/console">Console</a></li>
<li><a href="#/workplaces/{{workplace.ID}}/outbox">Emails</a></li>
<li><a href="#/workplaces/{{workplace.ID}}/contacts">Contacts</a></li>
</ul>
</div>
</div>
<div class="col-md-10 col-sm-10 col-sm-10">
</div>
</div>
</div>
<hr class="toolbar-hr">

View File

@@ -0,0 +1,40 @@
<div class="container top-toolbar" ng-controller="TopToolbarCtrl">
<div class="row">
<div class="col-xs-12">
<div class="btn-group btn-page-main">
<button type="button" class="btn btn-default gt-dropdown-toggle" data-toggle="dropdown">
{{section | capitalize}} <span ng-if="subSection" class="show-xs-only-inline dvdr">{{subSection}}</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu contacts-mobile-menu-top" role="menu">
<li>
<a href="#/workplaces/{{workplace.ID}}/outbox">Emails</a>
</li>
<li>
<a href="#/workplaces/{{workplace.ID}}/contacts">Contacts</a>
<!--- mobile menu -->
<ul class="nav show-xs-only">
<li>
<a href="#">My Databases</a>
<ul class="nav">
<li ng-class="{'active': g.ID == gid}" ng-repeat="g in groups.db"><a href="#/workplaces/{{wpid}}/contacts/{{g.placement}}/{{g.ID}}">{{g.GroupName}}</a></li>
</ul>
</li>
<li>
<a href="#">My Groups</a>
<ul class="nav">
<li ng-class="{'active': g.ID == gid}" ng-repeat="g in groups.local"><a href="#/workplaces/{{wpid}}/contacts/{{g.placement}}/{{g.ID}}">{{g.GroupName}}</a></li>
</ul>
</li>
</ul>
<!--- /mobile menu -->
</li>
</ul>
</div>
<div class="toolbar-separator"></div>
<!-- <button id="gl-btn-compose" type="button" class="hide-xs-only-inline btn btn-success btn-sm" ng-click="compose()">Compose</button> -->
<!-- <button ng-class="{'active': showExclusionList}" class="hide-xs-only-inline btn btn-default" ng-click="toggleExclusionList()">Show Exclusion List</button> -->
</div>
</div>
</div>
<hr class="toolbar-hr">

View File

@@ -0,0 +1,20 @@
<div class="container" ng-controller="TopToolbarCtrl">
<div class="top-toolbar">
<div class="row">
<div class="col-md-9 col-sm-9">
<h4>
<ol class="breadcrumb" ng-show="itemParams">
<li><a href="#/workplaces/{{workplace.ID}}/{{itemParams.root}}">{{itemParams.root | capitalize}}</a></li>
<li ng-show="itemParams.folder"><a href="#/workplaces/{{workplace.ID}}/{{itemParams.root}}/{{itemParams.folder}}">{{itemParams.folder}}</a></li>
<li class="active">{{itemParams.item.Subject}}</li>
</ol>
</h4>
</div>
<div class="col-md-3 col-sm-3">
<alert ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)">{{alert.msg}}</alert>
</div>
</div>
</div>
</div>
<hr class="toolbar-hr">

View File

@@ -0,0 +1,46 @@
<div class="container top-toolbar" ng-controller="TopToolbarCtrl">
<div class="row">
<div class="col-xs-12">
<div class="btn-group btn-page-main">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
{{uiSection}} <span class="show-xs-only-inline dvdr" > {{section | capitalize}} <span ng-if="subSection" class="dvdr">{{subSection}}</span></span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li>
<a href="#/workplaces/{{workplace.ID}}/outbox">Emails</a>
<!--- mobile menu -->
<ul class="nav show-xs-only" role="menu">
<li>
<a href="#/workplaces/{{workplace.ID}}/templates">Templates</a>
<ul class="nav">
<li ng-repeat="(catId, cat) in templateCats"><a href="#/workplaces/{{workplace.ID}}/templates/folder/{{catId}}"><span class="glyphicon glyphicon-folder-close"></span> {{cat}}</a></li>
<li sub="trash"><a href="#/workplaces/{{workplace.ID}}/templates/trash"><span class="glyphicon glyphicon-trash"></span> Trash</a></li>
</ul>
</li>
<li class="divider"></li>
<li>
<a href="#/workplaces/{{workplace.ID}}/drafts">Drafts</a>
<ul class="nav">
<li><a href="#/workplaces/{{workplace.ID}}/drafts/trash"><span class="glyphicon glyphicon-trash"></span> Trash</a></li>
</ul>
</li>
<li class="divider"></li>
<li>
<a href="#/workplaces/{{workplace.ID}}/outbox">Outbox</a>
<ul class="nav">
<li><a href="#/workplaces/{{workplace.ID}}/outbox/trash"><span class="glyphicon glyphicon-trash"></span> Trash</a></li>
</ul>
</li>
</ul>
<!--- /mobile menu -->
</li>
<li><a href="#/workplaces/{{workplace.ID}}/contacts">Contacts</a></li>
</ul>
</div>
<div class="toolbar-separator"></div>
<button id="gl-btn-compose" type="button" class="hide-xs-only-inline btn btn-success btn-sm" ng-click="compose()">Compose</button>
</div>
</div>
</div>
<hr class="toolbar-hr">

View File

@@ -0,0 +1,49 @@
<div class="container top-toolbar" ng-controller="TopToolbarCtrl">
<div class="row">
<div class="col-xs-12">
<div class="btn-group btn-page-main">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
{{uiSection}} <span class="show-xs-only-inline dvdr" > {{section | capitalize}} <span ng-if="subSection" class="dvdr">{{subSection}}</span></span> <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li>
<a href="#/workplaces/{{workplace.ID}}/outbox">Emails</a>
<!--- mobile menu -->
<ul class="nav show-xs-only" role="menu">
<li>
<a href="#/workplaces/{{workplace.ID}}/templates">Templates</a>
<ul class="nav">
<li ng-repeat="(catId, cat) in templateCats"><a href="#/workplaces/{{workplace.ID}}/templates/folder/{{catId}}"><span class="glyphicon glyphicon-folder-close"></span> {{cat}}</a></li>
<li sub="trash"><a href="#/workplaces/{{workplace.ID}}/templates/trash"><span class="glyphicon glyphicon-trash"></span> Trash</a></li>
</ul>
</li>
<li class="divider"></li>
<li>
<a href="#/workplaces/{{workplace.ID}}/drafts">Drafts</a>
<ul class="nav">
<li><a href="#/workplaces/{{workplace.ID}}/drafts/trash"><span class="glyphicon glyphicon-trash"></span> Trash</a></li>
</ul>
</li>
<li class="divider"></li>
<li>
<a href="#/workplaces/{{workplace.ID}}/outbox">Outbox</a>
<ul class="nav">
<li><a href="#/workplaces/{{workplace.ID}}/outbox/trash"><span class="glyphicon glyphicon-trash"></span> Trash</a></li>
</ul>
</li>
</ul>
<!--- /mobile menu -->
</li>
<li><a href="#/workplaces/{{workplace.ID}}/contacts">Contacts</a></li>
</ul>
</div>
<div class="toolbar-separator"></div>
<button id="gl-btn-compose" type="button" class="hide-xs-only-inline btn btn-success btn-sm" ng-click="compose()">Compose</button>
<div class="hide-xxs-only-inline">
<button ng-show="emlCanBeSent" type="button" ng-click="startSending()" class="btn btn-primary" ng-click="startSending">Start sending</button>
<button ng-show="emlCanBeStopped" ng-click="stopSending()" type="button" class="btn btn-default">Stop</button>
</div>
</div>
</div>
</div>
<hr class="toolbar-hr">

View File

@@ -0,0 +1,21 @@
<div class="container">
<h3 style="margin-top: 80px;">Select workplace</h3>
<table class="table table-bordered">
<thead>
<tr>
<th>Workplace name</th>
<th>Description</th>
<th>Created</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="wp in workplaces">
<td><a href="#/workplaces/{{wp.ID}}/outbox">{{wp.WPName}}</a></td>
<td>{{wp.Description}}</td>
<td>{{wp.Created}}</td>
</tr>
</tbody>
</table>
</div>

View File

@@ -0,0 +1,7 @@
<div id="sub-head" ui-view="topbar">
</div>
<div id="main" class="content-view" ui-view="content">
</div>

View File

@@ -0,0 +1,30 @@
TSynJSONTreeView
================
By *EMartin* (Esteban Martin).
# Presentation
`TSynJSONTreeView` is a treeview supporting mORMot's JSON document, the allowed tasks are:
- edit a node
- delete a node
- add a node
- save to file
- load from file
- generate JSON to string variable
- implement a custom input for edit/insert node
# Forum Thread
See http://synopse.info/forum/viewtopic.php?id=3451
# TODO
- FPC support (I just use Windows)
- Developed with Delphi 7, not tested with any other Delphi version.
# License
Feel free to use and/or append to Lib and extend if needed.

View File

@@ -0,0 +1 @@
{"HandleUserAuthentication":true,"HTTPServer":{"HttpQueueLength":1000,"MaxBandWidth":0,"MaxConnections":0,"BindPort":"8888","Authentication":"adDefault","EnableCORS":false,"ThreadCount":32,"Https":false,"HttpSysQueueName":"ARISQueue","WebSocketPassword":""},"HTTPServerWS":{"HttpQueueLength":0,"MaxBandWidth":0,"MaxConnections":0,"BindPort":"8889","Authentication":"adDefault","EnableCORS":false,"ThreadCount":0,"Https":false,"HttpSysQueueName":"ARISWSQueue","WebSocketPassword":"Bsyv1NapccWDNwPVgcQ+fU+pKhed5PGUVUT4h0Im+E07aA=="},"Log":{"Ident":0,"Level":["sllNone","sllInfo","sllDebug","sllTrace","sllWarning","sllError","sllEnter","sllLeave","sllLastError","sllException","sllExceptionOS","sllMemory","sllStackTrace","sllFail","sllSQL","sllCache","sllResult","sllDB","sllHTTP","sllClient","sllServer","sllServiceCall","sllServiceReturn","sllUserAuth","sllCustom1","sllCustom2","sllCustom3","sllCustom4","sllNewRun","sllDDDError","sllDDDInfo","sllMonitoring"],"LevelStackTrace":["sllError","sllLastError","sllException","sllExceptionOS","sllStackTrace","sllFail","sllDDDError"],"DestinationPath":"D:\\TecnoVoz\\Log\\","DefaultExtension":".synlog","IncludeComputerNameInFileName":false,"CustomFileName":"ARIS","ArchivePath":"D:\\TecnoVoz\\Log\\Archive","ArchiveAfterDays":1,"BufferSize":4096,"PerThreadLog":"ptIdentifiedInOnFile","HighResolutionTimeStamp":false,"LocalTimeStamp":true,"WithUnitName":true,"AutoFlushTimeOut":0,"NoEnvironmentVariable":false,"NoFile":false,"RotateFileCount":10,"RotateFileSizeKB":262144,"RotateFileDailyAtHour":-1,"StackTraceLevel":30,"StackTraceUse":"stOnlyAPI","FileExistsAction":"acAppend","EndOfLineCRLF":false},"SMTP":{"Authentication":"","Port":"25","Server":"tvzserver","SSLVersion":"sslvNone","UserName":"emartin","Password":"GaZZ0opaJqvttSQ="},"SQLDBConnections":{"ConnectionTimeoutMinutes":10,"Count":9,"ConnectionDefinitions":[{"DatabaseName":"DRIVER={ODBC Driver 11 for SQL Server};UID=USER;PWD=D3rNfXg2ug==;Server=DBEngines;DataBase=TEST;","DBMS":"dMSSQL","Kind":"TODBCConnectionProperties","Name":"TEST_MSSQL","ServerName":"","AllowGetObjects":false,"Description":"Conexi<78>n a la m<>quina virtual de bases de datos.","Properties":"","UserName":"TEST_USER","Password":""},{"DatabaseName":"FirebirdTest1","DBMS":"dFirebird","Kind":"TSQLDBZEOSConnectionProperties","Name":"APPROACH","ServerName":"firebird-2.5://DBEngines","AllowGetObjects":false,"Description":"","Properties":"hard_commit=true","UserName":"SYSDBA","Password":"D3rNfXg2ug=="},{"DatabaseName":"FirebirdTest2","DBMS":"dFirebird","Kind":"TSQLDBZEOSConnectionProperties","Name":"SCHEDULER","ServerName":"firebird-2.5://DBEngines","AllowGetObjects":false,"Description":"Any description with accented characters <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>","Properties":"hard_commit=true","UserName":"SYSDBA","Password":"D3rNfXg2ug=="}]},"LastElement":true}

View File

@@ -0,0 +1,15 @@
program SynJSONTVEditor;
uses
Forms,
fMain in 'fMain.pas' {frmJSONEditor},
SynJSONTreeView in 'SynJSONTreeView.pas',
fLevel in 'fLevel.pas' {frmLevel};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TfrmJSONEditor, frmJSONEditor);
Application.Run;
end.

Some files were not shown because too many files have changed in this diff Show More