/
levure.livecodescript
3541 lines (2760 loc) · 107 KB
/
levure.livecodescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
script "levureFramework"
##########
## This script must be assigned to a behavior of a stack that will be built as a standalone.
##########
constant kVersion = "0.9.12"
constant kAppStackName = "app"
constant kApplicationExternals = "levureAppExternals"
constant kLiveCodeExtensions = "livecode,livecodescript"
constant kLiveCodeModule = "lcm"
constant kLevureErr = "levureerr,"
constant kUIKey = "ui"
constant kUITemplatesKey = "templates"
constant kNestedKeysDelimiter = ">"
local sAppFolder # Folder where the `app` stack resides
local sAppA
local sRuntimePropertiesA
on mouseUp pBtnNum
# Load app if user clicks on button in standalone stack
if sRuntimePropertiesA["state"] is empty then
if pBtnNum is 1 and word 1 of the target is "button" and the owner of the owner of the target is me then
levureInitializeAndRunApplication
exit mouseUp
end if
end if
pass mouseUp
end mouseUp
after startup
levureInitializeAndRunApplication
end startup
on shutdown
if the environment is not "development" then
levureShutdownApplication
end if
pass shutdown
end shutdown
on relaunch
if sRuntimePropertiesA["state"] is "running" then
if sAppA["multiple instances"] then
pass relaunch
else
dispatch "RelaunchApplication" to stack kAppStackName
local i, tParams
repeat with i = 1 to the paramcount
put param(i) & cr after tParams
end repeat
delete the last char of tParams
#
# If `background` is returned then the engine won't bring any stacks forward.
#
# `send` is used to processed outside of relaunch. Saw instances where
# url processing opened a pref window but pref window would not come forward
# when called. Main window stayed in front. Adding the send in time fixed it.
# My guess is code brough a stack forward and then engine brought forward the defaultStack
# after relaunch finished. This may no longer be a bug. Need to test. In any case,
# send in time is desirable as engine is going to bring defaultStack forward and
# then developer code can handle any special cases.
if tParams is not empty then
# This handler is defined in a helper
send "ProcessCommandLineParameters tParams" to stack kAppStackName in 0 milliseconds
end if
if sAppA["relaunch in background"] then
return "background"
end if
end if
end if
end relaunch
/**
Summary: Displays errors that occur in a standalone during initialization or cleanup.
Description:
If an error occurs in a standalone while the framework is loading or shutting down the application
then the error will be displayed and the application will quit. The assumption is that something
unexpected happened and you don't want your application lingering around in memory unable to quit.
*/
on errorDialog pError
if the environment is "development" OR sRuntimePropertiesA["state"] is "running" then pass errorDialog
answer error pError
quit
end errorDialog
/**
Summary: Returns the version of the Levure framework in use.
Returns: The version in format x.x.x.x
*/
function levureVersion
return kVersion
end levureVersion
/**
Summary: Returns true if a helper is loaded.
pHelperFolderName: The name of the helper folder.
Example:
put levureIsHelperLoaded("preferences") into tUsePrefs
Returns: True/False
*/
function levureIsHelperLoaded pHelperFolderName
local i
set the itemDelimiter to "/"
repeat with i = 1 to the number of elements of sAppA["helpers"]
if sAppA["helpers"][i]["filename"] ends with pHelperFolderName then
return true
end if
end repeat
return false
end levureIsHelperLoaded
/**
Summary: Packages up a levure application for distribution.
pBuildProfile: The profile to build (e.g. `release` or `beta`). The profile must be defined in your `app.yml` file.
Description:
When you are ready to package up your application for distribution to someone you call this handler.
The build profile that you pass in is the value that will be returned by `levureBuildProfile()` when
running the standalones.
When packaging the application stacks will be encrypted if A) the `encrypted stacks` property is true in the `app.yml`
file and B) a password can be located. The password can be stored in the `app.yml` file (not advisable if you store your
project in a version control system) or in the `.env` file that sits alongside the `app.yml` file (add a PASSWORD=VALUE line).
During the packaging process any properties defined in the `build profiles` > `all profiles` and `build profiles` > `pBuildProfile`
sections of your `app.yml` file will affect how the application is packaged. Below is a description of properties you can define.
The `packager callback stackfiles` property in `app.yml` points to a stack that will receive the
`finalizePackagedAssets pBuildProfile, pBuildProfile, @xAppA, pAppFolder`,
`finalizeStandaloneForPlatform pBuildProfile, pPlatform, pAppA, pAppFolder, pFolderSavedIn`,
`finalizePackageForPlatform pBuildProfile, pPlatform, pAppA, pAppFolder, pOutputFolder`,
and `packagingComplete pBuildProfile, pOutputFolder` messages.
The `certificates` > `macos` > `name` property is the name of the certificate that the packager should use to sign your applications on macOS.
The packager will prefix the certificate with `Developer ID Application:` for apps being distributed outside of the Mac App Store
and with `3rd Party Mac Developer Application:` for apps being distributed through the Mac App Store, and with `Mac Developer:` for apps built
for testing Mac App Store applications. The packager assumes you are
distributing through the Mac App Store if the name of pBuildProfile is "mac app store" and for development if pBuildProfile is
"mac app store development".
The `copy files` property determines which files will be copied into the output folder.
Example:
levurePackageApplication "release"
Returns: Error message
*/
command levurePackageApplication pBuildProfile
local tError, tStackFilename
if the environment is not "development" then put "can only be run in development environment" into tError
if tError is empty then
_initializePackaging pBuildProfile, tStackFilename
put the result into tError
end if
if tError is empty then
local tStandaloneStack, tBuildProfile
put the effective filename of me into tStandaloneStack
# This stack will be removed from memory so send in time
send "packagerPackageApplication tStandaloneStack, pBuildProfile" to stack tStackFilename in 10 milliseconds
end if
return tError for error
end levurePackageApplication
/**
Summary: Message sent from the packager script.
Description:
Move along. Nothing to see here.
*/
command packagerDidFinishPackagingApplication pStandaloneStackFilename, pBuildProfile
# Remove from memory after packaging is complete
if there is a stack "Levure Framework Application Packager FrontScript" then
delete stack "Levure Framework Application Packager FrontScript"
end if
delete stack "Levure Framework Application Packager"
if pBuildProfile is among the items of "ios simulator,android simulator" then
go stack pStandaloneStackFilename
dispatch "revIDEDeployAction" to stack "revDeployLibrary"
end if
end packagerDidFinishPackagingApplication
/**
Summary: Message sent from the packager script.
Description:
Move along. Nothing to see here.
*/
command packagerDidFinishBuildingStandaloneForTesting
# Remove from memory after building standalone is complete
if there is a stack "Levure Framework Application Packager FrontScript" then
delete stack "Levure Framework Application Packager FrontScript"
end if
delete stack "Levure Framework Application Packager"
end packagerDidFinishBuildingStandaloneForTesting
/**
Summary: Builds a standalone that loads all of your development files when launched.
Description:
This handler will create standalone engines that can be used for testing on your target platforms.
A `test` folder will be created in the `builds` folder that is configured in your `app.yml` file.
The `test` folder will have executables for each desktop platform that you standalone.livecode stack
has been configured for in Standalone Settings.
None of the actual application stacks are bundled with the executables. When you launch any of
the executables the executable will load the files from your development folder. This allows you
to quickly test changes while running from a standalone.
The Levure packager will attempt to include the Remote Debugger
(available in LiveCode 9 and above for Business licenses) if it is available.
Example:
levureBuildStandalonesForTesting
Returns: Error message
*/
command levureBuildStandalonesForTesting
local tError, tStackFilename
if the environment is not "development" then return "can only be run in development environment"
if tError is empty then
_initializePackaging empty, tStackFilename
put the result into tError
end if
if tError is empty then
local tStandaloneStack
put the effective filename of me into tStandaloneStack
# This stack will be removed from memory so send in time
send "packagerBuildStandaloneForTesting tStandaloneStack, true" to stack tStackFilename in 10 milliseconds
end if
return tError for error
end levureBuildStandalonesForTesting
private command _initializePackaging pBuildProfile, @rPackagerFilename
local tError
if sAppA is not an array then
start using me
levureLoadAppConfig pBuildProfile
put the result into tError
end if
if tError is empty then
set the itemdelimiter to "/"
put levureFrameworkFolder() into rPackagerFilename
put "packager/packager.livecodescript" into the last item of rPackagerFilename
end if
return tError
end _initializePackaging
/**
Summary: Starts the server that listens for changes to application stack scripts.
[pPort]: Pass in a port if you plan on having two different Levure applications open in two different instances of the IDE. Otherwise the default port should suffice.
Description:
This handler allows you to work on a Levure application in the IDE and edit all of your script only stacks using
an external editor. The handler loads a stack into the IDE that starts a server on the `localhost`. The server listens
for requests notifying the server that a script only stack has been updated. The server will then update the script
of the matching stack in memory.
This handler is typically called in the `InitializeApplication` message that is sent to the `app` stack.
Currently Sublime Text is the only editor that will work using this setup. If you have the LiveCode language module
installed for LiveCode then each time you save a LiveCode file in Sublime Text a request is sent to the server.
Example:
command InitializeApplication
if the environment is "development" then
levureLoadExternalEditorServer
end if
end InitializeApplication
Returns: Empty
*/
command levureLoadExternalEditorServer pPort
local tStackFilename, tStackPath
set the itemdelimiter to "/"
put levureFrameworkFolder() into tStackFilename
put "utils/external_editor_server/external_editor_server.livecodescript" into tStackPath
put tStackPath into the last item of tStackFilename
if there is a stack tStackFilename then
if pPort is not an integer then
local tEnvA
put levureAppGetENV() into tEnvA
put tEnvA["EXTERNAL_EDITOR_PORT"] into pPort
end if
dispatch "levureExternalEditorStartServer" to stack tStackFilename with pPort
else
answer error tStackPath && "was not found"
end if
return empty
end levureLoadExternalEditorServer
/**
Summary: Returns the name of the `app` stack.
Description:
If you ever need to refer to the `app` stack by name you can call this function. It
saves you from hard coding `app` in your code.
Example:
dispatch "MyCustomMessage" to stack levureAppStackName()
Returns: "app"
*/
function levureAppStackName
return kAppStackName
end levureAppStackName
/**
Summary: Returns the filename of the `app` stack file.
Example:
put levureAppStackFilename() into tAppStackFilename
Returns: Path to file
*/
function levureAppStackFilename
return the filename of stack kAppStackName
end levureAppStackFilename
/**
Summary: Initializes and runs the application.
Description:
This handler is used internally by the framework to initialize and run the application.
Typically you will never need to call this handler as it is called automatically at `startup`
when your application is running in a standalone or when you click the button in the
`standalone.livecode` stack.
Example:
# In this example "MyStandalone" is the name of the standalone.livecode stack
start using stack "MyStandalone"
dispatch "levureInitializeAndRunApplication" to stack "MyStandalone"
Returns: Empty
*/
command levureInitializeAndRunApplication
local tError
put "loading" into sRuntimePropertiesA["state"]
set visible of me to false
set the loc of me to the screenloc
start using me
levureInitializeFramework
put the result into tError
if tError is empty then
## Use a send so that if any dialogs are displayed in developer handled messages the
## loading process will not stop
send "levureRunApplication" to me in 0 milliseconds
end if
if tError is not empty then
answer error "An error occurred while initializing the application [" & tError & "]."
if the environment is not "development" then
quit
end if
end if
return empty
end levureInitializeAndRunApplication
/**
Summary: Initializes the application without running it.
Description:
This handler is used internally by the framework to load the configuration information, load
all helpers, libraries, frontscripts, backscripts, behaviors, and ui assets. The `PreloadApplication`
message will be dispatched to the `app` stack.
Typically you will never need to call this handler. If you need to troubleshoot something
without runing your application you can call this handler after opening the `standalone.livecode`
file in the IDE. See example.
Example:
# In this example "MyStandalone" is the name of the standalone.livecode stack
start using stack "MyStandalone"
dispatch "levureInitializeFramework" to stack "MyStandalone"
put levureAppGetConfig() into tA
put tA["version"]
Returns: Error message
*/
command levureInitializeFramework
local tError
if the long id of me is the long id of this me OR word 1 of the long id of me is not "stack" then
put "the framework is not assigned to a stack as a behavior" into tError
end if
if tError is empty then
levureLoadAppConfig levureBuildProfile()
put the result into tError
end if
if tError is empty then
createApplicationDataFolders
put the result into tError
end if
if tError is empty then
dispatch "PreloadApplication" to stack kAppStackName
end if
if tError is empty then
loadExternals sAppA["externals to load"]
put the result into tError
end if
# extensions
if tError is empty then
loadExtensions sAppA
put the result into tError
end if
if tError is empty then
repeat with i = 1 to the number of elements of sAppA["helpers"]
loadExtensions sAppA["helpers"][i]
put the result into tError
if tError is not empty then
exit repeat
end if
end repeat
end if
if tError is empty then
loadAppAssets
put the result into tError
end if
return tError for error
end levureInitializeFramework
/**
Summary: Begins running the application during the startup sequence.
Description:
This handler is called "in time" during the startup sequence. You will not call this handler
in your code.
Returns: Empty
*/
command levureRunApplication
local tError, tStacksInApp
if tError is empty then
loadCommandLineArguments
end if
# Add lookup for all stacks in app. They will be loaded into memory as needed
# when referenced by name.
if tError is empty then
dispatch "InitializeApplication" to stack kAppStackName
if it is "handled" and the result is false then
## user can quit app if they want
if lockMessages is true then unlock messages
unloadApp
## Only quit if not in development. This allows developer to troubleshoot.
if the environment is not "development" then
quit
exit to top
end if
else
## On macOS we need a delay here so that appleEvents can be processed
## `OpenApplication` is sent to the application. This allows URLs that
## launched application to be tucked away in "process url"
## We don't want a delay when running on mobile platforms, however, as
## it can introduce a brief flicker when transitioning from splash screen
## to the first stack.
if the platform is "macos" then
send "levureFinishLoadingApplication" to me in 10 milliseconds
else
levureFinishLoadingApplication
end if
end if
end if
-- display tError
return empty
end levureRunApplication
private command loadCommandLineArguments
if the platform is not "macos" then
local tValue, tParams, i
repeat with i = 1 to ($# - 1)
put value("$" & i) into tValue
put tValue & cr after tParams
end repeat
delete the last char of tParams
if tParams is not empty then
dispatch "ProcessCommandLineParameters" with tParams
end if
end if
return empty
end loadCommandLineArguments
/**
Summary: Finishes loading the application during the startup sequence.
Description:
This handler is called "in time" during the startup sequence. You will not call this handler
in your code.
Returns: Empty
*/
command levureFinishLoadingApplication
local msgsAreLocked
dispatch "OpenApplication" to stack kAppStackName
put "running" into sRuntimePropertiesA["state"]
# Don't fire off any messages when closing the standalone stack
put the lockMessages into msgsAreLocked
lock messages
close me
set the lockMessages to msgsAreLocked
return empty
end levureFinishLoadingApplication
/**
Summary: Returns the folder where application data is stored for the application.
pUserOrShared: Pass in `shared` for the shared folder path. Pass in `user` for the user folder path. Default is `user`.
Description:
This handler combines the standard folder where application data is stored
on the current system with the application data folder defined in the `app.yml` file.
Example:
put levureApplicationDataFolder("user") into tUserDataFolder
Returns: Path to folder
*/
function levureApplicationDataFolder pUserOrShared
local tFolder
if pUserOrShared is not "shared" then put "user" into pUserOrShared
if platformApplicationDataFolder(pUserOrShared) is empty then
throw kLevureErr & param(0) && ": the" && quote & "application data folder" & quote \
&& "property has not been set for the current platform in app.yml"
end if
if pUserOrShared is not "shared" then
switch the platform
case "win32"
case "macos"
put specialFolderPath("support") & "/" into tFolder
break
case "linux"
put specialFolderPath("home") & "/." into tFolder
break
case "iphone"
put specialFolderPath("library") & "/Application Support/" into tFolder
break
case "android"
put specialFolderPath("documents") & "/Application Support/" into tFolder
break
default
return empty
end switch
else
switch the platform
case "macos"
put specialFolderPath("asup") & "/" into tFolder
break
case "win32"
put specialFolderPath("35") & "/" into tFolder
break
case "linux"
put "/opt/." into tFolder
break
default
return empty
end switch
end if
put platformApplicationDataFolder(pUserOrShared) after tFolder
return tFolder
end levureApplicationDataFolder
/**
Summary: Returns the current state of the application.
Description:
Returns a value of `loading`, `running`, or `shutting down`. These values reflect the
internal state of the Levure application.
While Levure is loading application files at startup
the state is `loading`.
When Levure has begun to shut down the application (e.g. the user quit the application) then
the state is `shutting down`.
In all other cases the state is `running`.
Example:
# In app.livecodescript
on appleEvent pClass, pId, pSender
# don't process events if application isn't running
if levureApplicationState() is not "running" then pass appleEvent
...
end appleEvent
Returns: "loading", "running", "shutting down"
*/
function levureApplicationState
return sRuntimePropertiesA["state"]
end levureApplicationState
/**
Summary: Returns the internal array that was created when reading the `app.yml` file.
Example:
put levureAppGetConfig() into tAppA
put tAppA["name"]
Returns: Array
*/
function levureAppGetConfig
return sAppA
end levureAppGetConfig
/**
Summary: Returns a text representation of the internal array that was created when reading the `app.yml` file.
Example:
put levureAppPrintConfig()
Returns: Array
*/
function levureAppPrintConfig
return _printArray(sAppA,,true)
end levureAppPrintConfig
/**
Summary: Returns an environmental variable stored in the `.env` file.
Description:
During development you can place an `.env` file alongside the `app.yml` file. The format is
a key=value pair, one per line. This function will return a key value.
Use the `.env` file to store values you don't want stored in a git repository. For example,
you should store the `password` used to password protect your application in the `.env` file.
As long as the `.env` file is not stored in your version control repository the password
will not be stored in the repository.
The Levure application packager will use this function to check for a password when packaging
your application.
Example:
# Assumes your .env file has a PASSWORD=VALUE line in it
put levureAppGetENV("password") into tPassword
Returns: String
*/
function levureAppGetENV
local tError, tEnvA
put readFileContents(sAppFolder & "/.env") into tEnvA
put the result into tError
if tError is empty then
local tKey
split tEnvA by CR AND "="
repeat for each key tKey in tEnvA
put word 1 to -1 of line 1 of tEnvA[tKey] into tEnvA[tKey]
end repeat
end if
return tEnvA
end levureAppGetENV
/**
Summary: Use to check if a property name is among the keys in the application configuration array.
Parameters:
pProp: The property to check. This can be a string or an indexed lookup array. If a string then nested keys can be separated by the `>` character.
Syntax: levureAppHasProperty(<pProp>)
Syntax: levureAppHasProperty(<pIndexedArray>)
Description:
This handler targets the internal array that was created when the app.yml file was loaded. If it is possible
that an application property doesn't exist then use this function before calling `levureAppGet()` or
`levureAppSet`. Both handlers will throw an error if the target property doesn't exist.
Example:
put levureAppHasProperty("preferences filename>user>default")
Example:
# Use an indexed lookup array
put "preferences filename" into tIndexA[1]
put "user" into tIndexA[2]
put "default" into tIndexA[3]
put levureAppHasProperty(tIndexA)
Returns: True/False
*/
function levureAppHasProperty pProp
local tIndexA
set the itemDelimiter to ">"
if the number of items of pProp > 1 then
split pProp by ">"
end if
if pProp is an array then
put pProp into tIndexA
put tIndexA[the number of elements of tIndexA] into pProp
delete variable tIndexA[the number of elements of tIndexA]
end if
if tIndexA is an array then
return pProp is among the keys of sAppA[tIndexA]
else
return pProp is among the keys of sAppA
end if
end levureAppHasProperty
/**
Summary: Gets an app property.
Parameters:
pProp: The property to check. This can be a string or an indexed lookup array. If a string then nested keys can be separated by the `>` character.
pCheckExistence: Pass in `true` to throw an error if `pProp` does not exist in the internal `sAppA` array. This can be used to ensure that a valid setting is being added to `app.yml`.
Syntax: levureAppGet(<pProp>)
Syntax: levureAppGet(<pIndexedArray>)
Description:
This handler targets the internal array that was created when the app.yml file
was loaded.
If the property passed in does not exist then an error will be thrown.
Example:
put levureAppGet("preferences filename>user>default")
Example:
# Use an indexed lookup array
put "preferences filename" into tIndexA[1]
put "user" into tIndexA[2]
put "default" into tIndexA[3]
put levureAppGet(tIndexA)
Returns: Mixed as it depends on property value
*/
function levureAppGet pProp, pCheckExistence
local tIndexA
put pCheckExistence is true into pCheckExistence
set the itemDelimiter to ">"
if pProp is not an array and the number of items of pProp > 1 then
split pProp by ">"
end if
if pProp is an array then
put pProp into tIndexA
put tIndexA[the number of elements of tIndexA] into pProp
delete variable tIndexA[the number of elements of tIndexA]
end if
if the number of elements of tIndexA >= 1 then
if not pCheckExistence or pProp is among the keys of sAppA[tIndexA] then
return sAppA[tIndexA][pProp]
else
throw kLevureErr & "invalid levure app property:" && _printPropParameter(pProp, tIndexA)
end if
else
if not pCheckExistence or pProp is among the keys of sAppA then
return sAppA[pProp]
else
throw kLevureErr & "invalid levure app property:" && _printPropParameter(pProp, tIndexA)
end if
end if
end levureAppGet
/**
Summary: Sets an app property for the life of the current session.
Parameters:
pProp: The property to check. This can be a string or an indexed lookup array. If a string then nested keys can be separated by the `>` character.
pValue: The value to set the property to.
pCheckExistence: Pass in `true` to throw an error if `pProp` does not exist in the internal `sAppA` array. This can be used to ensure that a valid setting is being added to `app.yml`.
Syntax: levureAppSet <pProp>, <pValue>
Syntax: levureAppSet <pIndexedArray>, <pValue>
Description:
This handler targets the internal array that was created when the app.yml file
was loaded. The value will only be updated for the current session. The app.yml
file is not updated.
Example:
levureAppSet "multiple instances", true
Example:
put "preferences filename" into tIndexA[1]
put "user" into tIndexA[2]
put "default" into tIndexA[3]
levureAppSet tIndexA, "com.mycompanyname.myapp-shared"
Returns: Empty
*/
command levureAppSet pProp, pValue, pCheckExistence
local tIndexA
put pCheckExistence is true into pCheckExistence
set the itemDelimiter to ">"
if pProp is not an array and the number of items of pProp > 1 then
split pProp by ">"
end if
if pProp is an array then
put pProp into tIndexA
put tIndexA[the number of elements of tIndexA] into pProp
delete variable tIndexA[the number of elements of tIndexA]
end if
if the number of elements of tIndexA > 1 then
if not pCheckExistence or pProp is among the keys of sAppA[tIndexA] then
put pValue into sAppA[tIndexA][pProp]
else
throw kLevureErr & "invalid levure app property:" && _printPropParameter(pProp, tIndexA)
end if
else
if not pCheckExistence or pProp is among the keys of sAppA then
put pValue into sAppA[pProp]
else
throw kLevureErr & "invalid levure app property:" && _printPropParameter(pProp, tIndexA)
end if
end if
return empty for error
end levureAppSet
private function _printPropParameter pProp, pIndexA
local i, tProp
repeat with i = 1 to the number of elements of pIndexA
put pIndexA[i] & " > " after tProp
end repeat
put pProp after tProp
return tProp
end _printPropParameter
/**
Summary: Returns an array of all `ui` category assets.
Returns: Numerically indexed array. "name", "filename", and "key". "key" is the key the UI assets is listed under in app.yml.
*/
function levureGetUIStacks
local tKey, tLookupA, i, j, tStacksA
repeat for each key tKey in sAppA["registered components"]["ui"]
put tKey into tLookupA
split tLookupA by kNestedKeysDelimiter
repeat with i = 1 to the number of elements of sAppA[tLookupA]
add 1 to j
put sAppA[tLookupA][i] into tStacksA[j]
put tKey into tStacksA[j]["key"]
end repeat
end repeat
return tStacksA
end levureGetUIStacks
/**
Summary: Returns the name of the build profile used to package the version of the application that is running.
Description:
When you package an application you package a specific build profile. This handler
returns the name of the build profile that was used. When running in the IDE "development"
is returned.
Example:
put levureAppGet("version") into tVersionString
if the levureBuildProfile() is "beta" then
put " (BETA)" after tVersionString
end if
Returns: Build profile name
*/
function levureBuildProfile
if the environment is "development" then
return "development"
else
return the uBuildProfile of me # Assigned at build time
end if
end levureBuildProfile
private command normalizeAppArray
put sAppA["multiple instances"] is true into sAppA["multiple instances"]
put sAppA["relaunch in background"] is true into sAppA["relaunch in background"]
# kUIKey and kUITemplatesKey are always a registered "ui" component
put empty into sAppA["registered components"]["ui"][kUIKey]
put empty into sAppA["registered components"]["ui"][kUITemplatesKey]
put false into sAppA["registered components"]["ui"][kUITemplatesKey]["encrypt binary stacks"]
repeat for each item tGroup in "user,shared"
repeat for each item tPlatform in "default,macos,windows,linux,ios,android"
if tGroup is "shared" and tPlatform is in "ios,android" then exit repeat
put normalizeFolderPath(sAppA["application data folder"][tGroup][tPlatform]) into sAppA["application data folder"][tGroup][tPlatform]
repeat while char 1 of sAppA["application data folder"][tGroup][tPlatform] is "/"
delete char 1 of sAppA["application data folder"][tGroup][tPlatform]
end repeat
end repeat
end repeat
repeat for each item tKey in "password,file extensions,file extension groups"
if tKey is not among the keys of sAppA then
put empty into sAppA[tKey]
end if
end repeat
return empty for value
end normalizeAppArray