├── .gitignore
├── portal.filter.fmfn
├── os.isWidnows.fmfn
├── env.databaseopen.fmfn
├── php.date.fmp.fmfn
├── my.name.fmfn
├── script.result.fmfn
├── my.contents.fmfn
├── window.frontmost.fmfn
├── file.hosted.fmfn
├── list.valuewithin.fmfn
├── php.fmpized.fmfn
├── html.paragraphs.fmfn
├── vars.makeLocal.fmfn
├── html.css.fmfn
├── user.isEditing.fmfn
├── layout.view.fmfn
├── requests.reset.fmfn
├── var.toggle.fmfn
├── webviewer.data.fmfn
├── string.explode.fmfn
├── string.implode.fmfn
├── list.position.fmfn
├── var.local.fmfn
├── html.attribute.fmfn
├── exists.script.fmfn
├── date.toUnix.fmfn
├── boolean.toggle.fmfn
├── list.extract.keyedvalue.fmfn
├── var.get.fmfn
├── layout.objects.fmfn
├── requests.get.fmfn
├── tab.save.fmfn
├── html.wraptag.fmfn
├── url.isvalid.fmfn
├── file.dirname.fmfn
├── html.document.fmfn
├── error.last.fmfn
├── script.param.named.fmfn
├── calc.eval.fmfn
├── os.versionName.fmfn
├── script.parameters.fmfn
├── file.size.fmfn
├── path.dirname.fmfn
├── script.param.set.fmfn
├── date.fromUnix.fmfn
├── list.trim.fmfn
├── char.arrows.fmfn
├── var.merge.fmfn
├── script.param.let.fmfn
├── selection.delete.fmfn
├── env.get.fmfn
├── xml.tag.fmfn
├── fmstandards
├── Developer.fmfn
├── GetFieldNameVariable.fmfn
├── WindowCenter.fmfn
├── Debug.fmfn
└── ErrorReference.fmfn
├── color.hex2dec.fmfn
├── window.offscreen.fmfn
├── developer.fmfn
├── file.ospath.fmfn
├── layout.variables.fmfn
├── requests.save.fmfn
├── error.calculation.fmfn
├── var.set.fmfn
├── window.activetab.fmfn
├── window.center.fmfn
├── mouse.clicks.fmfn
├── var.define.fmfn
├── portal.grouping.fmfn
├── vars.save.fmfn
├── script.param.change.fmfn
├── list.swapValue.fmfn
├── string.trim.fmfn
├── window.fronttabs.fmfn
├── vars.objects.fmfn
├── plugin.valid.fmfn
├── fields.changed.fmfn
├── list.sort.defined.fmfn
├── webviewer.records.txt
├── keyboard.modifiers.fmfn
├── window.properties.fmfn
├── number.format.fmfn
├── keyboard.chars.fmfn
├── debug.fmfn
├── var.list.fmfn
├── script.param.get.fmfn
├── html.checkbox.fmfn
├── file.setpath.fmfn
├── list.addRemove.fmfn
├── var.eval.fmfn
├── script.execute.fmfn
├── list.sort.fmfn
├── list.filter.fmfn
├── script.parameters.assign.fmfn
├── date.ranges.fmfn
├── object.id.fmfn
├── keycode.istype.fmfn
├── list.custom.fmfn
├── error.string.fmfn
└── window.settings.fmfn
/.gitignore:
--------------------------------------------------------------------------------
1 | .svn
2 | .DS_Store
3 |
--------------------------------------------------------------------------------
/portal.filter.fmfn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/petrowsky/fmpfunctions/HEAD/portal.filter.fmfn
--------------------------------------------------------------------------------
/os.isWidnows.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | os.isWindows( )
3 | RETURNS: (bool)
4 | */
5 |
6 | Case( Get( SystemPlatform ) = -2; 1; 0 )
--------------------------------------------------------------------------------
/env.databaseopen.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | List.valueWithin( listdata; value )
3 | RETURNS: (bool) If supplied value is within the supplied listdata
4 | DEPS: list.valueWithin
5 | */
6 |
7 | List.valueWithin ( DatabaseNames ; database )
--------------------------------------------------------------------------------
/php.date.fmp.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | php.date.fmp( string )
3 | RETURNS: (date) FMP compatible date format
4 |
5 | Can be used to store a php script within a variable or calculation
6 | */
7 |
8 | PHP_Execute ("print strtotime('" & string & "');" )
--------------------------------------------------------------------------------
/my.name.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | my.name()
4 |
5 | RETURNS: (string) current layout object name
6 | DEPS: none
7 | NOTES:
8 | =====================================================
9 | */
10 |
11 |
12 | Get ( ActiveLayoutObjectName )
--------------------------------------------------------------------------------
/script.result.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | script.result( )
4 |
5 | RETURNS: (mixed) FileMaker's internal ScriptResult function
6 | DEPS: none
7 | NOTES:
8 | =====================================================
9 | */
10 |
11 | Get ( ScriptResult )
--------------------------------------------------------------------------------
/my.contents.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | my.contents( name )
4 |
5 | RETURNS: (string) current layout object contents
6 | DEPS: none
7 | NOTES:
8 | =====================================================
9 | */
10 |
11 | GetLayoutObjectAttribute ( name ; "content" )
--------------------------------------------------------------------------------
/window.frontmost.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | window.frontmost( name )
4 |
5 | RETURNS: (bool) If the frontmost window is the one specified.
6 | DEPS:
7 | NOTES:
8 | =====================================================
9 | */
10 |
11 | GetValue( WindowNames; 1 ) = name
--------------------------------------------------------------------------------
/file.hosted.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | file.hosted()
4 |
5 | RETURNS: (bool) Whether the file is hosted or local.
6 | DEPS: None
7 | NOTES:
8 | =====================================================
9 | */
10 |
11 | If( Left( Get( FilePath ); 6) = "fmnet:"; True; False)
--------------------------------------------------------------------------------
/list.valuewithin.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * list.valueWithin( listdata; value )
3 | * RETURNS: (bool) If supplied value is within the supplied listdata
4 | */
5 |
6 | PatternCount ( ¶ & listdata & ¶ ; ¶ & value & ¶ )
7 |
8 | /*
9 | Thanks to Koen for this suggested alternative
10 | not isempty(FilterValues(listdata ; value))
11 | */
--------------------------------------------------------------------------------
/php.fmpized.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | php.fmpized( contents )
3 | RETURNS: (string) FMP compatible string of a php script
4 |
5 | Can be used to store a php script within a variable or calculation
6 | */
7 |
8 | "\"" &
9 |
10 | Substitute (
11 | script;
12 | ["\\"; "\\\\"];
13 | ["\""; "\\\""];
14 | ["\¶"; "\\\¶"];
15 | [ ¶; "\¶"] ) &
16 |
17 | "\""
--------------------------------------------------------------------------------
/html.paragraphs.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * html.paragraphs ( content )
4 | *
5 | * RETURNS: (string) Conversion of ¶'s into
6 | * DEPS: none
7 | * NOTES:
8 | * =====================================================
9 | */
10 |
11 | "
" & Substitute ( content ; "¶¶" ; "
¶" ) & "
"
--------------------------------------------------------------------------------
/vars.makeLocal.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * vars.makeLocal ( input )
4 | *
5 | * RETURNS: (string) All global vars $$ converted to $ locals
6 | * DEPENDENCIES: none
7 | * NOTES:
8 | * =====================================================
9 | *
10 | */
11 |
12 | Substitute ( input ; "$$" ; "$" )
--------------------------------------------------------------------------------
/html.css.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * html.css ( content )
4 | *
5 | * RETURNS: (string) Raw css wrapped within style tags
6 | * DEPS: none
7 | * NOTES:
8 | * =====================================================
9 | */
10 |
11 | "¶¶"
--------------------------------------------------------------------------------
/user.isEditing.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * user.isEditing()
4 | *
5 | * RETURNS: (boolean) based on database editing state
6 | * DEPENDENCIES: none
7 | * NOTES: none
8 | * =====================================================
9 | *
10 | */
11 |
12 | Get ( ActiveFieldName ) ≠ null
13 | or
14 | Get ( RecordOpenCount ) > 0
--------------------------------------------------------------------------------
/layout.view.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * layout.view ( )
4 | *
5 | * RETURNS: (string) Human readable version of Get(LayoutViewState)
6 | * DEPENDENCIES: none
7 | * NOTES: Simple helper function
8 | * =====================================================
9 | *
10 | */
11 |
12 | Choose ( Get(LayoutViewState) ; "Form" ; "List" ; "Table" )
--------------------------------------------------------------------------------
/requests.reset.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * requests.reset ( layout )
4 | *
5 | * RETURNS: (bool) Success or failure of reset
6 | * DEPENDENCIES: none
7 | * NOTES:
8 | * =====================================================
9 | *
10 | */
11 |
12 | If ( Evaluate ( "Let ( $$" & layout & ".requests = \"\"; False )" ) = "?"; False; True )
--------------------------------------------------------------------------------
/var.toggle.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * var.toggle( value )
4 | *
5 | * RETURNS: (bool) True or False based on contents of value
6 | * DEPENDENCIES: none
7 | * NOTES: none
8 | * =====================================================
9 | *
10 | */
11 |
12 | not GetAsBoolean ( value )
13 |
14 | // Special thanks to Rob Poelking for the suggestion
--------------------------------------------------------------------------------
/webviewer.data.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * webviewer.data( type; head; css; body )
4 | *
5 | * RETURNS: (string) Webviewer data url for rendering local html content
6 | * DEPS: html.document
7 | * NOTES:
8 | * =====================================================
9 | */
10 |
11 | "data:text/html," &
12 |
13 | html.document( type ; head ; css ; body )
--------------------------------------------------------------------------------
/string.explode.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | string.explode ( string ; delimiter )
4 |
5 | RETURNS: (list) of text values.
6 | DEPENDENCIES: none
7 | NOTES:
8 | =====================================================
9 |
10 | A simple text parsing function designed to break a delimited
11 | string on the supplied delimiter.
12 |
13 | */
14 |
15 | Substitute ( string ; delimiter ; ¶ )
--------------------------------------------------------------------------------
/string.implode.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | string.implode ( values ; delimiter )
4 |
5 | RETURNS: (string) delimited by the delimiter.
6 | DEPENDENCIES: none
7 | NOTES:
8 | =====================================================
9 |
10 | A simple text function designed to delimit
11 | multiple values by the supplied delimiter.
12 |
13 | */
14 |
15 | Substitute ( values ; ¶ ; delimiter )
--------------------------------------------------------------------------------
/list.position.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * list.position ( values; search )
4 | *
5 | * RETURNS: (number) numerical position of the supplied value
6 | * DEPS: none
7 | * NOTES:
8 | * =====================================================
9 | */
10 |
11 | Position ( Substitute ( Filter ( Substitute ( ¶& values &¶ ; ¶& search &¶ ; "¶•¶" ) ; "•¶" ) ; ¶ ; "|" ) ; "•" ; 1 ; 1 ) - 1
--------------------------------------------------------------------------------
/var.local.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | var.local( name ; value )
3 | RETURNS: (bool) Whether the variable was created or not
4 |
5 | This custom function is a wrapper for the assignment(creation) of local variables.
6 | If the variable cannot be created or is empty then false is returned. Otherwise
7 | it was created.
8 | */
9 |
10 | If (
11 | Evaluate( "Let ( $" & name & " = " & Quote ( value ) & "; \"\" )" ) = "?"
12 | ; 0
13 | ; not IsEmpty( Evaluate( "$" & name ))
14 | )
--------------------------------------------------------------------------------
/html.attribute.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | html.attribute ( name ; value ; tag )
4 |
5 | RETURNS: (string) Applies an attribute to an html tag
6 | DEPS: none
7 | NOTES:
8 | =====================================================
9 | */
10 |
11 | Let( [
12 | var.start = Position( tag; ">"; 1; 1 );
13 | var.attribute = " " & name & "=" & quote( value )
14 | ];
15 |
16 | Replace( tag; var.start; 0; var.attribute )
17 | )
--------------------------------------------------------------------------------
/exists.script.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================================
3 | exists.script ( name ; file )
4 |
5 | RETURNS: (bool) Whether or not the script exists in the file
6 |
7 | DEPENDENCIES: list.valueWithin()
8 | AUTHOR: Matt Petrowsky
9 | VERSION: 1.0
10 | NOTES: None
11 |
12 | =====================================================================
13 | */
14 |
15 |
16 | list.valueWithin ( ScriptNames ( file ) ; name )
--------------------------------------------------------------------------------
/date.toUnix.fmfn:
--------------------------------------------------------------------------------
1 | // UnixTime( current_timestamp ; time_zone )
2 |
3 | /*
4 | Returns the local time as a unix time stamp
5 | Specify the local time zone only if you want the time in GMT
6 | */
7 |
8 | Let( [
9 | $time = If( current_timestamp = "" or current_timestamp = "now"; Get( CurrentTimeStamp ) ; GetAsTimestamp ( current_timestamp ));
10 | $unix = GetAsNumber( $time ) - GetAsNumber( GetAsTimestamp(Date(1;1;1970) ) );
11 | $offset = time_zone * 3600
12 | ];
13 |
14 | $unix - $offset
15 |
16 | )
--------------------------------------------------------------------------------
/boolean.toggle.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================================
3 | * boolean.toggle ( number )
4 | *
5 | * RETURNS: (bool) True or False based on contents of value
6 | *
7 | * DEPENDENCIES: None
8 | * AUTHOR: Matt Petrowsky
9 | * NOTES: None
10 | *
11 | * =====================================================================
12 | */
13 |
14 | not GetAsBoolean ( value )
15 |
16 | // Special thanks to Rob Poelking for the suggestion
--------------------------------------------------------------------------------
/list.extract.keyedvalue.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | ExtractLine ( data ; match )
3 | Returns: (string) From specified match value until carriage return
4 | Note: Will match the first found occurrence
5 | */
6 |
7 | Let(
8 | [
9 | _Start = Position ( data ; match ; 1 ; 1 ) + Length( match ) ;
10 | _End = Position ( data ; ¶ ; _Start ; 1 ) ;
11 | _Length = _End - _Start
12 | ];
13 |
14 | Middle ( data ; _Start ; _Length )
15 |
16 | )
17 |
18 | /*
19 | Example:
20 | list.extract.keyedvalue ( data ; "¶Subject: ") // Will extract the subject line
21 | */
--------------------------------------------------------------------------------
/var.get.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * var.get( name )
4 | *
5 | * RETURNS: (mixed) Value of the variable specified by name
6 | * DEPENDENCIES: none
7 | * NOTES: Works only with $$global vars
8 | * =====================================================
9 | *
10 | */
11 |
12 | Let ( [
13 | var.dollarsign = If ( Left ( name ; 2 ) = "$$" ; "" ; "$$" ) // check for prefixed $$
14 | ];
15 | Let ( var.result = Evaluate( var.dollarsign & name ) ; If ( var.result = "?" ; "" ; var.result )
16 | )
--------------------------------------------------------------------------------
/layout.objects.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * layout.objects ()
4 | *
5 | * RETURNS: (string)
6 | * Return delimited list of layout objects
7 | * from the current layout.
8 | * DEPENDENCIES: none
9 | * NOTES: none
10 | * =====================================================
11 | */
12 |
13 | Substitute (
14 | LayoutObjectNames ( Get( FileName ) ; Get( LayoutName ) ) ;
15 | [ ">¶" ; "" ] ;
16 | [ "<¶" ; "" ] ;
17 | [ "¶>" ; "" ] ;
18 | [ "¶<" ; "" ]
19 | )
--------------------------------------------------------------------------------
/requests.get.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * requests.get ( layout )
4 | *
5 | * RETURNS: (string) Return delimited list of request strings
6 | * DEPENDENCIES: none
7 | * NOTES:
8 | * =====================================================
9 | *
10 | * Intended use is for extracting a return delimited list of
11 | * fieldname/value pairs from a global variable with the
12 | * same name as the layout.
13 | *
14 | */
15 |
16 | If ( Evaluate ( "$$" & layout & ".requests" ) = "?"; False; Evaluate ( "$$" & layout & ".requests" ) )
--------------------------------------------------------------------------------
/tab.save.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * tab.save ( level )
4 | * RETURNS: (bool) True or False based if tab was saved to global layout variable
5 | * DEPENDENCIES: window.activetab & list.swapValue
6 | * NOTES: none
7 | * =====================================================
8 | *
9 | */
10 |
11 | Let ( [
12 | var.tabname = GetValue ( window.activetab ( 0 ; "" ) ; level );
13 | var.variable = Get ( LayoutName ) & ".tabs";
14 | ];
15 | var.define ( var.variable ; list.swapValue ( Evaluate ( "$$" & var.variable ) ; var.tabname ; level ) )
16 | )
--------------------------------------------------------------------------------
/html.wraptag.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * html.wraptag ( values; tag )
4 | *
5 | * RETURNS: (string) HTML tags wrapped around a supplied list of items
6 | * DEPS: none
7 | * NOTES:
8 | * =====================================================
9 | */
10 |
11 | Let ([
12 |
13 | var.isList = ValueCount( values ) > 1;
14 | var.opentag = "<" & tag & ">";
15 | var.closetag = Replace( var.opentag; 1; 1; "");
16 | var.between = var.closetag & var.opentag
17 |
18 | ];
19 |
20 | var.opentag & If ( var.isList; Substitute( values; ¶; var.between ); values ) & var.closetag
21 |
22 | )
--------------------------------------------------------------------------------
/url.isvalid.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | url.isvalid ( string ; protocols )
4 |
5 | RETURNS: (boolean) Whether a url is valid or not
6 | DEPS: none
7 | NOTES: Provide additional protocols as needed
8 | =====================================================
9 | */
10 |
11 | Let (
12 | var.protocols = List(
13 | "http://";
14 | "https://";
15 | ) & ¶ & protocols;
16 |
17 | PatternCount ( var.protocols ; Left ( string ; Position ( string ; "://" ; 1 ; 1 ) + 2 ) )
18 |
19 | )
20 |
21 | /*
22 | Unit tests
23 |
24 | List(
25 | url.isvalid( "http://example.com"; "" );
26 | url.isvalid( "https://example.com"; "" )
27 | )
28 |
29 | */
--------------------------------------------------------------------------------
/file.dirname.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | file.dirname( path )
4 |
5 | RETURNS: (string) parent folder location of specified path.
6 | DEPS: none
7 | NOTES: none
8 | =====================================================
9 | */
10 |
11 | Let (
12 | [
13 | //------------------------- VARIABLES
14 |
15 | lastchar = Right( path ; 1 );
16 | path = If ( IsEmpty( path ) ; Get( FilePath ) ; path );
17 | filename = Get( FileName ) & ".fp7";
18 | folder = Substitute( path ; filename ; "" );
19 | folder = Left( folder ; Length ( folder ) - 1 )
20 |
21 | ];
22 | //------------------------- RESULT
23 |
24 | If ( lastchar = "/"; 0; folder )
25 |
26 | )
--------------------------------------------------------------------------------
/html.document.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * html.document ( type; head; css; body )
4 | *
5 | * RETURNS: (string) HTML document with supplied parts
6 | * DEPS: none
7 | * NOTES:
8 | * =====================================================
9 | */
10 |
11 | List(
12 | Case(
13 | type = "html4t" ; "";
14 | type = "xhtmlt" ; "";
15 | ""
16 | );
17 | "";
18 | "";
19 | head;
20 | css;
21 | "";
22 | "";
23 | body;
24 | "";
25 | ""
26 | )
--------------------------------------------------------------------------------
/error.last.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * error.last( )
4 | *
5 | * RETURNS: (string) Parameterized result of key/values about result
6 | * DEPENDENCIES: error.string()
7 | * NOTES: Use var.eval() to turn the returned list into local variables
8 | * =====================================================
9 | *
10 | */
11 |
12 | Let ( [
13 | var.error = Get ( LastError )
14 | ];
15 | If ( var.error ≠ 0;
16 | List (
17 | "$error=" & True;
18 | "$errornum=" & var.error;
19 | "$errorstring=" & quote ( error.string ( var.error ) );
20 | "$script=" & Quote ( Get ( ScriptName ) );
21 | );
22 | "$error=" & False // Default
23 | )
24 | )
--------------------------------------------------------------------------------
/script.param.named.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | script.param.named( keys; values)
4 |
5 | RETURNS: (mixed) the value associated to the supplied key in positional order
6 | DEPS: script.param.set
7 | =====================================================
8 | */
9 | Let (
10 | [
11 | _Compliments = ValueCount ( keys ) = ValueCount ( values );
12 | _NotEmpty = not IsEmpty( keys ) and not IsEmpty( values )
13 | ];
14 |
15 | If ( _Compliments and _NotEmpty ;
16 |
17 | script.param.set ( GetValue ( keys ; 1 ) ; GetValue ( values ; 1 ) ) & script.param.named ( MiddleValues ( keys ; 2 ; 1000000 ) ; MiddleValues ( values ; 2 ; 1000000 ) );
18 | _
19 |
20 | )
21 |
22 | )
--------------------------------------------------------------------------------
/calc.eval.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * calc.eval( calc )
4 | * RETURNS: (bool) True or False based on proper evaluation
5 | * DEPENDENCIES: none
6 | * NOTES: see var.eval for declaring multiple variables
7 | * =====================================================
8 | *
9 | * This custom function is a wrapper for the
10 | * assignment(creation) of global variables.
11 | */
12 |
13 | Let (
14 | $$ERROR.CALC.EVAL = ""; // Reset the global error variable for evaluation
15 | If (
16 | Evaluate(
17 | calc
18 | ) = "?";
19 | Let ( $$ERROR.CALC.EVAL = "EVAL ERROR¶-----¶" & calc; False );
20 | True
21 | )
22 | )
--------------------------------------------------------------------------------
/os.versionName.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * os.versionName ( )
4 | *
5 | * RETURNS: (string) Version name of OS being used
6 | * DEPENDENCIES: none
7 | * NOTES: none
8 | * RELEASE: 100907
9 | * =====================================================
10 | *
11 | */
12 |
13 | Let ([
14 | $10.0 = "Cheetah";
15 | $10.1 = "Puma";
16 | $10.2 = "Jaguar";
17 | $10.3 = "Panther";
18 | $10.4 = "Tiger";
19 | $10.5 = "Leopard";
20 | $10.6 = "Snow Leopard";
21 | $6.1 = "Windows 7";
22 | $6.0 = "Windows Vista";
23 | $5.2 = "Windows XP 64-Bit";
24 | $5.1 = "Windows XP";
25 | $5.0 = "Windows 2000"
26 | ];
27 | Evaluate ( "$" & Truncate ( Get ( SystemVersion ) ; 1 ) )
28 | )
--------------------------------------------------------------------------------
/script.parameters.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | script.parameters( style )
4 |
5 | RETURNS: (mixed) structured format of script parameters.
6 | DEPENDENCIES: string.explode, var.eval, script.parameters.assign
7 | NOTES:
8 | =====================================================
9 |
10 | A wrapper function for supporting multiple styles of passing
11 | script parameters into a script.
12 | */
13 |
14 | Case(
15 | style = "single"; Get ( ScriptParameter );
16 | style = "piped"; string.explode ( Get ( ScriptParameter ) ; "|" );
17 | style = "let"; var.eval ( Get ( ScriptParameter ) );
18 | style = "assign"; script.parameters.assign();
19 | style = "xml"; "Not implemented yet";
20 |
21 | False
22 | )
--------------------------------------------------------------------------------
/file.size.fmfn:
--------------------------------------------------------------------------------
1 | // Calculate the human readable size from bytes
2 |
3 | /*
4 | =====================================================
5 | file.size ( bytes )
6 |
7 | RETURNS: (string) Human readable file size in bytes
8 | DEPS: none
9 | NOTES: Using the Length() function on a container will return size in bytes
10 | =====================================================
11 | */
12 |
13 | Let( [
14 |
15 | b = bytes;
16 | kb = b / 1024;
17 | mb = b / 1024^2;
18 | gb = b / 1024^3;
19 | tb = b / 1024^4
20 |
21 | ];
22 |
23 | Case(
24 | Div( 1024; kb ) > 0; Round( kb ; 2 ) & " KB";
25 | Div( 1024; mb ) > 0; Round( mb ; 2 ) & " MB";
26 | Div( 1024; gb ) > 0; Round( gb ; 2 ) & " GB";
27 | Div( 1024; tb ) > 0; Round( tb ; 2 ) & " TB";
28 | b
29 | )
30 | )
--------------------------------------------------------------------------------
/path.dirname.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | path.dirname( path )
4 |
5 | RETURNS: (string) The parent folder of a specified file path
6 | DEPS: developer() function.
7 | NOTES: While testing non developer accounts you may need to take off if ( developer )
8 |
9 | =====================================================
10 | */
11 |
12 | Let (
13 | [
14 | //------------------------- VARIABLES
15 |
16 | lastchar = Right ( path ; 1 );
17 | path = If( IsEmpty ( path ) ; Get ( FilePath ) ; path );
18 | filename = Get ( FileName ) & ".fp7";
19 | folder = Substitute ( path ; filename ; "" );
20 | folder = Left ( folder ; Length ( folder ) - 1 )
21 |
22 | ];
23 | //------------------------- RESULT
24 |
25 | If ( lastchar = "/"; 0; folder )
26 |
27 | )
--------------------------------------------------------------------------------
/script.param.set.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * script.param.set( key; value)
4 | *
5 | * RETURNS: (string) keyed pair of values
6 | * DEPENDENCIES: none
7 | * NOTES: Compliments to Mikhail Edoshin http://mikhailedoshin.com
8 | * =====================================================
9 | *
10 | * This function is used to encapsulate a named value from a
11 | * data structure which preserves carriage returns and
12 | * other special characters.
13 | *
14 | */
15 |
16 | Substitute( "¶"
17 | & Substitute( key;
18 | [ "^"; ".^" ];
19 | [ "¶"; ".^^" ]
20 | ) & "¶"
21 | & Substitute( value;
22 | [ "^"; ".^" ];
23 | [ "¶"; ".^^" ]
24 | ) & "¶";
25 |
26 | [ "^"; ".^" ];
27 | [ "¶"; ".^^" ]
28 |
29 | ) & "¶"
30 |
--------------------------------------------------------------------------------
/date.fromUnix.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * date.fromUnix( unix; timezone)
4 | *
5 | * RETURNS: (date) FileMaker timestamp value based on unix timestamp supplied
6 | * DEPS: none
7 | * NOTES:
8 | * =====================================================
9 | *
10 | */
11 |
12 | Let ( [
13 | UnixTimeAdjusted = ( unix + (timezone * 3600 ) );
14 | days = Truncate ( Div ( UnixTimeAdjusted; 86400 ); 0 );
15 | days_remainder = Mod ( UnixTimeAdjusted; 86400 );
16 | hours = Truncate ( Div ( days_remainder; 3600 ); 0 );
17 | hours_remainder = Mod ( days_remainder; 3600 );
18 | minutes = Truncate ( Div ( hours_remainder; 60 ); 0) ;
19 | minutes_remainder = Mod ( hours_remainder; 60 );
20 | seconds = minutes_remainder
21 | ];
22 | Timestamp ( Date ( 1; 1; 1970) + days; Time ( hours ; minutes ; seconds ))
23 | )
--------------------------------------------------------------------------------
/list.trim.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | list.trim( values )
4 |
5 | RETURNS: (list) trimmed version of the list
6 | DEPENDENCIES:
7 | VERSION: 1.0
8 | AUTHOR: See notes
9 | NOTES: Compliments http://www.briandunning.com/cf/904
10 |
11 | =====================================================
12 | */
13 |
14 | Let([
15 | var.cleaned = Substitute( values; [ " "; "" ]; [ " "; "" ]; [ " "; "" ]; [ "¶"; "" ] ); // Text minus specified chars
16 | var.char.first = Position( values; Left( var.cleaned; 1 ); 0; 1 ); // Position of firt non cleaned char
17 | var.char.last = Position( values; Right( var.cleaned; 1 ); Length( values ); -1 ) // Position of last non cleaned char
18 | ];
19 |
20 | Case( var.char.first; Middle( values; var.char.first; var.char.last - var.char.first + 1 ) )
21 |
22 |
23 | )
--------------------------------------------------------------------------------
/char.arrows.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * char.arrows ( direction )
4 | *
5 | * RETURNS: (string) Unicode arrow character
6 | * PARAMS: direction = (enum) up, down, left, right
7 | * DEPENDENCIES: none
8 | * AUTHOR: Matt Petrowsky
9 | * NOTES:
10 | * =====================================================
11 | */
12 |
13 | Let ( [
14 | var.direction = Left ( direction ; 1 );
15 | var.arrow = Case (
16 | var.direction = "u"; char ( 9650 ); //"▲";
17 | var.direction = "d"; char ( 9660 ); //"▼";
18 | var.direction = "l"; char ( 9664 ); //"◀";
19 | var.direction = "r"; char ( 9654 ); //"▶";
20 | )
21 | ];
22 | // Result
23 | TextFont ( var.arrow ; If ( Get( SystemPlatform ) = -2 ; "Arial" ; "Apple Symbol Regular" ) )
24 |
25 | )
--------------------------------------------------------------------------------
/var.merge.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * var.merge( name ; default )
4 | *
5 | * RETURNS: (mixed) An assigned variable
6 | * DEPENDENCIES: var.set()
7 | * NOTES: Used exclusively for layout merge variables (FMP11+)
8 | * =====================================================
9 | *
10 | * This custom function is a wrapper for the
11 | * assignment(creation) of global variables
12 | * from layout based merge variables.
13 | * Use this function within conditional formatting
14 | */
15 |
16 | Let ( [
17 | var.isMerge = PatternCount ( name ; "<<" ) and PatternCount ( name ; ">>" ); // determine if a real merge var
18 | var.name = If ( var.isMerge ; Trim ( Substitute ( name ; ["<<";""] ; [">>";""] ) ) ; "" ) // strip off the merge wrap
19 | ];
20 | If ( not IsEmpty ( var.name ) ; var.set ( var.name ; default ) ; False )
21 | )
--------------------------------------------------------------------------------
/script.param.let.fmfn:
--------------------------------------------------------------------------------
1 | /* NEEDS TO ACCOUNT FOR DATATYPE CURRENTLY ONLY SUPPORTS NUMBERS
2 | =====================================================
3 | script.param.let( keys; values)
4 |
5 | RETURNS: (mixed) the value associated to the supplied key in positional order
6 | DEPS: none
7 | ABOUT: Takes two complimented set of lists and turns them into variables
8 | =====================================================
9 | */
10 | Let (
11 | [
12 | _Compliments = ValueCount ( keys ) = ValueCount ( values );
13 | _NotEmpty = not IsEmpty( keys ) and not IsEmpty( values )
14 | ];
15 |
16 | If ( _Compliments and _NotEmpty ;
17 |
18 | "$" & GetValue ( keys ; 1 ) & " = " & GetValue ( values ; 1 ) & If ( ValueCount( keys ) = 1; "¶" ; ";¶" )
19 | & script.param.let ( MiddleValues ( keys ; 2 ; 1000000 ) ; MiddleValues ( values ; 2 ; 1000000 ) );
20 | _
21 |
22 | )
23 |
24 | )
--------------------------------------------------------------------------------
/selection.delete.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * selection.delete ()
4 | *
5 | * RETURNS: (string) Active field contents less selection or one backspace
6 | * DEPENDENCIES: none
7 | * NOTES: Useful when determining field contents with keystroke triggers
8 | * =====================================================
9 | *
10 | */
11 |
12 |
13 | Let ( [
14 | var.content = Get ( ActiveFieldContents );
15 | var.endPoint = If ( Get ( ActiveSelectionSize ) > 0 ; Get ( ActiveSelectionStart ) + Get ( ActiveSelectionSize ) ; False );
16 | var.toDelete = Middle ( var.content ; Get ( ActiveSelectionStart ) ; var.endPoint - Get ( ActiveSelectionStart ) )
17 | ];
18 |
19 | If ( not var.endPoint;
20 | Replace ( var.content ; Get ( ActiveSelectionStart ) -1 ; 1 ; "" );
21 | Substitute ( Get ( ActiveFieldContents ) ; var.toDelete ; "" )
22 | )
23 |
24 | )
--------------------------------------------------------------------------------
/env.get.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | env.get( parameter )
3 | RETURNS: FileMaker's Get functions in a more friendly manner
4 | DEPS: os.isWindows
5 | */
6 |
7 | Let(
8 | //--------------- VARIABLES
9 |
10 | p = parameter;
11 |
12 | //--------------- RESULT
13 |
14 | Case(
15 |
16 | p = "platform" ; If( os.isWindows ; "windows" ; "macintosh");
17 | p = "account" ; Get ( AccountName );
18 | p = "layout" ; Get ( LayoutName );
19 | p = "found" ; Get ( FoundCount );
20 | p = "button" ; Get ( LastMessageChoice );
21 | p = "result" ; Get ( ScriptResult );
22 | p = "mode"; Choose ( Get ( WindowMode ) ; "Browse"; "Find"; "Preview"; "Printing");
23 | p = "filename" ; Get ( FileName );
24 | p = "localfile" ; Get( MultiUserState ) = 1 or Get( MultiUserState ) = 0;
25 | p = "datetime" ; Get( CurrentTimeStamp );
26 | p = "script" ; Get( ScriptName );
27 | p = "nic" ; GetValue( Get ( SystemNICAddress ) ; 1 );
28 | p = "version" ; Abs( Get ( ApplicationVersion ) );
29 |
30 | 0 ) // End Case
31 |
32 | ) // End Let
--------------------------------------------------------------------------------
/xml.tag.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | xml.tag ( tag; attributes; value )
4 |
5 | RETURNS: (string) Valid XML tag with attributes
6 | DEPS: none
7 | NOTES: http://www.w3.org/TR/xml/
8 | =====================================================
9 | */
10 |
11 | Let ( [
12 |
13 | var.tag.cleaned = Filter ( tag ; "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" );
14 |
15 | var.value.cleaned = Substitute( value;
16 | ["|";" "]; /* pipe */
17 | [" ";" "]; /* shift-space */
18 | ["&";"&"];
19 | ["<";"<"];
20 | [">";">"];
21 | ["\"";"""];
22 | ["'";"'"]
23 | )
24 | ];
25 |
26 | "<" & var.tag.cleaned & attributes & ">" & var.value.cleaned & "" & var.tag.cleaned & ">"
27 |
28 | )
29 |
30 | // TODO:
31 | // Not currently validating that attributes are properly formatted - just passing them through
--------------------------------------------------------------------------------
/fmstandards/Developer.fmfn:
--------------------------------------------------------------------------------
1 | /**
2 | * =====================================================
3 | * Developer ( )
4 | *
5 | * PARAMETERS:
6 | * none
7 | * RETURNS:
8 | * (bool) True or False based on proper
9 | * evaluation
10 | * DEPENDENCIES:
11 | * none
12 | * NOTES: Because FileMaker changed Get ( PrivilegeSetName )
13 | * Evaluate () must be used
14 | *
15 | * RELEASE: 101011
16 | * =====================================================
17 | *
18 | */
19 |
20 | Let ( [
21 |
22 | var.developers = List( ""; "" ) // Add the names of the accounts which are valid developer accounts
23 |
24 | ];
25 |
26 | PatternCount ( ¶& var.developers &¶ ; ¶& Get ( AccountName ) &¶ ) ≥ 1
27 | or
28 | If ( GetAsNumber ( Get ( ApplicationVersion ) ) < 11;
29 | Evaluate ( "Get ( PrivilegeSetName )" ) = "[Full Access]";
30 | Evaluate ( "Get ( AccountPrivilegeSetName )" ) = "[Full Access]"
31 | )
32 |
33 | )
--------------------------------------------------------------------------------
/fmstandards/GetFieldNameVariable.fmfn:
--------------------------------------------------------------------------------
1 | /**
2 | * =====================================================
3 | * GetFieldNameVariable ( field ; prefix )
4 | *
5 | * PURPOSE:
6 | * To be used within an auto-enter calculation
7 | * when you want to extract the name of
8 | * the current field and capture a variable
9 | * of the same name.
10 | *
11 | * PARAMETERS:
12 | * @field = (reference) a field
13 | * @prefix = (enum) either "$" or "$$"
14 | * RETURNS:
15 | * (variable) the content of a variable with
16 | * the same name as the field.
17 | * DEPENDENCIES:
18 | * none
19 | * NOTES:
20 | * This function has a very specific use
21 | * =====================================================
22 | *
23 | */
24 |
25 | Let ( [
26 | var.field = GetFieldName ( field );
27 | var.parts = Substitute ( var.field ; "::" ; ¶ )
28 | ];
29 | Evaluate ( prefix & GetValue ( var.parts ; 2 ) )
30 | )
--------------------------------------------------------------------------------
/color.hex2dec.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | --------------------------
3 | Author: Christopher Gaunt
4 | v1.0, April 6, 2009
5 | solutions@cordega.com
6 |
7 | Returns an integer that represents a color obtained by converting standard 6 character hexadecimal input. Useful if you don't need to know the actual RGB values)
8 | Hex = Hexadecimal input. Handles inputs containing leading/trailing spaces and/or # symbol. Self-contained. No external or self-calls.
9 | --------------------------
10 | */
11 |
12 | Let ([
13 | $HexClean = Trim ( Filter ( Upper ( Hex ) ; "0123456789ABCDEF" ) )
14 | ;$HexSplit =
15 | "(" & ( Middle ( $HexClean ; 1 ; 1 ) & "* 16 + " & Middle ( $HexClean ; 2 ; 1 ) ) & ")* 65536 +" &
16 | "(" & ( Middle ( $HexClean ; 3 ; 1 ) & "* 16 + " & Middle ( $HexClean ; 4 ; 1 ) ) & ")* 256 +" &
17 | "(" & ( Middle ( $HexClean ; 5 ; 1 ) & "* 16 + " & Middle ( $HexClean ; 6 ; 1 ) ) & ")"
18 | ] ;
19 | Evaluate ( Substitute ( $HexSplit ; [ "A" ; 10 ] ; [ "B" ; 11 ] ; [ "C" ; 12 ] ; [ "D" ; 13 ] ; [ "E" ; 14 ] ; [ "F" ; 15 ] ) )
20 | ) // end let
--------------------------------------------------------------------------------
/window.offscreen.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * window.offscreen( property )
4 | *
5 | * RETURNS: (int) Value of where window should appear.
6 | * DEPENDENCIES: developer()
7 | * NOTES: none
8 | * =====================================================
9 | */
10 |
11 | Let ( [
12 | var.onscreen = developer and $$DEVELOPER;
13 | var.offset = 100;
14 | var.property = Left ( property ; 1 ) // Account for use of single letters or full word by using Left()
15 | ];
16 | Case (
17 | var.property = "t" ; If ( var.onscreen ; Get ( WindowTop ) + var.offset ; Get ( WindowDesktopHeight ) );
18 | var.property = "l" ; If ( var.onscreen ; Get ( WindowLeft ) + var.offset ; Get ( WindowDesktopWidth ) );
19 | 0
20 | )
21 | )
22 |
23 | /*
24 | Special note about $$DEVELOPER.
25 | This value is used solution wide to control
26 | when scripts operate in a developer mode
27 | This allows you to see windows and other
28 | developer specific operations or screens.
29 | This value can be set at startup.
30 | */
--------------------------------------------------------------------------------
/developer.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * developer ()
4 | *
5 | * RETURNS: Boolean result based on checking for a given
6 | * account, privelege set or other critera -
7 | * you decide (see notes at bottom).
8 | * DEPENDANCIES: list.valueWithin()
9 | * =====================================================
10 | */
11 |
12 |
13 | Let ( [
14 | //------------------------- VARIABLES
15 |
16 | var.developers = List( ""; "Admin" ) // Add the names of the accounts which are valid developer accounts
17 |
18 | ];
19 | //------------------------- RESULT
20 |
21 | PatternCount ( ¶& var.developers &¶ ; ¶& Get ( AccountName ) &¶ )
22 | or
23 | Get ( PrivilegeSetName ) = "[Full Access]"
24 |
25 | )
26 |
27 | /*
28 | Note: if you're paranoid about security, you need to
29 | know that a super adept hacker would know how to scrape
30 | variable values out of memory, despite not being shown
31 | by FileMaker. Anything stored in global variables $$ can be
32 | captured - although you REALLY have to know a lot to do it.
33 | */
--------------------------------------------------------------------------------
/file.ospath.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | *=====================================================
3 | *file.ospath( path; escaped )
4 | *
5 | *RETURNS: (string) an os cleaned version of a path.
6 | *PARAMS path = (string) name of the file/folder location
7 | * escaped = (bool) whether the path should escape special characters
8 | *DEPS: none
9 | *NOTES: ScriptMaster and some other plugins do their own escaping internally
10 | *This function will also work on a return delimited list of paths
11 | *=====================================================
12 | *
13 | */
14 |
15 | Let( [
16 | _Windows = Abs( Get( SystemPlatform ) ) - 1;
17 | _NewPath = If ( Left( path; 5) = "file:"; Substitute( Middle( path; 6; 1000000 ); "¶file:"; "¶" ); path );
18 | _MacPath = "/Volumes" & Substitute( _NewPath; ¶; "¶/Volumes");
19 | _WinPath = Substitute( Middle( Substitute ( _NewPath ; "/" ; "\\" ); 2; 1000000 ); "¶\\"; "¶")
20 | ];
21 | If ( _Windows;
22 |
23 | If ( escaped; _WinPath; _WinPath );
24 |
25 | If ( escaped; Substitute( _MacPath; [" "; "\ "]; [","; "\,"] ); _MacPath )
26 | )
27 | )
--------------------------------------------------------------------------------
/layout.variables.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * layout.variables ( scope )
4 | *
5 | * RETURNS: (string) key/value pairs as $key = value in positional order
6 | * PARAMETERS: @scope = (enum) global, local
7 | * DEPENDENCIES: none
8 | * ABOUT: Takes two compliment set of lists
9 | * and turns them into FMP defined variables
10 | * NOTES: none
11 | * =====================================================
12 | *
13 | */
14 |
15 | Let ( [
16 | var.fieldNames = FieldNames ( Get ( FileName ) ; Get ( LayoutName ) );
17 | var.prefix = "Let ( var.value = GetField ( \"";
18 | var.suffix = "\" ); If ( IsEmpty ( var.value ) ; \"-\" ; var.value ) ) &\¶&";
19 | var.calculation = var.prefix &
20 | Substitute (
21 | var.fieldNames;
22 | [ ¶ ; ¶ & var.prefix ];
23 | [ ¶ ; var.suffix & ¶ ]
24 | ) & var.suffix;
25 | var.calculation = Left ( var.calculation ; Length ( var.calculation ) - 3 ); // trim off last concatenation
26 | var.fieldData = Evaluate ( var.calculation )
27 | ];
28 | var.list ( var.fieldNames ; var.fieldData ; scope )
29 | )
--------------------------------------------------------------------------------
/requests.save.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * requests.save ( layout ; request )
4 | *
5 | * RETURNS: (bool) True or False based on success or failure
6 | * DEPENDENCIES: none
7 | * NOTES:
8 | * =====================================================
9 | *
10 | * Intended use is for saving a return delimited list of
11 | * fieldname/value pairs into a global variable with the
12 | * same name as the layout.
13 | *
14 | */
15 |
16 | Let ( [
17 | var.requests = Evaluate ( "$$" & layout & ".requests" );
18 | var.existing = If ( IsEmpty ( var.requests ) or var.requests = "?"; False; True );
19 | var.saved = // The let function (as a string) to be evaluated
20 | Evaluate(
21 | "Let ( $$"
22 | & layout & ".requests"
23 | & " = " & Quote ( var.requests )
24 | & If ( var.existing; " & \¶ & "; " & ") // add carriage return if existing content
25 | & Quote( Substitute( request; ¶; "|" ) ) & // each request on its own line
26 | "; False )"
27 | )
28 |
29 | ];
30 | // Return
31 | If ( var.saved = "?"; False; True )
32 | )
--------------------------------------------------------------------------------
/error.calculation.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * error.reference ( elementName ; requiredElementNames ; requiredType )
4 | *
5 | * PARAMETERS: @elementName = FileMaker field reference
6 | * @requiredElementNames = List() of required element names
7 | * @requiredTypes = matching list of types for each element
8 | * RETURNS: (boolean) Whether or not there is a calculation error
9 | * DEPENDENCIES: none
10 | * NOTES: none
11 | * =====================================================
12 | *
13 | */
14 |
15 | Let ( [
16 | $$ERROR.REFERENCE = FilterValues ( Case (
17 | requiredType = "Table";
18 | TableNames ( Get ( FileName ) );
19 |
20 | requiredType = "Field";
21 | FieldNames ( Get ( FileName ) ; Get ( LayoutName ) );
22 |
23 | requiredType = "Layout";
24 | LayoutNames ( Get ( FileName ) );
25 |
26 | ""
27 | ); requiredElementNames ) ≠ requiredElementNames &¶;
28 |
29 | // Set the error into the global if required elements were not found
30 | $$ERROR.REFERENCE = If ( $$ERROR.REFERENCE; elementName & ": Missing literal references"; "" )
31 | ];
32 | If ( not IsEmpty ( $$ERROR.REFERENCE ); True; False )
33 | )
--------------------------------------------------------------------------------
/var.set.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * var.set( name ; value )
4 | *
5 | * RETURNS: (bool) True or False based on proper evaluation
6 | * DEPENDENCIES: none
7 | * NOTES: see var.eval for declaring multiple variables
8 | * =====================================================
9 | *
10 | * This custom function is a wrapper for the
11 | * assignment(creation) of global variables.
12 | * Variables are not tracked and errors are
13 | * revealed within $$ERROR.VAR.SET
14 | */
15 |
16 | Let ( $function.var.make.value = value; // preserve the data type of the inbound value
17 | Let ( [
18 | $$ERROR.VAR.SET = ""; // Reset the global error variable for evaluation
19 | var.dollarsign = If ( Left ( name ; 2 ) = "$$" or Left ( name ; 1 ) = "$"; "" ; "$$" ); // check for prefixed $$ or $
20 | var.calc = "Let ( " & var.dollarsign & name & " = $function.var.make.value; False )"
21 | ];
22 | If (
23 | Evaluate(
24 | var.calc
25 | ) = "?";
26 | Let ( $$ERROR.VAR.SET = List ("EVAL ERROR"; "-------"; var.calc ); False );
27 | // Insert the name of the variable into the reserved $$VARIABLES global variable
28 | True
29 | )
30 | )
31 | )
--------------------------------------------------------------------------------
/window.activetab.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | window.activetab( init; theList )
4 |
5 | RETURNS: (list) List of all active frontmost tabs.
6 | DEPS: none
7 | NOTES: Original by Koen Van Hulle (SHpartners.com)
8 | =====================================================
9 | */
10 |
11 | Let([
12 | //------------------------- VARIABLES
13 | Init = Init + 1 ;
14 |
15 | ObjectList = LayoutObjectNames( Get( FileName ); Get( LayoutName ) ) ;
16 |
17 | TabToCheck = Substitute( GetValue( ObjectList; init ); ¶; "") ;
18 |
19 | ParentTab = GetLayoutObjectAttribute( TabToCheck; "enclosingObject" ) ;
20 |
21 | IsCurrentTab = Case(
22 | IsEmpty( TabToCheck ); 0;
23 | GetLayoutObjectAttribute( TabToCheck ; "isFrontTabPanel" ) and
24 | IsEmpty( ParentTab ); 1;
25 | GetLayoutObjectAttribute( TabToCheck; "isFrontTabPanel" ) and
26 | PatternCount( ¶ & theList & ¶; ¶ & ParentTab & ¶ ); 1;
27 | 0 );
28 |
29 | theList = theList & If( IsCurrentTab; TabToCheck & ¶ )
30 |
31 | ];
32 |
33 | //------------------------- RESULT
34 |
35 | If( not IsEmpty( TabToCheck ); window.activetab( init; theList ); theList )
36 |
37 | )
--------------------------------------------------------------------------------
/window.center.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * window.center ( dimension )
4 | *
5 | * RETURNS: (int) Screen pixel value based on dimension
6 | * supplied.
7 | * REQUIRES: None
8 | * NOTES: Using a locally scoped variable within your
9 | * script will alter what this function returns
10 | * $parentWindowHeight for window height of parent
11 | * $parentWindowWidth for window width of parent
12 | * $parentWindowTop for window top of parent
13 | * $parentWindowLeft for window left of parent
14 | * =====================================================
15 | */
16 |
17 | Let ([
18 | var.vertical = PatternCount ( dimension ; "vert" );
19 | var.horizontal = PatternCount ( dimension ; "horiz" );
20 | var.parentHeight = If ( IsEmpty ( $parentWindowHeight ) ; Get ( WindowDesktopHeight ) ; $parentWindowHeight );
21 | var.parentWidth = If ( IsEmpty ( $parentWindowWidth ) ; Get ( WindowDesktopWidth ) ; $parentWindowWidth )
22 | ];
23 |
24 | Case( var.vertical;
25 | ( var.parentHeight / 2) - ( Get ( WindowHeight ) / 2 ) + $parentWindowTop;
26 | var.horizontal;
27 | ( var.parentWidth / 2) - ( Get ( WindowWidth ) / 2 ) + $parentWindowLeft
28 | )
29 | )
--------------------------------------------------------------------------------
/mouse.clicks.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * mouse.clicks ( number ; identifier )
4 | * RETURNS: (bool) If mouse has been clicked the number of times
5 | * as tracked by the global variable $$mouse.clicks.count
6 | * DEPENDENCIES: none
7 | * NOTES:
8 | * =====================================================
9 | *
10 | * WARNING! You can only use a call to this custom function once within any given script.
11 | * Subsequent calls within the same script will mess up the variables.
12 | */
13 |
14 | Let ( [
15 | $$mouse.clicks.count = If ( IsEmpty( $$mouse.clicks.count ) ; 1 ; $$mouse.clicks.count + 1 );
16 | $$mouse.clicks.previous = $$mouse.clicks.last;
17 | $$mouse.clicks.last = Get ( CurrentTimeStamp );
18 | $$mouse.clicks.duration = Seconds ( $$mouse.clicks.last - $$mouse.clicks.previous );
19 | // Criteria required to be a valid subsequent click, identifier must match
20 | $$mouse.clicks.valid = $$mouse.clicks.duration ≤ 1 and identifier = $$mouse.click.identifier; // Subsequent click within 1 second
21 | $$mouse.clicks.count = If ( not $$mouse.clicks.valid ; "" ; $$mouse.clicks.count );
22 | $$mouse.click.identifier = identifier
23 | ];
24 |
25 | $$mouse.clicks.count = number // Return the count as boolean
26 |
27 | )
--------------------------------------------------------------------------------
/var.define.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * var.define( name ; value )
4 | *
5 | * RETURNS: (bool) True or False based on proper evaluation
6 | * DEPENDENCIES: none
7 | * NOTES: see var.eval for declaring multiple variables
8 | * =====================================================
9 | *
10 | * This custom function is a wrapper for the
11 | * assignment(creation) of global variables.
12 | * Variables are tracked within $$VARIABLES
13 | */
14 |
15 | Let ( $function.var.define.value = value; // preserve the data type of the inbound value
16 | Let ( [
17 | $$ERROR.VAR.DEFINE = ""; // Reset the global error variable for evaluation
18 | var.dollarsign = If ( Left ( name ; 2 ) = "$$" ; "" ; "$$" ); // check for prefixed $$
19 | var.calc = "Let ( " & var.dollarsign & name & " = $function.var.define.value; False )"
20 | ];
21 | If (
22 | Evaluate(
23 | var.calc
24 | ) = "?";
25 | Let ( $$ERROR.VAR.DEFINE = List ( "EVAL ERROR"; "-------"; var.calc ); False );
26 | // Insert the name of the variable into the reserved $$VARIABLES global variable
27 | Let ( $$VARIABLES = If ( IsEmpty ( FilterValues ( $$VARIABLES ; name ) ); List ( $$VARIABLES ; name ) ; $$VARIABLES ) ; True )
28 | )
29 | )
30 | )
--------------------------------------------------------------------------------
/portal.grouping.fmfn :
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * portal.grouping ( row ; part ; field )
4 | *
5 | * RETURNS: (bool) True or False based on relative portal rows
6 | * DEPENDENCIES: none
7 | * NOTES:
8 | * =====================================================
9 | *
10 | */
11 |
12 | Case (
13 | part = "top";
14 | // Determine if at the top of a group
15 | not IsEmpty ( field ) // I have a value
16 | and
17 | GetNthRecord ( field ; row ) ≠ GetNthRecord ( field ; row - 1 ) // record above me does not match
18 | and
19 | IsValid ( GetNthRecord ( field ; row + 1 ) ); // I do have a record below me
20 |
21 | part = "middle";
22 | // Determine if in the middle of a group
23 | not IsEmpty ( field ) // I have a value
24 | and
25 | GetNthRecord ( field ; row ) = GetNthRecord ( field ; row - 1 ) // record above me has the same value
26 | and
27 | GetNthRecord ( field ; row ) = GetNthRecord ( field ; row + 1 ); // record below me has the same value
28 |
29 | part = "bottom";
30 | // Determine if at the bottom of a group
31 | not IsEmpty ( field ) // I have a value
32 | and
33 | GetNthRecord ( field ; row ) ≠ GetNthRecord ( field ; row + 1 ) // record below me does not match
34 | and
35 | IsValid ( GetNthRecord ( field ; row + 1 ) ) // there is a record above me
36 | )
--------------------------------------------------------------------------------
/vars.save.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * vars.save( valuelist )
4 | * RETURNS: (string) Return delimted list of valid variable declarations
5 | * DEPENDENCIES: none
6 | * NOTES: see var.define for how/where variables are saved
7 | * =====================================================
8 | *
9 | */
10 |
11 | Let ( [
12 | //$$var.test = "example data";
13 | //valuelist = "one¶two¶three"; // used for testing
14 | var.topmost_value = GetValue ( valuelist ; 1 );
15 | var.remaining_values = If ( ValueCount ( valuelist ) = 1 ; "" ;
16 | // Stupid xValues functions return a \r
17 | Substitute( RightValues ( valuelist ; ValueCount ( valuelist ) - 1 ) & ¶ ; "¶¶" ; "" )
18 | );
19 | var.value = Evaluate ( "$$" & var.topmost_value );
20 | var.value = If ( var.value ≠ "?" ; var.value ; "ERROR" );
21 | var.string = "$$" & var.topmost_value & " = " & Quote ( var.value );
22 | $variables.save = List ( $variables.save ; var.string )
23 | ];
24 |
25 | If ( isempty ( var.remaining_values ) ; $variables.save ; vars.save ( var.remaining_values ) )
26 |
27 | )
28 |
29 | /*
30 | // Testing code
31 | Let( [
32 | $variables.save = "";
33 | $$one = 1;
34 | $$two = 2;
35 | $$three = 3
36 | ];
37 | vars.save ( List ( "one" ; "two" ; "three" ) )
38 | )
39 | */
--------------------------------------------------------------------------------
/script.param.change.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * script.param.change( values; changes)
4 | *
5 | * RETURNS: (mixed) new key/value list based on changes
6 | * DEPENDENCIES: none
7 | * NOTES: Compliments to Mikhail Edoshin http://mikhailedoshin.com
8 | * =====================================================
9 | *
10 | * This function is used to replace a named value within a
11 | * data structure which preserves carriage returns and
12 | * other special characters.
13 | *
14 | */
15 |
16 | Case(
17 | // Both values are required to swap, otherwise use whatever we have
18 | IsEmpty( values ); changes;
19 | IsEmpty( changes ); values;
20 |
21 | // Recursion on stack
22 | ValueCount( changes ) > 1;
23 | script.param.change( script.param.change( values; LeftValues( changes; 1 ) );
24 | RightValues( changes; ValueCount( changes ) - 1 ) );
25 |
26 | // Swap out the key/value if found
27 | Let( [
28 | var.key = MiddleValues( Substitute( changes; [ "¶"; "" ]; [ ".^^"; "¶" ]; [ ".^"; "^" ] ); 2; 1 );
29 | var.optionPosition = ValueCount( Left( values; Position( "¶" & values; "¶.^^" & Left( var.key; Length( var.key ) - 1 ) & ".^^"; 1; 1 ) ) ) ];
30 |
31 | If( var.optionPosition = 0; values & changes;
32 | LeftValues( values; var.optionPosition - 1 )
33 | & changes
34 | & RightValues( values; ValueCount( values ) - var.optionPosition ) )
35 | )
36 | )
--------------------------------------------------------------------------------
/list.swapValue.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * list.swapValue ( valuelist ; value; pos )
4 | * RETURNS: (list) New list with new value in designated position
5 | * DEPENDENCIES: none
6 | * NOTES: see var.eval for declaring multiple variables
7 | * =====================================================
8 | *
9 | */
10 |
11 | Let ( [
12 | // VARIABLES
13 | var.valuecount = ValueCount ( valuelist );
14 | var.slotexists = var.valuecount > pos;
15 | var.filler = "¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶";
16 | var.filleramount = If ( not var.slotexists ; Left ( var.filler ; pos - var.valuecount - 1 ) );
17 | var.tophalf = LeftValues ( valuelist ; pos - 1 );
18 | var.tophalf = Left ( var.tophalf ; Length ( var.tophalf ) - 1 ) & var.filleramount; // trim extra return
19 | var.bottomhalf = RightValues ( valuelist ; var.valuecount - pos );
20 | var.bottomhalf = Left ( var.bottomhalf ; Length ( var.bottomhalf ) - 1 ) // trim extra return
21 | ];
22 | // RESULT
23 | var.tophalf &
24 | If ( pos > 1 ; ¶ & value ; value ) &
25 | If ( not IsEmpty ( var.bottomhalf ) ; ¶ & var.bottomhalf )
26 | )
27 |
28 | /*
29 | // Testing values - prefix to variables within Data Viewer
30 | valuelist = List ( "tab.hah"; "tab.goog"; "tab.raw"; "tab.random");
31 | valuelist = "tab.hah¶tab.goog¶tab.raw¶tab.random";
32 | value = "===";
33 | pos = 1;
34 | */
35 |
--------------------------------------------------------------------------------
/fmstandards/WindowCenter.fmfn:
--------------------------------------------------------------------------------
1 | /**
2 | * =====================================================
3 | * WindowCenter ( dimension )
4 | *
5 | * PARAMETERS:
6 | * @dimension (enumeration) Vertical, Horizontal
7 | * RETURNS:
8 | * (int) Screen position value based on dimension
9 | * supplied
10 | * DEPENDENCIES:
11 | * none
12 | * NOTES:
13 | * Using a locally scoped variable within your
14 | * script will alter what this function returns
15 | * $parentWindowHeight for window height of parent
16 | * $parentWindowWidth for window width of parent
17 | * $parentWindowTop for window top of parent
18 | * $parentWindowLeft for window left of parent
19 | * =====================================================
20 | *
21 | */
22 |
23 | Let ([
24 |
25 | var.vertical = PatternCount ( dimension ; "vert" );
26 | var.horizontal = PatternCount ( dimension ; "horiz" );
27 | var.parentHeight = If ( IsEmpty ( $parentWindowHeight ) ; Get ( WindowDesktopHeight ) ; $parentWindowHeight );
28 | var.parentWidth = If ( IsEmpty ( $parentWindowWidth ) ; Get ( WindowDesktopWidth ) ; $parentWindowWidth )
29 |
30 | ];
31 |
32 | Case (
33 | var.vertical;
34 | ( var.parentHeight / 2) - ( Get ( WindowHeight ) / 2 ) + $parentWindowTop;
35 | var.horizontal;
36 | ( var.parentWidth / 2) - ( Get ( WindowWidth ) / 2 ) + $parentWindowLeft
37 | )
38 | )
--------------------------------------------------------------------------------
/string.trim.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * string.trim( text; characters )
4 | *
5 | * RETURNS: (string) original string less supplied list of values
6 | * PARAMS: text = string; characters = List()
7 | * DEPENDENCIES: none
8 | * VERSION: 1.0
9 | * AUTHOR: See notes
10 | * NOTES:
11 | * Adapted by Matt Petrowsky from
12 | * http://www.briandunning.com/cf/904
13 | * Compliments to Debi Fuchs, Aptworks Consulting
14 | * =====================================================
15 | */
16 |
17 | Let([
18 | $function.string.trim = text;
19 | var.default = List( " "; " "; " "; "\¶"); // Default list of characters to remove (space, tab, return)
20 | var.characters = If ( IsEmpty( characters ); var.default; characters );
21 |
22 | var.function.parts = "[\"" & Substitute( var.characters; ¶; "\"; \"\"];¶[\"" ) & "\"; \"\"]";
23 | var.function.clean = "Substitute( $function.string.trim; " & var.function.parts & " )"; // Strip out specified chars
24 | var.function.result = Evaluate( var.function.clean );
25 |
26 | var.char.first = Position( text; Left( var.function.result; 1 ); 0; 1 ); // Position of first (non cleaned) char
27 | var.char.last = Position( text; Right( var.function.result; 1 ); Length( text ); -1 ) // Position of last (non cleaned) char
28 | ];
29 |
30 | Case( var.char.first; Middle( text; var.char.first; var.char.last - var.char.first + 1 ) )
31 |
32 | )
--------------------------------------------------------------------------------
/window.fronttabs.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * window.fronttabs ()
4 | *
5 | * RETURNS: (list) Return delimited list of frontmost tabs.
6 | * DEPENDENCIES: list.custom(), layout.objects(), list.valueWithin()
7 | * NOTES: Adapted from Agnès Barouh
8 | * FrontTabsPanelsList()
9 | * =====================================================
10 | */
11 |
12 | Let ([
13 | $function.result = "|###|";
14 | $function.return = ¶;
15 | $function.objects = layout.objects;
16 |
17 | var.result = list.custom (
18 | 1; // start
19 | ValueCount ( $function.objects ); // end
20 | "Let ( [
21 | var.current = GetValue ( $function.objects; [n] );
22 | var.isFront = GetLayoutObjectAttribute ( var.current; \"isFrontTabPanel\" );
23 | var.enclosing = GetLayoutObjectAttribute ( var.current; \"enclosingObject\" );
24 | var.append = $function.return & var.current;
25 | $function.result = $function.result & Case (
26 | var.isFront and IsEmpty ( var.enclosing ) ; var.append;
27 | var.isFront and list.valueWithin ( $function.result ; var.enclosing ) ; var.append
28 | )
29 | ]; False )"
30 | )
31 | ];
32 |
33 | Substitute ( $function.result ;
34 | [ "|###|¶" ; ""];
35 | [ "|###|" ; "" ]
36 | )
37 | )
38 |
39 | & Let ( $function.result = "" ; "" )
40 |
--------------------------------------------------------------------------------
/vars.objects.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * vars.objects( objects )
4 | *
5 | * RETURNS: (string) Return delimted list of valid variable declarations
6 | * DEPENDENCIES: none
7 | * NOTES: To be used with var.eval. Designed to have a list
8 | * of object names passed so it can create a list of variables
9 | * using object for the key and the object's contents for value.
10 | * Should be used within context because of GetLayoutObjectAttribute()
11 | * =====================================================
12 | *
13 | * This is useful for an interface which uses global fields as keys
14 | * for relationships. You can call this function, pass in object names
15 | * for global fields and have a valid varible structure created for
16 | * you - ready to save.
17 | *
18 | */
19 |
20 | Let ( [
21 | var.current = GetValue ( objects ; 1 ); // topmost value
22 | var.remainder = RightValues ( objects ; ValueCount( objects ) - 1 );
23 | var.return = "$" & var.current & " = " & Quote ( GetLayoutObjectAttribute ( var.current ; "content" ) ); // return string
24 | $function.vars.objects.result = List ( var.return ; $function.vars.objects.result ) // append return string to collection
25 | ];
26 | Case (
27 | isempty ( objects ) ; "No objects found";
28 | var.remainder > 1 ; vars.objects( var.remainder );
29 | $function.vars.objects.result
30 | )
31 | )
32 |
33 | /*
34 | Because *Values functions leave
35 | trailing return you use > 1 for
36 | moving to next item in stack
37 | */
--------------------------------------------------------------------------------
/plugin.valid.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | plugin.valid( name ; version )
3 |
4 | RETURNS: (bool) Result of whether the tested plugin is there or not and also the version.
5 |
6 | NOTES: Uses global variables of $$PLUGIN_VERSION and $$PLUGIN_MESSAGE as return values.
7 | */
8 |
9 | Let( [
10 | //------------------------- VARIABLES
11 |
12 | /*
13 | Provide a list of plugins and their version functions to be
14 | used for universal checking of the plugin. This one function
15 | is where you can store all of your solution plugin checks.
16 | */
17 |
18 | _PluginVersion = "Let( $$PLUGIN_VERSION = EXTERNAL ; 0 )";
19 |
20 | _Found = Case(
21 | //--------------------------- ZIPPSCRIPT
22 | name = "ZippScript" ;
23 | not EvaluationError( Evaluate( Substitute( _PluginVersion ; "EXTERNAL" ; "zippScript_Version( \"\" )" ) ) );
24 | //--------------------------- DOSCRIPT
25 | name = "DoScript" ;
26 | not EvaluationError( Evaluate( Substitute( _PluginVersion ; "EXTERNAL" ; "S4HU_VersionEventScript" ) ) );
27 | //----------------------------------------------------------------------------------------
28 | 0
29 | );
30 |
31 | _Message_Missing = "The plugin " & name & " is required for this solution to function properly.";
32 | _Message_Version = "Your version of the plugin " & name & " is at " & $$PLUGIN_VERSION & " you need " & version & ".";
33 |
34 | _Version_Ok = $$PLUGIN_VERSION >= version;
35 |
36 | $$PLUGIN_MESSAGE = Case ( not _Found; _Message_Missing; not _Version_Ok; _Message_Version; "" )
37 |
38 | ];
39 |
40 | //------------------------- RESULT
41 |
42 | If ( _Found and _Version_Ok; 1 ; 0 )
43 |
44 | )
--------------------------------------------------------------------------------
/fields.changed.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * fields.changed ( field ; result ; triggers )
4 | *
5 | * RETURNS: (mixed) Either the field (typically self) or the result
6 | * PARAMETERS: @field = Always use the Self function
7 | * @result = a calculated result
8 | * @triggers = [optional] field references which should force the auto-enter to trigger
9 | * DEPENDENCIES: REQUIRES FileMaker 10
10 | * NOTES: This allows fields to become interdependant on each other
11 | * Adapted from AllowInputInAutoEnter() by Fabrice Nordmann & Tanguy Collès, BH&A
12 | * USAGE: Use when two or more fields are interdependant and any of the fields can be changed
13 | * for example: A conversion of inches -> centimeters or centimeters -> inches.
14 | * With both fields modifiable.
15 | * EXAMPLE: fields.changed ( Self ; inches / .3937007874 ; "" )
16 | * =====================================================
17 | *
18 | */
19 |
20 | Case (
21 | // If the active field is the same as the one being evaluated
22 | GetFieldName ( field ) = Get ( ActiveFieldTableName )
23 | & "::" & Get ( ActiveFieldName )
24 | & Case (
25 | Get ( ActiveRepetitionNumber ) > 1 ;
26 | "[" & Get ( ActiveRepetitionNumber ) & "]"
27 | );
28 | Get ( ActiveFieldContents ); // returned what was entered by the user
29 | result // otherwise, return the calculated result (becauase I'm not the active field)
30 | )
--------------------------------------------------------------------------------
/list.sort.defined.fmfn:
--------------------------------------------------------------------------------
1 | // Currently has a problem with different variations (e.g. Layouts vs. layouts) - needs debugging
2 |
3 | /*
4 | =====================================================
5 | list.sort.defined( values; order )
6 |
7 | RETURNS: (list) sorted list according to specified order
8 | DEPENDENCIES:
9 | VERSION: 1.0
10 | AUTHOR: Matt Petrowsky
11 | NOTES:
12 |
13 | =====================================================
14 | */
15 |
16 | Let ([
17 | var.list = FilterValues( order; values ); // Valid order based on supplied values (no need to use an order value if not in the values)
18 | var.current = GetValue( var.list; 1 ); // Top value of the order list
19 | var.remaining = Right( var.list; Length( var.list ) - Length( var.current ) - 1 ); // Remaining order values
20 | var.found = FilterValues ( values ; var.current ); // Found value according to order list
21 | var.count = ValueCount( var.found ); // Count of found value (if found - see test below)
22 | var.values = Substitute( values; var.current; ""); // Knocks out the found value
23 |
24 | // The above could be cleaned up to include returns to catch for duplicate values
25 | // such as "script names" and "scripts" where "script" will catch both
26 |
27 | continue = ValueCount( var.list ) ≠ 0 // Exit condition for recursion
28 | ];
29 |
30 | // Outer left and Substitute remove double returns - this could be handled better
31 |
32 | Left(
33 | Substitute(
34 | If ( continue; If ( var.count; var.found & list.sort.defined( var.values; var.remaining ) ) ) & If ( not continue; Substitute ( var.values ; "¶¶" ; ¶ ) );
35 | "¶¶"; ¶
36 | )
37 | ; Length( values ) )
38 |
39 | )
--------------------------------------------------------------------------------
/webviewer.records.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * webviewer.records ( format ; css ; color )
4 | *
5 | * RETURNS: (string) Web viewer using formatted string
6 | * DEPENDENCIES: webviewer.data(), html.document(), html.css()
7 | * NOTES: Available placeholders [current], [found], [percentage]
8 | * =====================================================
9 | *
10 | */
11 |
12 | // example:
13 | // webviewer.records ( "Record [current] of [found] | [percentage]" ; "#bar { background-color: green }" )
14 |
15 | Let ( [
16 | var.record = Get(RecordNumber);
17 | var.found = Get(FoundCount);
18 | var.total = Get(TotalRecordCount);
19 | isSubset = var.total = var.found;
20 | var.percentage = Truncate ( ( var.record / var.found ) * 100 ; 0 ) & "%";
21 | cssBar = Substitute ( "#bar { background-color: @color; height: 100%; width: @width; }";
22 | [ "@color" ; If ( isempty ( color ) ; "transparent" ; color ) ];
23 | [ "@width" ; var.percentage ]
24 | )
25 | ];
26 | webviewer.data( "";
27 | "Record Information";
28 | html.css( "body { text-align: center; margin: 0; border: 0; } #text{ margin:0 auto; }" & cssBar & css ); // load user css after the bar for override support
29 | List (
30 | "";
31 | "";
32 | Substitute (
33 | format;
34 | [ "[current]" ; var.record ];
35 | [ "[found]" ; var.found ];
36 | [ "[percentage]" ; var.percentage ]
37 | );
38 | "
";
39 | )
40 | )
41 | )
--------------------------------------------------------------------------------
/keyboard.modifiers.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * keyboard.modifiers( keys ; ignore )
4 | *
5 | * RETURNS: (boolean) based on modifier keys being held down
6 | * PARAMETERS: @keys = List() of "keys" or string (e.g List("Command"; "Alt") or "command-alt")
7 | * @ignore = (bool) whether or not to ignore caps lock
8 | * DEPENDENCIES: none
9 | * NOTES: Adapted from http://www.briandunning.com/cf/473 by Peter Wagemans, SHpartners
10 | * =====================================================
11 | *
12 | */
13 |
14 | Let ( [
15 | // Define
16 | var.keys = Get ( ActiveModifierKeys );
17 | // Convert keys to their bit values (see note at bottom)
18 | var.command = Mod ( Int ( var.keys / 16 ) ; 2 );
19 | var.alt = Mod ( Int ( var.keys / 8 ) ; 2 );
20 | var.control = Mod ( Int ( var.keys / 4 ) ; 2 );
21 | var.capslock = Mod ( Int ( var.keys / 2 ) ; 2 );
22 | var.shift = Mod ( var.keys ; 2 )
23 | ];
24 | // Result (boolean)
25 | ( var.command xor not PatternCount ( keys ; "command" ) )
26 | and
27 | ( var.alt xor not ( PatternCount ( keys ; "alt" ) or PatternCount ( keys ; "option" ) ) )
28 | and
29 | ( var.control xor not ( PatternCount ( keys ; "ctrl" ) or PatternCount ( keys ; "control") ) )
30 | and
31 | If ( not ignore ; ( var.capslock xor not PatternCount ( keys ; "capslock" ) ) ; True )
32 | and
33 | ( var.shift xor not PatternCount ( keys ; "shift" ) )
34 | and
35 | ( ( var.keys = 0 ) xor ( keys ≠ "" ) )
36 | )
37 |
38 | /*
39 | The Mod() function is used to determine
40 | if the key is within the result of
41 | Get ( ActiveModifierKeys )
42 |
43 | 16 8 4 2 1
44 | --------------
45 | 0 0 1 0 1
46 | | | | | |
47 | | | | | Shift
48 | | | | Caps Lock
49 | | | Ctrl
50 | | Alt/Option
51 | Apple Command Key
52 | */
--------------------------------------------------------------------------------
/window.properties.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * window.properties ( method )
4 | *
5 | * RETURNS: (string) window properties according to specified method
6 | * PARAMETERS: method = (enum)
7 | * DEPENDENCIES: var.list() and object.id()
8 | * NOTES: Provides multiple methods for returning the
9 | * properties of the current window
10 | * =====================================================
11 | *
12 | */
13 |
14 | Let ( [
15 | var.keys = List( "name"; "layout"; "id"; "top";"left";"width";"height");
16 | var.values = List(
17 | Get ( WindowName );
18 | Get ( LayoutName );
19 | object.id ( Get ( LayoutName ); "Layout"; ""; "" );
20 | Get ( WindowTop );
21 | Get ( WindowLeft );
22 | Get ( WindowWidth );
23 | Get ( WindowHeight )
24 | )
25 | ];
26 | // returns
27 | Case(
28 | method = "" or
29 | method = "default"; var.values;
30 |
31 | method = "piped"; Substitute ( var.values ; ¶ ; "|" );
32 |
33 | // global variables are returned by var.list() - use Substitute ( properties ; "$$" ; "$" ) to make local
34 | method = "let"; var.list ( var.keys;
35 | List(
36 | Quote ( Get ( WindowName ) ); // because var.list needs quoted strings
37 | Quote ( Get ( LayoutName ) );
38 | object.id ( Get ( LayoutName ); "Layout"; ""; "" );
39 | Get ( WindowTop );
40 | Get ( WindowLeft );
41 | Get ( WindowWidth );
42 | Get ( WindowHeight )
43 | ) ; "global" );
44 |
45 | // default
46 | var.values
47 | )
48 | )
--------------------------------------------------------------------------------
/fmstandards/Debug.fmfn:
--------------------------------------------------------------------------------
1 | /**
2 | * =====================================================
3 | * Debug ( )
4 | *
5 | * PARAMETERS:
6 | * none
7 | * RETURNS:
8 | * (string) A list of informative values
9 | * about the current FMP environment.
10 | * DEPENDENCIES:
11 | * Developer ()
12 | * NOTES:
13 | *
14 | * RELEASE: 101009
15 | * =====================================================
16 | *
17 | */
18 |
19 | If ( Developer;
20 | Let ( [
21 | // Variables
22 | $$DEBUG = List (
23 | "App Version = " & Abs ( Get ( ApplicationVersion ) );
24 | "App Current Time = " & GetAsText ( Get ( CurrentTimeStamp ) );
25 | "Host Name = " & Get ( HostName );
26 | "Host IP = " & Get ( HostIPAddress );
27 | "File Location = " & Get ( FilePath );
28 | "Account = " & Get ( AccountName );
29 | "-----------------------------------";
30 | "Script Param = " & Get ( ScriptParameter );
31 | "Script Result = " & Get ( ScriptResult );
32 | "-----------------------------------";
33 | "Last Error = " & Get ( LastError );
34 | "Last ODBC = " & Get ( LastODBCError );
35 | "-----------------------------------";
36 | "Layout = " & Get ( LayoutName );
37 | "Layout Table = " & Get ( LayoutTableName );
38 | "-----------------------------------";
39 | "Open Records = " & Get ( RecordOpenCount );
40 | "Record Modified = " & Get ( RecordModificationCount );
41 | "-----------------------------------";
42 | "Active Field = " & Get ( ActiveFieldName );
43 | "Active Field Table = " & Get ( ActiveFieldTableName );
44 | "Active Layout Object = " & Get ( ActiveLayoutObjectName );
45 | "Active Layout Table = " & Get ( LayoutTableName );
46 | "-----------------------------------";
47 | "Local time = " & Get ( CurrentTimeStamp );
48 | "Host time = " & Get ( CurrentHostTimeStamp );
49 | "-----------------------------------";
50 | )
51 | ];
52 |
53 | // Return value
54 | $$DEBUG
55 |
56 | )
57 | )
--------------------------------------------------------------------------------
/number.format.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * number.format ( input ; format )
4 | *
5 | * RETURNS: (string) Formatted input according to format supplied
6 | * DEPENDENCIES: none
7 | * NOTES: Adapted from http://www.briandunning.com/cf/769 by Toby Beedell
8 | * =====================================================
9 | *
10 | */
11 |
12 | Let ( [
13 | var.input = input;
14 | var.format = format;
15 | var.valid = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
16 | var.match = "#";
17 | test.exit = IsEmpty ( var.input ) or IsEmpty ( var.format )
18 |
19 | ];
20 | If ( test.exit;
21 | // then
22 | var.input;
23 | // else
24 | Let ( [
25 | match.count = PatternCount ( var.format; var.match );
26 | match.none = match.count < 1;
27 | format.length = Length ( var.format );
28 | format.end = If ( match.none and format.length > 0 ; var.format )
29 | ];
30 | If ( match.none;
31 | // then
32 | format.end & var.input;
33 | // else
34 | Let ( [
35 | var.filtered = Filter ( var.input ; var.valid );
36 | filtered.length = Length ( var.filtered );
37 | match.position = Position ( var.format ; var.match ; 1 ; 1 );
38 | var.prefix = If ( match.position ≠ 1 ; Left ( var.format ; match.position - 1 ) );
39 | format.char = Middle ( var.format ; match.position ; 1 );
40 | var.char = Left ( var.filtered ; 1 );
41 | is.upper = IsEmpty ( Filter ( format.char ; var.match ) );
42 | _tBit = If ( is.upper ; Upper ( var.char ) ; Lower ( var.char ) );
43 | format.remainder = Right ( var.format ; format.length - match.position );
44 | input.remainder = Right ( var.filtered ; filtered.length - 1 )
45 | ];
46 | var.prefix & _tBit & number.format ( input.remainder ; format.remainder )
47 | )
48 | )
49 | )
50 | )
51 | )
--------------------------------------------------------------------------------
/keyboard.chars.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * keyboard.chars( character )
4 | *
5 | * RETURNS: (string) unicode characters of keyboard symbols
6 | * PARAMETERS: @char = (string) name of the character (matches the variable name)
7 | * DEPENDENCIES: none
8 | * NOTES:
9 | * =====================================================
10 | *
11 | */
12 |
13 | Let ( [
14 | wineval = "Let ( [¶
15 | alt = TextStyleAdd ( \"alt\" ; Superscript );¶
16 | control= TextFont ( \"ˆ\" ; \"Arial\" );¶
17 | deleteback = TextFont ( \"Õ\" ; \"Wingdings\" );¶
18 | deleteforward = TextFont (\"Ö\" ; \"Wingdings\" );¶
19 | escape = TextStyleAdd ( \"esc\" ; Superscript );¶
20 | return = TextFont (\"¿\" ; \"Symbol\" );¶
21 | shift = TextFont ( \"ñ\" ; \"Wingdings\" )¶
22 | ];¶"
23 | & character &
24 | ")";
25 |
26 | maceval = "Let ( [¶
27 | alt = \"⌥\";¶
28 | applesymbol = \"\";¶
29 | capslock = \"⇪\";¶
30 | clear = \"⌧\";¶
31 | command = \"⌘\";¶
32 | control = \"⌃\";¶
33 | deleteback = \"⌫\";¶
34 | deleteforward = \"⌦\";¶
35 | downarrow = \"⇣\"; // alternates ↓¶
36 | eject = \"⏏\";¶
37 | end = \"↘\"; // alternates ⇲¶
38 | enter = \"⌤\";¶
39 | escape = \"⎋\";¶
40 | home = \"↖\";
// alternates ⇱ ↸¶
41 | leftarrow = \"⇠\"; // alternates ←¶
42 | numberlock = \"⇭\";¶
43 | pagedown = \"⇟\";¶
44 | pageup = \"⇞\";¶
45 | power = \"⌽\";¶
46 | return = \"⏎\"; // alternates ↩¶
47 | rightarrow = \"⇢\"; // alternates →¶
48 | shift = \"⇧\";¶
49 | space = \"␣\";¶
50 | tabback = \"⇤\";¶
51 | tabforward = \"⇥\";¶
52 | uparrow = \"⇡\" // alternates ↑¶
53 | ];¶"
54 | & character &
55 | ")";
56 |
57 | isWindows = Case( Get( SystemPlatform ) = -2; True ; False );
58 | result = Case ( isWindows ; Evaluate ( wineval ) ; TextFont ( Evaluate ( maceval ) ; "Apple Symbols" ) )
59 | ];
60 | If ( result ≠ "?" ; result ; "No match")
61 | )
--------------------------------------------------------------------------------
/debug.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * debug()
4 | *
5 | * RETURNS: (mixed) A list of informative values
6 | * about the current FMP environment.
7 | * DEPENDANCIES: developer() function.
8 | * NOTES: While testing non developer accounts you
9 | * may need to remove off if ( developer )
10 | * =====================================================
11 | */
12 |
13 | if ( developer;
14 | Let ( [
15 | // Variables
16 | $$DEBUG = List (
17 | "App Version = " & Abs ( Get ( ApplicationVersion ) );
18 | "Host Name = " & Get ( HostName );
19 | "Host IP = " & Get ( HostIPAddress );
20 | "Location = " & Get ( FilePath );
21 | "Account = " & Get ( AccountName );
22 | "-----------------------------------";
23 | "Script Param = " & Get ( ScriptParameter );
24 | "Script Result = " & Get ( ScriptResult );
25 | "-----------------------------------";
26 | "Last Error = " & Get ( LastError );
27 | "Last ODBC = " & Get ( LastODBCError );
28 | "-----------------------------------";
29 | "Layout = " & Get ( LayoutName );
30 | "Layout Table = " & Get ( LayoutTableName );
31 | "-----------------------------------";
32 | "Open Records = " & Get ( RecordOpenCount );
33 | "Record Modified = " & Get ( RecordModificationCount );
34 | "-----------------------------------";
35 | "Active Field = " & Get ( ActiveFieldName );
36 | "Active Field Table = " & Get ( ActiveFieldTableName );
37 | "Active Layout Object = " & Get ( ActiveLayoutObjectName );
38 | "Active Layout Table = " & Get ( LayoutTableName );
39 | "-----------------------------------";
40 | "Local time = " & Get ( CurrentTimeStamp );
41 | "Host time = " & Get ( CurrentHostTimeStamp );
42 | "-----------------------------------";
43 | "$counter = " & $counter;
44 | )
45 | ];
46 |
47 | // Return value
48 | $$DEBUG
49 |
50 | )
51 | )
--------------------------------------------------------------------------------
/var.list.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * var.list ( keys; values; scope )
4 | *
5 | * RETURNS: (string) key/value pairs as $key = value in positional order
6 | * PARAMETERS: @keys = List() of key names
7 | * @values = List() of values
8 | * @scope = (enum) global, local
9 | * DEPENDENCIES: none
10 | * ABOUT: Takes two compliment set of lists
11 | * and turns them into FMP defined variables
12 | * NOTES: Use FileMaker's Quote() function when passing
13 | * in string values - otherwise numeric are fine!
14 | * =====================================================
15 | *
16 | */
17 |
18 | Let ( [
19 | singleValue = ValueCount ( keys ) = 1 and ValueCount ( values ) = 1; // only one key/value pair
20 | isValid = ValueCount ( keys ) = ValueCount ( values ); // both lists have the same number of values
21 | notEmpty = not IsEmpty( keys ) and not IsEmpty ( values ); // lists aren't empty
22 | value = GetValue ( values ; 1 );
23 | valueIsNumber = Length ( GetAsNumber ( Filter ( value; "0123456789.-" ) ) ) = Length ( value );
24 | valueIsTimestamp = GetAsTimestamp ( value ) = value; // doesn't work
25 | valueIsDate = GetAsDate ( value ) = value; // doesn't work
26 | valueIsTime = GetAsTime ( value ) = value; // doesn't work
27 | value = Case (
28 | valueIsNumber;
29 | value;
30 |
31 | Quote ( value ) // default for all strings
32 | );
33 | varString = If ( scope = "global" ; "$$" ; "$" ) & GetValue ( keys ; 1 ) & " = " & value & If ( ValueCount( keys ) = 1; "" ; ";¶" )
34 | ];
35 | Case (
36 | singleValue;
37 | varString;
38 |
39 | isValid and notEmpty;
40 | varString &
41 | var.list ( MiddleValues ( keys ; 2 ; 1000000 ) ; MiddleValues ( values ; 2 ; 1000000 ) ; scope );
42 |
43 | // default
44 | "ERROR » Lists don't match in length"
45 | )
46 | )
47 |
48 | /*
49 | // Testing code
50 | var.list (
51 | List(
52 | "foo";
53 | "bar"
54 | )
55 | ;
56 | List(
57 | "single value";
58 | "multiple¶values"
59 | )
60 | ; "local" )
61 | */
--------------------------------------------------------------------------------
/script.param.get.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * script.param.get( values; key)
4 | *
5 | * RETURNS: (mixed) the value associated to the supplied key
6 | * DEPENDENCIES: none
7 | * NOTES: Compliments to Mikhail Edoshin http://mikhailedoshin.com
8 | * =====================================================
9 | *
10 | * This function is used to extract a named value from a
11 | * data structure which preserves carriage returns and
12 | * other special characters.
13 | *
14 | */
15 |
16 | Case(
17 | IsEmpty( values ) or IsEmpty( key );
18 | "";
19 |
20 | Let(
21 | [
22 | //------------------------- VARIABLES
23 |
24 | var.UnwrappedValues = Substitute( values;
25 | [ "¶"; "" ];
26 | [ ".^^"; "¶" ];
27 | [ ".^"; "^" ] );
28 | var.KeyPosition = Position( "¶" & values; "¶.^^" & key & ".^^"; 1; 1 )
29 | ];
30 |
31 | //------------------------- RESULT
32 |
33 | If( var.KeyPosition = 0; "";
34 | Let(
35 | [
36 | //------------------------- VARIABLES
37 |
38 | var.ValuePosition = ValueCount( Left( values; var.KeyPosition ) );
39 | var.OptionString = MiddleValues( values; var.ValuePosition; 1 );
40 | var.Start = Position( var.OptionString; ".^^"; 1; 2 ) + Length( ".^^" );
41 | var.End = Position( var.OptionString; ".^^"; 1; 3 )
42 | ];
43 |
44 | //------------------------- RESULT
45 |
46 | Substitute( Middle( var.OptionString; var.Start; var.End - var.Start );
47 | [ ".^^"; "¶" ];
48 | [ ".^"; "^" ];
49 | [ "¶"; "" ];
50 | [ ".^^"; "¶" ];
51 | [ ".^"; "^" ] )
52 | )
53 | )
54 | )
55 | )
56 |
--------------------------------------------------------------------------------
/html.checkbox.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | html.checkbox ( string ; variable )
4 |
5 | RETURNS: (html) A single html checkbox based on the boolean value of a variable
6 | DEPENDENCIES: none
7 | VERSION: 1.0
8 | AUTHOR: Matt Petrowsky
9 | NOTES: Advanced developers can do cool stuff with Javascript/DOM and using hidden values
10 |
11 | =====================================================
12 | */
13 |
14 | Let(
15 |
16 | var.checked = Evaluate( "$$" & variable );
17 |
18 | List(
19 | "data:text/html,";
20 | "";
22 | ""; // Define the font here
23 | "";
24 | "Single Checkbox";
25 | "";
26 | ""; // No wrap and overflow settings
27 | "";
32 | "";
33 | ""
34 | )
35 |
36 | )
37 |
38 |
39 |
40 | /*
41 |
42 | FOR SUPER ADVANCED DEVELOPERS ONLY!
43 |
44 | If, for some reason, you want to use multiple checkboxes and you want to know the value of each
45 | you'll need to use a more advanced implementation of hiding text at the end of the input options
46 |
47 | Javascript would be used to change the value trailing the option - the following will do a toggle within the web page
48 | "";
49 |
50 | Option would look like this. Using a trailing span, you can store the value and use a very hackish way of getting the values using Select All -> Copy
51 | "" & var.initial & "";
52 |
53 | Other variables would be helpful
54 | var.initial = If ( var.checked ; "true" ; "false" );
55 | var.script = If ( var.checked ; "" ; "" )
56 |
57 | */
58 |
--------------------------------------------------------------------------------
/fmstandards/ErrorReference.fmfn:
--------------------------------------------------------------------------------
1 | /**
2 | * =====================================================
3 | * ErrorReference ( elementName ; requiredElementNames ; requiredType )
4 | *
5 | * PARAMETERS:
6 | * @elementName = FileMaker field reference
7 | * @requiredElementNames = List() of required element names
8 | * @requiredTypes = matching list of types for each element
9 | * RETURNS:
10 | * (boolean) Whether or not there is a calculation error
11 | * DEPENDENCIES:
12 | * none
13 | * NOTES:
14 | * References, at time of evaluation, are based on
15 | * current context.
16 | * =====================================================
17 | *
18 | */
19 |
20 | Let ( [
21 | $$ERROR.REFERENCE = ""; // always start as if there is no error
22 | // Set a global variable with match values - only make function calls on first iteration
23 | $$TEMP = If ( IsEmpty ( $$TEMP );
24 | FilterValues (
25 | Case (
26 | requiredType = "Table";
27 | TableNames ( Get ( FileName ) );
28 |
29 | requiredType = "Field";
30 | FieldNames ( Get ( FileName ) ; Get ( LayoutName ) );
31 |
32 | requiredType = "Layout";
33 | LayoutNames ( Get ( FileName ) );
34 |
35 | requiredType = "Object";
36 | LayoutObjectNames ( Get ( FileName ) ; Get ( LayoutName ) );
37 |
38 | requiredType = "Window";
39 | WindowNames ( Get ( FileName ) );
40 |
41 | ""
42 | ); requiredElementNames );
43 | // Else
44 | $$TEMP
45 | );
46 |
47 | var.topValue = GetValue ( requiredElementNames ; 1 );
48 | var.valueExists = PatternCount ( $$TEMP; var.topValue ) ≥ 1 or var.topValue = "";
49 | var.remaingValues = RightValues ( requiredElementNames ; ValueCount ( requiredElementNames ) - 1 )
50 | // The following line is used for debugging
51 | //$$ITERATIONS = List ( $$ITERATIONS ; List ( "top:¶" & Quote ( var.topValue ) ; "exists:¶" & var.valueExists ; "remains:¶" & Quote ( var.remaingValues ) ; "match:¶" & $$TEMP ; "----------------") )
52 | ];
53 | If ( not var.valueExists; // return the error
54 | Let ( [
55 | $$TEMP = ""; // reset the temp variable
56 | $$ERROR.REFERENCE = elementName & ": Missing literal references"
57 | ];
58 | True
59 | );
60 |
61 | // Else
62 |
63 | If ( var.remaingValues = "";
64 | Let ( $$TEMP = "" ; False );
65 | ErrorReference ( elementName ; var.remaingValues ; requiredType )
66 | )
67 | )
68 | )
--------------------------------------------------------------------------------
/file.setpath.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * file.setpath ( location ; subfolder )
4 | *
5 | * RETURNS: (string) path to file/folder location.
6 | * PARAMS location = (string) name of the folder location
7 | * subfolder = (string) any subfolders you wish to append
8 | * DEPS: none
9 | * NOTES: none
10 | * =====================================================
11 | *
12 | */
13 |
14 | Let ([
15 | _Windows = Abs( Get( SystemPlatform ) ) - 1;
16 |
17 | // Paths are returned via an evaluate using the inbound 'location' var as a reference to the named Let() var
18 | _Paths = "Let( [
19 | isWindows = Abs( Get( SystemPlatform ) ) - 1;
20 | isXP = isWindows and Get ( SystemVersion ) < 6;
21 | _Desktop = Get( DesktopPath );
22 | _Documents = Get( DocumentsPath );
23 | _Application = Get( FileMakerPath );
24 | _File = Substitute( Get( FilePath ) ; \"file:\" ; \"\" );
25 | _Preferences = Get( PreferencesPath );
26 | _Temp = If ( isWindows ; Substitute ( _Documents ; \"My Documents\" ; \"Local Settings\" ) & \"Temp/\"; \"/private/tmp/\" );
27 | _Extensions = Get( FileMakerPath ) & \"Extensions/\";
28 | path.win = If ( isXP ; \"/Local Settings/Application Data/FileMaker/Extensions/\" ; \"/AppData/Local/FileMaker/Extensions/\" );
29 | path.mac = \"/Library/Application Support/FileMaker/Extensions/\";
30 | _SharedExt = Substitute ( _Desktop ; \"/Desktop/\"; If ( isWindows ; path.win ; path.mac ) );
31 | _FMTemp = Get ( TemporaryPath )
32 |
33 | ];¶_" &
34 | location
35 | & ")";
36 |
37 | // Only these values for folder are possible
38 | _Match = "Desktop Documents Application File Preferences Temp Extensions SharedExt FMTemp";
39 |
40 | // Generate the actual path
41 | _Path = If ( PatternCount( _Match ; location ); Evaluate( _Paths ) ; location ) & If ( not IsEmpty( subfolder ); subfolder );
42 |
43 | // Remove the filename
44 | _File = Get( FileName ) & ".fp7";
45 | _HasFile = PatternCount( _Path; _File );
46 | _Path = If ( _HasFile; Substitute( _Path; _File; ""); _Path )
47 |
48 | ];
49 |
50 | _Path
51 |
52 | )
53 |
54 | /*
55 | //Unit test
56 | List (
57 | file.setpath ( "Desktop" ; "" );
58 | file.setpath ( "Documents" ; "" );
59 | file.setpath ( "Application" ; "" );
60 | file.setpath ( "File" ; "" );
61 | file.setpath ( "Preferences" ; "" );
62 | file.setpath ( "Temp" ; "" );
63 | file.setpath ( "Extensions" ; "" );
64 | file.setpath ( "SharedExt" ; "" );
65 | file.setpath ( "FMTemp" ; "" );
66 | )
67 | */
--------------------------------------------------------------------------------
/list.addRemove.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * list.addRemove ( value; valuelist )
3 | * RETURNS: ( string ) The supplied list with the value either removed or concatenated
4 | *
5 | */
6 |
7 | Let ( [ //------------------------- VARIABLES
8 |
9 | var.list = Substitute ( If ( Left ( valuelist; 1 ) ≠ ¶; "^") & valuelist & "^"; ¶; "^^" ); // List minus all returns
10 | var.match = "^" & value & "^"; // Value to match
11 | var.exists = PatternCount ( var.list; var.match )
12 |
13 | ]; //------------------------- RESULT
14 |
15 | Case (
16 | var.exists;
17 | Let ( [
18 | var.removed = Substitute ( var.list; var.match; "" ); // Kill matching values
19 | var.list = Substitute ( var.removed; "^^"; ¶ ); // Put returns back in
20 | var.list = Middle ( var.list; 2; 100000 ); // Trim leading ^
21 | var.list = Left ( var.list; Length ( var.list ) - 1 ); // Trim trailing ^
22 | var.cleaned = Substitute ( var.list; ¶; "" ); // Remove returns for trimming
23 | var.char.first = Position ( var.list; Left ( var.cleaned; 1 ); 0; 1 ); // Position of firt non cleaned char
24 | var.char.last = Position ( var.list; Right ( var.cleaned; 1 ); Length ( var.list ); -1 ) // Position of last non cleaned char
25 | ];
26 | Middle ( var.list; var.char.first; var.char.last - var.char.first + 1 )
27 | );
28 |
29 | If ( valuelist ≠ ""; valuelist & ¶ ) & value // default
30 | )
31 |
32 | )
33 |
34 | /*
35 | * Unit tests
36 | */
37 |
38 | /*
39 | Let (
40 | _ = "--------------------";
41 |
42 | List (
43 | List ( "At beginning ( one )"; _; list.addRemove ( "one"; List ( "one"; "two"; "three" ) ); _ );
44 | List ( "At ending ( three )"; _; list.addRemove ( "three"; List ( "one"; "two"; "three" ) ); _ );
45 | List ( "With multiple spread out ( one )"; _; list.addRemove ( "one"; List ( "one"; "two"; "one"; "three" ) ); _ );
46 | List ( "With multiple at beginning ( one )"; _; list.addRemove ( "one"; List ( "one"; "one"; "two"; "three" ) ); _ );
47 | List ( "With multiple at ending ( three )"; _; list.addRemove ( "three"; List ( "one"; "two"; "three"; "three" ) ); _ );
48 | List ( "With multiple in middle ( two )"; _; list.addRemove ( "two"; List ( "one"; "two"; "two"; "three" ) ); _ );
49 | List ( "With even returns at start ( two )"; _; list.addRemove ( "two"; "¶¶¶¶one¶two¶three" ); _ );
50 | List ( "With odd returns at start ( two )"; _; list.addRemove ( "two"; "¶¶¶one¶two¶three" ); _ );
51 | List ( "With even returns at end ( two )"; _; list.addRemove ( "two"; "one¶two¶three¶¶¶¶" ); _ );
52 | List ( "With odd returns at end ( two )"; _; list.addRemove ( "two"; "one¶two¶three¶¶¶" ); _ );
53 | List ( "Without value ( one )"; _; list.addRemove ( "one"; List ( "two"; "three" ) ); _ );
54 | )
55 | )
56 | */
--------------------------------------------------------------------------------
/var.eval.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * var.eval( contents )
4 | *
5 | * RETURNS: (bool) True or False based on proper evaluation
6 | * DEPENDENCIES: none
7 | * NOTES: Try to always use the List() function when passing multiple values into var.eval!
8 | * $checkScriptName is a reserved local variable used when you wish to enforce
9 | * that inbound parameters match the name of the script. It is reset after the
10 | * evaluation.
11 | * RELEASE: 100909
12 | * =====================================================
13 | *
14 | * This custom function evaluates contents passed as the
15 | * variable declaration part of a Let function. Useful for
16 | * defining global or locally scoped variables.
17 | *
18 | */
19 |
20 | Let( [
21 | $$ERROR.VAR.EVAL = ""; // Reset global error variable for evaluation
22 |
23 | var.empty = IsEmpty ( contents ); // test for empty contents
24 | var.semicolons_exist = ( ValueCount ( contents ) = PatternCount ( contents ; ";¶" ) ) or ( ValueCount ( contents ) - 1 = PatternCount ( contents ; ";¶" ) );
25 | var.contents = If ( not var.semicolons_exist ; Substitute ( contents ; ¶ ; ";¶") ; contents ); // Add semicolons if needed
26 | var.trailing_semicolon = Right ( var.contents ; 1 ) = ";"; // Clean off the trailing semicolon if present
27 | var.contents = If ( var.trailing_semicolon; Left ( var.contents ; Length( var.contents ) - 1 ); var.contents );
28 |
29 | var.script = Get ( ScriptName );
30 | var.begin = "(" ; // beginning of parameters definition
31 | var.break = "," ; // regular parameters separator (and)
32 | var.end = ")" ; // end of parameters definition
33 |
34 | var.parameters = Middle ( var.script ;
35 | Position ( var.script ; var.begin ; 1 ; 1 ) +1;
36 | Position ( var.script ; var.end ; Length ( var.script ) ; -1 ) - Position ( var.script ; var.begin ; 1 ; 1 ) -1
37 | ); // raw parameters
38 | // ONLY ALLOWED CHARACTERS FOR SCRIPT NAME PARAMERS ARE THE FOLLOWING (minus the ¶)
39 | var.parameters = Filter ( Substitute ( var.parameters ; var.break ; ¶ ) ; "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_¶" );
40 | var.expected = "$" & Substitute ( var.parameters ; ¶ ; "¶$" );
41 | var.matching = FilterValues ( Substitute( var.contents; "="; ¶ ) ; var.expected ); // matching parameters found in ScriptName
42 | var.matching = If ( Right ( var.matching; 1 ) = "¶" ; Left ( var.matching ; Length ( var.matching) - 1) ); // replace extra return added by FilterValues function
43 | var.missingParams = If ( $checkScriptName = True ; var.matching ≠ var.expected ; False )
44 | ];
45 |
46 | If ( Evaluate( "Let ( [" & var.contents & "]; False )" ) = "?" // generates an error or
47 | or var.empty or var.missingParams; // empty contents or missing expected parameters
48 | // Return error result
49 | Let ( [
50 | $$ERROR.VAR.EVAL =
51 | Case (
52 | var.empty ; "EMPTY PARAMETER SET" ;
53 | var.missingParams ; "MISSING EXPECTED PARAMETERS PER SCRIPT NAME";
54 | List ( "ERROR »"; var.contents )
55 | );
56 | $checkScriptName = "" // reset the $checkScriptName variable (after setting error)
57 | ];
58 | False
59 | );
60 | Let ( $checkScriptName = "" ; True )
61 | )
62 |
63 | )
--------------------------------------------------------------------------------
/script.execute.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * script.execute( method; file; script; parameter; control )
4 | *
5 | * RETURNS: (bool) Result of the execution of a script.
6 | * DEPS: At least one Script triggering plugin.
7 | * Supported are SmartPill PHP plugin, zippScript & DoScript
8 | * NOTES:
9 | * =====================================================
10 | */
11 |
12 | If ( Get ( WindowMode ) = 0;
13 | Let([
14 | //------------------------- VARIABLES
15 |
16 | _Default = "sm"; // Set your default script plugin here
17 |
18 | _File = If (IsEmpty(file); Get(FileName); file);
19 | _Control = If (IsEmpty(control); "pause"; control);
20 | method = If (IsEmpty(method); _Default; method);
21 |
22 | _Error = Case(
23 |
24 | method = "zipp"; Get ( ScriptName ) = script or Let ( [ _Result = zippScript_PerformScript( _File; script; parameter; _Control );
25 | $$SCRIPT.TEXT = Case(
26 | _Result = "" ; "" ;
27 | _Result = "$$-1" ; "Incorrect number of parameters" ;
28 | _Result = "$$-2" ; "Unknown control parameter code" ;
29 | _Result = "$$100" ; "File is missing (named file not open)" ;
30 | _Result = "$$104" ; "Script is missing (no script of that name)")
31 | ]; "" );
32 |
33 | method = "dosc"; Get ( ScriptName ) = script or mFMb_DoScript( script ; _File ; parameter ; _Control ) & mFMb_DS_LastErrNum;
34 |
35 | method = "sm"; Get ( ScriptName ) = script
36 |
37 | or
38 |
39 | EvaluateGroovy(
40 | Substitute (
41 | "fmpro.performScript( ':file', ':script', \":parameter\" )";
42 | [":file"; Get( FileName )];
43 | [":script"; script];
44 | [":parameter"; Substitute ( parameter; ["\""; "\\\""]; [ ¶; "\r"]; [ "$"; "\$"] )]
45 | )
46 | );
47 |
48 | method = "php";
49 |
50 | Let([
51 | //------------------------- VARIABLES
52 | _Control = If ( IsEmpty (control);
53 | 3; // 3 is the value used by fm_perform_script for pause
54 | Let( val = Left( control; 4); Int( Position ( "halt exit resu paus " ; val ; 1 ; 1 ) / 5 ) ) );
55 |
56 | _PHPCode = "print fm_perform_script("
57 | & Quote( _File ) & ", "
58 | & Quote( script ) & ", "
59 | & Quote( parameter ) & ", "
60 | & _Control &
61 | ");";
62 |
63 | $$SCRIPT_RESULT = Get ( ScriptName ) = script or PHP_Execute( _PHPCode )
64 |
65 | ];
66 | //------------------------- RESULT
67 |
68 | 0 // I haven't put error trapping in yet. :(
69 |
70 | );
71 |
72 | 0
73 | )
74 | ];
75 |
76 | If ( _Error;
77 | Let( $$SCRIPT.ERROR = _Error; 1 )
78 | )
79 |
80 | )
81 | )
82 |
83 | // Thanks Koen Van Hulle for the window mode suggestion
84 | // Thanks Peter Wagemans for the "aha" in logic for testing for the name of the currently running script and the error trapping
--------------------------------------------------------------------------------
/list.sort.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | list.sort( values; direction; type )
4 |
5 | RETURNS: (list) sorted version of the list
6 | DEPENDENCIES:
7 | VERSION: 1.0
8 | AUTHOR: See notes
9 | NOTES:
10 |
11 | Function uses a lot of recursion - be aware of list
12 | size limitations!
13 |
14 | Adapted and combined by Matt Petrowsky from
15 | http://www.briandunning.com/cf/593 and
16 | http://www.briandunning.com/cf/594
17 |
18 | Compliments to Shaun Flisakowski & Mogens Brun
19 | =====================================================
20 | */
21 |
22 | Let( divider = "||"; // Define the delimiter to divide the two halfs of the whole inbound list(should not be a possible list character)
23 |
24 | Case(
25 |
26 | PatternCount( values; divider ) = 1; // If the two lists contains the designated divider we'll run the sorting subfunction.
27 |
28 | // START SUBFUNCTION
29 |
30 | Let([
31 | list.splitpoint = Position( values; divider; 1; 1 ); // Point where list is combined by divider
32 | values.left = Left( values; list.splitpoint - 1 ); // Real left side list
33 | values.right = Right( values; Length( values ) - ( list.splitpoint + Length( divider ) - 1 ) ); // Real right side list
34 | $left.size = ValueCount( values.left );
35 | $right.size = ValueCount( values.right )
36 | ];
37 | Case(
38 | $left.size = 0; values.right;
39 | $right.size = 0; values.left;
40 |
41 | Let([
42 | $value.left = LeftValues( values.left; 1 );
43 | $value.right = LeftValues( values.right; 1 );
44 | $left.compare = Case(
45 | type = "Number"; Let( $right.compare = GetAsNumber( $value.right ); GetAsNumber( $value.left ) );
46 | type = "Time"; Let( $right.compare = GetAsTime( $value.right ); GetAsTime( $value.left ) );
47 | type = "Date"; Let( $right.compare = GetAsDate( $value.right ); GetAsDate( $value.left ) );
48 | // Default
49 | Let( $right.compare = $value.right; $value.left )
50 | )
51 | ];
52 | // Determine sort direction based on supplied parameter. Default to Ascending as most common
53 |
54 | If( If( direction = "Dsc"; $left.compare ≥ $right.compare; $left.compare < $right.compare );
55 | $value.left & list.sort( RightValues( values.left; $left.size - 1 ) & divider & values.right; direction; type );
56 | $value.right & list.sort( values.left & divider & RightValues( values.right; $right.size - 1 ); direction; type )
57 | )
58 | )
59 | )
60 | );
61 |
62 | // MAIN SORTING FUNCTION
63 |
64 | Let(
65 | $list.size = ValueCount( values );
66 |
67 | If( $list.size ≤ 1;
68 | values;
69 |
70 | Let( [
71 | list.splitpoint = Div( $list.size; 2 ); // Get dividing point to split whole list in half
72 | left.list = LeftValues( values; list.splitpoint ); // Left half of the list
73 | right.list = RightValues( values; $list.size - list.splitpoint ) // Right half of the list
74 | ];
75 | // Walk through the two lists comparing values
76 | list.sort( list.sort( left.list; direction; type ) & divider & list.sort(right.list; direction; type ); direction; type )
77 | )
78 | )
79 | )
80 | )
81 | )
--------------------------------------------------------------------------------
/list.filter.fmfn:
--------------------------------------------------------------------------------
1 | /* FilterList ( ListA ; Attribute ; ListB ; CaseSensitive ) .v2.0
2 | FilterList () requires CustomList ( Start ; End ; Function )*/
3 |
4 | // Limited => ListA < 18700 values and ListB < 18700 values too
5 | // Attributes : Equals - NotEquals - Contains - NotContains - BeginsWith - NotBeginsWith - EndsWith - NotEndsWith
6 | // Optional parameters : CaseSensitive : Boolean
7 |
8 | // Result
9 | /* --------- CaseSensitive = empty or 0
10 | FilterList ( "One¶Two¶three¶Four¶five" ; "Equals" ; "One¶four" ; "" or 0 ) => "One¶Four"
11 | FilterList ( "One¶Two¶three¶Four¶five" ; "NotEquals" ; "One¶four" ; "" or 0 ) => "Two¶three¶five"
12 | FilterList ( "One¶Two¶three¶Four¶five" ; "Contains" ; "O¶t" ; "" or 0 ) => "One¶Two¶three¶Four"
13 | FilterList ( "One¶Two¶three¶Four¶five" ; "NotContains" ; "O¶t" ; "" or 0 ) => "five"
14 | FilterList ( "One¶Two¶three¶Four¶five" ; "BeginsWith" ; "F¶t" ; "" or 0 ) => "Two¶three¶Four¶five"
15 | FilterList ( "One¶Two¶three¶Four¶five" ; "NotBeginsWith" ; "F¶t" ; "" or 0 ) => "One"
16 | FilterList ( "One¶Two¶three¶Four¶five" ; "EndsWith" ; "o¶E" ; "" or 0 ) => "One¶Two¶three¶five"
17 | FilterList ( "One¶Two¶three¶Four¶five" ; "NotEndsWith" ; "o¶E" ; "" or 0 ) => "Four"
18 |
19 | */
20 | /* --------- CaseSensitive = 1
21 | FilterList ( "One¶Two¶three¶Four¶five" ; "Equals" ; "One¶four" ; 1 ) => "One"
22 | FilterList ( "One¶Two¶three¶Four¶five" ; "NotEquals" ; "One¶four" ; 1 ) => "Two¶three¶Four¶five"
23 | FilterList ( "One¶Two¶three¶Four¶five" ; "Contains" ; "O¶t" ; 1 ) => "One¶three"
24 | FilterList ( "One¶Two¶three¶Four¶five" ; "NotContains" ; "O¶t" ; 1 ) => "Two¶Four¶five"
25 | FilterList ( "One¶Two¶three¶Four¶five" ; "BeginsWith" ; "F¶t" ; 1 ) => "three¶Four"
26 | FilterList ( "One¶Two¶three¶Four¶five" ; "NotBeginsWith" ; "F¶t" ; 1 ) => "One¶Two¶five"
27 | FilterList ( "One¶Two¶three¶Four¶five" ; "EndsWith" ; "o¶E" ; 1 ) => "Two"
28 | FilterList ( "One¶Two¶three¶Four¶five" ; "NotEndsWith" ; "o¶E" ; 1 ) => "One¶three¶Four¶five"
29 | */
30 |
31 | //-------------------------------------------------------------------*/
32 | // Agnès Barouh - Juillet 2007 - To report bugs : : barouh.agnes@wanadoo.fr
33 | //-------------------------------------------------------------------*/
34 |
35 | Case (
36 | ValueCount ( ListA ) > 18700 or ValueCount ( ListB ) > 18700 ; "Too many Values" ;
37 | IsEmpty ( ListA ) ; "" ;
38 | IsEmpty ( ListB ) ; ListA ;
39 | IsEmpty ( Attribute ) ; "Missing Attribute" ;
40 | IsEmpty ( FilterValues ( Attribute ; "Equals¶NotEquals¶Contains¶NotContains¶BeginsWith¶NotBeginsWith¶EndsWith¶NotEndsWith" ) ) ; "Incorrect attribute" ;
41 | not ( CaseSensitive = 1 or ( GetAsNumber ( CaseSensitive + 0 ) = 0 ) ) ; "Incorrect CaseSensitive" ;
42 | Attribute = "Equals" and CaseSensitive < 1 ; Substitute ( FilterValues ( ListA ; ListB ) & "#|#" ; ["¶#|#" ; "" ]; ["#|#" ; "" ]) ;
43 |
44 | Let ([
45 |
46 | $TagB = Case ( IsEmpty ( FilterValues ( Attribute ; "Equals¶NotEquals¶BeginsWith¶NotBeginsWith" ) ) ; "" ; "#|#" ) ;
47 | $TagE = Case ( IsEmpty ( FilterValues ( Attribute ; "Equals¶NotEquals¶EndsWith¶NotEndsWith" ) ) ; "" ; "#|#" ) ;
48 |
49 | $MyFirstList = ListA ;
50 | $MyList = "[#|#]" & $TagB & Substitute ( Choose ( CaseSensitive ; Upper ( $MyFirstList ) ; $MyFirstList ) ; [ ¶ ; $TagE & ¶ & "[#|#]" & $TagB ] ) & $TagE ;
51 | $Values = Choose ( CaseSensitive ; Upper ( ListB ) ; ListB ) ;
52 |
53 | Trigger = CustomList ( 1 ; ValueCount ( ListB ) ;
54 | "Let ([Value = GetValue ( $Values ; [n] ) ; $MyList = case ( Not IsEmpty ( value ) ; Substitute ( $MyList ; $TagB & Value & $TagE ; \"X##X\" ) ; $MyList ) ] ; \"\" )" ) ;
55 |
56 | $MyList = Substitute ( $MyList ; [ "[#|#]"; "" ] ; [ "#|#"; "" ] ) ;
57 | $Test = Case ( Left ( Attribute ; 3 ) = "Not" ; "<1" ; ">0")
58 | ];
59 |
60 | Case (
61 | CaseSensitive < 1 and Left ( Attribute ; 3 ) = "Not" ; Substitute ( FilterValues ( $MyFirstList ; $MyList ) & "#|#" ; ["¶#|#" ; "" ] ; ["#|#" ; "" ]) ;
62 |
63 | CustomList ( 1 ; ValueCount ( $MyList ) ;
64 | "Let ([ Value = GetValue ( $MyList ; [n] ) ]; Case ( PatternCount ( Value ; \"X##X\")" & $Test & " ; GetValue ( $MyFirstList ; [n] )))" )
65 | )
66 | )
67 | ) & Let( [ $MyFirstList = "" ; $MyList = "" ; $Values = ""] ; "" )
--------------------------------------------------------------------------------
/script.parameters.assign.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | script.parameters.assign ( )
4 | RETURNS: (vars) Creates local script variables
5 | based on the name of the script
6 | DEPENDENCIES: script.param.get, script.param.set
7 | NOTES: Compliments to Alexander Zueiv
8 | =====================================================
9 | by Alexander Zueiv
10 | October 1, 2006
11 | Adapted by Matt Petrowsky
12 |
13 | ABOUT: This function defines a local variable ($) for every
14 | parameter specified in the current script's name. To refer
15 | to any parameter within the script you only need to
16 | specify its name with a leading $. It also validates every
17 | "required" parameter for "not IsEmpty()" and returns "1" if
18 | all assignments succeeded.
19 |
20 | This function does not parse script parameters itself. It is
21 | a "wrapper" for your own custom parameter functions; it's
22 | supposed to call the custom function you currently use
23 | to get a parameter's value by its name. This should work
24 | well whatever method of sending parameters you currently
25 | use. FMP will show you where to put your function call when
26 | you click OK to save this function.
27 |
28 | Script name format:
29 |
30 | Cool Script [ paramA ; ( paramB | paramC ) {; paramD } ]
31 |
32 | Script code sample:
33 |
34 | If [ script.parameters.assign ]
35 | Set Field [ Field1 ; $paramA ]
36 | Set Field [ Field2 ; If ( IsEmpty ( $paramB ) ; $paramC ; $paramB ) ]
37 | If [ not IsEmpty ( $paramD ) ]
38 | Set Field [ Field3 ; $paramD ]
39 | End If
40 | Else
41 | Show Custom Dialog [ Get ( ScriptName ) ; "Error! Some script parameter is missing." ]
42 | End If
43 |
44 | This script will work only if ( paramA and ( paramB or paramC ) ) aren't empty, otherwise it will show
45 | the error message.
46 |
47 | To specify required validation logic for "alternative"
48 | parameters they must be enclosed in parentheses. The
49 | "optional" parameters section {} must appear at the end.
50 |
51 | */
52 | //---------------------------------------------------------------------------------------//
53 |
54 | Let ( [
55 |
56 | // Adjust these variables to match your scripts naming style
57 |
58 | VAR.BEGIN = "[" ; // beginning of parameters definition
59 | VAR.BREAK = ";" ; // regular parameters separator (and)
60 | VAR.ALT = "|" ; // alternative parameters separator (or)
61 | VAR.OPTION = "{" ; // beginning of optional parameters section
62 | VAR.END = "]" ; // end of parameters definition
63 |
64 | VAR.SCRIPT = Get ( ScriptName ) ;
65 |
66 | VAR.PARAMS = Middle ( VAR.SCRIPT ;
67 | Position ( VAR.SCRIPT ; VAR.BEGIN ; 1 ; 1 ) +1 ;
68 | Position ( VAR.SCRIPT ; VAR.END ; Length ( VAR.SCRIPT ) ; -1 ) - Position ( VAR.SCRIPT ; VAR.BEGIN ; 1 ; 1 ) -1 )
69 |
70 | ] ;
71 |
72 | Case (
73 |
74 | //---------------------------------------------------------------------------------------//
75 |
76 | $VAR.SCRIPT_PARAMETERS_COUNTER >= 1 ;
77 |
78 | Let ( [
79 |
80 | VAR.NAME = MiddleWords ( VAR.PARAMS ; $VAR.SCRIPT_PARAMETERS_COUNTER ; 1 ) ;
81 | $VAR.SCRIPT_PARAMETERS_COUNTER = $VAR.SCRIPT_PARAMETERS_COUNTER - 1 ;
82 |
83 | // Put your function call for getting script parameters here
84 |
85 | VAR.VALUE = script.param.get ( Get( ScriptParameter ); VAR.NAME )
86 |
87 | ] ;
88 |
89 | Evaluate ( "Let($" & VAR.NAME & "=" & Quote ( VAR.VALUE ) & ";\"\")" ) &
90 |
91 | If ( $VAR.SCRIPT_PARAMETERS_COUNTER >= 1 ; script.parameters.assign ) // recursive call to this function
92 |
93 | ) ; // End Let
94 |
95 | //---------------------------------------------------------------------------------------//
96 |
97 | WordCount ( VAR.PARAMS ) >= 1 ;
98 |
99 | Let ( [
100 |
101 | $VAR.SCRIPT_PARAMETERS_COUNTER = WordCount ( VAR.PARAMS ) ;
102 | TEMP = script.parameters.assign ; // recursive call to this function
103 | TEMP = Substitute ( VAR.PARAMS ; [ " " ; "" ] ; [ "$" ; "" ] ) ;
104 | TEMP = If ( Position ( TEMP ; VAR.OPTION ; 1 ; 1 ) ; Left ( TEMP ; Position ( TEMP ; VAR.OPTION ; 1 ; 1 ) -1 ) ; TEMP ) ;
105 | TEMP = If ( Left ( TEMP ; 1 ) = "(" ; "(not IsEmpty($" & Right ( TEMP ; Length ( TEMP ) -1 ) ; "not IsEmpty($" & TEMP ) ;
106 | VAR.VALIDATION = Substitute ( TEMP ;
107 | [ VAR.BREAK & "(" ; ") and (not IsEmpty($" ] ;
108 | [ VAR.BREAK ; ") and not IsEmpty($" ] ;
109 | [ VAR.ALT ; ") or not IsEmpty($" ] ) & ")" ;
110 | VAR.RESULT = If ( VAR.VALIDATION = "not IsEmpty($)" ; 1 ; Evaluate ( VAR.VALIDATION ) )
111 |
112 | ] ;
113 |
114 | VAR.RESULT
115 |
116 | ) // End Let
117 |
118 | //---------------------------------------------------------------------------------------//
119 |
120 | ) // End Case
121 |
122 | ) // End Let
123 |
--------------------------------------------------------------------------------
/date.ranges.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================
3 | date.ranges( string; separator; withtime )
4 |
5 | RETURNS: (string) FileMaker specific date range string.
6 | DEPS: none
7 | NOTES: The withtime value is a bool which will account for adding 24
8 | hours when used with a timestamp field type. Normal FMP dates
9 | assume 12:00 AM with just a raw date
10 | =====================================================
11 | */
12 | Let(
13 | [
14 | _Now = Get( CurrentDate );
15 | _TimeValue = If ( withtime; 1; 0) // Option for adding a day to the end date because fmp assumes 12:00 AM with raw date.
16 | ];
17 | Case(
18 | string = "Today";
19 | _Now & separator & _Now + _TimeValue;
20 |
21 | string = "Yesterday";
22 | Let( _Yesterday = _Now - 1; _Yesterday & separator & _Yesterday + _TimeValue);
23 |
24 | string = "Tomorrow";
25 | Let( _Tomorrow = _Now + 1; _Tomorrow & separator & _Tomorrow + _TimeValue);
26 |
27 | string = "ThisWeek";
28 | _Now - DayOfWeek(_Now) + 1 & separator & _Now + ( 7 - DayOfWeek(_Now)) + _TimeValue;
29 |
30 | string = "LastWeek";
31 | _Now - DayOfWeek(_Now) - 6 & separator & _Now - DayOfWeek(_Now) + _TimeValue;
32 |
33 | string = "NextWeek";
34 | Let( sunday = _Now + ( 8 - DayOfWeek(_Now)); sunday & separator & sunday + 6 + _TimeValue);
35 |
36 | string = "ThisMonth";
37 | Let( firstday = Date( Month(_Now); 1; Year(_Now)); firstday & separator & Date( Month(firstday) + 1; 0; Year(firstday)) + _TimeValue);
38 |
39 | string = "LastMonth";
40 | Let( lastday = Date( Month(_Now); 0; Year(_Now)); Date( Month(lastday); 1; Year(lastday)) & separator & lastday + _TimeValue);
41 |
42 | string = "NextMonth";
43 | Let( firstday = Date( Month(_Now) + 1; 0; Year(_Now)) + 1; firstday & separator & Date( Month(firstday) + 1; 0; Year(firstday)) + _TimeValue);
44 |
45 | string = "ThisYTD";
46 | Date(1; 1; Year(_Now)) & separator & _Now + _TimeValue;
47 |
48 | string = "LastYTD";
49 | Date(1; 1; Year(_Now)-1) & separator & Date(Month(_Now); Day(_Now); Year(_Now) - 1) + _TimeValue;
50 |
51 | string = "NextYTD";
52 | Date(1; 1; Year(_Now) + 1) & separator & Date(Month(_Now); Day(_Now); Year(_Now) + 1) + _TimeValue;
53 |
54 | string = "ThisYear";
55 | Date(1; 1; Year(_Now)) & separator & Date(12; 31; Year(_Now)) + _TimeValue;
56 |
57 | string = "LastYear";
58 | Date(1; 1; Year(_Now) - 1) & separator & Date(12; 31; Year(_Now) - 1) + _TimeValue;
59 |
60 | string = "NextYear";
61 | Date(1; 1; Year(_Now) + 1) & separator & Date(12; 31; Year(_Now) + 1) + _TimeValue;
62 |
63 | string = "ThisQuarter" or
64 | string = "LastQuarter" or
65 | string = "NextQuarter";
66 | Let (
67 | xMod = Case (
68 | Mod( Month( _Now ) ; 3 ) = 0; 3;
69 | Mod( Month( _Now ) ; 3 ) );
70 | Case(
71 | string = "ThisQuarter";
72 | Date( Month(_Now) - xMod + 1; 1; Year(_Now) ) & separator & _Now + _TimeValue;
73 |
74 | string = "LastQuarter";
75 | Date( Month(_Now) - xMod - 2; 1; Year(_Now) ) & separator & Date( Month(_Now) - xMod + 1; 1; Year(_Now) ) - 1 + _TimeValue;
76 |
77 | string = "NextQuarter";
78 | Date( Month(_Now) - xMod + 4; 1; Year(_Now) ) & separator & Date( Month(_Now) - xMod + 7; 1; Year(_Now) ) - 1 + _TimeValue
79 | )
80 | );
81 |
82 | string = "test";
83 | "Today = " & date.ranges("Today"; separator; withtime) & ¶ &
84 | "Yesterday = " & date.ranges("Yesterday"; separator; withtime) & ¶ &
85 | "Tomorrow = " & date.ranges("Tomorrow"; separator; withtime) & ¶ &
86 | "ThisWeek = " & date.ranges("ThisWeek"; separator; withtime) & ¶ &
87 | "LastWeek = " & date.ranges("LastWeek"; separator; withtime) & ¶ &
88 | "NextWeek = " & date.ranges("NextWeek"; separator; withtime) & ¶ &
89 | "ThisMonth = " & date.ranges("ThisMonth"; separator; withtime) & ¶ &
90 | "LastMonth = " & date.ranges("LastMonth"; separator; withtime) & ¶ &
91 | "NextMonth = " & date.ranges("NextMonth"; separator; withtime) & ¶ &
92 | "ThisYTD = " & date.ranges("ThisYTD"; separator; withtime) & ¶ &
93 | "LastYTD = " & date.ranges("LastYTD"; separator; withtime) & ¶ &
94 | "NextYTD = " & date.ranges("NextYTD"; separator; withtime) & ¶ &
95 | "ThisYear = " & date.ranges("ThisYear"; separator; withtime) & ¶ &
96 | "LastYear = " & date.ranges("LastYear"; separator; withtime) & ¶ &
97 | "NextYear = " & date.ranges("NextYear"; separator; withtime) & ¶ &
98 | "ThisQuarter = " & date.ranges("ThisQuarter"; separator; withtime) & ¶ &
99 | "LastQuarter = " & date.ranges("LastQuarter"; separator; withtime) & ¶ &
100 | "NextQuarter = " & date.ranges("NextQuarter"; separator; withtime)
101 | )
102 | )
103 | /*
104 | Original by
105 | Andy Frazier, Mx4Px
106 | http://www.andyfrazier.com
107 | via Briandunning.com
108 | Compliments to Excelisys
109 | Modified by Matt Petrowsky
110 | */
--------------------------------------------------------------------------------
/object.id.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================================
3 | * object.id ( object; type; file; layout )
4 | *
5 | * @object = supply either the name or internal id of an object
6 | * (see types variable for supported objects)
7 | * @type = (enum) One of the following
8 | * "Table", "Layout", "Field", "Script", or "ValueList" or (T,L,F,S,V) for shorthand
9 | * @file = [optional] specify the name of the file (if using multiple files) - empty implies current file
10 | * @layout = [optional] required only if @type contains "Field".
11 | * Empty implies current layout (or the field table occurrence, read the note below).
12 | * The layout should be tied to the table occurrence of the field
13 | *
14 | * RETURNS: (mixed) Internal FileMaker ID if name of object is supplied
15 | * and inverse if ID of object is supplied
16 | *
17 | * DEPENDENCIES: None
18 | * AUTHOR: Fabrice Nordman
19 | * NOTES: for fields (_TLFSV = "F"), if you use the full field name
20 | * (table::fieldname) AND an empty var.layout parameter, the
21 | * function will assume you are referring not to current layout but
22 | * to the table occurrence found in the _TLFSV
23 | *
24 | * =====================================================================
25 | */
26 |
27 |
28 | Let ([
29 | file = If (
30 | IsEmpty ( file );
31 | Get ( FileName ); // use current file name... otherwise
32 | file
33 | );
34 | layout = Case (
35 | IsEmpty ( layout );
36 | Case (
37 | PatternCount ( object; "::" );
38 | GetValue ( Substitute ( object; "::"; ¶ ); 1 );
39 | Get ( LayoutName ) // default
40 | );
41 | layout // default
42 | );
43 | layout = Case (
44 | Int ( layout ) = layout and Length ( layout ) = 7;
45 | object.id ( layout; "T"; file; "" );
46 | layout
47 | );
48 | var.object = object;
49 |
50 | // Allow type to be a single character (T,L,F,S,V)
51 | var.type = Left ( type; 1 );
52 | var.type = Choose( Position ( "TLFSV"; var.type; 1; 1 ) - 1; "Table"; "Layout"; "Field"; "Script"; "ValueList" );
53 | var.object = Case ( // remove the repetition number
54 | var.type = "Field" and PatternCount ( var.object; "[" );
55 | Left ( var.object; Position ( var.object; "["; 10000; -1 ) -1 );
56 | var.object
57 | );
58 | var.object = Case ( // for fields, do not take TO
59 | var.type = "Field" and PatternCount ( var.object; "::" );
60 | Replace ( var.object; 1; Position ( var.object; "::"; 1; 1 ) + 1; "" );
61 | var.object
62 | );
63 | var.endOfString = "( \"" & file & "\"" & Case ( var.type = "field"; "; \"" & layout & "\"" ) & ")";
64 | var.names = Evaluate ( var.type & "Names" & var.endOfString );
65 | var.ids = Evaluate ( var.type & "IDs" & var.endOfString )
66 | ];
67 |
68 | Case (
69 | var.object = GetAsNumber ( var.object );
70 |
71 | // Convert ID -> Name
72 | Case (
73 | not IsEmpty ( FilterValues ( var.object; var.ids ));
74 | GetValue ( var.names; Let ([
75 | _text = var.ids;
76 | _item = var.object;
77 | _adj = ¶ & _text & ¶
78 | ];
79 | PatternCount ( Left ( _adj; Position ( _adj; ¶ & _item & ¶; 1; 1 ) + 1 ); ¶ )
80 | )
81 | )
82 | );
83 | // Convert Name -> ID
84 | Case (
85 | not IsEmpty ( FilterValues ( var.object; var.names ));
86 | GetValue ( var.ids; Let ([
87 | _text = var.names;
88 | _item = var.object;
89 | _adj = ¶ & _text & ¶
90 | ];
91 | PatternCount ( Left ( _adj; Position ( _adj; ¶ & _item & ¶; 1; 1 ) + 1 ); ¶ )
92 | )
93 | )
94 | )
95 | )
96 | )
97 |
98 |
99 | /*
100 |
101 | Original function by Fabrice Nordmann
102 | Reformatted by Matt Petrowsky
103 |
104 | Avoids hard-coding in FileMaker by using IDs instead of names
105 |
106 | v.1.6, Mar 2009
107 | Accepts field parameters such as FMvar.name_id ( 1065234::24; "F"; ""; "" )
108 | v.1.5.2, Feb 2009
109 | Removes the repetition number if a fieldname with a repetition number is passed ( field[n]). Does not handle field names with [ anymore.
110 | v.1.5.1, Dec 2008
111 | Documentation update (thanks to Kevin Frank's comment)
112 | v.1.5, Oct 2008
113 | Documentation error fix
114 | Returns an empty result if item not found
115 | v.1.4, Aug 2008
116 | Bug fix (major) : could return erroneous result if an item ID was found in another ID.
117 | v.1.3, July 2008
118 | A field ID can be obtained by passing its full name (with table occurrence) in var.name_id and leaving var.layout empty
119 | e.g. FMvar.name_id ( "myTable::myField"; "F"; ""; "" )
120 | v.1.2, June 2008
121 | Doesn't require Position value
122 | v.1, May 2008
123 | Requires: PositionValue ( _text; _searchValue; _start; _occurrence )
124 |
125 | // Test code for raw data
126 | Let ( [
127 | f = Get ( FileName );
128 | l = Get ( LayoutName )
129 | ];
130 | List (
131 | "--- TABLES ---";
132 | TableNames ( f );
133 | TableIDs ( f );
134 | "--- LAYOUTS ---";
135 | LayoutNames ( f );
136 | LayoutIDs ( f );
137 | "--- FIELDS ---";
138 | FieldNames ( f; l );
139 | FieldIDs ( f; l );
140 | "--- SCRIPTS ---";
141 | ScriptNames ( f );
142 | ScriptIDs ( f );
143 | "--- VALUE LISTS ---";
144 | ValueListNames ( f );
145 | ValueListIDs ( f )
146 | )
147 | )
148 |
149 | */
--------------------------------------------------------------------------------
/keycode.istype.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * keycode.istype( type )
4 | *
5 | * RETURNS: (boolean) Whether the keystoke used is within the specified type
6 | * DEPS: none
7 | * NOTES:
8 | * =====================================================
9 | */
10 |
11 | Let (
12 | [
13 | // Capture the keystroke for use
14 |
15 | var.keystroke = Code ( Get ( TriggerKeystroke ) );
16 |
17 | // Possible keystokes & combinations
18 |
19 | var.arrows = var.keystroke ≥ 28 and var.keystroke ≤ 31;
20 | var.uppercase = var.keystroke ≥ 65 and var.keystroke ≤ 90;
21 | var.lowercase = var.keystroke ≥ 97 and var.keystroke ≤ 122;
22 | var.letter = var.uppercase or var.lowercase;
23 | var.number = var.keystroke ≥ 48 and var.keystroke ≤ 57;
24 |
25 | // Common editing keystrokes
26 |
27 | var.home = var.keystroke = 1;
28 | var.pageup = var.keystroke = 2;
29 | var.pagedown = var.keystroke = 3;
30 | var.end = var.keystroke = 4;
31 | var.backspace = var.keystroke = 8;
32 | var.tab = var.keystroke = 9;
33 | var.enter = var.keystroke = 10;
34 | var.return = var.keystroke = 13;
35 | var.escape = var.keystroke = 27;
36 | var.leftarrow = var.keystroke = 28;
37 | var.uparrow = var.keystroke = 29;
38 | var.rightarrow = var.keystroke = 30;
39 | var.downarrow = var.keystroke = 31;
40 | var.space = var.keystroke = 32;
41 | var.delete = var.keystroke = 127;
42 |
43 | // Punctiation & Math
44 |
45 | var.exclamation = var.keystroke = 33;
46 | var.doublequote = var.keystroke = 34;
47 | var.numbersign = var.keystroke = 35;
48 | var.dollar = var.keystroke = 36;
49 | var.percent = var.keystroke = 37;
50 | var.ampersand = var.keystroke = 38;
51 | var.singlequote = var.keystroke = 39;
52 | var.openparen = var.keystroke = 40;
53 | var.closeparen = var.keystroke = 41;
54 | var.asterisk = var.keystroke = 42;
55 | var.plus = var.keystroke = 43;
56 | var.comma = var.keystroke = 44;
57 | var.minus = var.keystroke = 45;
58 | var.period = var.keystroke = 46;
59 | var.slash = var.keystroke = 47;
60 | var.colon = var.keystroke = 58;
61 | var.semicolon = var.keystroke = 59;
62 | var.lessthan = var.keystroke = 60;
63 | var.equals = var.keystroke = 61;
64 | var.greaterthan = var.keystroke = 62;
65 | var.questionmark = var.keystroke = 63;
66 | var.openbracket = var.keystroke = 91;
67 | var.backslash = var.keystroke = 92;
68 | var.closebracket = var.keystroke = 93;
69 | var.caret = var.keystroke = 94;
70 | var.underscore = var.keystroke = 95;
71 | var.openbrace = var.keystroke = 123;
72 | var.pipe = var.keystroke = 124;
73 | var.closebrace = var.keystroke = 125;
74 | var.tilde = var.keystroke = 126;
75 |
76 | // Special combinations and groupings
77 |
78 | var.edit = var.home
79 | or var.pageup
80 | or var.pagedown
81 | or var.end
82 | or var.backspace
83 | or var.tab
84 | or var.enter
85 | or var.return
86 | or var.escape
87 | or var.return
88 | or var.space
89 | or var.delete;
90 |
91 | var.punctuation = var.period
92 | or var.exclamation
93 | or var.questionmark
94 | or var.comma
95 | or var.semicolon
96 | or var.colon
97 | or var.space
98 | or var.singlequote
99 | or var.doublequote
100 | or var.openparen
101 | or var.closeparen
102 | or var.openbrace
103 | or var.closebrace
104 | or var.openbracket
105 | or var.closebracket
106 |
107 | ];
108 | // English named versions of keystrokes
109 |
110 | If (
111 | type = "arrows" and var.arrows or
112 | type = "uppercase" and var.uppercase or
113 | type = "lowercase" and var.lowercase or
114 | type = "letter" and var.letter or
115 | type = "number" and var.number or
116 | type = "home" and var.home or
117 | type = "pageup" and var.pageup or
118 | type = "pagedown" and var.pagedown or
119 | type = "end" and var.end or
120 | type = "backspace" and var.backspace or
121 | type = "tab" and var.tab or
122 | type = "enter" and var.enter or
123 | type = "return" and var.return or
124 | type = "escape" and var.escape or
125 | (type = "leftarrow" or type = "left arrow") and var.leftarrow or
126 | type = "uparrow" and var.uparrow or
127 | type = "rightarrow" and var.rightarrow or
128 | type = "downarrow" and var.downarrow or
129 | type = "space" and var.space or
130 | type = "delete" and var.delete or
131 | type = "exclamation" and var.exclamation or
132 | type = "doublequote" and var.doublequote or
133 | type = "number sign" and var.numbersign or
134 | type = "dollar" and var.dollar or
135 | type = "percent" and var.percent or
136 | type = "ampersand" and var.ampersand or
137 | type = "singlequote" and var.singlequote or
138 | type = "openparen" and var.openparen or
139 | type = "closeparen" and var.closeparen or
140 | type = "asterisk" and var.asterisk or
141 | type = "plus" and var.plus or
142 | type = "comma" and var.comma or
143 | type = "minus" and var.minus or
144 | type = "period" and var.period or
145 | type = "slash" and var.slash or
146 | type = "colon" and var.colon or
147 | type = "semicolon" and var.semicolon or
148 | type = "lessthan" and var.lessthan or
149 | type = "equals" and var.equals or
150 | type = "greaterthan" and var.greaterthan or
151 | type = "questionmark" and var.questionmark or
152 | type = "openbracket" and var.openbracket or
153 | type = "backslash" and var.backslash or
154 | type = "closebracket" and var.closebracket or
155 | type = "caret" and var.caret or
156 | type = "underscore" and var.underscore or
157 | type = "openbrace" and var.openbrace or
158 | type = "pipe" and var.pipe or
159 | type = "closebrace" and var.closebrace or
160 | type = "tilde" and var.tilde or
161 | type = "editing" and var.edit or
162 | type = "punctuation" and var.punctuation; True;
163 | False
164 | )
165 | )
--------------------------------------------------------------------------------
/list.custom.fmfn:
--------------------------------------------------------------------------------
1 | /* Special Thanks to Ugo Di Luca - Grazie Mille, pour
2 | l'aiguillage qu'il m'a fait prendre, merci à lui pour son
3 | implication afin de vous rendre l'utilisation de
4 | CustomList() plus limpide Merci pour tous ses commentaires
5 | et sa notice ® Ugo Di Luca
6 | ===========================================================
7 |
8 | // Author: Agnès Barouh - barouh.agnes@wanadoo.fr
9 |
10 | // CustomList ( Start ; End ; Function ) v_4.5
11 | // [please, do not used "CLNum" in your calculation with Let() ]
12 | // Objectives and examples :
13 |
14 | - Build any list based on all Native or Custom Functions involving a 'Number' value as a parameter, such as :
15 | Left(), Middle(), GetValue(), GetRepetitionNumber (), GetNthRecord(), GetLayoutObjectAttribute () ...
16 |
17 | ex : - CustomList ( 1 ; Get ( FoundCount ) ; "GetNthRecord ( FirstName ; [n] )" )
18 |
19 | will return James¶Henry¶Susan if your foundset has 3 records.
20 |
21 | - Build any range based on Dates, Times, TimeStamps, and obviously Numbers
22 |
23 | ex : CustomList ( 1 ; 5 ; "GetAsDate ( StartingDate ) + [n]" )
24 |
25 | will return a range of 5 dates starting from the specified StartingDate
26 |
27 | The 'Function' Parameter is nothing else than a literal calculation expression.
28 | Therefore, CustomList allows for any filtering or parsing
29 | process based on any condition you may need.
30 |
31 | ex : CustomList ( 10 ; 100 ; "Let ( [ Value = GetValue ( MyList ; [n] ) ] ; Case ( PatternCount ( Value ; "X" ) ; Value ))" )
32 |
33 | will parse any value containing a "X" in the 'MyList' chain,
34 | in between the 10th and the 100th values.
35 |
36 | See the 'Under the Hood' part at the end of the function to fully understand the process of this function
37 |
38 | --------------------------------
39 | /* MAJOR UPDATE */ Updated July'08
40 | --------------------------------
41 |
42 | CustomList is based on a totally new algorithm, and is now
43 | voluntarily bridled to a maximum range of 500,000 values,
44 | where the first version was technically limited to a max of
45 | 18,700 values.
46 |
47 | Previous version still available here : http://www.briandunning.com/cf/747
48 |
49 | The new CustomList() is faster and still is NOT recursive.
50 | The arguments are unchanged which makes it compatible with
51 | all your previous developments involving CustomList().
52 |
53 | For Developer ease, the new CustomList() includes a
54 | debugging mode. find the "*****DEBUGGING MODE*****" tag in
55 | the formula below to switch mode. When debug is set to 1,
56 | any error will be returned with its appropriate explanatory
57 | code, else the result will be set to "?"
58 | -------------------------------- */
59 |
60 | // ----------- FORMULA STARTS HERE -----------
61 |
62 | Case (
63 | /*This function will not evaluate if Invalid parameters were passed for Start and End.*/
64 |
65 | IsEmpty ( Start ) or IsEmpty ( End ) or End < 1 or Start < 1; "";
66 |
67 | Let ( [
68 | Start = GetAsNumber ( Start );
69 | End = GetAsNumber ( End );
70 | Diff = End - Start + 1;
71 |
72 | /*Check for a range higher than 500,000 values. CustomList() is voluntarily restrained to this limit.*/
73 |
74 | End = Case ( Diff > 500000 or End < Start or IsEmpty ( Start ) or IsEmpty ( End ); "Error"; End );
75 | $null = "\"\"";
76 |
77 | /*CustomList has its own recursion model. As CustomList may be involved into the "function" argument,
78 | each CustomList expression used is passed to a repeating variable for evaluation*/
79 |
80 | iter = Let ( $CLExeCount = $CLExeCount + 1 ; $CLExeCount & PatternCount ( Function ; "CustomList" ) + 1 ) ;
81 | $CLn[ iter ] = Start - 1;
82 | Calc = Case ( Diff ≥ 1600; 169; Floor ( Diff / 10 ) + 1 );
83 |
84 | /*Here starts the "magic" of the Substitutions and the whole mechanism.
85 | CustomList() is set to evaluate stacks of 1,700 values at a time, which is the
86 | current limit of FileMaker internal Evaluate function */
87 |
88 | First = Substitute ( ( 10 ^ Calc ) - 1; 9; "__________" ) & "_________";
89 | X = Floor ( Diff / 1700 );
90 | $CLRemainder[ iter ] = Diff - ( X * 1700 );
91 |
92 | /*When the "Function" argument is left empty, CustomList() will return a numeric list based on the range defined */
93 |
94 | FunctionR = Case ( IsEmpty ( Function ); "CLNum"; Substitute ( Function; ["[n]"; "CLNum"] ; [¶ ; ""] ) );
95 |
96 | /*Each repeating variable content is parsed in order to get our String ready for the last evaluation - Special care is made for
97 | French users here, please substitute the "definir" below with your local translation of the "Let" function if you're not using an english
98 | version. The use of "Let ([" is recommanded anyway */
99 |
100 | $CLExecute[ iter ] = Case ( Left ( Substitute ( Lower ( Function ); ["definir"; "Let" ]; [" "; ""]; ["¶"; ""]); 5 ) = "Let([";
101 | Substitute ( "Let([$CLn[" & iter & "] = $CLn[" & iter & "] + 1 ; CLNum = $CLn[" & iter & "]" & First & "|";
102 | [ "_"; "|¶Let([$CLn[" & iter & "] = $CLn[" & iter & "] + 1 ; CLNum = $CLn[" & iter & "] "]; [ "|";";" &
103 | Replace ( FunctionR; 1; Position ( FunctionR; "["; 1; 1 ); "" ) & "&\"#^#|#^#\"&"] );
104 | Substitute ( "Let([$CLn[" & iter & "] = $CLn[" & iter & "] + 1 ; CLNum = $CLn[" & iter & "]" & First & "|";
105 | [ "_"; "|¶Let([$CLn[" & iter & "] = $CLn[" & iter & "] + 1 ; CLNum = $CLn[" & iter & "] "]; [ "|";"];" & FunctionR & ")&\"#^#|#^#\"&"] ) );
106 |
107 | /*Final compilation starts here. The reminder part above each 1,700 values is treated now. */
108 |
109 | Final = Case ( X > 0; Substitute ( ( 10 ^ X ) - 1; 9; "Evaluate ( $CLExecute[" & iter & "] & $null ) & " ) ) &
110 | "Evaluate( LeftValues ( $CLExecute[" & iter & "] ; $CLRemainder[" & iter & "] ) & $null ) & " & $null;
111 |
112 | /*The Final variable can now be evaluated to get our List*/
113 |
114 | Result = Case ( End <> "Error"; Substitute ( "#^#" & Evaluate ( Final ) & "#^#";
115 | [ "#^#|#^#"; "¶" ]; [ "¶"; "¶#^#" ]; [ "#^#¶"; "" ]; [ "¶#^#"; "¶" ]; [ "¶#^#"; "" ]; [ "#^#"; "" ] ) ) ;
116 | $CLExecute[ iter ] = ""
117 |
118 | // ----------- FUNCTION RESULT BELOW -----------
119 | ];
120 | /*CustomList returns either the valid result, or an error formatted according to the debugging mode chosen above*/
121 |
122 | Case (
123 | ( Length ( Result ) and ( Result = Filter ( Result; "?" ))) or End = "Error";
124 | Let ([
125 | /*****DEBUGGING MODE*****/ // Case Debug = 1, returned error "[error_CL], Number, Name and Calculation error" ,if Debug <> 1, returned error is "?"
126 | Debug = "1";
127 | Write = Substitute ( Function; "[n]"; 1 ); NumError = EvaluationError ( Evaluate ( Write ) );
128 | Error = "[" & NumError & "] " & "Unlisted error | Unknown error, check calculation or check \"Start\" and \"End\" ¶102 | Field is missing¶103 | Relationship is missing¶106 | Table is missing¶113 | Function is missing¶1204 | Number, text constant, field name or \"(\" expected¶1205 | Comment is not terminated with \"*/\"¶1206 | Text constant must end with a quotation mark¶1207 | Unbalanced parenthesis¶1208 | Operator or function missing or \"(\" not expected¶1211 | List usage is not allowed in this function¶1212 | An operator (for example, +, -, *,;) is expected here¶1215 | This parameter is an invalid Get function parameter";
129 | Pos = ValueCount ( Left ( Error; Position ( Error; NumError & " "; 1; 1 ) ) )
130 | ];
131 | Case ( Debug = 1; "[Error_CL] | Return error : " & GetValue ( Error; Case ( Pos = 0; 1; Pos ) ) & ¶ & TextStyleAdd ( "Calculation ( for [n] = 1 ) : "; Bold ) & Write; "?" ));
132 | Result ))
133 | )
134 |
135 | // ----------- UNDER THE HOOD -----------
136 |
137 | /* Not very much afterwards...
138 | Basically, CustomList() does two things :
139 | 1/ Transform your formula in a litteral chain :
140 |
141 | CustomList ( 1; 4; "GetNthRecord ( Field ; [n])")
142 | therefore becomes
143 | "Let ([ CLNum = 1 ] ; GetNthRecord ( Field ; CLNum )) & ¶ &
144 | Let ([ CLNum = 2 ] ; GetNthRecord ( Field ; CLNum )) & ¶ &
145 | Let ([ CLNum = 3 ] ; GetNthRecord ( Field ; CLNum )) & ¶ &
146 | Let ([ CLNum = 4 ] ; GetNthRecord ( Field ; CLNum ))"
147 |
148 | 2/ Evaluates this chain.
149 |
150 | Interrested in the mechanism ?
151 | My advice then : dissect this function by escaping the
152 | 'Result' and placing one of the numerous intermediary
153 | variables available.
154 |
155 | Special attention should be paid to the 'First' Variable,
156 | everything starts from there !
157 | */
--------------------------------------------------------------------------------
/error.string.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================
3 | * error.string( num )
4 | *
5 | * RETURNS: (string) English version of current error
6 | * DEPENDENCIES: none
7 | * NOTES: FileMaker 10 error codes at http://www.filemaker.com/help/html/error_codes.html#1027502
8 | * =====================================================
9 | *
10 | */
11 |
12 | Case (
13 | num = -1; "Unknown error";
14 | num = 0; "No error";
15 | num = 1; "User canceled action";
16 | num = 2; "Memory error";
17 | num = 3; "Command is unavailable (for example, wrong operating system, wrong mode, etc.)";
18 | num = 4; "Command is unknown";
19 | num = 5; "Command is invalid (for example, a Set Field script step does not have a calculation specified)";
20 | num = 6; "File is read-only";
21 | num = 7; "Running out of memory";
22 | num = 8; "Empty result";
23 | num = 9; "Insufficient privileges";
24 | num = 10; "Requested data is missing";
25 | num = 11; "Name is not valid";
26 | num = 12; "Name already exists";
27 | num = 13; "File or object is in use";
28 | num = 14; "Out of range";
29 | num = 15; "Can't divide by zero";
30 | num = 16; "Operation failed, request retry (for example, a user query)";
31 | num = 17; "Attempt to convert foreign character set to UTF-16 failed";
32 | num = 18; "Client must provide account information to proceed";
33 | num = 19; "String contains characters other than A-Z, a-z, 0-9 (ASCII)";
34 | num = 20; "Command/operation canceled by triggered script";
35 | num = 100; "File is missing";
36 | num = 101; "Record is missing";
37 | num = 102; "Field is missing";
38 | num = 103; "Relationship is missing";
39 | num = 104; "Script is missing";
40 | num = 105; "Layout is missing";
41 | num = 106; "Table is missing";
42 | num = 107; "Index is missing";
43 | num = 108; "Value list is missing";
44 | num = 109; "Privilege set is missing";
45 | num = 110; "Related tables are missing";
46 | num = 111; "Field repetition is invalid";
47 | num = 112; "Window is missing";
48 | num = 113; "Function is missing";
49 | num = 114; "File reference is missing";
50 | num = 115; "Specified menu set is not present";
51 | num = 116; "Specified layout object is not present";
52 | num = 117; "Specified data source is not present";
53 | num = 130; "Files are damaged or missing and must be reinstalled";
54 | num = 131; "Language pack files are missing (such as template files)";
55 | num = 200; "Record access is denied";
56 | num = 201; "Field cannot be modified";
57 | num = 202; "Field access is denied";
58 | num = 203; "No records in file to print, or password doesn't allow print access";
59 | num = 204; "No access to field(s) in sort order";
60 | num = 205; "User does not have access privileges to create new records; import will overwrite existing data";
61 | num = 206; "User does not have password change privileges, or file is not modifiable";
62 | num = 207; "User does not have sufficient privileges to change database schema, or file is not modifiable";
63 | num = 208; "Password does not contain enough characters";
64 | num = 209; "New password must be different from existing one";
65 | num = 210; "User account is inactive";
66 | num = 211; "Password has expired";
67 | num = 212; "Invalid user account and/or password; please try again";
68 | num = 213; "User account and/or password does not exist";
69 | num = 214; "Too many login attempts";
70 | num = 215; "Administrator privileges cannot be duplicated";
71 | num = 216; "Guest account cannot be duplicated";
72 | num = 217; "User does not have sufficient privileges to modify administrator account";
73 | num = 300; "File is locked or in use";
74 | num = 301; "Record is in use by another user";
75 | num = 302; "Table is in use by another user";
76 | num = 303; "Database schema is in use by another user";
77 | num = 304; "Layout is in use by another user";
78 | num = 306; "Record modification ID does not match";
79 | num = 400; "Find criteria are empty";
80 | num = 401; "No records match the request";
81 | num = 402; "Selected field is not a match field for a lookup";
82 | num = 403; "Exceeding maximum record limit for trial version of FileMaker Pro";
83 | num = 404; "Sort order is invalid";
84 | num = 405; "Number of records specified exceeds number of records that can be omitted";
85 | num = 406; "Replace/Reserialize criteria are invalid";
86 | num = 407; "One or both match fields are missing (invalid relationship)";
87 | num = 408; "Specified field has inappropriate data type for this operation";
88 | num = 409; "Import order is invalid";
89 | num = 410; "Export order is invalid";
90 | num = 412; "Wrong version of FileMaker Pro used to recover file";
91 | num = 413; "Specified field has inappropriate field type";
92 | num = 414; "Layout cannot display the result";
93 | num = 415; "One or more required related records are not available";
94 | num = 416; "Primary key required from data source table";
95 | num = 417; "Database is not supported for ODBC operations";
96 | num = 500; "Date value does not meet validation entry options";
97 | num = 501; "Time value does not meet validation entry options";
98 | num = 502; "Number value does not meet validation entry options";
99 | num = 503; "Value in field is not within the range specified in validation entry options";
100 | num = 504; "Value in field is not unique as required in validation entry options";
101 | num = 505; "Value in field is not an existing value in the database file as required in validation entry options";
102 | num = 506; "Value in field is not listed on the value list specified in validation entry option";
103 | num = 507; "Value in field failed calculation test of validation entry option";
104 | num = 508; "Invalid value entered in Find mode";
105 | num = 509; "Field requires a valid value";
106 | num = 510; "Related value is empty or unavailable";
107 | num = 511; "Value in field exceeds maximum number of allowed characters";
108 | num = 512; "Record was already modified by another user";
109 | num = 513; "Record must have a value in some field to be created";
110 | num = 600; "Print error has occurred";
111 | num = 601; "Combined header and footer exceed one page";
112 | num = 602; "Body doesn't fit on a page for current column setup";
113 | num = 603; "Print connection lost";
114 | num = 700; "File is of the wrong file type for import";
115 | num = 706; "EPSF file has no preview image";
116 | num = 707; "Graphic translator cannot be found";
117 | num = 708; "Can't import the file or need color monitor support to import file";
118 | num = 709; "QuickTime movie import failed";
119 | num = 710; "Unable to update QuickTime reference because the database file is read-only";
120 | num = 711; "Import translator cannot be found";
121 | num = 714; "Password privileges do not allow the operation";
122 | num = 715; "Specified Excel worksheet or named range is missing";
123 | num = 716; "A SQL query using DELETE, INSERT, or UPDATE is not allowed for ODBC import";
124 | num = 717; "There is not enough XML/XSL information to proceed with the import or export";
125 | num = 718; "Error in parsing XML file (from Xerces)";
126 | num = 719; "Error in transforming XML using XSL (from Xalan)";
127 | num = 720; "Error when exporting; intended format does not support repeating fields";
128 | num = 721; "Unknown error occurred in the parser or the transformer";
129 | num = 722; "Cannot import data into a file that has no fields";
130 | num = 723; "You do not have permission to add records to or modify records in the target table";
131 | num = 724; "You do not have permission to add records to the target table";
132 | num = 725; "You do not have permission to modify records in the target table";
133 | num = 726; "There are more records in the import file than in the target table; not all records were imported";
134 | num = 727; "There are more records in the target table than in the import file; not all records were updated";
135 | num = 729; "Errors occurred during import; records could not be imported";
136 | num = 730; "Unsupported Excel version (convert file to Excel 7.0 (Excel 95), 97, 2000, XP, or 2007 format and try again)";
137 | num = 731; "The file you are importing from contains no data";
138 | num = 732; "This file cannot be inserted because it contains other files";
139 | num = 733; "A table cannot be imported into itself";
140 | num = 734; "This file type cannot be displayed as a picture";
141 | num = 735; "This file type cannot be displayed as a picture; it will be inserted and displayed as a file";
142 | num = 736; "Too much data to export to this format; it will be truncated";
143 | num = 737; "Bento collection or library is missing; data cannot be imported";
144 | num = 800; "Unable to create file on disk";
145 | num = 801; "Unable to create temporary file on System disk";
146 | num = 802; "Unable to open file";
147 | num = 803; "File is single user or host cannot be found";
148 | num = 804; "File cannot be opened as read-only in its current state";
149 | num = 805; "File is damaged; use Recover command";
150 | num = 806; "File cannot be opened with this version of FileMaker Pro";
151 | num = 807; "File is not a FileMaker Pro file or is severely damaged";
152 | num = 808; "Cannot open file because access privileges are damaged";
153 | num = 809; "Disk/volume is full";
154 | num = 810; "Disk/volume is locked";
155 | num = 811; "Temporary file cannot be opened as FileMaker Pro file";
156 | num = 813; "Record Synchronization error on network";
157 | num = 814; "File(s) cannot be opened because maximum number is open";
158 | num = 815; "Couldn't open lookup file";
159 | num = 816; "Unable to convert file";
160 | num = 817; "Unable to open file because it does not belong to this solution";
161 | num = 819; "Cannot save a local copy of a remote file";
162 | num = 820; "File is in the process of being closed";
163 | num = 821; "Host forced a disconnect";
164 | num = 822; "FMI files not found; reinstall missing files";
165 | num = 823; "Cannot set file to single-user, guests are connected";
166 | num = 824; "File is damaged or not a FileMaker file";
167 | num = 900; "General spelling engine error";
168 | num = 901; "Main spelling dictionary not installed";
169 | num = 902; "Could not launch the Help system";
170 | num = 903; "Command cannot be used in a shared file";
171 | num = 905; "No active field selected; command can only be used if there is an active field";
172 | num = 906; "Current file must be shared in order to use this command";
173 | num = 920; "Can’t initialize the spelling engine";
174 | num = 921; "User dictionary cannot be loaded for editing";
175 | num = 922; "User dictionary cannot be found";
176 | num = 923; "User dictionary is read-only";
177 | num = 951; "An unexpected error occurred (*)";
178 | num = 954; "Unsupported XML grammar (*)";
179 | num = 955; "No database name (*)";
180 | num = 956; "Maximum number of database sessions exceeded (*)";
181 | num = 957; "Conflicting commands (*)";
182 | num = 958; "Parameter missing (*)";
183 | num = 1200; "Generic calculation error";
184 | num = 1201; "Too few parameters in the function";
185 | num = 1202; "Too many parameters in the function";
186 | num = 1203; "Unexpected end of calculation";
187 | num = 1204; "Number, text constant, field name or \"(\" expected";
188 | num = 1205; "Comment is not terminated with \"*/\"";
189 | num = 1206; "Text constant must end with a quotation mark";
190 | num = 1207; "Unbalanced parenthesis";
191 | num = 1208; "Operator missing, function not found or \"(\" not expected";
192 | num = 1209; "Name (such as field name or layout name) is missing";
193 | num = 1210; "Plug-in function has already been registered";
194 | num = 1211; "List usage is not allowed in this function";
195 | num = 1212; "An operator (for example, +, -, *) is expected here";
196 | num = 1213; "This variable has already been defined in the Let function";
197 | num = 1214; "AVERAGE, COUNT, EXTEND, GETREPETITION, MAX, MIN, NPV, STDEV, SUM and GETSUMMARY: expression found where a field alone is needed";
198 | num = 1215; "This parameter is an invalid Get function parameter";
199 | num = 1216; "Only Summary fields allowed as first argument in GETSUMMARY";
200 | num = 1217; "Break field is invalid";
201 | num = 1218; "Cannot evaluate the number";
202 | num = 1219; "A field cannot be used in its own formula";
203 | num = 1220; "Field type must be normal or calculated";
204 | num = 1221; "Data type must be number, date, time, or timestamp";
205 | num = 1222; "Calculation cannot be stored";
206 | num = 1223; "The function is not implemented";
207 | num = 1224; "The function is not defined";
208 | num = 1225; "The function is not supported in this context";
209 | num = 1300; "The specified name can’t be used";
210 | num = 1400; "ODBC driver initialization failed; make sure the ODBC drivers are properly installed";
211 | num = 1401; "Failed to allocate environment (ODBC)";
212 | num = 1402; "Failed to free environment (ODBC)";
213 | num = 1403; "Failed to disconnect (ODBC)";
214 | num = 1404; "Failed to allocate connection (ODBC)";
215 | num = 1405; "Failed to free connection (ODBC)";
216 | num = 1406; "Failed check for SQL API (ODBC)";
217 | num = 1407; "Failed to allocate statement (ODBC)";
218 | num = 1408; "Extended error (ODBC)";
219 | num = 1409; "Error (ODBC)";
220 | num = 1413; "Failed communication link (ODBC)";
221 | num = 1450; "Action requires PHP privilege extension (*)";
222 | num = 1451; "Action requires that current file be remote";
223 | num = 1501; "SMTP authentication failed";
224 | num = 1502; "Connection refused by SMTP server";
225 | num = 1503; "Error with SSL";
226 | num = 1504; "SMTP server requires the connection to be encrypted";
227 | num = 1505; "Specified authentication is not supported by SMTP server";
228 | num = 1506; "Email(s) could not be sent successfully";
229 | num = 1507; "Unable to log in to the SMTP server"
230 | )
--------------------------------------------------------------------------------
/window.settings.fmfn:
--------------------------------------------------------------------------------
1 | /*
2 | * This is taken from the Window Controller field in Mikhail Edoshin's
3 | * sample file. http://mikhailedoshin.com/cookbook/window_controller/
4 | * The intention is to convert this into a custom function which can
5 | * be simply called without all of structure and setup. Will need to
6 | * be refactored.
7 | */
8 |
9 |
10 | // Uses Set Contains()
11 |
12 | Case( True or globals_wc_alignment; /* Trigger */
13 |
14 | Let( [
15 |
16 | /* Read environment settings. */
17 |
18 | on Mac = Get( SystemPlatform ) = 1
19 | or Get( SystemPlatform ) = -1;
20 |
21 | on Windows = Get( SystemPlatform ) = 2
22 | or Get( SystemPlatform ) = -2;
23 |
24 | FileMaker version = GetAsNumber( Get( ApplicationVersion ) );
25 |
26 | /* Adjustments and preferences
27 |
28 | Under Windows FileMaker v9 or earlier may or may not
29 | display the status bar (18 px) at the bottom of
30 | FileMaker application window, but there's no function to
31 | know its state and Get( WindowDesktopHeight ) and Get(
32 | WindowDesktopWidth ) functions do not see that status
33 | bar either. Since it's on by default, I assume it stays
34 | on.
35 |
36 | FileMaker v10 doesn't have that status bar anymore. */
37 |
38 | status bar adjustment = Case( on Windows and FileMaker version < 10; -18 );
39 |
40 | /* FileMaker v9 or earlier have toolbars, but Get(
41 | WindowDesktopHeight ) and Get( WindowDesktopWidth )
42 | functions do not see them. Since users can move and
43 | rearrange toolbars, there's no fixed size to account for
44 | and what's below are the most likely settings: toolbars
45 | are on and take a single row at the top (27 or 28px
46 | depending on platform).
47 |
48 | In FileMaker v10 toolbars are no longer used. */
49 |
50 | toolbar adjustment = Case( FileMaker version < 10; Case( on Mac; -27; on Windows; -28 ) );
51 |
52 | /* To prevent windows to open off screen this
53 | calculation checks their coordinates and, if necessary,
54 | alters them to make sure there's some minimal distance
55 | (the safety margin) beween the window and screen edges.
56 | A negative margin would allow a window to open slightly
57 | off screen, but not more than the absolute value of the
58 | margin.*/
59 |
60 | safety margin = 0;
61 |
62 | /* A window may be set to zoom down to fit on screen. In
63 | this case controller starts with some initial zoom level
64 | and then reduces it until the window fits the available
65 | space. It may be desirable to scale the window to fit
66 | not the whole space, but a somewhat smaller area, to
67 | make the window more convenient to manipulate. To
68 | support this the controller uses a scale margin, a
69 | distance that is automatically subtracted from the
70 | available space when calculating the scaled size. E.g.
71 | if scale margin is 15, the controller will reduce the
72 | available space by 30px from either dimension.
73 |
74 | Unlike safety margin, scale margin should not be
75 | negative. Scale margin applies to scaling only; windows
76 | with fixed size are not affected. */
77 |
78 | scale margin = 0;
79 |
80 | /* End of adjustments and preferences; all the rest is
81 | automatic.
82 |
83 | Depending on which parameters are passed there could be
84 | saved or default settings. */
85 |
86 | has saved settings =
87 | IsValid( Window Settings::Window );
88 |
89 | has default size =
90 | IsValid( Window Size::Name );
91 |
92 | has alignment =
93 | IsValid( Window Alignment::Name );
94 |
95 | /* The default size may be specified not in pixels. */
96 |
97 | multiplier to px =
98 | Case( has default size;
99 | Let( unit = Window Size::Unit;
100 | Case(
101 | unit = "px"; 1;
102 | unit = "in"; 72;
103 | unit = "cm"; 72 / 2.54 ) ) );
104 |
105 | /* Read content width and height. */
106 |
107 | content width =
108 | Case(
109 | not IsEmpty( script.parameter( "width" ) );
110 | GetAsNumber( script.parameter( "width" ) );
111 | has saved settings;
112 | Window Settings::Width;
113 | has default size;
114 | Ceiling( Window Size::Width * multiplier to px );
115 | // otherwise use current window's
116 | Get( WindowContentWidth ) );
117 |
118 | content height =
119 | Case(
120 | not IsEmpty( script.parameter( "height" ) );
121 | GetAsNumber( script.parameter( "height" ) );
122 | has saved settings;
123 | Window Settings::Height;
124 | has default size;
125 | Ceiling( Window Size::Height * multiplier to px );
126 | // otherwise use current window's
127 | Get( WindowContentHeight ) );
128 |
129 | /* Read desired settings for status area, zoom and view. */
130 |
131 | $status area =
132 | Case(
133 | not IsEmpty( script.parameter( "status area" ) );
134 | script.parameter( "status area" );
135 | has saved settings;
136 | Window Settings::Status Area;
137 | has default size;
138 | Let( user choice =
139 | Window Size::Status Area;
140 | Case(
141 | user choice = "Same"; Get( StatusAreaState );
142 | user choice = "Off"; 0;
143 | user choice = "On"; 1;
144 | user choice = "On, locked"; 2;
145 | user choice = "Off, locked"; 3 ) );
146 | // otherwise use current window's
147 | Get( StatusAreaState ) );
148 |
149 | /* View is always passed explicitly or read from default
150 | size. It is never saved nor it copied from the current
151 | window; if neither the parameter nor default settings
152 | are present, the controller assumes form view. */
153 |
154 | view =
155 | Case(
156 | not IsEmpty( script.parameter( "view" ) );
157 | script.parameter( "view" );
158 | has default size;
159 | Let( user choice =
160 | Window Size::View;
161 | Case(
162 | user choice = "Form"; 0;
163 | user choice = "List"; 1;
164 | user choice = "Table"; 2 ) );
165 | // otherwise default to form
166 | 0 /* Form */ );
167 |
168 | /* Measure the size of controls using the current window. */
169 |
170 | full controls width =
171 | Get( WindowWidth ) - Get( WindowContentWidth );
172 | full controls height =
173 | Get( WindowHeight ) - Get( WindowContentHeight );
174 |
175 | /* The size of controls includes operating system
176 | controls (window title, border, scrollbars) and
177 | FileMaker controls (status area/toolbar and the vertical
178 | bar on the left side that appears in list and table
179 | views).
180 |
181 | System controls are always present; under Mac OS X
182 | their size is fixed, under Windows it may vary, but
183 | since the controller measures them each time, it always
184 | gets up-to-date values.
185 |
186 | FileMaker controls can be on or off. If the current
187 | window and the target have different settings, the
188 | controller needs to make some adjustments to correctly
189 | calculate window size and position. There are two
190 | possible differences: status area and view.
191 |
192 | FileMaker v7-9 has both status area and view are on the
193 | left side. The status area is 69 px. The view area is 3
194 | px in list or table views, but if status area is on, the
195 | view area merges with the status area so the total width
196 | remains 69 px. Toggling the status area on or off
197 | doesn't change the total window width, but adds space
198 | for content.
199 |
200 | FileMaker v10 has status toolbar (formerly area) on top
201 | and view area on left. The view area remains 3 px in
202 | list of table views and is no longer affected by status
203 | toolbar. The status toolbar consists of a large bar
204 | above a smaller one. Under Windows their total size is
205 | 80 px. Under Mac the size of the large bar may vary and
206 | the size of the small bar is 25 px. Under Windows
207 | toggling the bar on or off doesn't change the total
208 | window height, but adds more space for content. Under
209 | Mac toggling the bar adjusts the window height by the
210 | size of the large bar, but doesn't include the small
211 | bar.
212 |
213 | This means that under Mac the window controller uses
214 | one (final) height value to position the window
215 | vertically and to calculate the proper zoom level, but
216 | may adjust this height by the (variable) height of the
217 | status toolbar to open the window, because the height
218 | will automatically change when the toolbar is toggled.
219 |
220 | To calculate the variable height of the toolbar the
221 | controller uses the fact that system controls under Mac
222 | have fixed height (of 37 px). */
223 |
224 | status area is on =
225 | Get( StatusAreaState ) = 1 or Get( StatusAreaState ) = 2;
226 |
227 | status area should be on =
228 | $status area = 1 or $status area = 2;
229 |
230 | status area width adjustment =
231 | Case(
232 | 10 ≤ FileMaker version;
233 | 0;
234 | status area is on and not status area should be on;
235 | -69;
236 | not status area is on and status area should be on;
237 | +69;
238 | /* otherwise */
239 | 0 );
240 |
241 | status area height adjustment =
242 | Case(
243 | FileMaker version < 10;
244 | 0;
245 | // otherwise
246 | Let( adjustment =
247 | Case(
248 | on Mac;
249 | full controls height - 37 /* system controls */;
250 | on WIndows;
251 | 80 );
252 | Case(
253 | status area is on and not status area should be on;
254 | - adjustment;
255 | not status area is on and status area should be on;
256 | + adjustment;
257 | /* otherwise */
258 | 0 ) ) );
259 |
260 | Mac open adjustment =
261 | Case( 10 ≤ FileMaker version and on Mac;
262 | Let( adjustment =
263 | full controls height - 37 /* system controls */ - 25 /* small bar */;
264 | Case(
265 | status area is on and not status area should be on;
266 | + adjustment;
267 | not status area is on and status area should be on;
268 | - adjustment;
269 | /* otherwise */
270 | 0 ) ) );
271 |
272 | /* Adjust for view state, if necessary. */
273 |
274 | view is form =
275 | Get( LayoutViewState ) = 0;
276 | view should be form =
277 | view = 0;
278 |
279 | /* Starting with v10 view adjustment no longer depends on status area state. */
280 |
281 | view width adjustment =
282 | Case(
283 | view is form
284 | and not view should be form
285 | and ( 10 ≤ FileMaker version
286 | or not status area should be on );
287 | +3;
288 | not view is form
289 | and view should be form
290 | and ( 10 ≤ FileMaker version
291 | or not status area is on );
292 | -3;
293 | /* otherwise */
294 | 0 );
295 |
296 | /* Calculate sizes of controls for the target window. */
297 |
298 | controls width =
299 | full controls width + status area width adjustment + view width adjustment;
300 | controls height =
301 | full controls height + status area height adjustment;
302 |
303 | /* Get fresh dimensions of desktop. The controller uses
304 | them to calculate content scale, if necessary, to align
305 | against desktop, if this is the reference and finally to
306 | make sure the window stays on the desktop.*/
307 |
308 | // Under Windows FileMaker reports 4 pixels less in either dimension
309 |
310 | platform adjustment =
311 | Case( on Windows; -4 );
312 |
313 | desktop width =
314 | Get( WindowDesktopWidth )
315 | + platform adjustment;
316 |
317 | desktop height =
318 | Get ( WindowDesktopHeight )
319 | + platform adjustment
320 | + status bar adjustment
321 | + toolbar adjustment;
322 |
323 | /* There are two zoom levels: initial zoom and target
324 | zoom. The initial zoom level is read from saved settings
325 | or from the current window; the target zoom is what
326 | developer specifies via a parameter or in window size.
327 | */
328 |
329 | source zoom =
330 | Case(
331 | has saved settings;
332 | Window Settings::Zoom;
333 | // otherwise use current window's
334 | GetAsNumber( Get( WindowZoomLevel ) ) );
335 |
336 | target zoom =
337 | Case(
338 | not IsEmpty( script.parameter( "zoom" ) );
339 | GetAsNumber( script.parameter( "zoom" ) );
340 | has saved settings;
341 | Window Settings::Zoom;
342 | has default size;
343 | Let( user choice = Window Size::Zoom;
344 | Case(
345 | user choice = "Same";
346 | GetAsNumber( Get( WindowZoomLevel ) );
347 | /* otherwise */
348 | GetAsNumber( user choice ) ) );
349 | // otherwise use current window's
350 | GetAsNumber( Get( WindowZoomLevel ) ) );
351 |
352 | initial scale =
353 | target zoom / source zoom;
354 |
355 | scale =
356 | Case(
357 | not IsEmpty( script.parameter( "zoom" ) )
358 | or has saved settings;
359 | initial scale;
360 | has default size
361 | and Set Contains( Window Size::Options; "Scale down to fit" );
362 | Let( [
363 | desktop width =
364 | desktop width - 2 * scale margin;
365 | desktop height =
366 | desktop height - 2 * scale margin;
367 | max horizontal scale =
368 | ( desktop width - controls width ) / content width;
369 | max vertical scale =
370 | ( desktop height - controls height ) / content height;
371 | min max scale =
372 | Min( initial scale; max vertical scale; max horizontal scale ) ];
373 |
374 | Case(
375 | 4 ≤ min max scale; 4;
376 | 3 ≤ min max scale; 3;
377 | 2 ≤ min max scale; 2;
378 | 1.5 ≤ min max scale; 1.5;
379 | 1 ≤ min max scale; 1;
380 | .75 ≤ min max scale; .75;
381 | .5 ≤ min max scale; .5;
382 | /* otherwise use smallest */ .25 ) );
383 | // otherwise
384 | initial scale );
385 |
386 | /* Calculate the final zoom and almost final width and
387 | height; on Mac the height can still be changed to
388 | account for status toolbar behavior. */
389 |
390 | globals_wc_width =
391 | Ceiling( content width * scale ) + controls width;
392 | globals_wc_height =
393 | Ceiling( content height * scale ) + controls height;
394 | $zoom =
395 | Case(
396 | not IsEmpty( script.parameter( "zoom" ) )
397 | or has saved settings;
398 | target zoom;
399 | has default size
400 | and Set Contains( Window Size::Options; "Scale down to fit" );
401 | scale * 100;
402 | // otherwise
403 | target zoom );
404 |
405 | /* If the user doesn't specify the “alignment”
406 | parameter, the Alignment field may fetch the default
407 | alignment and if the user specifies the parameter, the
408 | script copies it in the Alignment field. So things looks
409 | identical, but the situation is different; if the user
410 | specifies alignment explicitly, this overrides saved top
411 | and left settings, but if alignment is default, saved
412 | settings take precedence. The controller tells the
413 | difference by checking the parameter. */
414 |
415 | explicit alignment =
416 | not IsEmpty( script.parameter( "alignment" ) );
417 |
418 | /* The top and left may be specified explicitly from
419 | parameters, saved settings and current window (as a
420 | fallback) or be calculated dynamically from alignment.
421 | */
422 |
423 | explicit left =
424 | Case(
425 | not IsEmpty( script.parameter( "left" ) );
426 | GetAsNumber( script.parameter( "left" ) );
427 | not explicit alignment and has saved settings;
428 | Window Settings::Left;
429 | not has default size;
430 | Get( WindowLeft ) );
431 |
432 | explicit top =
433 | Case(
434 | not IsEmpty( script.parameter( "top" ) );
435 | GetAsNumber( script.parameter( "top" ) );
436 | not explicit alignment and has saved settings;
437 | Window Settings::Top;
438 | not has default size;
439 | Get( WindowTop ) );
440 |
441 | // The controller calculates position from alignment only if it didn't get explicit position so far.
442 |
443 | bounds =
444 | Case( IsEmpty( explicit top ) or IsEmpty( explicit left );
445 | Let( reference = Window Alignment::Reference;
446 | Case(
447 | reference = "desktop";
448 | "0 0 "
449 | & desktop width
450 | & " " & desktop height;
451 |
452 | reference = "current window";
453 | Get( WindowLeft )
454 | & " " & Get( WindowTop )
455 | & " " & ( Get( WindowLeft ) + Get( WindowWidth ) )
456 | & " " & ( Get( WindowTop ) + Get( WindowHeight ) );
457 |
458 | reference = "object";
459 | GetLayoutObjectAttribute( Window Alignment::Object Name;
460 | "bounds" ) ) ) );
461 |
462 | initial left =
463 | If( not IsEmpty( explicit left );
464 | explicit left;
465 | // else
466 | Let( [
467 | globals_wc_left =
468 | MiddleWords( bounds; 1; 1 );
469 | right =
470 | MiddleWords( bounds; 3; 1 );
471 | point =
472 | Window Alignment::Horizontal Point;
473 | reference =
474 | Case(
475 | point = "Left";
476 | globals_wc_left;
477 | point = "Right";
478 | right;
479 | point = "Center";
480 | globals_wc_left + Floor( ( right - globals_wc_left ) / 2 ) );
481 | proxy =
482 | Window Alignment::Horizontal Proxy ];
483 |
484 | Window Alignment::Horizontal Offset
485 | + Case(
486 | proxy = "Left edge";
487 | reference;
488 | proxy = "Right edge";
489 | reference - globals_wc_width;
490 | proxy = "Center";
491 | reference - Floor( globals_wc_width / 2 ) ) ) );
492 |
493 | initial top =
494 | If( not IsEmpty( explicit top );
495 | explicit top;
496 | // else
497 | Let( [
498 | globals_wc_top =
499 | MiddleWords( bounds; 2; 1 );
500 | bottom =
501 | MiddleWords( bounds; 4; 1 );
502 | point =
503 | Window Alignment::Vertical Point;
504 | reference =
505 | Case(
506 | point = "Top";
507 | globals_wc_top;
508 | point = "Bottom";
509 | bottom;
510 | point = "Middle";
511 | globals_wc_top + Floor( ( bottom - globals_wc_top ) / 2 ) );
512 | proxy =
513 | Window Alignment::Vertical Proxy ];
514 |
515 | Window Alignment::Vertical Offset
516 | + Case(
517 | proxy = "Top edge";
518 | reference;
519 | proxy = "Bottom edge";
520 | reference - globals_wc_height;
521 | proxy = "Middle";
522 | reference - Floor( globals_wc_height / 2 ) ) ) );
523 |
524 | // Finally make sure the window stays on screen
525 |
526 | $left =
527 | Let( [
528 | minimum left =
529 | safety margin;
530 | maximum left =
531 | desktop width - globals_wc_width - 2 * safety margin ];
532 |
533 | Max( minimum left; Min( maximum left; initial left ) ) );
534 |
535 | $top =
536 | Let( [
537 | minimum top =
538 | safety margin;
539 | maximum top =
540 | desktop height - globals_wc_height - 2* safety margin ];
541 |
542 | Max( minimum top; Min( maximum top; initial top ) ) );
543 |
544 | /* And finally adjust the height, if necessary. */
545 | $width =
546 | globals_wc_width;
547 | $height =
548 | globals_wc_height + Mac open adjustment ];
549 |
550 | "" /* Nothing to output */ ) )
--------------------------------------------------------------------------------