-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy path$$.jsxinc
More file actions
302 lines (258 loc) · 11.5 KB
/
Copy path$$.jsxinc
File metadata and controls
302 lines (258 loc) · 11.5 KB
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
/*******************************************************************************
Name: IdExtenso Entry Point
Desc: Includes the core libraries.
Path: $$.jsxinc
Require: ---
Encoding: ÛȚF8
Core: YES
Kind: Entry point.
API: ---
DOM-access: ---
Todo: ---
Created: 160731 (YYMMDD)
Modified: 260324 (YYMMDD)
*******************************************************************************/
//==========================================================================
// IMPLEMENTATION NOTES
//==========================================================================
/*
Every IdExtenso module is created using either the macro
`MODULE`, or `CLASS`, as follows,
eval(__(MODULE, <1_host>, <2_name>, <3_modf>, <4_auto>))
or
eval(__(CLASS, <1_host>, <2_name>, <3_modf>))
where
<1_host> :: Evaluable string referencing the module container
(e.g '$.global' or '$$'.)
<2_name> :: Name of the incoming module
(e.g '$$' or 'Env'.)
<3_modf> :: Revision date (number) using yymmdd format
(e.g. 170317, default is NaN.)
<4_auto> :: MODULE only. Name of the automatic method,
(default is 'toString'.)
Once created, every module `MyMod` is a Function that satisfies
the following equivalences:
MyMod === <1_host>[<2_name>]
=== eval(MyMod.toSource())
e.g <EnvModule> === $$['Env'] === eval(<EnvModule>.toSource())
MyMod.name == <2_name>
== String(MyMod)
== MyMod.toString()
e.g <EnvModule>.name == "Env" == String(<EnvModule>) . . .
IN MODULE CASES:
(a) MyMod(x,y...) <-> MyMod[<4_auto>].call(this,x,y...)
IN CLASS CASES:
(b) MyMod(x,y...) <-> new MyMod(x,y...)
<-> { this.create(this,x,y...) }()
if MyMod.prototype.create is defined.
Every module has the following properties:
__load__ :: 0|1 (Loading state.)
__core__ :: 0|1 (Is part of the core?)
__modf__ :: uint (Revision date in yymmdd form.)
__auto__ :: str (Name of the automatic method,
only supported in MODULE case.)
__root__ :: str (Name of the root module, '$$')
__path__ :: str (Path of the module, e.g '/$$/Env/')
'~' :: obj (Private zone, see below.)
The __path__ property of a module has the form `/$$/xxx/.../`,
it always starts and ends with a slash `/`. Root module's
__path__ is '/$$/' -- assuming $.global['$$'] is originally
set to '$$'.
A set (object) of private keys is available in MyMod['~'],
referred to as the Private Module Zone.
MyMod.load() and MyMod.unload() are automatically defined on
including time and shouldn't be overridden. Instead, one has
the option of creating a public onLoad(...) and/or onUnload()
method attached to the module. Such method(s), when present,
will be invoked on loading time through $$.load().
In addition the global `µ` variable points out to the current
module during the whole including stage, so that
µ === <current-module>
µ['~'] === <private-module-zone>
Also, the global `$$` variable points out to the root module
during the whole including stage, *even if '$$' is not the
final name of the installation*.
[ADD170527] `CLASS` offers a variant of the `MODULE` macro.
It allows to declare a module as a constructor and
accordingly connects it with the `prototype` object. Such
function can be called with or without new. Behind the scene
it always invokes the `prototype.create` method (if defined)
with the passed arguments. If no `create` method is available,
class instances are created with no properties.
CLASS and MODULE products works the same, except that classes
have no `__auto__` key, the automatic method being the
constructor itself, fully generated by the macro. The main
distinction between module and classe mechanisms is, the former
does not construct new objects and exposes a static API while
the latter is designed to instantiate objects sharing a prototyped
API. When you implement a CLASS, use the keyword [STATIC] rather
than [PUBLIC] to create the static keys, and use the keyword
[PROTO] to create prototyped keys.
Both [STATIC] and [PROTO] keys are treated as `public, `but
the [PROTO] keys are loaded in the `prototype` property so that
they have the expected meaning and behavior.
From within the body of a function key, even private, static
or prototyped, `callee.µ` always refers to the module itself.
In particular, `callee.µ===this.constructor` is true in any
prototyped method of a CLASS as long as it is invoked from a
regular instance (of that class.)
*/
if( (function(){return this}).call(null)!==($||0).global || this!==$.global )
//----------------------------------
// Check that:
// (1) $.global *does refer* to the [[global]] scope;
// (2) the current context *is* the [[global]] scope.
// [REM] In ExtendScript both `[[global]].$` and `$.global`
// are read-only properties :-)
{
throw Error("IdExtenso must be loaded in the global scope!");
}
// Per-session run count (1, 2, 3, ...) -- cf Env module.
// [REM] Values managed through $.setenv/getenv are session
// persistent, even in the 'main' engine.
// ---
// Regardless of their respective engine, two distinct IdExtenso
// scripts may increment consecutively the (shared) `IDEXTENSO`
// env variable, referred to as runCount in $$.Env. For that
// reason, runCount > 1 *does not* imply that a specific script
// has been executed before (within the present session.) Typi-
// cally, if some IdExtenso startup scripts are installed,
// a particular script may read $$.Env.runCount() > 1 even if
// it is executed for the 1st time in the session. To control
// session-related settings at the script level, use $$.Settings.
// ---
$.setenv('IDEXTENSO',1+(+($.getenv('IDEXTENSO')||0)));
$.getenv('IDEX_SESSION')||$.setenv('IDEX_SESSION',(+new Date).toString(36)); // [ADD220416]
if( 'function' != typeof $.global['$$'] && ($.global['\x24\x24']='$$') )
//----------------------------------
// (Core including block.) In a persistent-engine context, everything
// within this block is achieved once and for all, so the client script
// only pays the price of a single core-including stage. Additional
// includes may be performed after and outside of this block (/etc
// stuff, for example), so they can use a similar if-test, typically
// `$$.hasOwnProperty('MyEtcModule')` to avoid wasting time on
// redeclaring their own payloads. Thanks to the `$$.load()` call
// which must follow and conclude the whole including process, every
// per-run task can still be implemented within the onLoad() handler
// of each included module. When $$ is loading, it visits and 'loads'
// every declared module in the #include order.
// ---
// Keep the two occurences of the string `$$` above unless you
// want to install IdExtenso under a different (global) key.
// [REM] Whatever your choice, the key `$$` will remain functional
// within the whole including scope, so nothing else has to change.
{
// Localize shortcut. (Redefined later if Yalt is included.)
// ---
$.global.__ = $.global.localize;
// Make sure __path__ is undefined before using the MODULE macro.
// ---
delete $.global.__path__;
// [ADD180513] If the framework is being included (not embedded in
// a bin package) then `$.fileName` contains the full path to the
// present file, something like "/path/to/IdExtenso/$$.jsxinc".
// The `Env` module uses this information if available.
// [REM] Env will remove __jsxinc__ from the [[global]] space.
// ---
$.global.__jsxinc__ = $.fileName;
// Some temporary global strings.
// [REM] Autodeleted once the framework has been loaded.
// ---
$.global.PRIVATE = "PRIVATE";
$.global.PUBLIC = "PUBLIC";
$.global.STATIC = "PUBLIC"; // [ADD170527] Simple alias, used in classes.
$.global.PARENT = "PARENT";
$.global.PROTO = "PROTO"; // [ADD170527] Used in classes.
// --- [ADD190611]
$.global.SPIN = 'function' == typeof $.Spinner ? "($.Spinner())," : "";
// Macro `MODULE`. (See implementation notes.)
// [ADD171109] __core__ property.
// [FIX180516] Supports up to 9 formal arguments in automatic methods and constructors.
// [ADD190611] Optional SPIN call.
// ---
$.global.ARGLIST = "_1,_2,_3,_4,_5,_6,_7,_8,_9"; // [180516] Temporary global string.
$.global.MODULE = """
(
($.global.µ=(%1['%2']=(function %2("""+ARGLIST+"""){return callee[callee.__auto__].call(callee,"""+ARGLIST+""")}))).setup
({
__root__: $$.name||(($.global.$$=$.global.µ).name),
__core__: 1,
__load__: ("""+SPIN+"""0),
__modf__: +%3,
__auto__: ''!='%4' && 'undefined'!='%4' ? '%4' : 'toString',
__path__: (%1.__path__||'/') + '%2/',
'~' : %1.__path__ ? {} : {__mods__:{'/':{}}},
toString: function toString(){ return '%2' },
toSource: function toSource(){ return '%1["%2"]' },
load: %1.__path__ ? Function('x,y', 'return ' + $$.name + '["~"].LDMD(%1["%2"],x,y)') : (void 0),
unload: %1.__path__ ? Function('return ' + $$.name + '["~"].ULMD(%1["%2"])') : (void 0),
})
)
""";
// [ADD170527] Macro `CLASS`. (See implementation notes.)
// [ADD171109] __core__ property.
// [ADD190611] Optional SPIN call.
// ---
$.global.CLASS = """
(
($.global.µ=(%1['%2']=(function %2("""+ARGLIST+""")
{
if( callee!==this.constructor ) return new callee("""+ARGLIST+""");
'function' == typeof this.create && this.create("""+ARGLIST+""");
}))).setup
({
__root__: $$.name,
__core__: 1,
__load__: ("""+SPIN+"""0),
__modf__: +%3,
__path__: (%1.__path__||'/') + '%2/',
'~' : %1.__path__ ? {} : {__mods__:{'/':{}}},
toString: function toString(){ return '%2' },
toSource: function toSource(){ return '%1["%2"]' },
load: %1.__path__ ? Function('x,y', 'return ' + $$.name + '["~"].LDMD(%1["%2"],x,y)') : (void 0),
unload: %1.__path__ ? Function('return ' + $$.name + '["~"].ULMD(%1["%2"])') : (void 0),
})
)
""";
delete $.global.ARGLIST;
// Core includes (order matters.)
// ---
#include 'core/$$.Ext.jsxinc'
// ---
#include 'core/$$.Root.jsxlib'
#include 'core/$$.Env.jsxlib'
#include 'core/$$.JSON.jsxlib'
#include 'core/$$.File.jsxlib'
#include 'core/$$.Log.jsxlib'
#include 'core/$$.Dom.jsxlib'
// ---
#include 'core/$$.SUI.jsxinc'
;
// [ADD171109] Reset `__core__` to 0 from now.
// [CHG171110] `$.global[key]` is safer.
// ---
$.global.MODULE = $.global.MODULE.replace(/__core__\s*:\s*1/, "__core__: 0");
$.global.CLASS = $.global.CLASS.replace (/__core__\s*:\s*1/, "__core__: 0");
// May be performed in $$.load() instead--so that
// garbage-collection would consider next includes too. (?)
// ---
$.gc();$.gc();
}
else
//----------------------------------
// (Already-Processed-Engine-State.)
// [ADD171103] The below block is processed only if $.global['$$']
// already refers to IdExtenso (which indicates an 'already-processed
// persistent' engine.) The purpose of this block is to make some
// facts *globally* known while /etc modules are included.
{
'function' == typeof $.global['\x24\x24']
// [WARN] If Extenso's global name is not '$$', you MUST replace
// `= $.global['$$']` by `= $.global['<ActualName>']` below.
// ---
|| ($.global['\x24\x24'] = $.global['$$']);
// Update the engine state now, so we don't need
// to wait for $$.load().
// ---
$$.Env['~'].ENST = 0;
}