sugoi internally added
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
package sugoi.form;
|
||||
|
||||
class FieldSet
|
||||
{
|
||||
public var name:String;
|
||||
public var form:Form;
|
||||
public var label:String;
|
||||
public var visible:Bool;
|
||||
public var elements:Array<FormElement<Dynamic>>;
|
||||
|
||||
public function new(?name:String = "", ?label:String = "", ?visible:Bool = true)
|
||||
{
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.visible = visible;
|
||||
|
||||
elements = [];
|
||||
}
|
||||
|
||||
public function getOpenTag()
|
||||
{
|
||||
return "<fieldset id=\""+form.name+"_"+name+"\" name=\""+form.name+"_"+name+"\" class=\""+(visible?"":"fieldsetNoDisplay")+"\" ><legend>" + label + "</legend>";
|
||||
}
|
||||
|
||||
public function getCloseTag()
|
||||
{
|
||||
return "</fieldset>";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,578 @@
|
||||
package sugoi.form;
|
||||
|
||||
import haxe.crypto.Md5;
|
||||
import sugoi.form.elements.Input;
|
||||
import sugoi.i18n.translator.ITranslator;
|
||||
import sugoi.form.elements.*;
|
||||
import sugoi.Web;
|
||||
import sys.db.Types;
|
||||
import sys.db.Object;
|
||||
import sys.db.Manager;
|
||||
import sys.db.TableInfos;
|
||||
|
||||
enum FormMethod
|
||||
{
|
||||
GET;
|
||||
POST;
|
||||
}
|
||||
|
||||
class Form
|
||||
{
|
||||
public var id:String;
|
||||
public var name:String;
|
||||
public var action:String;
|
||||
public var method:FormMethod;
|
||||
public var elements:Array<FormElement<Dynamic>>;
|
||||
public var fieldsets:Map<String,FieldSet>;
|
||||
public var forcePopulate:Bool; //the form is populated by web params if isValid() is called
|
||||
public var submitButton:FormElement<String>;
|
||||
private var extraErrors:List<String>;
|
||||
public var requiredClass:String;
|
||||
public var requiredErrorClass:String;
|
||||
public var invalidErrorClass:String;
|
||||
public var labelRequiredIndicator:String;
|
||||
public var defaultClass : String;
|
||||
public var multipart:Bool;
|
||||
|
||||
public static var translator : ITranslator;
|
||||
|
||||
//submit button
|
||||
public var submitButtonLabel:String;
|
||||
public var autoGenSubmitButton:Bool; //add a submit button automatically
|
||||
|
||||
//conf
|
||||
public static var USE_TWITTER_BOOTSTRAP = true;
|
||||
public static var USE_DATEPICKER = true; //http://eonasdan.github.io/bootstrap-datetimepicker/
|
||||
|
||||
public var toString : Void->String; //you can change the way the form is rendered
|
||||
|
||||
public function new(name:String, ?action:String, ?method:FormMethod)
|
||||
{
|
||||
requiredClass = "formRequired";
|
||||
requiredErrorClass = "formRequiredError";
|
||||
invalidErrorClass = "formInvalidError";
|
||||
labelRequiredIndicator = " *";
|
||||
defaultClass = Form.USE_TWITTER_BOOTSTRAP ? "form-horizontal":"";
|
||||
|
||||
forcePopulate = true;
|
||||
multipart = false;
|
||||
autoGenSubmitButton = true;
|
||||
|
||||
this.id = name;
|
||||
this.name = name;
|
||||
|
||||
if (action == null) {
|
||||
this.action = Web.getURI();
|
||||
}else {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
this.method = (method == null) ? FormMethod.POST : method;
|
||||
|
||||
elements = new Array();
|
||||
extraErrors = new List();
|
||||
fieldsets = new Map();
|
||||
addFieldset("__default", new FieldSet("__default", "Default", false));
|
||||
|
||||
addElement(new CSRFProtection());
|
||||
|
||||
toString = render;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a form element to the form
|
||||
* @param element
|
||||
* @param ?fieldSetKey Add it to a specific fieldset
|
||||
* @param ?index which index do u want to push it
|
||||
* @return
|
||||
*/
|
||||
public function addElement(element:FormElement<Dynamic>,?index:Int, ?fieldSetKey:String = "__default"):FormElement<Dynamic>
|
||||
{
|
||||
element.parentForm = this;
|
||||
if (index != null) {
|
||||
var out = elements.slice(0, index);
|
||||
out = out.concat([element]);
|
||||
out = out.concat(elements.slice(index));
|
||||
elements = out;
|
||||
}else {
|
||||
elements.push(element);
|
||||
}
|
||||
|
||||
// add it to a group if requested
|
||||
if (fieldSetKey != null){
|
||||
if (!fieldsets.exists(fieldSetKey)) throw "No fieldset '" + fieldSetKey + "' exists in '" + name + "' form.";
|
||||
fieldsets.get(fieldSetKey).elements.push(element);
|
||||
}
|
||||
|
||||
//if ( Std.is(element, RichtextWym) )
|
||||
//wymEditorCount++;
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
public function removeElement(element:FormElement<Dynamic>):Bool
|
||||
{
|
||||
if ( elements.remove(element) )
|
||||
{
|
||||
element.parentForm= null;
|
||||
for ( fs in fieldsets )
|
||||
{
|
||||
fs.elements.remove(element);
|
||||
}
|
||||
|
||||
//if ( Std.is(element, RichtextWym) )
|
||||
//wymEditorCount--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function setSubmitButton(el:FormElement<String>):FormElement<String>
|
||||
{
|
||||
submitButton = el;
|
||||
submitButton.parentForm = this;
|
||||
return el;
|
||||
}
|
||||
|
||||
public function addFieldset(fieldSetKey:String, fieldSet:FieldSet)
|
||||
{
|
||||
fieldSet.form = this;
|
||||
fieldsets.set(fieldSetKey, fieldSet);
|
||||
}
|
||||
|
||||
public function getFieldsets():Map<String,FieldSet>
|
||||
{
|
||||
return fieldsets;
|
||||
}
|
||||
|
||||
public function getLabel( elementName : String ) : String
|
||||
{
|
||||
return getElement( elementName ).getLabel();
|
||||
}
|
||||
|
||||
public function getElement(name:String):FormElement<Dynamic> {
|
||||
if (name == null || name=='') throw "Element name is null";
|
||||
for (element in elements){
|
||||
if (element.name == name) return element;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function removeElementByName(name:String) {
|
||||
var e = getElement(name);
|
||||
if (e != null) removeElement(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the typed value of a form element.
|
||||
* The value can be of any type !
|
||||
*
|
||||
* @param elementName
|
||||
* @return
|
||||
*/
|
||||
public function getValueOf(elementName:String):Dynamic {
|
||||
return getElement(elementName).value;
|
||||
}
|
||||
|
||||
public function getElementTyped<T>(name:String, type:Class<T>):T{
|
||||
var o:T = cast(getElement(name));
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* return datas contained in current form elements
|
||||
* @return
|
||||
*/
|
||||
public function getData():Map<String,Dynamic>
|
||||
{
|
||||
var data = new Map<String,Dynamic>();
|
||||
for (element in getElements())
|
||||
{
|
||||
if (element.name == null) throw "Element has no name : "+element.toString();
|
||||
data.set( element.name,element.getValue() );
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* return datas in an anonymous object
|
||||
* @return
|
||||
*/
|
||||
public function getDatasAsObject():Dynamic {
|
||||
|
||||
var data = { };
|
||||
for ( el in elements) {
|
||||
Reflect.setField(data, el.name, el.value);
|
||||
}
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* populate Form from anonymous object or if null from web params.
|
||||
* @param custom
|
||||
*/
|
||||
public function populate(?custom:Dynamic){
|
||||
if (custom != null) {
|
||||
//from object
|
||||
for (element in getElements()) {
|
||||
var n = element.name;
|
||||
var v = Reflect.field(custom, n);
|
||||
if (v != null)
|
||||
element.value = v;
|
||||
}
|
||||
} else {
|
||||
for (element in getElements()) {
|
||||
//populate from web params
|
||||
element.populate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update a spod object from the content of the form
|
||||
* @param data
|
||||
* @param obj
|
||||
*/
|
||||
public function toSpod(obj:sys.db.Object) {
|
||||
if (!isValid()) throw "submitted form should be valid";
|
||||
var data = getData();
|
||||
|
||||
//if not new object, lock it
|
||||
var id = Std.parseInt(data.get("id"));
|
||||
if (id == 0) id = null;
|
||||
if (id != null) {
|
||||
obj.lock();
|
||||
}
|
||||
|
||||
for (f in data.keys()) {
|
||||
|
||||
//check if field was in the original form
|
||||
if (this.getElement(f) == null) throw "field '"+f+"' was not in the original form";
|
||||
var v = data.get(f);
|
||||
if (f == "id") continue;
|
||||
|
||||
//Values are already cleaned by each form elements when populated
|
||||
/*if (Std.is(v, String)) {
|
||||
v = StringTools.trim(v);
|
||||
if (v == "") v = null;
|
||||
}*/
|
||||
|
||||
//Debug : trace(f + " -> " + v+"<br>");
|
||||
try{
|
||||
Reflect.setProperty(obj, f, v);
|
||||
}catch (e:Dynamic){
|
||||
throw "Error '" + e+"' while setting value " + v + " to " + f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a form from any object
|
||||
* @param obj
|
||||
*/
|
||||
public static function fromObject(obj:Dynamic) {
|
||||
var form = new Form('fromObj');
|
||||
for (f in Reflect.fields(obj)) {
|
||||
var val = Reflect.field(obj, f);
|
||||
if (val == "") val = null;
|
||||
form.addElement(new sugoi.form.elements.StringInput(f, f, val));
|
||||
}
|
||||
return form;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a form from a spod object
|
||||
*/
|
||||
public static function fromSpod(obj:sys.db.Object) {
|
||||
|
||||
//generate a form name
|
||||
var cl = Type.getClass(obj);
|
||||
var name = Type.getClassName(cl);
|
||||
|
||||
var form = new Form("form"+Md5.encode(name));
|
||||
var ti = new TableInfos(Type.getClassName(Type.getClass(obj)));
|
||||
|
||||
//translator
|
||||
//var t = Form.translator;
|
||||
var t = new Map<String,String>();
|
||||
if (Reflect.hasField(cl, "getLabels")){
|
||||
t = Reflect.callMethod(cl, Reflect.getProperty(cl,"getLabels"),[]);
|
||||
}
|
||||
var label = function(s) return if (t.get(s) == null) s else t.get(s);
|
||||
|
||||
//get metas of this object
|
||||
var metas = haxe.rtti.Meta.getFields(Type.getClass(obj));
|
||||
|
||||
//loop on db object fields to create form elements
|
||||
for (f in ti.fields) {
|
||||
|
||||
var e : FormElement<Dynamic>;
|
||||
//field value
|
||||
var v :Dynamic = Reflect.field(obj, f.name);
|
||||
//trace( "field " + f.name+" of " + obj + " is " + v+"<br/>");
|
||||
|
||||
//meta of this field
|
||||
var meta :Dynamic = Reflect.field(metas, f.name);
|
||||
//trace(f.name+"=>" + meta + "<br/>");
|
||||
|
||||
//hide this field in forms
|
||||
if (meta!=null && Reflect.hasField(meta,'hideInForms')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//check if its a foreign key
|
||||
var rl = Lambda.filter(ti.relations, function(r) return r.key == f.name );
|
||||
var isNull = ti.nulls.get(f.name);
|
||||
|
||||
//foreign keys
|
||||
if (rl.length > 0 ) {
|
||||
|
||||
var r = rl.first();
|
||||
//trace(f.name + ' is a key for ' + r.key + "/"+r.prop);
|
||||
var objects = new List();
|
||||
|
||||
meta = Reflect.field(metas, r.prop);
|
||||
if (meta != null) {
|
||||
//trace(r.prop+"=>" + meta + "<br/>");
|
||||
if (meta.formPopulate != null) {
|
||||
//If @formPopulate() meta is set, use this function to populate select box.
|
||||
objects = Reflect.callMethod(obj, Reflect.field(obj,Std.string(meta.formPopulate[0])) , []);
|
||||
}
|
||||
|
||||
//if @hideInForms meta is set, hide the fields in the form
|
||||
if (meta!=null && Reflect.hasField(meta,'hideInForms')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
}else {
|
||||
//get all available values
|
||||
objects = r.manager.all(false).map(function(d) {
|
||||
return {
|
||||
label : d.toString(),
|
||||
value : Reflect.field(d,r.manager.table_keys[0])
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
e = new IntSelect(f.name, label(r.prop), Lambda.array(objects),v, !isNull);
|
||||
|
||||
}else {
|
||||
//not foreign key
|
||||
|
||||
switch (f.type) {
|
||||
case DId, DUId:
|
||||
e = new IntInput(f.name, "id", v, false);
|
||||
untyped e.inputType = ITHidden;
|
||||
|
||||
case DEncoded:
|
||||
e = new StringInput(f.name, label(f.name), v);
|
||||
|
||||
case DFlags(fl, auto):
|
||||
e = new Flags(f.name,label(f.name), Lambda.array(fl), Std.parseInt(v));
|
||||
|
||||
case DTinyInt, DUInt, DSingle, DInt:
|
||||
e = new IntInput(f.name, label(f.name) , v , !isNull);
|
||||
|
||||
case DFloat:
|
||||
e = new FloatInput(f.name, label(f.name), v, !isNull );
|
||||
|
||||
case DBool :
|
||||
e = new Checkbox(f.name, label(f.name), Std.string(v) == 'true');
|
||||
|
||||
case DString(n):
|
||||
e = new StringInput(f.name,label(f.name), v, !isNull ,null,"maxlength="+n);
|
||||
|
||||
case DTinyText, DSmallText, DText, DSerialized:
|
||||
e = new TextArea(f.name, label(f.name), v,!isNull);
|
||||
|
||||
case DTimeStamp, DDateTime:
|
||||
|
||||
if (USE_DATEPICKER) {
|
||||
|
||||
//WTF bugfix : the type is correct (Date) but is null when traced in DatePicker
|
||||
var d :Date = cast v;
|
||||
e = new DatePicker(f.name, label(f.name), d);
|
||||
untyped e.format = "LLLL";
|
||||
}else {
|
||||
e = new DateInput(f.name, label(f.name), v);
|
||||
}
|
||||
|
||||
case DDate :
|
||||
|
||||
if (USE_DATEPICKER) {
|
||||
//trace(f.name+" => " + v);
|
||||
//trace(Type.getClassName(Type.getClass(v)));
|
||||
|
||||
//WTF bugfix : the type is correct (Date) but is null when traced in DatePicker
|
||||
var d :Date = cast v;
|
||||
e = new DatePicker(f.name, label(f.name), d);
|
||||
untyped e.format = "LL";
|
||||
}else {
|
||||
e = new DateDropdowns(f.name, label(f.name), v);
|
||||
}
|
||||
|
||||
|
||||
case DEnum(name):
|
||||
e = new sugoi.form.elements.Enum(f.name, label(f.name), name, Std.parseInt(v), !isNull);
|
||||
|
||||
default :
|
||||
e = new StringInput(f.name, label(f.name) , "unknown field type : "+f.type+", value : "+v);
|
||||
}
|
||||
}
|
||||
|
||||
form.addElement(e);
|
||||
}
|
||||
return form;
|
||||
}
|
||||
|
||||
|
||||
public function clearData()
|
||||
{
|
||||
for (element in getElements()){
|
||||
element.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints form open tag <form ...>
|
||||
*/
|
||||
public function getOpenTag():String
|
||||
{
|
||||
//if there is a file input in the form, make it multipart
|
||||
for ( e in elements) {
|
||||
if (Type.getClass(e) == sugoi.form.elements.FileUpload || Type.getClass(e) == sugoi.form.elements.ImageUpload){
|
||||
multipart = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return '<form id="' + id + '" class="'+defaultClass+'" name="' + name + '" method="' + method +'" action="' + action +'" ' + (multipart?'enctype="multipart/form-data"':'') + ' >';
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints form close tag ...</form>
|
||||
*/
|
||||
public function getCloseTag():String
|
||||
{
|
||||
var s = new StringBuf();
|
||||
s.add('<div style="clear:both; height:0px;"> </div>');
|
||||
s.add('<input type="hidden" name="' + name + '_formSubmitted" value="true" /></form>');
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public function isValid():Bool
|
||||
{
|
||||
if (!isSubmitted()) return false;
|
||||
|
||||
populate();
|
||||
|
||||
var valid = true;
|
||||
|
||||
for (element in getElements()){
|
||||
//trace(element.name+" -> "+element.value+" : "+element.isValid()+"<br>");
|
||||
element.filter();
|
||||
if (!element.isValid()) valid = false;
|
||||
}
|
||||
if (extraErrors.length > 0) valid = false;
|
||||
return valid;
|
||||
}
|
||||
|
||||
public function checkToken() {
|
||||
return isValid();
|
||||
}
|
||||
|
||||
public function addError(error:String)
|
||||
{
|
||||
extraErrors.add(error);
|
||||
}
|
||||
|
||||
public function getErrorsList():List<String>
|
||||
{
|
||||
isValid();
|
||||
|
||||
var errors:List<String> = new List();
|
||||
|
||||
for(e in extraErrors)
|
||||
errors.add(e);
|
||||
|
||||
for (element in getElements())
|
||||
for (error in element.getErrors())
|
||||
errors.add(error);
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
public function getElements():Array<FormElement<Dynamic>>
|
||||
{
|
||||
return elements;
|
||||
}
|
||||
|
||||
public function isSubmitted():Bool
|
||||
{
|
||||
//if (multipart){
|
||||
//var req = sugoi.tools.Utils.getMultipart(1024 * 1024 * 12);
|
||||
//for ( r in req.keys() ) App.current.params.set(r, req.get(r));
|
||||
//}
|
||||
|
||||
return App.current.params.get(name + "_formSubmitted") == "true";
|
||||
}
|
||||
|
||||
public function getSubmittedValue():String
|
||||
{
|
||||
return App.current.params.get(name + "_formSubmitted");
|
||||
}
|
||||
|
||||
public function getErrors():String
|
||||
{
|
||||
if (!isSubmitted())
|
||||
return "";
|
||||
|
||||
var s:StringBuf = new StringBuf();
|
||||
var errors = getErrorsList();
|
||||
|
||||
if (errors.length > 0)
|
||||
{
|
||||
if (USE_TWITTER_BOOTSTRAP) s.add('<div class="alert alert-danger">');
|
||||
s.add("<ul class=\"formErrors\" >");
|
||||
for (error in errors)
|
||||
{
|
||||
s.add("<li>"+error+"</li>");
|
||||
}
|
||||
s.add("</ul>");
|
||||
if (USE_TWITTER_BOOTSTRAP) s.add('</div>');
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render form's HTML
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
|
||||
var s:StringBuf = new StringBuf();
|
||||
s.add(getOpenTag());
|
||||
|
||||
//errors
|
||||
if (isSubmitted())
|
||||
s.add(getErrors());
|
||||
|
||||
for (element in getElements())
|
||||
if (element != submitButton && element.internal == false)
|
||||
s.add("\t"+element.getFullRow()+"\n");
|
||||
|
||||
//submit button
|
||||
if (submitButton != null) {
|
||||
submitButton.parentForm = this;
|
||||
}else if(autoGenSubmitButton){
|
||||
submitButton = new Submit('submit', submitButtonLabel != null ? submitButtonLabel : 'OK');
|
||||
submitButton.parentForm = this;
|
||||
}
|
||||
if(submitButton!=null) s.add(submitButton.getFullRow());
|
||||
|
||||
s.add(getCloseTag());
|
||||
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
package sugoi.form;
|
||||
|
||||
import sugoi.form.filters.IFilter;
|
||||
import sugoi.form.validators.Validator;
|
||||
using StringTools;
|
||||
|
||||
class FormElement<T>
|
||||
{
|
||||
public var parentForm:Form;
|
||||
public var name:String;
|
||||
public var label:String;
|
||||
public var description:String;
|
||||
|
||||
//value can be any type : Int, Float, Enum...
|
||||
public var value:T;
|
||||
|
||||
public var required:Bool;
|
||||
public var errors:List<String>;
|
||||
public var attributes:String;
|
||||
public var active:Bool;
|
||||
|
||||
public var cssClass:String;
|
||||
public var inited:Bool;
|
||||
public var internal:Bool;
|
||||
|
||||
public var validators:List<Validator<T>>;
|
||||
public var filters:List<IFilter<T>>;
|
||||
|
||||
public function new()
|
||||
{
|
||||
active = true;
|
||||
errors = new List();
|
||||
validators = new List();
|
||||
filters = new List();
|
||||
inited = false;
|
||||
internal = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* apply all linked filter to the data
|
||||
*/
|
||||
public function filter() {
|
||||
for ( f in filters) {
|
||||
value = f.filter(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current value of the elements is valid
|
||||
*/
|
||||
public function isValid():Bool
|
||||
{
|
||||
errors.clear();
|
||||
|
||||
if (!active) return true;
|
||||
|
||||
if ( value == null && required ) {
|
||||
//required field is empty
|
||||
errors.add("<span class=\"formErrorsField\">\"" + ((label != null && label != "") ? label : name) + "\"</span> ne doit pas être vide.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value!=null) {
|
||||
//check validity
|
||||
if (!validators.isEmpty()){
|
||||
for (validator in validators)
|
||||
{
|
||||
if (!validator.isValid(value)) return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function init(){
|
||||
inited = true;
|
||||
}
|
||||
|
||||
public function addValidator(validator:Validator<T>){
|
||||
validators.add(validator);
|
||||
}
|
||||
|
||||
public function addFilter(filter:IFilter<T>) {
|
||||
filters.add(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the element with a value taken from the web params
|
||||
*/
|
||||
public function populate():Void
|
||||
{
|
||||
if (!inited) init();
|
||||
|
||||
var n = parentForm.name + "_" + name;
|
||||
var v = App.current.params.get(n);
|
||||
value = getTypedValue(v);
|
||||
|
||||
//Debug
|
||||
//trace("value of " + name +"("+n+") is " + v + ", typed :"+ value+"<br/>");
|
||||
}
|
||||
|
||||
/**
|
||||
* From string (web param) to typed value.
|
||||
* This method is in charge of cleaning the input which may be unsafe ( triming, escaping ...)
|
||||
*/
|
||||
public function getTypedValue(str:String):T{
|
||||
throw "getTypedValue() function not implemented in \""+name+"\"";
|
||||
}
|
||||
|
||||
public function getErrors():List<String>
|
||||
{
|
||||
isValid();
|
||||
|
||||
for (val in validators)
|
||||
for(err in val.errors)
|
||||
errors.add("<span class=\"formErrorsField\">" + label + "</span> : " + err);
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in HTML
|
||||
*/
|
||||
public function render():String
|
||||
{
|
||||
if (!inited) init();
|
||||
return Std.string(value);
|
||||
}
|
||||
|
||||
public function remove():Bool
|
||||
{
|
||||
if ( parentForm!= null ){
|
||||
return parentForm.removeElement(this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* renders the element with label+tr+td...
|
||||
*/
|
||||
public function getFullRow():String {
|
||||
var s = new StringBuf();
|
||||
if(Form.USE_TWITTER_BOOTSTRAP) s.add('<div class="form-group">\n');
|
||||
s.add(getLabel());
|
||||
s.add("<div class='col-sm-8'>" + this.render() + "</div>");
|
||||
if (Form.USE_TWITTER_BOOTSTRAP) s.add('</div>\n');
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public function getType():String
|
||||
{
|
||||
return Std.string(Type.getClass(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CSS classes for the form element label
|
||||
*/
|
||||
public function getLabelClasses() : String
|
||||
{
|
||||
var css = "";
|
||||
if (Form.USE_TWITTER_BOOTSTRAP) css = "col-sm-4 control-label";
|
||||
|
||||
var requiredSet = false;
|
||||
if (required) {
|
||||
css += " "+parentForm.requiredClass;
|
||||
if (parentForm.isSubmitted() && required && value == null) {
|
||||
css += " "+parentForm.requiredErrorClass;
|
||||
requiredSet = true;
|
||||
}
|
||||
}
|
||||
if(!requiredSet && parentForm.isSubmitted() && !isValid()){
|
||||
css += " "+parentForm.invalidErrorClass;
|
||||
}
|
||||
|
||||
//if ( cssClass != null )
|
||||
//css += ( css == "" ) ? cssClass : " " + cssClass;
|
||||
|
||||
return css;
|
||||
}
|
||||
|
||||
public function getLabel():String
|
||||
{
|
||||
var n = parentForm.name + "_" + name;
|
||||
return "<label for=\"" + n + "\" class=\""+getLabelClasses()+"\" id=\"" + n + "__Label\">" + label +(required?parentForm.labelRequiredIndicator:'') +"</label>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return CSS classes of the element
|
||||
*/
|
||||
public function getClasses() : String
|
||||
{
|
||||
var css = ( cssClass != null ) ? cssClass : parentForm.defaultClass;
|
||||
|
||||
if ( required && parentForm.isSubmitted() )
|
||||
{
|
||||
if ( value == null )
|
||||
css += " " + parentForm.requiredErrorClass;
|
||||
if ( !isValid() )
|
||||
css += " " + parentForm.invalidErrorClass;
|
||||
}
|
||||
if(css == null) css = "";
|
||||
return css.trim();
|
||||
}
|
||||
|
||||
public function getErrorClasses()
|
||||
{
|
||||
var css = "";
|
||||
|
||||
if ( required && parentForm.isSubmitted() )
|
||||
{
|
||||
if ( value == null )
|
||||
css += " " + parentForm.requiredErrorClass;
|
||||
if ( !isValid() )
|
||||
css += " " + parentForm.invalidErrorClass;
|
||||
}
|
||||
|
||||
return css.trim();
|
||||
}
|
||||
|
||||
private inline function safeString(s:Dynamic) {
|
||||
return s == null ? "" : Std.string(s).htmlEscape().split('"').join(""");
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the element in HTML
|
||||
*/
|
||||
public function toString() :String
|
||||
{
|
||||
return render();
|
||||
}
|
||||
|
||||
/**
|
||||
* get element value with the correct type
|
||||
*/
|
||||
public function getValue():T{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
enum FormMethod
|
||||
{
|
||||
GET;
|
||||
POST;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package sugoi.form;
|
||||
|
||||
interface Formatter
|
||||
{
|
||||
function format(data:Dynamic):String;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package sugoi.form;
|
||||
|
||||
typedef FormData<T> = Array<{label:String,value:T}>;
|
||||
|
||||
class ListData
|
||||
{
|
||||
public static function getDateElement( low : Int, high : Int, ?labels : Array<String> ) : FormData<Int>
|
||||
{
|
||||
var data = [];
|
||||
if ( labels != null ){
|
||||
for ( i in low ... high + 1 )
|
||||
data.push( { label:labels[i-1], value:i } );
|
||||
}else{
|
||||
for ( i in low ... high + 1 ){
|
||||
var n = Std.string(i);
|
||||
data.push( { label:((i < 10) ? "0" + n : n), value: i } );
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static function getMinutes():FormData<Int> {
|
||||
var data = [];
|
||||
for ( i in 0...12) {
|
||||
var x = i * 5;
|
||||
data.push( {label: (x<10) ? "0"+Std.string(x) : Std.string(x) ,value: x } );
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static function fromArray(arr:Array<Dynamic>) {
|
||||
var data = [];
|
||||
for (a in arr) {
|
||||
data.push( {key:Std.string(a),value:Std.string(a) } );
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static function getDays(?reverse = true):Array<{label:String,value:Int}>
|
||||
{
|
||||
var data= [];
|
||||
for (i in 1...31+1) {
|
||||
data.push( { label:Std.string(i), value:i } );
|
||||
}
|
||||
return(data);
|
||||
}
|
||||
|
||||
//public static var months_short = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
||||
public static var months_short = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
||||
//public static var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
||||
public static var months = ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Décembre"];
|
||||
|
||||
/**
|
||||
* Get months list
|
||||
*/
|
||||
public inline static function getMonths(?short = false):Array<{label:String,value:Int}>
|
||||
{
|
||||
var input = short ? months_short : months;
|
||||
var out = [];
|
||||
var c = 1;
|
||||
for ( i in input) {
|
||||
out.push( { label:i, value:c } );
|
||||
c++;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* get years list
|
||||
*/
|
||||
public static function getYears(from:Int, to:Int, ?reverse = true):Array<{label:String,value:Int}>
|
||||
{
|
||||
var data = [];
|
||||
|
||||
if (reverse){
|
||||
for (i in 0...(to-from+1)) {
|
||||
var n = to - i;
|
||||
data.push( { label:Std.string(n), value:n } );
|
||||
}
|
||||
}else {
|
||||
for (i in 0...(to-from+1)) {
|
||||
var n = from + i;
|
||||
data.push( { label:Std.string(n), value:n } );
|
||||
}
|
||||
}
|
||||
return(data);
|
||||
}
|
||||
|
||||
/*public static function getLetters(uppercase=false){
|
||||
if (uppercase) return(array(a=>"A", b=>"B", c=>"C", d=>"D", e=>"E", f=>"F", g=>"G", h=>"H", i=>"I", j=>"J", k=>"K", l=>"L", m=>"M", n=>"N", o=>"O", p=>"P", q=>"Q", r=>"R", s=>"S", t=>"T", u=>"U", v=>"V", w=>"W", x=>"X", y=>"Y", z=>"Z"));
|
||||
return(array(a=>"a", b=>"b", c=>"c", d=>"d", e=>"e", f=>"f", g=>"g", h=>"h", i=>"i", j=>"j", k=>"k", l=>"l", m=>"m", n=>"n", o=>"o", p=>"p", q=>"q", r=>"r", s=>"s", t=>"t", u=>"u", v=>"v", w=>"w", x=>"x", y=>"y", z=>"z"));
|
||||
}*/
|
||||
|
||||
public static function hashToList(hash:Map<String,String>, ?startCounter:Int=0):List<Dynamic>
|
||||
{
|
||||
var data:List<Dynamic> = new List();
|
||||
|
||||
for (key in hash.keys())
|
||||
{
|
||||
data.add( { key:key, value:hash.get(key) } );
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static function arrayToList(array:Array<String>, ?startCounter:Int=0):List<Dynamic>
|
||||
{
|
||||
var data:List<Dynamic> = new List();
|
||||
|
||||
var c = startCounter;
|
||||
for (v in array)
|
||||
{
|
||||
data.add( { key:c, value:v } );
|
||||
c++;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static function flatArraytoList(array:Array<String>):List<Dynamic>
|
||||
{
|
||||
var data:List<Dynamic> = new List();
|
||||
|
||||
for (i in array) data.add( { key:i, value:i } );
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package sugoi.form;
|
||||
|
||||
class Rules
|
||||
{
|
||||
|
||||
public function new()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static function isNumber(element:FormElement)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static function greaterThan(element:FormElement, value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static function lessThan(element:FormElement, value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package sugoi.form.elements;
|
||||
|
||||
import form.Form;
|
||||
import form.FormElement;
|
||||
|
||||
|
||||
class Button extends FormElement
|
||||
{
|
||||
public var type:ButtonType;
|
||||
|
||||
//public function new(name:String, label:String, ?value:String = "Submit", ?type:ButtonType = null)
|
||||
public function new(name:String, label:String, ?value:String = null, ?type:ButtonType = null)
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
this.type = (type == null) ? ButtonType.SUBMIT : type;
|
||||
}
|
||||
|
||||
override public function isValid():Bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
override public function render() :String
|
||||
{
|
||||
return "<button type=\"" + type + "\" class=\"" + getClasses() +"\" value=\"" + value + "\" " + attributes + " name=\"" +parentForm.name + "_" +name + "\" id=\"" +parentForm.name + "_" +name + "\" >" +label + "</button>";
|
||||
|
||||
}
|
||||
|
||||
public function toString() :String
|
||||
{
|
||||
return render();
|
||||
}
|
||||
|
||||
override public function getLabel():String
|
||||
{
|
||||
var n = parentForm.name + "_" + name;
|
||||
|
||||
return "<label for=\"" + n + "\" ></label>";
|
||||
}
|
||||
|
||||
override public function getPreview():String
|
||||
{
|
||||
return "<tr><td></td><td>" + this.render() + "<td></tr>";
|
||||
}
|
||||
|
||||
override public function populate():Void
|
||||
{
|
||||
super.populate();
|
||||
var n = parentForm.name + "_" + name;
|
||||
if ( App.current.params.exists(n) )
|
||||
parentForm.submittedButtonName = name;
|
||||
}
|
||||
}
|
||||
|
||||
enum ButtonType
|
||||
{
|
||||
SUBMIT;
|
||||
BUTTON;
|
||||
RESET;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package sugoi.form.elements;
|
||||
import sugoi.form.FormElement;
|
||||
import sugoi.form.elements.Input;
|
||||
#if neko
|
||||
import neko.Web;
|
||||
#else
|
||||
import php.Web;
|
||||
#end
|
||||
|
||||
/**
|
||||
* creates a hidden token in forms to avoid CSRF
|
||||
*/
|
||||
class CSRFProtection extends StringInput
|
||||
{
|
||||
|
||||
public function new()
|
||||
{
|
||||
|
||||
value = haxe.crypto.Md5.encode(App.current.session.sid + App.config.KEY.substr(0, 5));
|
||||
super("token","", value, true);
|
||||
inputType = ITHidden;
|
||||
}
|
||||
|
||||
override public function isValid() {
|
||||
if (value == null) throw "empty token";
|
||||
var valid = Web.getParams().get(parentForm.name + "_" + name) == value;
|
||||
|
||||
if (!valid) {
|
||||
errors.add("Bad token");
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
override public function getFullRow() {
|
||||
return render();
|
||||
}
|
||||
|
||||
override public function render() {
|
||||
|
||||
return "<input type=\"hidden\" value=\"" + value + "\" " + attributes + " name=\"" +parentForm.name + "_" +name + "\" id=\"" +parentForm.name + "_" +name + "\" />";
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package sugoi.form.elements;
|
||||
|
||||
import sugoi.form.Form;
|
||||
import sugoi.form.FormElement;
|
||||
|
||||
class Checkbox extends FormElement<Bool>
|
||||
{
|
||||
|
||||
public function new(name:String, label:String, ?checked:Bool=false, ?required:Bool=false, ?attibutes:String="")
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.value = checked;
|
||||
this.required = required;
|
||||
this.attributes = attibutes;
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
var n = parentForm.name + "_" +name;
|
||||
|
||||
var checkedStr = value ? "checked" : "";
|
||||
|
||||
return "<input type=\"checkbox\" id=\"" + n + "\" name=\"" + n + "\" class=\"" + getClasses() + "\" value=\"true\" " + checkedStr + " />";
|
||||
}
|
||||
|
||||
|
||||
override public function getTypedValue(str:String):Bool
|
||||
{
|
||||
return str == "1" || str == "true";
|
||||
}
|
||||
|
||||
override public function isValid():Bool
|
||||
{
|
||||
errors.clear();
|
||||
if ( required && value == null )
|
||||
{
|
||||
errors.add("Please check '" + ((label != null && label != "") ? label : name) + "'");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package sugoi.form.elements;
|
||||
import sugoi.form.Form;
|
||||
import sugoi.form.FormElement;
|
||||
import sugoi.form.Formatter;
|
||||
import sugoi.form.ListData;
|
||||
|
||||
/**
|
||||
* Manage an array of string with a checkbox group
|
||||
*/
|
||||
class CheckboxGroup extends FormElement<Array<String>>
|
||||
{
|
||||
public var data:Array<Dynamic>;
|
||||
public var selectMessage:String;
|
||||
public var labelLeft:Bool;
|
||||
public var verticle:Bool;
|
||||
public var labelRight:Bool;
|
||||
public var formatter:Formatter;
|
||||
public var columns:Int;
|
||||
|
||||
public function new(name:String, label:String,data:FormData<String>, ?selected:Array<String>, ?verticle:Bool=true, ?labelRight:Bool=true)
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.data = data;
|
||||
this.value = selected != null ? selected : new Array();
|
||||
this.verticle = verticle;
|
||||
this.labelRight = labelRight;
|
||||
|
||||
columns = 1;
|
||||
}
|
||||
|
||||
override public function populate()
|
||||
{
|
||||
|
||||
var v = Web.getParamValues(parentForm.name + "_" + name);
|
||||
|
||||
if (parentForm.isSubmitted())
|
||||
{
|
||||
value = (v != null) ? v : [];
|
||||
} else {
|
||||
if (v != null) value = v;
|
||||
}
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
var s = "";
|
||||
var n = parentForm.name + "_" +name;
|
||||
|
||||
var tagCss = getClasses();
|
||||
var labelCss = getLabelClasses();
|
||||
|
||||
var c = 0;
|
||||
var datas = Lambda.array(data);
|
||||
if (datas != null)
|
||||
{
|
||||
var rowsPerColumn = Math.ceil(datas.length / columns);
|
||||
s = "<table><tr>";
|
||||
for (i in 0...columns)
|
||||
{
|
||||
s += "<td valign=\"top\">\n";
|
||||
s += "<table>\n";
|
||||
|
||||
for (j in 0...rowsPerColumn)
|
||||
{
|
||||
if (c >= datas.length) break;
|
||||
|
||||
s += "<tr>";
|
||||
|
||||
var row:Dynamic = datas[c];
|
||||
|
||||
var checkbox = "<input type=\"checkbox\" class=\"" + tagCss + "\" name=\""+n+"[]\" id=\""+n+c+"\" value=\"" + row.value + "\" " + (value != null ? Lambda.has(value, row.value) ? "checked":"":"") +" ></input>\n";
|
||||
var label;
|
||||
|
||||
if (formatter != null){
|
||||
label = "<label for=\"" + n + c + "\" class=\""+''/*labelCss*/+"\" >" + formatter.format(row.label) +"</label>\n";
|
||||
//}else if(Form.translator!=null){
|
||||
//label = "<label for=\"" + n + c + "\" class=\"" + ''/*labelCss*/+"\" >" + Form.translator._(row.label) +"</label>\n";
|
||||
}else {
|
||||
label = "<label for=\"" + n + c + "\" class=\"" + ''/*labelCss*/+"\" >" + row.label +"</label>\n";
|
||||
}
|
||||
|
||||
if (labelRight)
|
||||
{
|
||||
s += "<td>" + checkbox + "</td>\n";
|
||||
s += "<td> " + label + "</td>\n";
|
||||
} else {
|
||||
s += "<td>" + label + " </td>\n";
|
||||
s += "<td>" + checkbox + "</td>\n";
|
||||
}
|
||||
s += "</tr>";
|
||||
c++;
|
||||
}
|
||||
s += "</table>";
|
||||
s += "</td>";
|
||||
}
|
||||
s += "</tr></table>\n";
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package sugoi.form.elements;
|
||||
|
||||
import sugoi.Web;
|
||||
import sugoi.form.FormElement;
|
||||
import sugoi.form.validators.Validator;
|
||||
import sugoi.form.ListData;
|
||||
|
||||
/**
|
||||
* A list of selectBox for day + month + year
|
||||
*/
|
||||
class DateDropdowns extends FormElement<Date>
|
||||
{
|
||||
public var maxOffset:Int;
|
||||
public var minOffset:Int;
|
||||
|
||||
//public var date : Date; //valeur typée à la place de value:Dynamic
|
||||
|
||||
public var yearMin:Int;
|
||||
public var yearMax:Int;
|
||||
|
||||
private var daySelector:Selectbox<Int>;
|
||||
private var monthSelector:Selectbox<Int>;
|
||||
private var yearSelector:Selectbox<Int>;
|
||||
|
||||
public function new(name:String, label:String, ?_value:Date, ?required:Bool=false, yearMin:Int=1950, yearMax:Int=null, ?validators:Array<Validator<Date>>, ?attibutes:String="")
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
|
||||
if (_value == null) {
|
||||
value = Date.now();
|
||||
}else {
|
||||
value = _value;
|
||||
}
|
||||
|
||||
this.required = required;
|
||||
this.attributes = attibutes;
|
||||
this.yearMin = yearMin;
|
||||
this.yearMax = yearMax;
|
||||
|
||||
maxOffset = null;
|
||||
minOffset = null;
|
||||
|
||||
var day :Int = null;
|
||||
var month :Int = null;
|
||||
var year :Int = null;
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
day = value.getDate();
|
||||
month = (value.getMonth()+1);
|
||||
year = value.getFullYear();
|
||||
}
|
||||
|
||||
var t = sugoi.form.Form.translator;
|
||||
daySelector = new IntSelect(name+"_day", t._("day"),ListData.getDays(),day,true);
|
||||
monthSelector = new IntSelect(name+"_month", t._("month"),ListData.getMonths(),month,true);
|
||||
yearSelector = new IntSelect(name+"_year", t._("year"), ListData.getYears(Date.now().getFullYear()-3, Date.now().getFullYear()+3, true), year, true);
|
||||
|
||||
daySelector.internal = monthSelector.internal = yearSelector.internal = true;
|
||||
|
||||
//if (Form.USE_TWITTER_BOOTSTRAP) {
|
||||
//daySelector.cssClass = "input-mini";
|
||||
//}
|
||||
//trace("date : " + date);
|
||||
}
|
||||
public function shortLabels()
|
||||
{
|
||||
daySelector.nullMessage = "-D-";
|
||||
monthSelector.nullMessage = "-M-";
|
||||
yearSelector.nullMessage = "-Y-";
|
||||
monthSelector.data = ListData.getMonths(true);
|
||||
}
|
||||
|
||||
override public function init()
|
||||
{
|
||||
super.init();
|
||||
|
||||
parentForm.addElement(daySelector);
|
||||
parentForm.addElement(monthSelector);
|
||||
parentForm.addElement(yearSelector);
|
||||
}
|
||||
|
||||
override public function populate()
|
||||
{
|
||||
|
||||
var day = Std.parseInt(App.current.params.get(parentForm.name + "_" + daySelector.name));
|
||||
var month = Std.parseInt(App.current.params.get(parentForm.name + "_" + monthSelector.name));
|
||||
var year = Std.parseInt(App.current.params.get(parentForm.name + "_" + yearSelector.name));
|
||||
|
||||
value = (day != null && month != null && year != null ) ? new Date(year, month - 1, day, 0, 0, 0) : null;
|
||||
}
|
||||
|
||||
override public function isValid():Bool
|
||||
{
|
||||
/*var valid = super.isValid();
|
||||
|
||||
if ( required && valid )
|
||||
{
|
||||
var n = form.name + "_" + name;
|
||||
var day = Std.parseInt(App.current.params.get(n));
|
||||
var month = Std.parseInt(App.current.params.get(n));
|
||||
var year = Std.parseInt(App.current.params.get(n));
|
||||
|
||||
if (day == null || month == null || year == null )
|
||||
{
|
||||
errors.add("<span class=\"formErrorsField\">" + ((label != null && label != "") ? label : name) + "</span> is an invalid date.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return valid;*/
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
super.render();
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
try{
|
||||
var v:Date = cast value;
|
||||
daySelector.value = v.getDate();
|
||||
monthSelector.value = v.getMonth()+1;
|
||||
yearSelector.value = v.getFullYear();
|
||||
}catch(e:Dynamic){}
|
||||
}
|
||||
|
||||
return '<div class="row">
|
||||
<div class="col-xs-2">'+daySelector.render()+'</div>
|
||||
<div class="col-xs-6">'+monthSelector.render()+'</div>
|
||||
<div class="col-xs-4">'+yearSelector.render()+'</div>
|
||||
</div>';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package sugoi.form.elements;
|
||||
import sugoi.form.FormElement;
|
||||
import sugoi.form.validators.Validator;
|
||||
import sugoi.form.ListData;
|
||||
|
||||
/**
|
||||
* date selectBox : day month year hour minutes
|
||||
*/
|
||||
class DateInput extends DateDropdowns
|
||||
{
|
||||
private var hourSelector:Selectbox<Int>;
|
||||
private var minuteSelector:Selectbox<Int>;
|
||||
|
||||
public function new(name:String, label:String, ?value:Date, ?required:Bool=false, yearMin:Int=1950, yearMax:Int=null, ?validators:Array<Validator<Date>>, ?attibutes:String="")
|
||||
{
|
||||
super(name, label, value, required, yearMin, yearMax, validators, attibutes);
|
||||
var t = sugoi.form.Form.translator;
|
||||
hourSelector = new Selectbox<Int>(name+"_hour" , t._("hour") , ListData.getDateElement(0,23), value.getHours(),true,"-",'title="Hour"');
|
||||
minuteSelector = new Selectbox<Int>(name+"_minute", t._("minute"), ListData.getDateElement(0, 59), value.getMinutes(), true, "-", 'title="Minute"');
|
||||
|
||||
if (Form.USE_TWITTER_BOOTSTRAP) {
|
||||
hourSelector.cssClass = "form-control";
|
||||
minuteSelector.cssClass = "form-control";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override public function isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
hourSelector.parentForm = this.parentForm;
|
||||
minuteSelector.parentForm = this.parentForm;
|
||||
|
||||
var s = super.render() + " : ";
|
||||
|
||||
if (value != null){
|
||||
var v:Date = cast value;
|
||||
hourSelector.value = v.getHours();
|
||||
minuteSelector.value = v.getMinutes();
|
||||
}
|
||||
s += hourSelector.render() + " h ";
|
||||
s += minuteSelector.render() + " m ";
|
||||
return s;
|
||||
}
|
||||
|
||||
override public function populate()
|
||||
{
|
||||
//super.populate();
|
||||
var n = parentForm.name + "_" + hourSelector.name;
|
||||
var v = App.current.params.get(n);
|
||||
var params = App.current.params;
|
||||
|
||||
if (v != null)
|
||||
{
|
||||
var minute = Std.parseInt(params.get(parentForm.name + "_" + minuteSelector.name));
|
||||
var hour = Std.parseInt(params.get(parentForm.name + "_" + hourSelector.name));
|
||||
var day = Std.parseInt(params.get(parentForm.name + "_" + daySelector.name));
|
||||
var month = Std.parseInt(params.get(parentForm.name + "_" + monthSelector.name));
|
||||
var year = Std.parseInt(params.get(parentForm.name + "_" + yearSelector.name));
|
||||
|
||||
value = new Date(year, month - 1, day, hour, minute, 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package sugoi.form.elements;
|
||||
|
||||
import sugoi.Web;
|
||||
import sugoi.form.FormElement;
|
||||
import sugoi.form.validators.Validator;
|
||||
import sugoi.form.ListData;
|
||||
|
||||
/**
|
||||
* DatePicker for Bootstrap 3
|
||||
*
|
||||
* You'll need to install some additionnal js librairies (moment.js, jquery)
|
||||
* more info at : http://eonasdan.github.io/bootstrap-datetimepicker/
|
||||
*/
|
||||
class DatePicker extends FormElement<Date>
|
||||
{
|
||||
public var maxOffset:Int;
|
||||
public var minOffset:Int;
|
||||
|
||||
public var yearMin:Int;
|
||||
public var yearMax:Int;
|
||||
|
||||
private var daySelector:Selectbox<Int>;
|
||||
private var monthSelector:Selectbox<Int>;
|
||||
private var yearSelector:Selectbox<Int>;
|
||||
|
||||
public var format : String; //moment.js format
|
||||
|
||||
public function new(name:String, label:String, ?v:Date, ?required:Bool=false, yearMin:Int=1950, yearMax:Int=null, ?validators:Array<Validator<Date>>, ?attibutes:String="")
|
||||
{
|
||||
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
format = 'LLLL';
|
||||
|
||||
if (v == null) {
|
||||
this.value = Date.now();
|
||||
}else {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
//trace(value);
|
||||
|
||||
this.required = required;
|
||||
this.attributes = attibutes;
|
||||
this.yearMin = yearMin;
|
||||
this.yearMax = yearMax;
|
||||
|
||||
maxOffset = null;
|
||||
minOffset = null;
|
||||
|
||||
var day = "";
|
||||
var month = "";
|
||||
var year = "";
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
day = ""+value.getDate();
|
||||
month = ""+(value.getMonth()+1);
|
||||
year = ""+value.getFullYear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override public function populate()
|
||||
{
|
||||
//data is stored as float in the html form element
|
||||
var d = App.current.params.get(parentForm.name + "_" + name);
|
||||
//trace(parentForm.name + "_" + name+"="+d);
|
||||
//value = Date.fromTime(Std.parseFloat(d));
|
||||
value = Date.fromString(d);
|
||||
}
|
||||
|
||||
override public function isValid():Bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
|
||||
//component init date
|
||||
//var d = value.getFullYear() +"-" + (value.getMonth() + 1) + "-" + value.getDate() + " " + value.getHours() + ":" + value.getMinutes()+":00";
|
||||
var d = value.toString();
|
||||
var defaultDate = 'moment("' + d + '", "YYYY-MM-DD HH:mm:ss")';
|
||||
|
||||
return "
|
||||
<div class='input-group date' id='datetimepicker-"+name+"'>
|
||||
<span class='input-group-addon'>
|
||||
<span class='glyphicon glyphicon-calendar'></span>
|
||||
</span>
|
||||
<input type='text' class='form-control' />
|
||||
</div>
|
||||
|
||||
<input type='hidden' name='"+parentForm.name+"_"+name+"' id='datetimepickerdata-"+name+"' value='"+d+"'/>
|
||||
<script type='text/javascript'>
|
||||
$(function () {
|
||||
$('#datetimepicker-"+name+"').datetimepicker(
|
||||
{
|
||||
locale:'fr',
|
||||
format:'"+this.format+"',
|
||||
defaultDate:"+defaultDate+"
|
||||
}
|
||||
);
|
||||
//stores the date in mysql format in a hidden input element
|
||||
$('#datetimepicker-"+name+"').on('dp.change',function(e){
|
||||
var d = $('#datetimepicker-"+name+"').data('DateTimePicker').date();//moment.js obj
|
||||
//fix 2038 date overflow bug https://en.wikipedia.org/wiki/Year_2038_problem
|
||||
if(d.year()>2037) d.year(2037);
|
||||
console.log(d.toString());
|
||||
$('#datetimepickerdata-"+name+"').val( d.format('YYYY-MM-DD HH:mm:ss'));
|
||||
});
|
||||
});
|
||||
</script>";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2008, TouchMyPixel & contributors
|
||||
* Original author : Matt Benton <matt@touchmypixel.com>
|
||||
* Contributers: Tarwin Stroh-Spijer
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE TOUCH MY PIXEL & CONTRIBUTERS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE TOUCH MY PIXEL & CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
package form.elements;
|
||||
|
||||
import form.Form;
|
||||
import form.FormElement;
|
||||
import poko.Poko;
|
||||
|
||||
enum EmbeddedVideoService
|
||||
{
|
||||
youtube;
|
||||
vimeo;
|
||||
}
|
||||
|
||||
typedef EmbeddedVideoConfig =
|
||||
{
|
||||
var videoID:String;
|
||||
var width:Int;
|
||||
var height:Int;
|
||||
}
|
||||
|
||||
typedef VimeoConfig =
|
||||
{ > EmbeddedVideoConfig,
|
||||
var color:String;
|
||||
var showPortrait:Bool;
|
||||
var showTitle:Bool;
|
||||
var showByline:Bool;
|
||||
}
|
||||
|
||||
class EmbeddedVideoOptions extends FormElement
|
||||
{
|
||||
// Type of video service
|
||||
public var service:EmbeddedVideoService;
|
||||
/**
|
||||
* Common options
|
||||
*/
|
||||
//public var videoID:String;
|
||||
//public var width:Int;
|
||||
//public var height:Int;
|
||||
/**
|
||||
* Vimeo options
|
||||
*/
|
||||
// Can be Blue, Orange, Lime, Fuschia, White or #RRGGBB
|
||||
//public var color:String;
|
||||
//public var showPortrait:Bool;
|
||||
//public var showTitle:Bool;
|
||||
//public var showByline:Bool;
|
||||
|
||||
public var vimeo (default, null) : VimeoConfig;
|
||||
|
||||
public function new(name:String, label:String, service:EmbeddedVideoService)
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
var n = form.name + "_" + name;
|
||||
if ( service == EmbeddedVideoService.vimeo )
|
||||
{
|
||||
var color = new Input(n + "Color", "Color", "Blue");
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function toString() :String
|
||||
{
|
||||
return render();
|
||||
}
|
||||
|
||||
override public function populate():Void
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*var date:Date = cast value;
|
||||
var year = date.getFullYear();
|
||||
var month = date.getMonth();
|
||||
var day = date.getDate();
|
||||
|
||||
var l = new List();
|
||||
var s = "";
|
||||
|
||||
var elYear = new Selectbox(form, "1", ListData.getYears(1990, 2000, true), Std.string(year), false, "");
|
||||
var elMonth = new Selectbox(form, "2", ListData.getMonths(), Std.string(year), false);
|
||||
var elDay = new Selectbox(form, "3", ListData.getDays() , Std.string(year), false);
|
||||
|
||||
form.addElement(name + "[]", elYear);
|
||||
form.addElement(name + "[]", elMonth);
|
||||
form.addElement(name + "[]", elDay);
|
||||
|
||||
s += elYear.toString();
|
||||
s += elMonth.toString();
|
||||
s += elDay.toString();
|
||||
|
||||
form.initElements();
|
||||
*/
|
||||
@@ -0,0 +1,128 @@
|
||||
package sugoi.form.elements;
|
||||
import sugoi.form.Form;
|
||||
import sugoi.form.FormElement;
|
||||
import sugoi.form.Formatter;
|
||||
import sugoi.form.elements.Flags;
|
||||
|
||||
class Enum extends FormElement<Int>
|
||||
{
|
||||
public var enumName:String;
|
||||
public var selectMessage:String;
|
||||
public var labelLeft:Bool;
|
||||
public var verticle:Bool;
|
||||
public var labelRight:Bool;
|
||||
var checked : Array<Bool>;
|
||||
|
||||
|
||||
public var columns:Int;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* @param label
|
||||
* @param data list of enums
|
||||
* @param value int (enum index)
|
||||
* @param ?verticle
|
||||
* @param ?labelRight
|
||||
*/
|
||||
public function new(name:String, label:String, enumName:String, value:Int, ?required=false, ?verticle:Bool=false, ?labelRight:Bool=true)
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.enumName = enumName;
|
||||
|
||||
this.verticle = verticle;
|
||||
this.labelRight = labelRight;
|
||||
|
||||
//trace("value = " + value);
|
||||
|
||||
if (required && value == null){
|
||||
this.value = /*Type.resolveEnum(enumName).createByIndex(0)*/0;
|
||||
}else{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
columns = 1;
|
||||
}
|
||||
|
||||
override function getTypedValue(str:String):Int {
|
||||
if (str == null) return null;
|
||||
|
||||
str = StringTools.trim(str);
|
||||
if (str == "") {
|
||||
return null;
|
||||
}else{
|
||||
return Std.parseInt(str);
|
||||
}
|
||||
}
|
||||
|
||||
override function getValue(){
|
||||
if (value == null) return null;
|
||||
return Type.resolveEnum(enumName).createByIndex(value);
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
var s = "";
|
||||
var n = parentForm.name + "_" +name;
|
||||
|
||||
var tagCss = getClasses();
|
||||
//no label css otherwise the style col-sm-4 will be added, and we dont want that
|
||||
// as its for the left column labels
|
||||
//var labelCss = getLabelClasses();
|
||||
|
||||
var c = 0;
|
||||
|
||||
var array = Type.allEnums(Type.resolveEnum(enumName));
|
||||
|
||||
var rowsPerColumn = Math.ceil(array.length / columns);
|
||||
s = "<table style='margin-bottom:8px;'><tr>";
|
||||
for (i in 0...columns)
|
||||
{
|
||||
s += "<td valign=\"top\">\n";
|
||||
s += "<table>\n";
|
||||
|
||||
for (j in 0...rowsPerColumn)
|
||||
{
|
||||
if (c >= array.length) break;
|
||||
|
||||
s += "<tr>";
|
||||
|
||||
var row:Dynamic = array[c];
|
||||
var checked = value == Type.enumIndex(row);
|
||||
var checkbox = "<input type=\"radio\" class=\"" + tagCss + "\" name=\""+n+"\" id=\""+n+row+"\" value=\""+Type.enumIndex(row)+"\" " + (checked? "checked":"") +" ></input>\n";
|
||||
var label;
|
||||
|
||||
var t = Form.translator;
|
||||
if (t == null){
|
||||
label = "<label for=\"" + n + c + "\" >" + Std.string(row) +"</label>\n";
|
||||
}else{
|
||||
label = "<label for=\"" + n + c + "\" >" + t._(Std.string(row)) +"</label>\n";
|
||||
}
|
||||
|
||||
|
||||
if (labelRight)
|
||||
{
|
||||
s += "<td style='vertical-align:middle;padding-right: 8px;'>" + checkbox + "</td> \n";
|
||||
s += "<td style='vertical-align:middle;'>" + label + "</td>\n";
|
||||
} else {
|
||||
s += "<td style='vertical-align:middle;padding-right: 8px;'>" + label + "</td> \n";
|
||||
s += "<td style='vertical-align:middle;'>" + checkbox + "</td>\n";
|
||||
}
|
||||
|
||||
s += "</tr>";
|
||||
c++;
|
||||
}
|
||||
s += "</table>";
|
||||
s += "</td>";
|
||||
}
|
||||
s += "</tr></table>\n";
|
||||
|
||||
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package sugoi.form.elements;
|
||||
import haxe.crypto.Md5;
|
||||
import haxe.Timer;
|
||||
import sugoi.form.Form;
|
||||
import sys.io.File;
|
||||
|
||||
/**
|
||||
* Manage an <input type="file" /> element.
|
||||
*/
|
||||
class FileUpload extends FormElement<haxe.io.Bytes>
|
||||
{
|
||||
public var fileName: String;
|
||||
public var maxSize : Int; //Max file size in Mb
|
||||
|
||||
public function new(name:String, label:String, ?value:haxe.io.Bytes, ?required:Bool=false, toFolder:String=null, ?keepFullFileName:Bool=true )
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
this.required = required;
|
||||
fileName = null;
|
||||
maxSize = 6;
|
||||
}
|
||||
|
||||
override public function getTypedValue(s:String):haxe.io.Bytes
|
||||
{
|
||||
var request = sugoi.tools.Utils.getMultipart(1024 * 1024 * maxSize);
|
||||
|
||||
//trace(request.toString());
|
||||
|
||||
var strData = request.get(parentForm.name + "_" + name);
|
||||
fileName = request.get(parentForm.name + "_" + name+"_filename");
|
||||
|
||||
return new haxe.io.StringInput(strData).readAll();
|
||||
|
||||
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
var n = parentForm.name + "_" +name;
|
||||
//var path = toFolder.substr((Sys.getCwd() + "tmp/").length);
|
||||
//var path = toFolder;
|
||||
|
||||
var str:String = "";
|
||||
|
||||
//str += '<span class="fileName">'+getOriginalFileName()+'</span><br/>';
|
||||
str += '<input type="file" name="' + n + '" id="' + n + '" ' + attributes + ' />';
|
||||
//if (!required && value != '' && value != null) str += '[ <a href="#" onclick="document.getElementById(\'' + n + '__delete\').value = \'1\'; return false;">remove</a> ]';
|
||||
//str += '<input type="hidden" name="' + n + '__previous" id="' + n + '__previous" value="'+value+'"/>';
|
||||
//str += '<input type="hidden" name="' + n + '__delete" id="' + n + '__delete" value="0"/>';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains MD5 and original filename.
|
||||
*/
|
||||
//public function getFileName()
|
||||
//{
|
||||
//if (keepFullFileName)
|
||||
//{
|
||||
//var s = Std.string(value);
|
||||
//return s.substr(s.lastIndexOf("/") + 1);
|
||||
//} else {
|
||||
//return value;
|
||||
//}
|
||||
//}
|
||||
|
||||
/**
|
||||
* Orginal filename.
|
||||
*/
|
||||
//public function getOriginalFileName()
|
||||
//{
|
||||
//if (keepFullFileName)
|
||||
//{
|
||||
//var s = Std.string(value);
|
||||
//return s.substr(s.lastIndexOf("/") + 33);
|
||||
//} else {
|
||||
//return Std.string(value).substr(33);
|
||||
//}
|
||||
//}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package sugoi.form.elements;
|
||||
import sugoi.form.Form;
|
||||
import sugoi.form.FormElement;
|
||||
import sugoi.form.Formatter;
|
||||
#if php
|
||||
import php.Web;
|
||||
#else
|
||||
import neko.Web;
|
||||
#end
|
||||
|
||||
|
||||
enum FakeFlag {
|
||||
Flag1;
|
||||
Flag2;
|
||||
Flag3;
|
||||
Flag4;
|
||||
Flag5;
|
||||
Flag6;
|
||||
Flag7;
|
||||
Flag8;
|
||||
Flag9;
|
||||
Flag10;
|
||||
Flag11;
|
||||
Flag12;
|
||||
Flag13;
|
||||
Flag14;
|
||||
Flag15;
|
||||
Flag16;
|
||||
Flag17;
|
||||
Flag18;
|
||||
Flag19;
|
||||
Flag20;
|
||||
Flag21;
|
||||
Flag22;
|
||||
Flag23;
|
||||
Flag24;
|
||||
Flag25;
|
||||
Flag26;
|
||||
Flag27;
|
||||
Flag28;
|
||||
Flag29;
|
||||
Flag30;
|
||||
Flag31;
|
||||
Flag32;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage flags stored in an Int , various flags are defined by an Enum
|
||||
*/
|
||||
class Flags<T> extends FormElement<Int>
|
||||
{
|
||||
public var data:Array<String>;
|
||||
public var selectMessage:String;
|
||||
public var labelLeft:Bool;
|
||||
public var verticle:Bool;
|
||||
public var labelRight:Bool;
|
||||
var checked : Array<Bool>;
|
||||
|
||||
public var columns:Int;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* @param label
|
||||
* @param data list of enums
|
||||
* @param value int
|
||||
* @param ?verticle
|
||||
* @param ?labelRight
|
||||
*/
|
||||
public function new(name:String, label:String, data:Array<String>, value:Int, ?verticle:Bool=true, ?labelRight:Bool=true)
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.data = data;
|
||||
this.value = value;
|
||||
this.verticle = verticle;
|
||||
this.labelRight = labelRight;
|
||||
if (value == null) value = 0;
|
||||
|
||||
checked = [];
|
||||
var i = 0;
|
||||
for( f in data) {
|
||||
checked.push( value & (1 << i) != 0 );
|
||||
i++;
|
||||
}
|
||||
|
||||
columns = 1;
|
||||
}
|
||||
|
||||
override public function populate()
|
||||
{
|
||||
|
||||
var v = Web.getParamValues(parentForm.name + "_" + name);
|
||||
value = 0;
|
||||
|
||||
if (v != null) {
|
||||
//App.log("flags populate : " + v );
|
||||
var val = new haxe.EnumFlags<FakeFlag>();
|
||||
//var i = 0;
|
||||
for (vv in v) {
|
||||
val.set( FakeFlag.createByIndex(Std.parseInt(vv)) );
|
||||
//i++;
|
||||
}
|
||||
|
||||
value = val.toInt();
|
||||
}
|
||||
|
||||
|
||||
//if (form.isSubmitted()){
|
||||
//value = (v != null) ? v : new Array();
|
||||
//} else {
|
||||
//if (v != null) value = v;
|
||||
//}
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
var s = "";
|
||||
var n = parentForm.name + "_" +name;
|
||||
|
||||
var tagCss = getClasses();
|
||||
var labelCss = getLabelClasses();
|
||||
|
||||
var c = 0;
|
||||
var array = Lambda.array(data);
|
||||
if (array != null)
|
||||
{
|
||||
//trace("L" + array.length);
|
||||
var rowsPerColumn = Math.ceil(array.length / columns);
|
||||
s = "<table><tr>";
|
||||
for (i in 0...columns)
|
||||
{
|
||||
s += "<td valign=\"top\">\n";
|
||||
s += "<table>\n";
|
||||
|
||||
for (j in 0...rowsPerColumn)
|
||||
{
|
||||
if (c >= array.length) break;
|
||||
|
||||
s += "<tr>";
|
||||
|
||||
var row:Dynamic = array[c];
|
||||
|
||||
var checkbox = "<input type=\"checkbox\" class=\"" + tagCss + "\" name=\""+n+"[]\" id=\""+n+c+"\" value=\""+c+"\" " + (checked[c]? "checked":"") +" ></input>\n";
|
||||
var label;
|
||||
|
||||
var t = Form.translator;
|
||||
|
||||
label = "<label for=\"" + n + c + "\" class=\""+''/*labelCss*/+"\" > " + t._(row) +"</label>\n";
|
||||
|
||||
|
||||
if (labelRight)
|
||||
{
|
||||
s += "<td style='vertical-align:middle;'>" + checkbox + "</td>\n";
|
||||
s += "<td style='vertical-align:middle;'>" + label + "</td>\n";
|
||||
} else {
|
||||
s += "<td style='vertical-align:middle;'>" + label + "</td>\n";
|
||||
s += "<td style='vertical-align:middle;'>" + checkbox + "</td>\n";
|
||||
}
|
||||
s += "</tr>";
|
||||
|
||||
c++;
|
||||
}
|
||||
s += "</table>";
|
||||
s += "</td>";
|
||||
}
|
||||
s += "</tr></table>\n";
|
||||
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package sugoi.form.elements;
|
||||
import sugoi.form.filters.FloatFilter;
|
||||
|
||||
class FloatInput extends Input<Float>
|
||||
{
|
||||
|
||||
public function new(name, label, value, ?required=false){
|
||||
super(name, label, value, required);
|
||||
}
|
||||
|
||||
override public function getTypedValue(str:String):Float{
|
||||
|
||||
var f = new FloatFilter();
|
||||
var n = f.filterString(str);
|
||||
|
||||
if (n==null && this.required){
|
||||
return 0.0;
|
||||
}else{
|
||||
return n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package sugoi.form.elements;
|
||||
|
||||
/**
|
||||
* ...
|
||||
* @author fbarbut
|
||||
*/
|
||||
class FloatSelect extends Selectbox<Float>
|
||||
{
|
||||
|
||||
override function getTypedValue(str:String):Float{
|
||||
str = StringTools.trim(str);
|
||||
if (str == "" || str==null) {
|
||||
return null;
|
||||
}else{
|
||||
return Std.parseFloat(str);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package sugoi.form.elements;
|
||||
|
||||
import sugoi.Web;
|
||||
import sugoi.form.FormElement;
|
||||
import sugoi.form.validators.Validator;
|
||||
import sugoi.form.ListData;
|
||||
|
||||
class HourDropDowns extends FormElement<Date>
|
||||
{
|
||||
var hourSelector:Selectbox<Int>;
|
||||
var minuteSelector:Selectbox<Int>;
|
||||
|
||||
public function new(name:String, label:String, ?_value:Date, ?required:Bool=false,?attributes="")
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
|
||||
if (_value == null) {
|
||||
value = Date.now();
|
||||
}else {
|
||||
value = _value;
|
||||
}
|
||||
|
||||
this.required = required;
|
||||
this.attributes = attributes;
|
||||
|
||||
var hours = 0;
|
||||
var minutes = 0;
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
hours = value.getHours();
|
||||
minutes = value.getMinutes();
|
||||
}
|
||||
|
||||
var t = sugoi.form.Form.translator;
|
||||
|
||||
hourSelector = new IntSelect(name+"_hour", t._("hour"), ListData.getDateElement(0, 23), value.getHours(), true, "-", 'title="Hour"');
|
||||
minuteSelector = new IntSelect(name+"_minute", t._("minute"), ListData.getMinutes(), value.getMinutes(), true, "-", 'title="Minute"');
|
||||
|
||||
hourSelector.internal = minuteSelector.internal = true;
|
||||
|
||||
if (Form.USE_TWITTER_BOOTSTRAP) {
|
||||
minuteSelector.cssClass = "form-control";
|
||||
hourSelector.cssClass = "form-control";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
override public function init()
|
||||
{
|
||||
super.init();
|
||||
|
||||
parentForm.addElement(hourSelector);
|
||||
parentForm.addElement(minuteSelector);
|
||||
}
|
||||
|
||||
override public function populate()
|
||||
{
|
||||
var hour = Std.parseInt(App.current.params.get(parentForm.name + "_" + hourSelector.name));
|
||||
var minute = Std.parseInt(App.current.params.get(parentForm.name + "_" + minuteSelector.name));
|
||||
var now = Date.now();
|
||||
value = (hour!= null && minute != null) ? new Date(now.getFullYear(),now.getMonth(), now.getDay(), hour, minute, 0) : null;
|
||||
}
|
||||
|
||||
override public function isValid():Bool
|
||||
{
|
||||
return super.isValid();
|
||||
}
|
||||
|
||||
override public function render():String{
|
||||
super.render();
|
||||
var s = "<span class='form-inline'>";
|
||||
if (value != null){
|
||||
try{
|
||||
var v:Date = cast value;
|
||||
hourSelector.value = v.getHours();
|
||||
minuteSelector.value = v.getMinutes();
|
||||
}catch(e:Dynamic){}
|
||||
}
|
||||
|
||||
s += hourSelector.render();
|
||||
s += " : ";
|
||||
s += minuteSelector.render();
|
||||
|
||||
return s+"</span>";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package sugoi.form.elements;
|
||||
|
||||
/**
|
||||
* Use this to fill some custom HTML between form elements
|
||||
*
|
||||
* @author fbarbut<francois.barbut@gmail.com>
|
||||
*/
|
||||
class Html extends sugoi.form.FormElement<String>
|
||||
{
|
||||
var html : String;
|
||||
|
||||
public function new(name:String,html:String,?label="")
|
||||
{
|
||||
this.name = name;
|
||||
this.html = html;
|
||||
this.label = label;
|
||||
super();
|
||||
}
|
||||
|
||||
override public function render()
|
||||
{
|
||||
return html;
|
||||
}
|
||||
|
||||
override public function getTypedValue(str:String):String
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package sugoi.form.elements;
|
||||
import sugoi.form.Form;
|
||||
import sys.io.File;
|
||||
|
||||
/**
|
||||
* Manage an <input type="file" /> element for uploading images.
|
||||
*/
|
||||
class ImageUpload extends FormElement<haxe.io.Bytes>
|
||||
{
|
||||
public var fileName: String;
|
||||
public var maxSize : Int; // Max file size in Mb
|
||||
public var previewMaxSize : Int; // Image preview max size in pixels
|
||||
public var url : String;
|
||||
public var text : String;
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param label
|
||||
* @param url file URL for previewing the image
|
||||
* @param required
|
||||
*/
|
||||
public function new(name:String, label:String, ?url:String, ?required:Bool=false )
|
||||
{
|
||||
super();
|
||||
|
||||
this.name = "upload_"+name;
|
||||
this.label = label;
|
||||
|
||||
this.url = url;
|
||||
this.required = required;
|
||||
fileName = null;
|
||||
maxSize = 6;
|
||||
previewMaxSize = 200;
|
||||
}
|
||||
|
||||
override public function getTypedValue(s:String):haxe.io.Bytes
|
||||
{
|
||||
var request = sugoi.tools.Utils.getMultipart(1024 * 1024 * maxSize);
|
||||
|
||||
var strData = request.get(parentForm.name + "_" + name + "_data");
|
||||
if (strData != null && strData != ""){
|
||||
fileName = request.get(parentForm.name + "_" + name + "_data_filename");
|
||||
return new haxe.io.StringInput(strData).readAll();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function hasDeleteAction():Bool{
|
||||
var n = parentForm.name + "_" +name;
|
||||
return (App.current.params.get(n + "_delete") == "1");
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an input + image preview + delete btn
|
||||
*/
|
||||
override public function render():String
|
||||
{
|
||||
var n = parentForm.name + "_" +name;
|
||||
var str = new StringBuf();
|
||||
str.add('<div class="imageUpload" style="position: relative;">');
|
||||
if (url!= null)str.add('<img id="' + n + '_preview" src="$url" class="img-thumbnail" style="max-width:'+previewMaxSize+'px;max-height:'+previewMaxSize+'px;float:right;">');
|
||||
str.add('<input class="btn btn-default" type="file" name="' + n + '_data" id="' + n + '" ' + attributes + ' />');
|
||||
if (text != null) str.add('<p>$text</p>');
|
||||
if (!required && url!= null){
|
||||
str.add('<a style="position:absolute;right:3px;top:3px;" href="#" class="btn btn-default btn-xs" onclick="document.getElementById(\'' + n + '_delete\').value = \'1\';document.getElementById(\'' + n + '_preview\').style.display=\'none\';this.style.display=\'none\';return false;">');
|
||||
str.add('<span class="glyphicon glyphicon-remove" alt="Remove"></span>');
|
||||
str.add('</a>');
|
||||
}
|
||||
str.add('<input type="hidden" name="' + n + '_delete" id="' + n + '_delete" value="0"/>');
|
||||
str.add('</div>');
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package sugoi.form.elements;
|
||||
|
||||
import sugoi.form.Form;
|
||||
import sugoi.form.FormElement;
|
||||
import sugoi.form.validators.*;
|
||||
import sugoi.form.Formatter;
|
||||
|
||||
using StringTools;
|
||||
|
||||
enum InputType{
|
||||
ITText;
|
||||
ITPassword;
|
||||
ITHidden;
|
||||
ITColor; //http://caniuse.com/#feat=input-color
|
||||
}
|
||||
|
||||
class Input<T> extends FormElement<T>
|
||||
{
|
||||
public var password(get,set):Bool;
|
||||
public var disabled:Bool;
|
||||
public var showLabelAsDefaultValue:Bool;
|
||||
public var printRequired:Bool;
|
||||
|
||||
public var formatter:Formatter;
|
||||
public var inputType : InputType;
|
||||
|
||||
public function new(name:String, label:String, ?value:T, ?required=false, ?validators:Array<Validator<T>>, ?attributes="")
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
this.required = required;
|
||||
this.attributes = attributes;
|
||||
|
||||
if (validators != null)
|
||||
{
|
||||
for (i in validators)
|
||||
{
|
||||
this.validators.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
this.password = false;
|
||||
this.disabled = false;
|
||||
inputType = ITText;
|
||||
|
||||
printRequired = false;
|
||||
if(Form.USE_TWITTER_BOOTSTRAP) cssClass = "form-control";
|
||||
}
|
||||
|
||||
public function get_password(){
|
||||
return inputType == ITPassword;
|
||||
}
|
||||
|
||||
public function set_password(v:Bool){
|
||||
if (v){
|
||||
inputType = ITPassword;
|
||||
}else{
|
||||
inputType = ITText;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
var n = parentForm.name + "_" +name;
|
||||
var tType = switch(inputType){
|
||||
case ITHidden: "hidden";
|
||||
case ITPassword : "password" ;
|
||||
case ITText : "text" ;
|
||||
case ITColor : "color";
|
||||
}
|
||||
|
||||
return "<input class=\""+ getClasses() +"\" type=\""+tType+"\" name=\""+n+"\" id=\""+n+"\" value=\"" +safeString(value)+ "\" "+attributes+" "+ (disabled?"disabled":"")+"/>" + ((required && parentForm.isSubmitted() && printRequired)?" required":"") ;
|
||||
}
|
||||
|
||||
override public function getTypedValue(str:String):T{
|
||||
|
||||
if (str == "" || str==null) {
|
||||
return null;
|
||||
}
|
||||
return cast StringTools.trim(str);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* render label + field
|
||||
*/
|
||||
override public function getFullRow():String {
|
||||
if (this.inputType == ITHidden){
|
||||
return this.render();
|
||||
}else{
|
||||
return super.getFullRow();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package sugoi.form.elements;
|
||||
|
||||
|
||||
|
||||
class IntInput extends Input<Int>
|
||||
{
|
||||
|
||||
public function new(name, label, value, ?required=false){
|
||||
super(name, label, value, required);
|
||||
}
|
||||
|
||||
override public function getTypedValue(str:String):Int{
|
||||
if(str!=null) str = StringTools.trim(str);
|
||||
|
||||
if (str == "" || str==null) {
|
||||
|
||||
if (this.required){
|
||||
return 0;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}else{
|
||||
var v = Std.parseInt(str);
|
||||
|
||||
if (v == null){
|
||||
if (this.required){
|
||||
return 0;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}else{
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package sugoi.form.elements;
|
||||
|
||||
/**
|
||||
* ...
|
||||
* @author fbarbut
|
||||
*/
|
||||
class IntSelect extends Selectbox<Int>
|
||||
{
|
||||
|
||||
override function getTypedValue(str:String):Int{
|
||||
|
||||
if (str != null) str = StringTools.trim(str);
|
||||
|
||||
if (str==null || str=="") {
|
||||
return null;
|
||||
}else{
|
||||
return Std.parseInt(str);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* ...
|
||||
* @author Tonypee
|
||||
*/
|
||||
|
||||
package form.elements;
|
||||
|
||||
typedef KeyVal = {
|
||||
var key:String;
|
||||
var value:Dynamic;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package form;
|
||||
|
||||
class Label
|
||||
{
|
||||
public var forElement:FormElement;
|
||||
public var value:String;
|
||||
|
||||
public function new()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function populate(data:String)
|
||||
{
|
||||
value = data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package sugoi.form.elements;
|
||||
import sugoi.form.Form;
|
||||
import sugoi.form.FormElement;
|
||||
|
||||
class RadioGroup extends FormElement<String>
|
||||
{
|
||||
public var data:ListData.FormData<String>;
|
||||
public var selectMessage:String;
|
||||
public var labelLeft:Bool;
|
||||
public var labelRight:Bool;
|
||||
public var vertical:Bool;
|
||||
|
||||
public function new(name:String, label:String, ?data:Array<{label:String,value:String}>, ?selected:String, ?defaultValue:String, ?vertical:Bool=true, ?labelRight:Bool=true,?required=false)
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.data = data != null ? data : [];
|
||||
this.value = selected != null ? selected : defaultValue;
|
||||
this.vertical = vertical;
|
||||
this.labelRight = labelRight;
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
public function addOption(label:String, value:String)
|
||||
{
|
||||
data.push( { label:label, value:value } );
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
var s = "";
|
||||
var n = parentForm.name + "_" +name;
|
||||
|
||||
var c = 0;
|
||||
if (data != null)
|
||||
{
|
||||
for (row in data)
|
||||
{
|
||||
var vClass = vertical ? " radioItemVertical" : " radioItemHorizontal";
|
||||
s += '<div class="radioItem'+vClass+'">';
|
||||
var radio = "<input type=\"radio\" name=\""+n+"\" id=\""+n+c+"\" value=\"" + row.value + "\" " + (row.value == Std.string(value) ? "checked":"") +" />\n";
|
||||
var label = "<label for=\"" + n+c + "\" >" + row.label +"</label>";
|
||||
|
||||
s += labelRight ? radio + " "+label+" ": label+" "+radio+" ";
|
||||
s += '</div>';
|
||||
//if (verticle) s += "<br />";
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
override function getTypedValue(str:String){
|
||||
if(str==null) return null;
|
||||
str = StringTools.trim(str);
|
||||
return (str == "") ? return null : str;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package sugoi.form.elements;
|
||||
|
||||
import sugoi.form.Form;
|
||||
import sugoi.form.FormElement;
|
||||
|
||||
class Readonly<T> extends FormElement<T>
|
||||
{
|
||||
public var display:Bool;
|
||||
|
||||
public function new(name:String, label:String, ?value:T, ?required:Bool = false, ?display:Bool = false, ?attributes:String = "")
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
this.required = required;
|
||||
this.display = display;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
var n = parentForm.name + "_" + name;
|
||||
|
||||
var str:StringBuf = new StringBuf();
|
||||
|
||||
str.add("<input type=\"hidden\" name=\"" + n + "\" id=\"" + n + "\" value=\"" +value + "\"/>");
|
||||
if (display) {
|
||||
str.add(value);
|
||||
}
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
override public function getTypedValue(str:String):T
|
||||
{
|
||||
if (str == "" || str==null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return cast StringTools.trim(str);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package form.elements;
|
||||
/*
|
||||
* TinyMCE rich text editor
|
||||
*
|
||||
*/
|
||||
|
||||
import form.Form;
|
||||
import form.FormElement;
|
||||
|
||||
class Richtext extends FormElement
|
||||
{
|
||||
public var width:Float;
|
||||
public var height:Float;
|
||||
public var content_css:String;
|
||||
public var mode:RichtextMode;
|
||||
|
||||
public function new(name:String, label:String, ?value:String, ?required:Bool=false, ?attibutes:String="")
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
this.required = required;
|
||||
this.attributes = attibutes;
|
||||
|
||||
width = 300;
|
||||
height = 300;
|
||||
content_css = "css/cms/richtext_default.css";
|
||||
|
||||
mode = RichtextMode.SIMPLE;
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
var n = form.name + "_" +name;
|
||||
|
||||
if(content_css != "") content_css += "?" + Date.now().getTime();
|
||||
|
||||
var str:StringBuf = new StringBuf();
|
||||
str.add("\n <textarea name=\"" + n + "\" id=\"" + n + "\" >"+value+"</textarea>");
|
||||
str.add("\n <script> ");
|
||||
str.add("\n tinyMCE.init({ ");
|
||||
str.add("\n mode : \"exact\", ");
|
||||
str.add("\n elements : \""+n+"\", ");
|
||||
|
||||
str.add("\n theme : \""+(mode == RichtextMode.SIMPLE ? "simple" : "advanced")+"\", ");
|
||||
|
||||
str.add("\n width : \""+width+"\", ");
|
||||
str.add("\n height : \""+height+"\", ");
|
||||
str.add("\n content_css : \"" + content_css + "\", ");
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case SIMPLE:
|
||||
case FORMAT:
|
||||
str.add("\n plugins : \"advlink,inlinepopups,paste\", ");
|
||||
str.add("\n theme_advanced_buttons1 : \"bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,outdent,indent,|,link,unlink,|,pastetext,cleanup,removeformat\", ");
|
||||
str.add("\n theme_advanced_buttons2 : \"\", ");
|
||||
str.add("\n theme_advanced_toolbar_location : \"top\", ");
|
||||
str.add("\n theme_advanced_statusbar_location : \"bottom\", ");
|
||||
str.add("\n theme_advanced_resizing : true, ");
|
||||
case SIMPLE_TABLES:
|
||||
str.add("\n plugins : \"table,advlink,inlinepopups,paste\", ");
|
||||
str.add("\n theme_advanced_buttons1 : \"bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,outdent,indent,|,link,unlink,|,pastetext,cleanup,removeformat\", ");
|
||||
str.add("\n theme_advanced_buttons2 : \"table,tablecontrols\", ");
|
||||
str.add("\n theme_advanced_buttons3 : \"\", ");
|
||||
|
||||
str.add("\n theme_advanced_toolbar_location : \"top\", ");
|
||||
str.add("\n theme_advanced_statusbar_location : \"bottom\", ");
|
||||
str.add("\n theme_advanced_resizing : true, ");
|
||||
case ADVANCED:
|
||||
str.add("\n theme_advanced_styles: \"Small 1=small1\", ");
|
||||
str.add("\n plugins : \"safari,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template\", ");
|
||||
str.add("\n theme_advanced_buttons1 : \"bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,styleselect,formatselect,fontselect,fontsizeselect,|,forecolor\", ");
|
||||
str.add("\n theme_advanced_buttons2 : \"cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,code\", ");
|
||||
str.add("\n theme_advanced_buttons3 : \"tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,emotions,iespell,media,advhr,|,print,|,ltr,rtl,|,fullscreen\", ");
|
||||
str.add("\n theme_advanced_buttons4 : \"insertlayer,moveforward,movebackward,absolute,|,styleprops,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,pagebreak\", ");
|
||||
str.add("\n theme_advanced_toolbar_location : \"top\", ");
|
||||
str.add("\n theme_advanced_toolbar_align : \"left\", ");
|
||||
str.add("\n theme_advanced_statusbar_location : \"bottom\", ");
|
||||
str.add("\n theme_advanced_resizing : false, ");
|
||||
}
|
||||
str.add("\n file_browser_callback : 'myFileBrowser', ");
|
||||
|
||||
str.add("\n }); ");
|
||||
str.add("\n </script>\n ");
|
||||
|
||||
if (!isValid()) str.add(" required");
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
public function toString() :String
|
||||
{
|
||||
return render();
|
||||
}
|
||||
}
|
||||
|
||||
enum RichtextMode
|
||||
{
|
||||
SIMPLE;
|
||||
FORMAT;
|
||||
SIMPLE_TABLES;
|
||||
ADVANCED;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* WYMEditor ( XHTML wysiwig editor )
|
||||
* http://files.wymeditor.org/wymeditor-1.0.0b2/examples/
|
||||
*/
|
||||
package form.elements;
|
||||
|
||||
import form.Form;
|
||||
import form.FormElement;
|
||||
|
||||
class RichtextWym extends FormElement
|
||||
{
|
||||
public var width:Float;
|
||||
public var height:Float;
|
||||
public var allowImages:Bool;
|
||||
public var allowTables:Bool;
|
||||
public var editorStyles:String;
|
||||
public var containersItems:String;
|
||||
public var classesItems:String;
|
||||
|
||||
public function new(name:String, label:String, ?value:String, ?required:Bool=false, ?attibutes:String="")
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
this.required = required;
|
||||
this.attributes = attibutes;
|
||||
|
||||
width = 500;
|
||||
height = 300;
|
||||
|
||||
allowImages = true;
|
||||
allowTables = false;
|
||||
editorStyles = "";
|
||||
containersItems = "";
|
||||
classesItems = "";
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
var n = form.name + "_" +name;
|
||||
|
||||
editorStyles = StringTools.replace(editorStyles, "\n", " ");
|
||||
editorStyles = StringTools.replace(editorStyles, "\r", " ");
|
||||
|
||||
var str:StringBuf = new StringBuf();
|
||||
str.add("\n <textarea name=\"" + n + "\" id=\"" + n + "\" >" + value + "</textarea>");
|
||||
str.add("<script type=\"text/javascript\">");
|
||||
str.add("jQuery(function() {");
|
||||
str.add(" jQuery('#" + n + "').wymeditor({");
|
||||
str.add("logoHtml: '',");
|
||||
//str.add(" stylesheet: './css/site.css',");
|
||||
str.add("editorStyles: [\""+editorStyles+"\"],");
|
||||
str.add("postInit: function(wym) {");
|
||||
str.add(" jQuery(wym._box).find(wym._options.containersSelector).removeClass('wym_dropdown').addClass('wym_panel').find('h2 > span').remove();");
|
||||
str.add(" jQuery(wym._box).find(wym._options.iframeSelector).css('height', '"+height+"px').css('width', '"+width+"px');");
|
||||
str.add("},");
|
||||
str.add("toolsItems: [");
|
||||
str.add(" {'name': 'Bold', 'title': 'Strong', 'css': 'wym_tools_strong'}, ");
|
||||
str.add(" {'name': 'Italic', 'title': 'Emphasis', 'css': 'wym_tools_emphasis'},");
|
||||
str.add(" {'name': 'CreateLink', 'title': 'Link', 'css': 'wym_tools_link'},");
|
||||
str.add(" {'name': 'Unlink', 'title': 'Unlink', 'css': 'wym_tools_unlink'},");
|
||||
if(allowImages) str.add("{'name': 'InsertImage', 'title': 'Image', 'css': 'wym_tools_image'},");
|
||||
str.add(" {'name': 'InsertOrderedList', 'title': 'Ordered_List', 'css': 'wym_tools_ordered_list'},");
|
||||
str.add(" {'name': 'InsertUnorderedList', 'title': 'Unordered_List', 'css': 'wym_tools_unordered_list'},");
|
||||
if(allowTables) str.add("{'name': 'InsertTable', 'title': 'Table', 'css': 'wym_tools_table'},");
|
||||
str.add(" {'name': 'Paste', 'title': 'Paste_From_Word', 'css': 'wym_tools_paste'},");
|
||||
str.add(" {'name': 'Undo', 'title': 'Undo', 'css': 'wym_tools_undo'},");
|
||||
str.add(" {'name': 'Redo', 'title': 'Redo', 'css': 'wym_tools_redo'},");
|
||||
str.add(" {'name': 'ToggleHtml', 'title': 'HTML', 'css': 'wym_tools_html'}");
|
||||
str.add("],");
|
||||
str.add("containersItems: [" + containersItems + "],");
|
||||
if (classesItems != "") {
|
||||
str.add("classesItems: [" + classesItems + "],");
|
||||
}else {
|
||||
str.add("classesHtml: '',");
|
||||
}
|
||||
str.add("postInitDialog: function (wym, wdw) { if(wymeditor_filebrowser != null) wymeditor_filebrowser(wym, wdw); }");
|
||||
str.add(" });");
|
||||
str.add("});");
|
||||
str.add("</script>");
|
||||
|
||||
if (!isValid()) str.add(" required");
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
public function toString() :String
|
||||
{
|
||||
return render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package sugoi.form.elements;
|
||||
import sugoi.form.Form;
|
||||
import sugoi.form.FormElement;
|
||||
|
||||
class Selectbox<T> extends FormElement<T>
|
||||
{
|
||||
public var data:Array<{label:String,value:T}>;
|
||||
public var nullMessage:String;
|
||||
public var onChange:String;
|
||||
public var size:Int;
|
||||
public var multiple:Bool;
|
||||
|
||||
public function new(name:String, label:String, ?data:Array<{label:String,value:T}>, ?selected:T, required:Bool=false, ?nullMessage="-", ?attributes="")
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.data = data != null ? data: new Array();
|
||||
this.value = selected;
|
||||
this.required = required;
|
||||
this.nullMessage = nullMessage;
|
||||
this.attributes = attributes;
|
||||
size = 1;
|
||||
multiple = false;
|
||||
onChange = "";
|
||||
if(Form.USE_TWITTER_BOOTSTRAP) cssClass = "form-control";
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
var s = "";
|
||||
var n = parentForm.name;
|
||||
n += "_" +name;
|
||||
|
||||
s += '\n<select name="' + n + '" id="' + n + '" '+attributes+' class="'+ getClasses() +'" onChange="'+onChange+'" size="'+size+'" '+(multiple ? "multiple" : "")+'/>';
|
||||
|
||||
if (nullMessage != "")
|
||||
s += "<option value=\"\" " + (Std.string(value) == "" ? "selected":"") + ">" + nullMessage + "</option>";
|
||||
|
||||
if (data != null){
|
||||
for (row in data) {
|
||||
s += "<option value=\"" + Std.string(row.value) + "\" " + (Std.string(row.value) == Std.string(value) ? "selected":"") + ">" + Std.string(row.label) + "</option>";
|
||||
}
|
||||
}
|
||||
s += "</select>";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package sugoi.form.elements;
|
||||
|
||||
|
||||
|
||||
class StringInput extends Input<String>
|
||||
{
|
||||
|
||||
override public function getTypedValue(str:String):String{
|
||||
|
||||
if (str != null)
|
||||
str = StringTools.trim(str);
|
||||
|
||||
if (str == "" || str==null) {
|
||||
return null;
|
||||
}else{
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package sugoi.form.elements;
|
||||
|
||||
/**
|
||||
* ...
|
||||
* @author fbarbut
|
||||
*/
|
||||
class StringSelect extends Selectbox<String>
|
||||
{
|
||||
|
||||
override function getTypedValue(str:String){
|
||||
str = StringTools.trim(str);
|
||||
if (str == "" || str==null) {
|
||||
return null;
|
||||
}else{
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package sugoi.form.elements;
|
||||
import sugoi.form.Form;
|
||||
import sugoi.form.FormElement;
|
||||
|
||||
|
||||
class Submit extends FormElement<String>
|
||||
{
|
||||
public function new(name:String, value:String)
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
|
||||
}
|
||||
|
||||
override public function isValid():Bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
override public function render() :String
|
||||
{
|
||||
if (Form.USE_TWITTER_BOOTSTRAP) cssClass = "btn btn-primary";
|
||||
|
||||
var s = "<input type=\"submit\" class=\"" + getClasses() +"\" value=\"" + value + "\" " + attributes + " name=\"" +parentForm.name + "_" +name + "\" id=\"" +parentForm.name + "_" +name + "\" />";
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
override public function getFullRow():String
|
||||
{
|
||||
return "<div class='col-sm-4'></div><div class='col-sm-8'>" + this.render() + "</div>";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
package sugoi.form.elements;
|
||||
|
||||
import sugoi.form.elements.Input;
|
||||
import sugoi.form.Form;
|
||||
import sugoi.form.validators.*;
|
||||
|
||||
class TextArea extends StringInput
|
||||
{
|
||||
public var height:Int;
|
||||
|
||||
public function new(name:String, label:String, ?value:String, ?required:Bool=false, ?validators:Array<Validator<String>>, ?attributes:String)
|
||||
{
|
||||
super(name, label, value, required, validators, attributes);
|
||||
|
||||
}
|
||||
|
||||
override public function render():String
|
||||
{
|
||||
var n = parentForm.name + "_" +name;
|
||||
|
||||
//if (showLabelAsDefaultValue && value == label){
|
||||
//addValidator(new BoolValidator(false, "Not valid"));
|
||||
//}
|
||||
|
||||
if ((value == null || value == "") && showLabelAsDefaultValue) {
|
||||
value = label;
|
||||
}
|
||||
|
||||
var s = "";
|
||||
if (required && parentForm.isSubmitted() && printRequired) s += "required<br />";
|
||||
|
||||
s += "<textarea class=\""+ getClasses() +"\" name=\"" + n + "\" id=\"" + n + "\" " + attributes + " >" + safeString(value) + "</textarea>";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package sugoi.form.filters;
|
||||
|
||||
class Filter
|
||||
{
|
||||
public function new() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package sugoi.form.filters;
|
||||
|
||||
/**
|
||||
* Converts a String to a Float
|
||||
*/
|
||||
class FloatFilter extends Filter implements IFilter<Float>
|
||||
{
|
||||
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public function filter(f:Float):Float{
|
||||
return f;
|
||||
}
|
||||
|
||||
public function filterString(n:String):Float {
|
||||
|
||||
if (n == null || n=="") return null;
|
||||
n = StringTools.trim(n);
|
||||
n = StringTools.replace(n, ",", ".");
|
||||
var f = Std.parseFloat(n);
|
||||
if( Math.isNaN(f) ) f = null;
|
||||
return f;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package sugoi.form.filters;
|
||||
|
||||
|
||||
interface IFilter<T>
|
||||
{
|
||||
|
||||
public function filter(data:T):T;
|
||||
|
||||
public function filterString(data:String):T;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
package sugoi.form.validators;
|
||||
import sugoi.form.validators.Validator;
|
||||
|
||||
class BoolValidator extends Validator<Bool>
|
||||
{
|
||||
public var errorNotValid:String;
|
||||
public var valid:Bool;
|
||||
|
||||
public function new(valid:Bool, ?error:String)
|
||||
{
|
||||
super();
|
||||
|
||||
this.valid = valid;
|
||||
|
||||
if (error != null) {
|
||||
errorNotValid = error;
|
||||
}else {
|
||||
errorNotValid = "Not valid.";
|
||||
}
|
||||
}
|
||||
|
||||
override public function isValid(value):Bool
|
||||
{
|
||||
if (!valid)
|
||||
errors.push(errorNotValid);
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2008, TouchMyPixel & contributors
|
||||
* Original author : Tony Polinelli <tonyp@touchmypixel.com>
|
||||
* Contributers: Tarwin Stroh-Spijer
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE TOUCH MY PIXEL & CONTRIBUTERS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE TOUCH MY PIXEL & CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package sugoi.form.validators;
|
||||
import sugoi.form.Form;
|
||||
import sugoi.form.FormElement;
|
||||
import sugoi.form.Validator;
|
||||
|
||||
class CustomValidator extends Validator
|
||||
{
|
||||
public var validationFunction : Dynamic->Bool;
|
||||
public var errorNotValid:String;
|
||||
|
||||
public function new( validationFunction : Dynamic->Bool, ?errorMessage:String = null )
|
||||
{
|
||||
super();
|
||||
this.validationFunction = validationFunction;
|
||||
this.errorNotValid = errorMessage;
|
||||
}
|
||||
|
||||
override public function isValid( value : Dynamic ) : Bool
|
||||
{
|
||||
super.isValid( value );
|
||||
|
||||
var valid = false;
|
||||
if ( validationFunction != null )
|
||||
valid = validationFunction( value);
|
||||
|
||||
if (!valid)
|
||||
errors.add(errorNotValid);
|
||||
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2008, TouchMyPixel & contributors
|
||||
* Original author : Tony Polinelli <tonyp@touchmypixel.com>
|
||||
* Contributers: Tarwin Stroh-Spijer
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE TOUCH MY PIXEL & CONTRIBUTERS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE TOUCH MY PIXEL & CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package sugoi.form.validators;
|
||||
//import sugoi.form.Validator;
|
||||
//import poko.utils.StringTools2;
|
||||
//import site.cms.common.DateTimeMode;
|
||||
|
||||
class DateTimeValidator extends Validator
|
||||
{
|
||||
//public static var EMAIL_REGEX : EReg = "([0-9]{4})[-\.[:space:]]([0-9]{2})[-\.[:space:]]([0-9]{2})";
|
||||
public var format:EReg;
|
||||
|
||||
public var minDate:Date;
|
||||
public var maxDate:Date;
|
||||
|
||||
public var errorDateOutOfRange:String;
|
||||
public var errorDateNotValid:String;
|
||||
public var errorDateNotExist:String;
|
||||
|
||||
public function new( ?mode : DateTimeMode = null, ?minDate:Date, ?maxDate:Date )
|
||||
{
|
||||
super();
|
||||
|
||||
if ( mode == DateTimeMode.date )
|
||||
{
|
||||
format = new EReg("[0-9]{4}-[0-9]{2}-[0-9]{2}", null);
|
||||
errorDateNotValid = "Is not in the correct format. YYYY-MM-DD is required.";
|
||||
}
|
||||
else if ( mode == DateTimeMode.time )
|
||||
{
|
||||
format = new EReg("[0-9]{2}:[0-9]{2}:[0-9]{2}", null);
|
||||
errorDateNotValid = "Is not in the correct format. HH:MM:SS is required.";
|
||||
}
|
||||
else
|
||||
{
|
||||
format = new EReg("[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}", null);
|
||||
errorDateNotValid = "Is not in the correct format. YYYY-MM-DD HH:MM:SS is required.";
|
||||
}
|
||||
|
||||
errorDateOutOfRange = "Must be between %s and %s";
|
||||
|
||||
|
||||
if (minDate != null) this.minDate = minDate;
|
||||
if (maxDate != null) this.maxDate = maxDate;
|
||||
}
|
||||
|
||||
override public function isValid(value:Dynamic):Bool
|
||||
{
|
||||
var valid = true;
|
||||
var d:Date;
|
||||
|
||||
// value is date
|
||||
if (Type.getClass(value) == Date){
|
||||
d = value;
|
||||
// value conforms to format, convert to date
|
||||
}else if (Type.getClass(value) == String && format.match(value)) {
|
||||
d = Date.fromString(value);
|
||||
}else {
|
||||
errors.add(errorDateNotValid);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check date range
|
||||
if (minDate != null){
|
||||
if (d.getTime() < minDate.getTime())
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (maxDate != null){
|
||||
if (d.getTime() > maxDate.getTime())
|
||||
valid = false;
|
||||
}
|
||||
|
||||
// date must be out of range if invalid at this point
|
||||
if (!valid)
|
||||
errors.add(StringTools2.printf(errorDateOutOfRange, [dateOnly(minDate), dateOnly(maxDate)]));
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
private function dateOnly(d:Date):String
|
||||
{
|
||||
return StringTools.lpad(Std.string(d.getFullYear()), "0", 4) + "-" + StringTools.lpad(Std.string(d.getMonth()), "0", 2) + "-" + StringTools.lpad(Std.string(d.getDate()), "0", 2);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
var v:DateValidator = new DateValidator(Date.fromString("1981-12-09"), Date.fromString("2030-11-11"));
|
||||
|
||||
// -------------------------------------------------
|
||||
// check input
|
||||
trace("<br /><br />INPUT<br />");
|
||||
|
||||
v.reset();
|
||||
trace(true);
|
||||
trace(v.isValid("1981-12-09"));
|
||||
trace(v.errors);
|
||||
|
||||
v.reset();
|
||||
trace(false);
|
||||
trace(v.isValid("x981-12-09"));
|
||||
trace(v.errors);
|
||||
|
||||
v.reset();
|
||||
trace(false);
|
||||
trace(v.isValid("1985-90-90"));
|
||||
trace(v.errors);
|
||||
|
||||
// -------------------------------------------------
|
||||
// check ranges
|
||||
trace("<br /><br />RANGES<br />");
|
||||
|
||||
v.reset();
|
||||
trace(true);
|
||||
trace(v.isValid(Date.fromString("1981-12-09")));
|
||||
trace(v.errors);
|
||||
|
||||
v.reset();
|
||||
trace(false);
|
||||
trace(v.isValid(Date.fromString("1981-12-08")));
|
||||
trace(v.errors);
|
||||
|
||||
v.reset();
|
||||
trace(true);
|
||||
trace(v.isValid(Date.now()));
|
||||
trace(v.errors);
|
||||
|
||||
v.reset();
|
||||
trace(true);
|
||||
trace(v.isValid(Date.fromString("2030-11-11")));
|
||||
trace(v.errors);
|
||||
|
||||
v.reset();
|
||||
trace(false);
|
||||
trace(v.isValid(Date.fromString("2030-11-12")));
|
||||
trace(v.errors);
|
||||
*/
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2008, TouchMyPixel & contributors
|
||||
* Original author : Tony Polinelli <tonyp@touchmypixel.com>
|
||||
* Contributers: Tarwin Stroh-Spijer
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE TOUCH MY PIXEL & CONTRIBUTERS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE TOUCH MY PIXEL & CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package sugoi.form.validators;
|
||||
import sugoi.form.Validator;
|
||||
import poko.utils.StringTools2;
|
||||
|
||||
class DateValidator extends Validator
|
||||
{
|
||||
//public static var EMAIL_REGEX : EReg = "([0-9]{4})[-\.[:space:]]([0-9]{2})[-\.[:space:]]([0-9]{2})";
|
||||
public var format:EReg;
|
||||
|
||||
public var minDate:Date;
|
||||
public var maxDate:Date;
|
||||
|
||||
public var errorDateOutOfRange:String;
|
||||
public var errorDateNotValid:String;
|
||||
public var errorDateNotExist:String;
|
||||
|
||||
public function new(?minDate:Date, ?maxDate:Date)
|
||||
{
|
||||
super();
|
||||
|
||||
format = new EReg("[0-9]{4}-[0-9]{2}-[0-9]{2}", null);
|
||||
|
||||
errorDateOutOfRange = "Must be between %s and %s";
|
||||
errorDateNotValid = "Is not in the correct format. YYYY-MM-DD is required.";
|
||||
|
||||
if (minDate != null) this.minDate = minDate;
|
||||
if (maxDate != null) this.maxDate = maxDate;
|
||||
}
|
||||
|
||||
override public function isValid(value:Dynamic):Bool
|
||||
{
|
||||
var valid = true;
|
||||
var d:Date;
|
||||
|
||||
// value is date
|
||||
if (Type.getClass(value) == Date){
|
||||
d = value;
|
||||
// value conforms to format, convert to date
|
||||
}else if (Type.getClass(value) == String && format.match(value)) {
|
||||
d = Date.fromString(value);
|
||||
}else {
|
||||
errors.add(errorDateNotValid);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check date range
|
||||
if (minDate != null){
|
||||
if (d.getTime() < minDate.getTime())
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (maxDate != null){
|
||||
if (d.getTime() > maxDate.getTime())
|
||||
valid = false;
|
||||
}
|
||||
|
||||
// date must be out of range if invalid at this point
|
||||
if (!valid)
|
||||
errors.add(StringTools2.printf(errorDateOutOfRange, [dateOnly(minDate), dateOnly(maxDate)]));
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
private function dateOnly(d:Date):String
|
||||
{
|
||||
return StringTools.lpad(Std.string(d.getFullYear()), "0", 4) + "-" + StringTools.lpad(Std.string(d.getMonth()), "0", 2) + "-" + StringTools.lpad(Std.string(d.getDate()), "0", 2);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
var v:DateValidator = new DateValidator(Date.fromString("1981-12-09"), Date.fromString("2030-11-11"));
|
||||
|
||||
// -------------------------------------------------
|
||||
// check input
|
||||
trace("<br /><br />INPUT<br />");
|
||||
|
||||
v.reset();
|
||||
trace(true);
|
||||
trace(v.isValid("1981-12-09"));
|
||||
trace(v.errors);
|
||||
|
||||
v.reset();
|
||||
trace(false);
|
||||
trace(v.isValid("x981-12-09"));
|
||||
trace(v.errors);
|
||||
|
||||
v.reset();
|
||||
trace(false);
|
||||
trace(v.isValid("1985-90-90"));
|
||||
trace(v.errors);
|
||||
|
||||
// -------------------------------------------------
|
||||
// check ranges
|
||||
trace("<br /><br />RANGES<br />");
|
||||
|
||||
v.reset();
|
||||
trace(true);
|
||||
trace(v.isValid(Date.fromString("1981-12-09")));
|
||||
trace(v.errors);
|
||||
|
||||
v.reset();
|
||||
trace(false);
|
||||
trace(v.isValid(Date.fromString("1981-12-08")));
|
||||
trace(v.errors);
|
||||
|
||||
v.reset();
|
||||
trace(true);
|
||||
trace(v.isValid(Date.now()));
|
||||
trace(v.errors);
|
||||
|
||||
v.reset();
|
||||
trace(true);
|
||||
trace(v.isValid(Date.fromString("2030-11-11")));
|
||||
trace(v.errors);
|
||||
|
||||
v.reset();
|
||||
trace(false);
|
||||
trace(v.isValid(Date.fromString("2030-11-12")));
|
||||
trace(v.errors);
|
||||
*/
|
||||
@@ -0,0 +1,40 @@
|
||||
package sugoi.form.validators;
|
||||
import sugoi.form.validators.Validator;
|
||||
|
||||
class EmailValidator extends Validator<String>
|
||||
{
|
||||
public var errorNotValid:String;
|
||||
public static var emailRegex = ~/^[^()<>@,;:\\"\[\]\s[:cntrl:]]+@[A-Z0-9][A-Z0-9-]*(\.[A-Z0-9][A-Z0-9-]*)*\.(xn--[A-Z0-9]+|[A-Z]{2,8})$/i;
|
||||
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
#if js
|
||||
errorNotValid = "Not a valid email address";
|
||||
#else
|
||||
errorNotValid = switch(App.current.getLang()){
|
||||
case "fr" : "Adresse email invalide";
|
||||
default : "Not a valid email address";
|
||||
};
|
||||
#end
|
||||
}
|
||||
|
||||
override public function isValid(value:Dynamic):Bool
|
||||
{
|
||||
super.isValid(value);
|
||||
|
||||
var valid = emailRegex.match(Std.string(value));
|
||||
if (!valid)
|
||||
errors.add(errorNotValid);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
public inline static function check(value:String):Bool
|
||||
{
|
||||
var val = new EmailValidator();
|
||||
return val.isValid(value);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2008, TouchMyPixel & contributors
|
||||
* Original author : Tony Polinelli <tonyp@touchmypixel.com>
|
||||
* Contributers: Tarwin Stroh-Spijer
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE TOUCH MY PIXEL & CONTRIBUTERS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE TOUCH MY PIXEL & CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
package sugoi.form.validators;
|
||||
|
||||
import sugoi.form.Validator;
|
||||
import poko.utils.StringTools2;
|
||||
|
||||
class ListValidator extends Validator
|
||||
{
|
||||
public var list:Array<Dynamic>;
|
||||
public var mode:ListValidatorMode;
|
||||
|
||||
public var errorAllow:String;
|
||||
public var errorDeny:String;
|
||||
|
||||
public function new(?mode:ListValidatorMode)
|
||||
{
|
||||
super();
|
||||
|
||||
errorAllow = "Only the values %s are allowed.";
|
||||
// this is used for the complete list of denied values
|
||||
//errorDeny = "The values %s are not allowed.";
|
||||
errorDeny = "The value '%s' is not allowed.";
|
||||
|
||||
this.mode = mode != null ? mode : ListValidatorMode.ALLOW;
|
||||
}
|
||||
|
||||
override public function isValid(value:Dynamic):Bool
|
||||
{
|
||||
super.isValid(value);
|
||||
|
||||
var valueExists = Lambda.has(list, value);
|
||||
var valid = (mode == ListValidatorMode.ALLOW) ? valueExists : !valueExists;
|
||||
if (!valid) {
|
||||
// this one returns a list of denied values, which is nice, but though thought it might be a security risk somehow?
|
||||
//errors.push(StringTools2.printf(mode == ListValidatorMode.ALLOW ? errorAllow : errorDeny, [joinAsSentence(list, "'")]));
|
||||
if (mode == ListValidatorMode.ALLOW) {
|
||||
errors.push(StringTools2.printf(errorAllow, [joinAsSentence(list, "'")]));
|
||||
}else {
|
||||
errors.push(StringTools2.printf(errorDeny, [value]));
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
private function joinAsSentence(a:Array<Dynamic>, ?wrapWith:String):String
|
||||
{
|
||||
if (wrapWith != null) {
|
||||
for(i in 0...a.length)
|
||||
a[i] = wrapWith + a[i] + wrapWith;
|
||||
}
|
||||
var e = a.pop();
|
||||
var s = a.join(", ") + " and " + e;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
enum ListValidatorMode
|
||||
{
|
||||
ALLOW;
|
||||
DENY;
|
||||
}
|
||||
|
||||
/*
|
||||
var v:ListValidator = new ListValidator(ListValidatorMode.ALLOW);
|
||||
var a:Array<Dynamic> = ["good", "bad", "stupid"];
|
||||
v.list = a;
|
||||
trace(v.isValid("good"));
|
||||
trace(v.errors);
|
||||
v.reset();
|
||||
v.list = a;
|
||||
trace(v.isValid("bad"));
|
||||
trace(v.errors);
|
||||
v.reset();
|
||||
v.list = a;
|
||||
trace(v.isValid("ugly"));
|
||||
trace(v.errors);
|
||||
v.reset();
|
||||
*/
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2008, TouchMyPixel & contributors
|
||||
* Original author : Tony Polinelli <tonyp@touchmypixel.com>
|
||||
* Contributers: Tarwin Stroh-Spijer
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE TOUCH MY PIXEL & CONTRIBUTERS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE TOUCH MY PIXEL & CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
package sugoi.form.validators;
|
||||
|
||||
import sugoi.form.Validator;
|
||||
import poko.utils.StringTools2;
|
||||
|
||||
class NumberValidator extends Validator
|
||||
{
|
||||
public var isInt:Bool;
|
||||
public var min:Float;
|
||||
public var max:Float;
|
||||
|
||||
public var errorNumber:String;
|
||||
public var errorInt:String;
|
||||
public var errorMin:String;
|
||||
public var errorMax:String;
|
||||
|
||||
public function new(min:Float=0, max:Float=999999999999, isInt:Bool=false)
|
||||
{
|
||||
super();
|
||||
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.isInt = isInt;
|
||||
|
||||
errorNumber = "Must be a number";
|
||||
errorInt = "Must be an integer";
|
||||
errorMin = "Minimum number %s";
|
||||
errorMax = "Maximum number %s";
|
||||
}
|
||||
|
||||
override public function isValid(value:Dynamic):Bool
|
||||
{
|
||||
super.isValid(value);
|
||||
|
||||
var valid = true;
|
||||
var f = Std.parseFloat(Std.string(value));
|
||||
var i = Std.int(f);
|
||||
|
||||
if (Math.isNaN(f))
|
||||
{
|
||||
errors.add(errorNumber);
|
||||
valid = false;
|
||||
}else{
|
||||
|
||||
if (isInt && i != f) {
|
||||
errors.add(errorInt);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
var n:Float = isInt ? i : f;
|
||||
|
||||
if (n < min) {
|
||||
errors.add(StringTools2.printf(errorMin, [min]));
|
||||
valid = false;
|
||||
}else if (n > max) {
|
||||
errors.add(StringTools2.printf(errorMax, [max]));
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
var v:NumberValidator = new NumberValidator();
|
||||
v.isInt = false;
|
||||
v.min = -5;
|
||||
v.max = 10.55;
|
||||
trace(v.validate(5));
|
||||
trace(v.errors);
|
||||
v.reset();
|
||||
trace(v.validate( -6));
|
||||
trace(v.errors);
|
||||
v.reset();
|
||||
trace(v.validate( -3));
|
||||
trace(v.errors);
|
||||
v.reset();
|
||||
trace(v.validate(11.5));
|
||||
trace(v.errors);
|
||||
v.reset();
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2008, TouchMyPixel & contributors
|
||||
* Original author : Tony Polinelli <tonyp@touchmypixel.com>
|
||||
* Contributers: Tarwin Stroh-Spijer
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE TOUCH MY PIXEL & CONTRIBUTERS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE TOUCH MY PIXEL & CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
package sugoi.form.validators;
|
||||
import sugoi.form.Form;
|
||||
import sugoi.form.FormElement;
|
||||
import sugoi.form.Validator;
|
||||
import poko.utils.StringTools2;
|
||||
|
||||
class RegexValidator extends Validator
|
||||
{
|
||||
public var regex:EReg;
|
||||
public var regexOptions:String;
|
||||
public var errorRegex:String;
|
||||
|
||||
public function new(regex:EReg, ?errorMessage:String=null )
|
||||
{
|
||||
super();
|
||||
this.regex = regex;
|
||||
errorRegex = (errorMessage != null) ? errorMessage : "Regex Failed";
|
||||
}
|
||||
|
||||
override public function isValid(value:Dynamic):Bool
|
||||
{
|
||||
super.isValid(value);
|
||||
|
||||
var valid:Bool = true;
|
||||
|
||||
if (!regex.match(Std.string(value)))
|
||||
{
|
||||
errors.add(StringTools2.printf(errorRegex, [regex]));
|
||||
valid = false;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2008, TouchMyPixel & contributors
|
||||
* Original author : Tony Polinelli <tonyp@touchmypixel.com>
|
||||
* Contributers: Tarwin Stroh-Spijer
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE TOUCH MY PIXEL & CONTRIBUTERS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE TOUCH MY PIXEL & CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
package sugoi.form.validators;
|
||||
import sugoi.form.Validator;
|
||||
import poko.utils.StringTools2;
|
||||
import EReg;
|
||||
|
||||
class StringValidator extends Validator
|
||||
{
|
||||
public var minChars:Int;
|
||||
public var maxChars:Int;
|
||||
public var charList:String;
|
||||
public var mode:StringValidatorMode;
|
||||
|
||||
public var regex:EReg;
|
||||
public var regexError:String;
|
||||
|
||||
public var errorMinChars:String;
|
||||
public var errorMaxChars:String;
|
||||
public var errorDenyChars:String;
|
||||
public var errorAllowChars:String;
|
||||
|
||||
public function new(?minChars:Int=0, ?maxChars:Int=999999, ?charList:String="", ?mode:StringValidatorMode, ?regex:EReg = null, ?regexError:String)
|
||||
{
|
||||
super();
|
||||
|
||||
errorMinChars = "Must be at least %s characters long";
|
||||
errorMaxChars = "Must be less than %s characters long";
|
||||
errorDenyChars = "Cannot contain the characters '%s'";
|
||||
errorAllowChars = "Must contain only the characers '%s'";
|
||||
|
||||
this.minChars = minChars;
|
||||
this.maxChars = maxChars;
|
||||
this.charList = charList;
|
||||
this.mode = mode;
|
||||
if (this.mode == null) this.mode = StringValidatorMode.ALLOW;
|
||||
|
||||
this.regex = regex;
|
||||
this.regexError = regexError != null ? regexError : "Doesn't match required input.";
|
||||
|
||||
errors = new List();
|
||||
}
|
||||
|
||||
override public function isValid(value:Dynamic):Bool
|
||||
{
|
||||
super.isValid(value);
|
||||
|
||||
var valid = true;
|
||||
var s = Std.string(value);
|
||||
|
||||
if (minChars != null && minChars > 0 && s.length < minChars)
|
||||
{
|
||||
valid = false;
|
||||
errors.add(StringTools2.printf(errorMinChars, [ minChars]));
|
||||
}
|
||||
|
||||
if (maxChars != null && maxChars > 0 && s.length > maxChars)
|
||||
{
|
||||
valid = false;
|
||||
errors.add(StringTools2.printf(errorMaxChars, [maxChars]));
|
||||
}
|
||||
|
||||
if (charList.length > 0)
|
||||
{
|
||||
switch(mode)
|
||||
{
|
||||
case StringValidatorMode.ALLOW:
|
||||
for (i in 0...s.length)
|
||||
{
|
||||
var letter = s.charAt(i);
|
||||
if (charList.indexOf(letter) == -1)
|
||||
{
|
||||
valid = false;
|
||||
// errors.add(StringTools2.printf(errorAllowChars, [StringTools2.toSentenceList(charList)]));
|
||||
errors.add(StringTools2.printf(errorAllowChars, [charList]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
case StringValidatorMode.DENY:
|
||||
for (i in 0...s.length)
|
||||
{
|
||||
var letter = s.charAt(i);
|
||||
if (charList.indexOf(letter) != -1)
|
||||
{
|
||||
valid = false;
|
||||
//errors.add(StringTools2.printf(errorDenyChars, [StringTools2.toSentenceList(charList)]));
|
||||
errors.add(StringTools2.printf(errorDenyChars, [charList]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (regex != null)
|
||||
{
|
||||
if (!regex.match(s))
|
||||
{
|
||||
valid = false;
|
||||
errors.add(regexError);
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
enum StringValidatorMode
|
||||
{
|
||||
ALLOW;
|
||||
DENY;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package sugoi.form.validators;
|
||||
|
||||
class Validator<T>
|
||||
{
|
||||
public var errors:List<String>;
|
||||
|
||||
public function new()
|
||||
{
|
||||
errors = new List();
|
||||
}
|
||||
|
||||
public function isValid(value:T):Bool
|
||||
{
|
||||
errors.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function reset()
|
||||
{
|
||||
errors.clear();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user