source upload
@@ -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>
|
@@ -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.
|
@@ -0,0 +1,4 @@
|
||||
key.store=my-release-key.keystore
|
||||
key.alias=alias_name
|
||||
key.store.password=likjes69
|
||||
key.alias.password=likjes69
|
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 138 KiB |
After Width: | Height: | Size: 49 KiB |
@@ -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
|
@@ -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>
|
@@ -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
|
@@ -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 \
|
@@ -0,0 +1,6 @@
|
||||
/** Automatically generated file. DO NOT MODIFY */
|
||||
package com.kredix;
|
||||
|
||||
public final class BuildConfig {
|
||||
public final static boolean DEBUG = true;
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
@@ -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.
|
@@ -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.
|
||||
|
||||
|
@@ -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.
|
@@ -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.
|
@@ -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.
|
@@ -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>
|
@@ -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.
|
||||
|
@@ -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.
|
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 8.3 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">mORMot</string>
|
||||
</resources>
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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
|
||||
|
@@ -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.
|
@@ -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
|
|
@@ -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.
|
@@ -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)
|
@@ -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
|
@@ -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
|
@@ -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.
|
||||
|
@@ -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.
|
||||
|
@@ -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.
|
@@ -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.
|
@@ -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
|
@@ -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.
|
@@ -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
|
@@ -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.
|
@@ -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!
|
@@ -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.
|
@@ -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!
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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
|
@@ -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>© G-Lock Software</p>
|
||||
</div>
|
||||
</div></body>
|
||||
</html>
|
@@ -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;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
};
|
@@ -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;
|
||||
});
|
||||
|
@@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
@@ -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;
|
||||
});
|
@@ -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;
|
||||
});
|
@@ -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';
|
||||
};
|
@@ -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;
|
||||
});
|
||||
});
|
@@ -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;
|
||||
});
|
||||
});
|
@@ -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>
|
@@ -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>
|
@@ -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>
|
@@ -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"><{{c.Email}}></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>
|
@@ -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>
|
@@ -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>
|
@@ -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>
|
@@ -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>
|
@@ -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>
|
@@ -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}} <{{itm.Email}}></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>
|
@@ -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>
|
@@ -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>
|
@@ -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">×</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>
|
@@ -0,0 +1,30 @@
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" ng-click="close()" aria-hidden="true">×</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>
|
@@ -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>
|
@@ -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>
|
@@ -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>
|
@@ -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>
|
@@ -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">
|
@@ -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">
|
@@ -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">
|
@@ -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">
|
@@ -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">
|
@@ -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>
|
@@ -0,0 +1,7 @@
|
||||
<div id="sub-head" ui-view="topbar">
|
||||
</div>
|
||||
|
||||
<div id="main" class="content-view" ui-view="content">
|
||||
|
||||
|
||||
</div>
|
@@ -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.
|
@@ -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}
|
@@ -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.
|