squared 0.1.9 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,1348 +1,302 @@
1
- # squared 5.4
1
+ # squared 0.1
2
2
 
3
- ## Documentation
3
+ * [source](https://github.com/anpham6/squared-ruby)
4
+ * [manifest](https://github.com/anpham6/squared-repo)
5
+ * [docs](https://squared.readthedocs.io)
4
6
 
5
- ### HTML
7
+ ## Version Compatibility
6
8
 
7
- * [squared](https://squared.readthedocs.io)
8
- * [E-mc](https://e-mc.readthedocs.io)
9
-
10
- > [!NOTE]
11
- > Content in the README was migrated into `Read the Docs`. The file is no longer fully maintained.
12
-
13
- ### README
14
-
15
- * [squared-express](https://github.com/anpham6/squared-express#readme)
16
- * [E-mc](https://github.com/anpham6/e-mc#readme)
17
- * [Pi-r](https://github.com/anpham6/pi-r#readme)
9
+ | Date | squared | Ruby 2 | Ruby 3 |
10
+ | :------: | ------: | -----: | -----: |
11
+ | 12-07-24 | 0.1.0 | 2.4.0 | 3.0.0 |
18
12
 
19
13
  ## Installation
20
14
 
21
- * NodeJS 16 LTS
22
-
23
- ### NPX
24
-
25
- ```sh
26
- > npm init
27
- > npm i sqd-cli sqd-serve
28
-
29
- > npx sqd init
30
- # OR
31
- > npx sqd init --public --local-serve # Same as squared-express
32
-
33
- > npx sqd serve --access-all
34
- # OR
35
- > node serve.cjs --access-all
36
- ```
37
-
38
- ```sh
39
- > npm init
40
- > npm i squared sqd-serve
41
-
42
- > mkdir dist html
43
- > cp -r ./node_modules/squared/dist/* ./dist
44
- > cp ./node_modules/squared/html/* ./html # optional
45
- > cp ./node_modules/sqd-serve/config/json/* . # yaml
46
-
47
- > npx serve
48
- ```
49
-
50
- ### GitHub
51
-
52
15
  ```sh
53
- > git clone https://github.com/anpham6/squared
54
- > cd squared
55
-
56
- > npm i
57
- > npm run prod
58
-
59
- > cd ..
60
-
61
- > git clone https://github.com/anpham6/squared-express
62
- > cd squared-express
63
-
64
- > npm i
65
- > npm run prod
66
- > npm run deploy # deploy:yaml
67
-
68
- > cd ../squared
69
-
70
- > node serve.cjs --access-all # squared.{json,yml}
16
+ gem install squared
71
17
  ```
72
18
 
73
- ### Repo
74
-
75
- * Python 3.6+
76
- * [Commands](https://source.android.com/docs/setup/reference/repo)
77
-
78
- #### Install
79
-
80
- ```sh
81
- mkdir -p ~/bin/repo
82
- PATH="${HOME}/bin:${PATH}"
83
-
84
- curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
85
- chmod a+rx ~/bin/repo
86
- # OR
87
- scripts/repo-install.sh ~/bin
88
- ```
19
+ ### Optional
89
20
 
90
- #### Usage
21
+ * [Repo](https://source.android.com/docs/setup/reference/repo)
22
+ * Python 3.6
23
+ * Not compatible with Windows
91
24
 
92
25
  ```sh
93
- mkdir workspaces
94
- cd workspaces
95
-
96
- repo init -u https://github.com/anpham6/squared-repo -m latest.xml
97
- repo sync -j4
98
-
99
- cd squared
100
- npm i
26
+ mkdir -p ~/.bin
27
+ PATH="${HOME}/.bin:${PATH}"
28
+ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.bin/repo
29
+ chmod a+rx ~/.bin/repo
101
30
  ```
102
31
 
103
- #### Ruby
104
-
105
- Workspace management uses [Ruby](https://www.ruby-lang.org/en/documentation/installation) for syncing and building. It is not installed by default on most operating systems.
106
-
107
- ```sh
108
- mkdir workspaces
109
- cd workspaces # REPO_ROOT
32
+ ## Example - Rakefile
110
33
 
111
- wget https://unpkg.com/squared/Rakefile
34
+ Projects from any accessible folder can be added relative to the parent directory (e.g. *REPO_ROOT*) or absolutely. The same Rakefile can also manage other similarly cloned `Repo` repositories remotely by setting the `REPO_ROOT` environment variable to the location. Missing projects will simply be excluded from the task runner.
112
35
 
113
- rake -T # List tasks
36
+ ```ruby
37
+ require "squared"
114
38
 
115
- # REPO_BUILD={dev,prod}
116
- # PIPE_FAIL=1
117
- rake repo:init # nightly
118
- rake repo:init[latest] # squared
119
- rake repo:init[0.11.x] # e-mc
39
+ require "squared/workspace"
40
+ require "squared/workspace/repo" # Optional
41
+ require "squared/workspace/project/node" #
42
+ require "squared/workspace/project/python" #
43
+ require "squared/workspace/project/ruby" #
120
44
  # OR
121
- REPO_ROOT=/tmp/123 NODE_INSTALL=pnpm repo:init
122
- ```
45
+ require "squared/app" # All workspace related modules
123
46
 
124
- > [!TIP]
125
- > Use the supplied Rakefile inside the **squared** project folder once the source has been downloaded.
47
+ # NODE_ENV = production
126
48
 
127
- #### Docker
128
-
129
- ```sh
130
- # NODE_TAG=latest
131
- # RUBY_VERSION=2.4.0-3.3.0
132
- # MANIFEST=nightly,staging,prod,android
133
- # BUILD={dev,prod}
134
- # DEV={0,1,local}
135
- # DOCS=any
136
- # PIPE_FAIL={0,1}
137
- docker build -t squared --build-arg MANIFEST=prod --build-arg SQUARED=prod .
138
- docker build -t node --build-arg NODE_TAG=20 --build-arg NODE_INSTALL=pnpm -f Dockerfile.slim . # no docs
49
+ # REPO_ROOT = /workspaces #
50
+ # REPO_HOME = /workspaces/squared # Dir.pwd
51
+ # rake = /workspaces/squared/Rakefile # main?
139
52
  # OR
140
- # RUBY_TAG=latest
141
- # NODE_VERSION=22.x
142
- docker build -t ruby --build-arg RUBY_TAG=3.0 --build-arg NODE_VERSION=20.x --build-arg PIPE_FAIL=0 -f Dockerfile.ruby .
143
-
144
- # Express
145
- docker run -it --name express --rm -p 127.0.0.1:80:80 \
146
- --mount type=bind,src=${PWD},dst=/workspaces/squared/.config \
147
- --mount type=bind,src=${PWD}/html,dst=/workspaces/squared/www \
148
- squared
149
-
150
- # Terminal
151
- docker run -it --name debian squared /bin/bash # irb
152
- ```
153
-
154
- ### Browser
155
-
156
- * Download (squared@version): https://unpkg.com/squared
157
- * Global JS variable: **squared**
158
- * ES2018
159
-
160
- > - https://unpkg.com/squared/dist/squared.min.js
161
- > - https://unpkg.com/squared/dist/squared.base-dom.min.js
162
- > - https://unpkg.com/squared/dist/vdom.framework.min.js
163
-
164
- > * https://unpkg.com/squared/dist/squared.min.js
165
- > * https://unpkg.com/squared/dist/vdom-lite.framework.min.js
166
-
167
- ## Usage
168
-
169
- Library files are in the `/dist` folder. A minimum of **two** files are required to run *squared*.
170
-
171
- 1. squared
172
- 2. squared-base - *required: except vdom-lite*
173
- 3. **squared-svg** - *optional*
174
- 4. framework (e.g. **android** | **chrome** | vdom | vdom-lite)
175
- 5. extensions - *optional*
176
-
177
- Usable combinations: 1-2-4 + 1-2-4-5 + 1-2-3-4-5 + 1-vdom-lite
178
-
179
- File bundles for common combinations are available in the `/dist/bundles` folder and do not require a call to **setFramework**.
180
-
181
- > [!WARNING]
182
- > Libraries in bold are transpiled with **ES2020**.
183
-
184
- ### Example: android
185
-
186
- The primary function `parseDocument` can be called on multiple elements and multiple times per session. The application will continuously and progressively build the layout files into a single entity with combined shared resources.
187
-
188
- * ES2020
189
-
190
- > [!CAUTION]
191
- > Using `parseDocumentSync` is not recommended when your page has images or fonts.
192
-
193
- ```html
194
- <script src="/dist/squared.min.js"></script>
195
- <script src="/dist/squared.base.min.js"></script>
196
- <script src="/dist/squared.svg.min.js"></script>
197
- <script src="/dist/android.framework.min.js"></script>
198
- <script>
199
- squared.settings.targetAPI = 35; // Optional
200
-
201
- document.addEventListener("DOMContentLoaded", async () => {
202
- squared.setFramework(android, {/* settings */});
203
-
204
- await squared.parseDocument(): Node // document.body (default)
205
- // OR
206
- await squared.parseDocument(/* HTMLElement */, /* "fragment-id" */, /* ...etc */): Node[]
207
- // OR
208
- await squared.parseDocument(
209
- { // Custom settings do not affect other layouts
210
- element: document.body,
211
- projectId: "project-1", // Default is "_"
212
- resourceQualifier: "land", // "res/*" folder suffix
213
- /* OR */
214
- resourceQualifier: {
215
- suffix: "land", // Used for "true" or "undefined" groups (optional)
216
- layout: true, // Will copy to "res/layout-land" when "suffix" is defined
217
- string: undefined, // Will copy to default location "res/values" when "suffix" is undefined
218
- font: false, // Will not copy anything to "res/font" or "res/font-land"
219
- image: "hdpi", // Will copy to "res/drawable-hdpi"
220
- video: "w720dp", // Will copy to "res/raw-w720dp"
221
- audio: "w720dp", // Same as "video" and treated separately
222
- animation: "v34", // Will copy to "res/anim-v34"
223
- menu: "" // Will copy to default location "res/menu"
224
- /* integer + fraction + array + color + dimension + style + theme = Same as "string" */
225
- },
226
- enabledMultiline: false,
227
- enabledSubstitute: true,
228
- include: ["android.substitute"], // Automatically removed after finalize
229
- exclude: ["squared.list", "squared.grid"], // Disabled only during parseDocument
230
- excludeQuery: [{
231
- selector: "main > article", // Hide elements
232
- /* OR */
233
- resource: squared.base.lib.constant.NODE_RESOURCE.BOX_STYLE, // Exclusions during processing
234
- procedure: squared.base.lib.constant.NODE_PROCEDURE.OPTIMIZATION,
235
- section: squared.base.lib.constant.APP_SECTION.DOM_TRAVERSE
236
- }],
237
- customizationsBaseAPI: -1,
238
- observe(mutations, observer, settings) { // Uses MutationObserver
239
- squared.reset(); // Required when calling "parseDocument" after a File action
240
- squared.parseDocument(settings).then(() => {
241
- squared.copyTo("/path/project", { modified: true }).then(response => console.log(response));
242
- });
243
- },
244
- afterCascade(sessionId, node) {/* Restore previous state */},
245
- beforeRender(layout: LayoutUI) {/* Edit initial values */},
246
- afterFinalize(node: NodeUI) {/* Edit controller values */}
247
- },
248
- { // Only "element" is required
249
- element: "fragment-1",
250
- projectId: "project-1", // Implicit once projectId is not "_"
251
- resourceQualifier: "land",
252
- pathname: "app/src/main/res/layout-hdpi", // Will not be overridden by resourceQualifier "land"
253
- filename: "fragment.xml",
254
- baseLayoutAsFragment: {
255
- name: "androidx.navigation.fragment.NavHostFragment",
256
- documentId: "main_content",
257
- app: {
258
- navGraph: "@navigation/product_list_graph",
259
- defaultNavHost: "true"
260
- }
261
- },
262
- beforeCascade(sessionId) {
263
- document.getElementById("fragment-id").style.display = "block"; // Use inline styles
264
- }
265
- }
266
- );
267
- await squared.parseDocument({
268
- element: "fragment-2",
269
- projectId: "sqd2", // Explicit
270
- resourceQualifier: "port", // Will not conflict with projectId "project-1"
271
- enabledFragment: true,
272
- fragmentableElements: [
273
- {
274
- selector: "main", // querySelector
275
- name: "androidx.navigation.fragment.NavHostFragment",
276
- filename: "navigation.xml",
277
- documentId: "main_content"
278
- },
279
- "main > article" // Declarative double nested fragments are invalid (querySelectorAll)
280
- ],
281
- options: {
282
- "android.resource.fragment": {
283
- dynamicNestedFragments: true // FragmentContainerView or FrameLayout as the container (name and tag are ignored)
284
- }
285
- }
286
- });
287
- // OR - Chromium
288
- squared.prefetch("css").then(() => squared.parseDocument()); // Cross-origin support
289
- Promise.all(
290
- squared.prefetch("css", true), // All stylesheets
291
- squared.prefetch("css", "./undetected.css", element.shadowRoot),
292
- squared.prefetch("svg", "http://embedded.example.com/icon.svg", "../images/android.svg")
293
- )
294
- .then(() => squared.parseDocument());
295
-
296
- // Modify attributes
297
-
298
- const body = squared.findDocumentNode(document.body);
299
- body.android("layout_width", "match_parent");
300
- body.lockAttr("android", "layout_width");
301
-
302
- await squared.close(/* projectId */); // Next call to parseDocument will reset project (optional)
303
-
304
- squared.kill("30s").then(result => {/* killed when result > 0 */}); // Abort next request in 30 seconds
305
-
306
- // File actions - implicitly calls "close"
307
-
308
- await squared.save(/* "project-1" */, /* broadcastId | timeout */); // Uses defaults from settings
309
- // OR
310
- await squared.saveAs(/* archive filename */, { projectId: "project-1" });
311
- await squared.saveAs(/* archive filename */, { timeout: 10 }); // Kills request if not complete in 10 seconds
312
- await squared.saveAs(/* archive filename */, { throwErrors: true }).catch(err => console.log(err)); // Will cancel partial archive download
313
- // OR
314
- await squared.copyTo(/* directory */, {/* options */});
315
- await squared.copyTo(/* directory */, { modified: true }); // Can be used with observe
316
- // OR
317
- await squared.appendTo(/* archive location */, {/* options */});
318
-
319
- // Other features
320
-
321
- squared.observe();
322
- // OR
323
- await squared.observeSrc(
324
- "link[rel=stylesheet]", // HTMLElement
325
- (ev, element) => {
326
- squared.reset();
327
- squared.parseDocument().then(() => squared.copyTo("/path/project"));
328
- },
329
- { port: 8080, secure: false, action: "reload" /* "hot" */, expires: "1h" } // squared.json: "observe"
330
- );
331
-
332
- squared.reset(/* projectId */); // Start new "parseDocument" session (optional)
333
- });
334
- </script>
335
- ```
336
-
337
- > [!CAUTION]
338
- > Calling `saveAs` or `copyTo` methods before the images have completely loaded can cause them to be excluded from the generated layout. In these cases you should use the asynchronous `parseDocument` method to set a callback for your commands.
339
-
340
- ### Example: chrome
341
-
342
- Used primarly for developing single page layouts but can also bundle assets using query selector syntax. It is adequate for most projects and gives you the ability to develop your application as a module in place.
343
-
344
- * ES2020
345
-
346
- ```html
347
- <script src="/dist/squared.min.js"></script>
348
- <script src="/dist/squared.base.min.js"></script>
349
- <script src="/dist/chrome.framework.min.js"></script>
350
- <script>
351
- document.addEventListener("DOMContentLoaded", async () => {
352
- squared.setFramework(chrome, {/* settings */});
353
-
354
- await squared.save(); // Uses defaults from settings
355
- // OR
356
- await squared.saveAs(/* archive filename */, {/* options */});
357
- // OR
358
- await squared.copyTo(/* directory */, {/* options */});
359
- // OR
360
- await squared.appendTo(/* archive location */, {/* options */});
361
-
362
- // Observe
363
- await squared.copyTo(/* directory */, { useOriginalHtmlPage: false, observe: /* Same as Android */ | true /* Auto-reload */}).then(() => squared.observe());
364
- });
365
- </script>
366
- ```
367
-
368
- ### Example: vdom
369
-
370
- The most minimal framework possible (*55kb gzipped*) and can be useful when debugging through DevTools. The `lite` version is about half the bundle size and is recommended for most browser applications.
371
-
372
- * ES2018
373
-
374
- ```html
375
- <script src="/dist/squared.min.js"></script>
376
- <script src="/dist/squared.base-dom.min.js"></script>
377
- <script src="/dist/vdom.framework.min.js"></script>
378
- <script>
379
- document.addEventListener("DOMContentLoaded", async () => {
380
- squared.setFramework(vdom, {/* settings */});
381
-
382
- const element = squared.querySelector("body", true /* synchronous */);
383
- // OR
384
- const elements = await squared.querySelectorAll("*");
385
- // OR
386
- const element = squared.fromElement(document.body, true /* synchronous */);
387
- // OR
388
- const elements = await squared.getElementById("content-id").querySelectorAll("*");
389
- });
390
- </script>
391
- ```
392
-
393
- There are **ES2018** minified versions (\*.min.js) and also **ES2018** non-minified versions.
394
-
395
- ## User Settings
396
-
397
- These settings are available in the global variable `squared` to customize your desired output structure. Each framework shares a common set of settings and also a subset of their own settings.
398
-
399
- ### Example: android
400
-
401
- - [Read the Docs](https://squared.readthedocs.io/en/latest/settings/android.html)
402
-
403
- ```javascript
404
- squared.settings = {
405
- targetAPI: 35,
406
- supportRTL: true,
407
- supportNegativeLeftTop: true,
408
- preloadImages: true,
409
- preloadFonts: true,
410
- preloadLocalFonts: true, // Chromium
411
- preloadCustomElements: true,
412
- enabledSVG: true,
413
- enabledMultiline: true,
414
- enabledViewModel: true,
415
- enabledIncludes: false,
416
- enabledFragment: false,
417
- enabledSubstitute: false,
418
- enabledCompose: false,
419
- dataBindableElements: [], // { selector, attr, expression, namespace?, twoWay? } (see Data Binding section)
420
- includableElements: [], // { selectorStart, selectorEnd, pathname?, filename?, merge?, viewModel? }
421
- substitutableElements: [], // { selector, tag, tagChild?, renderChildren?, autoLayout? }
422
- fragmentableElements: [], // selector | ExtensionFragmentElement
423
- composableElements: [], // selector or property (see Jetpack Compose section)
424
- baseLayoutAsFragment: false | "fragment-name" | ["fragment-name", "fragment-tag"] | { selector, pathname?, filename?, name?, tag? }, // ExtensionFragmentElement
425
- baseLayoutToolsIgnore: "", // Android Studio (e.g. "TooManyViews, HardcodedText")
426
- fontMeasureAdjust: 0.75, // thicker < 0 | thinner > 0 (data-android-font-measure-adjust)
427
- lineHeightAdjust: 1.1, // shorter < 1 | taller > 1 (data-android-line-height-adjust)
428
- preferMaterialDesign: false | "MaterialComponents" | "Material3", // Default is "Material3"
429
- createDownloadableFonts: true,
430
- createElementMap: false,
431
- pierceShadowRoot: true,
432
- adaptStyleMap: true, // Use rendered values for output
433
- lockElementSettings: true,
434
- customizationsBaseAPI: 0, // 0 - All | -1 - None
435
- customizationsBaseAPI: [0, 33, 34], // Multiple
436
- removeDeprecatedAttributes: true, // Remove all
437
- removeDeprecatedAttributes: ["enabled", "singleLine"], // Remove all except "enabled" + "singleLine"
438
- removeUnusedResourceViewId: false,
439
- idNamingStyle: "android",
440
- idNamingStyle: "html", // Use element tagName
441
- idNamingStyle: {
442
- "__default__": "html", // Optional
443
- "DIV": "comments", // HTML is uppercase (comments_1 then comments_2)
444
- "svg": ["vector", 0], // SVG elements areis lowercase (vector_0 then vector_1)
445
- "#text": "text", // Plain text
446
- "::first-letter": "dropcap", // Pseudo element
447
- "main > section": ["content", 1, 2], // content_1 then content_3
448
- "form input[type=submit]": function(node) {
449
- return "submit_" + node.id;
450
- }
451
- },
452
- customizationsOverwritePrivilege: true,
453
- outputMainFileName: "activity_main.xml",
454
- outputFragmentFileName: "fragment_main.xml",
455
- /* Project - parseDocument (first only) */
456
- resourceQualifier: "", // "land" -> "res/layout-land" | "port" -> "res/layout-port" (appended to every "res" folder)
457
- resourceSystemColors: {
458
- "system_accent1_100": "white", // Will be converted to ARGB
459
- "system_accent1_200": ['#ff0000', 0.75], // opacity
460
- "system_accent1_300": squared.lib.color.parseColor("#000", 1)
461
- },
462
- manifestPackage: "", // OR: RequestData<{ namespace: "android.application.id" }>
463
- manifestLabelAppName: "android",
464
- manifestThemeName: "AppTheme",
465
- manifestParentThemeName: "Theme.AppCompat.Light.NoActionBar",
466
- manifestActivityName: ".MainActivity",
467
- outputDocumentEditing: true,
468
- outputDocumentCSS: [], // CSS properties to be processed at server (e.g. "boxShadow")
469
- outputDirectory: "app/src/main",
470
- createManifest: false, // Update AndroidManifest.xml
471
- createBuildDependencies: false | "ktx" | "baseline-profile" | ["ktx", "baseline-profile"], // Update build.gradle
472
-
473
- // Not customizable with parseDocument
474
- builtInExtensions: [
475
- "squared.accessibility",
476
- "android.delegate.background",
477
- "android.delegate.negative-x",
478
- "android.delegate.positive-x",
479
- "android.delegate.max-width-height",
480
- "android.delegate.percent",
481
- "android.delegate.content",
482
- "android.delegate.scrollbar",
483
- "android.delegate.radiogroup",
484
- "android.delegate.multiline",
485
- "squared.relative",
486
- "squared.css-grid",
487
- "squared.flexbox",
488
- "squared.table",
489
- "squared.column",
490
- "squared.list",
491
- "squared.grid",
492
- "squared.sprite",
493
- "squared.whitespace",
494
- "android.resource.background",
495
- "android.resource.svg",
496
- "android.resource.strings",
497
- "android.resource.fonts",
498
- "android.resource.dimens",
499
- "android.resource.styles",
500
- "android.resource.data",
501
-
502
- /* EXCLUDED (breaks layout) */
503
- "android.resource.includes", // enabledIncludes
504
- "android.substitute", // enabledSubstitute
505
- "android.resource.fragment", // enabledFragment
506
- "jetpack.compose.view" // enabledCompose
507
- ],
508
- compressImages: false, // TinyPNG API Key <https://tinypng.com/developers>
509
- compressImages: "****************", // API key
510
- convertImages: "", // png | jpeg | webp | gif | bmp
511
- showAttributes: true,
512
- showAttributes: {
513
- "hyphenationFrequency": "full", // Replace all ("android" is the default namespace)
514
- "android:fontFeatureSettings": null, // Delete all
515
- "app:menu": [
516
- "@menu/menu_1", "@menu/menu_2", // Replace with "@menu/menu_2" when value is "@menu/menu_1"
517
- "@menu/menu_3", null // Delete attribute when value is "@menu/menu_3"
518
- ],
519
- /* OR */
520
- "app:menu": {
521
- "@menu/menu_1": "@menu/menu_2",
522
- "@menu/menu_3": null
523
- }
524
- },
525
- showComments: false | ["boxShadow"] | { self: ["boxShadow"], nextSibling: ["marginBottom"], previousSibling: ["marginTop"], parent: ["position", "top", "left"] }, // TODO in layout.xml
526
- showComments: { include: { tagName: true | ["button"], attributes: true | ["style"], dataset: false, bounds: true }, self: ["boxShadow", ".className"] },
527
- showErrorMessages: false,
528
- convertPixels: "dp", // "sp" | "pt" | "in" | "mm"
529
- convertLineHeight: "sp", // "dp" | "pt" | "in" | "mm"
530
- convertEntities: ["numeric"], // v5.4
531
- convertEntities: ["codepoints", {/* JSON (last) */}], // https://html.spec.whatwg.org/entities.json
532
- insertSpaces: 4,
533
- outputDocumentHandler: "android",
534
- outputEmptyCopyDirectory: false, // Sub directories within target directory (OR: RequestData<{ emptyDir: false }>)
535
- outputSummaryModal: false | "path/summary.css" | ".status-4 { color: purple; }",
536
- outputTasks: {
537
- "**/drawable/*.xml": { handler: "gulp", task: "minify" }
538
- },
539
- outputWatch: {
540
- "**/drawable/*.png": true,
541
- "**/drawable/*.jpg": { interval: 1000, expires: "2h" }
542
- },
543
- outputArchiveName: "android-xml",
544
- outputArchiveFormat: "zip", // tar | 7z | gz
545
- outputArchiveCache: false // Downloadable URL in ResponseData<downloadUrl>
546
- };
547
-
548
- // Optional
549
- squared.settings = {
550
- resolutionDPI: 160, // 320dpi = 2560x1600
551
- resolutionScreenWidth: 1280,
552
- resolutionScreenHeight: 800,
553
- framesPerSecond: 60,
554
- useShapeGeometryBox: true, // Bounding box uses native SVG method getBbox
555
- formatUUID: "8-4-4-4-12", // UUID: 8-4-[12345]3-[89ab]3-12
556
- formatDictionary: "0123456789abcdef",
557
- outputConfigName: "sqd.config",
558
- observePort: 8080,
559
- observeSecurePort: 8443,
560
- observeExpires: "1h", // Server defaults will be used
561
- broadcastPort: 3080,
562
- broadcastSecurePort: 3443
563
- };
564
- ```
565
-
566
- ### Example: chrome
567
-
568
- - [Read the Docs](https://squared.readthedocs.io/en/latest/settings/chrome.html)
569
-
570
- ```javascript
571
- squared.settings = {
572
- preloadImages: false,
573
- preloadFonts: false,
574
- preloadLocalFonts: false,
575
- preloadCustomElements: false,
576
- excludePlainText: true,
577
- createElementMap: true,
578
- pierceShadowRoot: true,
579
- adaptStyleMap: false,
580
- builtInExtensions: [],
581
- showErrorMessages: false,
582
- webSocketPort: 80,
583
- webSocketSecurePort: 443,
584
- outputDocumentHandler: "chrome",
585
- outputEmptyCopyDirectory: false,
586
- outputSummaryModal: false,
587
- outputTasks: {
588
- "*.js": [{ handler: "gulp", task: "minify" }, { handler: "gulp", task: "beautify" }]
589
- },
590
- outputWatch: { "*": true },
591
- outputArchiveName: "chrome-data",
592
- outputArchiveFormat: "zip",
593
- outputArchiveCache: false
594
- };
595
-
596
- // Optional (Same as Android)
597
-
598
- ```
599
-
600
- ### Example: vdom
601
-
602
- - [Read the Docs](https://squared.readthedocs.io/en/latest/settings/vdom.html)
603
-
604
- ```javascript
605
- squared.settings = {
606
- createElementMap: true,
607
- pierceShadowRoot: false,
608
- adaptStyleMap: false,
609
- builtInExtensions: [],
610
- showErrorMessages: false
611
- };
612
- ```
613
-
614
- ## Local Storage
615
-
616
- Custom named user settings per framework can be saved to local storage as JSON and reused across all pages in the same domain. Extensions are configured using the same procedure.
617
-
618
- ```javascript
619
- // Save
620
- squared.setFramework(android, { compressImages: true }, "android-example");
621
-
622
- // Load
623
- squared.setFramework(android, "android-example");
624
- ```
625
-
626
- ```javascript
627
- // Save
628
- await squared.copyTo("/path/project", {/* options will be saved */}, "copy-example", true); // Will overwrite and not merge with previously saved settings
629
-
630
- // Load
631
- await squared.copyTo("/path/project", {/* takes precedence */}, "http://localhost:3000/copy-to/base-config.json"); // Object.assign({ base-config.json }, options)
632
- await squared.copyTo("/path/project", {/* takes precedence */}, "copy-example"); // Object.assign({ copy-example }, options)
633
-
634
- await squared.copyTo("/path/project", "http://localhost:3000/copy-to/base-config.json"); // options = { base-config.json }
635
- await squared.copyTo("/path/project", "copy-example"); // options = { copy_example }
636
- ```
637
-
638
- ## Public Properties and Methods
639
-
640
- - [Read the Docs](https://squared.readthedocs.io/en/latest/methods/squared.html)
641
-
642
- ```javascript
643
- .settings // See user preferences section
644
-
645
- setFramework(app: {}, options?: PlainObject, setting?: string, cache?: boolean) // Install application interpreter
646
- setFramework(app: {}, loadName: string, cache?: boolean) // Load settings from local storage
647
-
648
- // http - hostname(:port)? | https - hostname:443
649
- setHostname(value: string /* http(s)://hostname(:port) */) // Use another cors-enabled server for processing files (--cors <origin>)
650
-
651
- setEndpoint(name: string, value: string) // Set alternate pathname for API v1 functions (ASSETS_COPY | ASSETS_ARCHIVE | LOADER_DATA | THREADS_KILL | WEBSOCKET_OBSERVE)
652
- setLocalAddress(...values: (string | URL | Location)[]) // Additional hostnames which are interpreted as localhost (e.g. http://127.0.0.1)
653
-
654
- prefetch(type: "css" | "javascript" | "image" | "svg", all?: boolean, ...targets: unknown[]) // Cross-origin support for CSS
655
-
656
- parseDocument(...elements: (HTMLElement | string | ElementSettings)[]) // See installation section (Promise)
657
- parseDocumentSync(...elements: (HTMLElement | string | ElementSettings)[]) // Skips preloadImages and preloadFonts (synchronous)
658
-
659
- latest(count?: number) // Most recent parseDocument session ids (1 newest / -1 oldest: string, other: string[])
660
-
661
- auth(token: string) // Set JWT authorization token for all requests
662
-
663
- save(projectId?: string) // Save current session to a new archive using default settings
664
- save(projectId?: string, broadcastId?: string)
665
- save(projectId?: string, timeout?: number)
666
-
667
- close(projectId?: string) // Close current session
668
- reset(projectId?: string) // Clear cache and reopen new session
669
- clear() // Clear all data stored in memory
670
-
671
- toString() // Current framework loaded
672
- toString(projectId: string) // await squared.close(projectId) (required)
673
-
674
- add(...names: (string | Extension | ExtensionRequestObject)[]) // See extension configuration section
675
- remove(...names: (string | Extension)[]) // Remove extensions by namespace or control
676
- get(...names: string[]) // Retrieve extensions by namespace
677
- attr(name: string | Extension, attrName: string, value?: unknown) // Set or get extension options attribute value
678
- apply(name: string | Extension, options: PlainObject, setting?: string) // See extension configuration section
679
-
680
- extend(functionMap: {}, framework?: /* 0 - ALL | 1 - vdom | 2 - android | 4 - chrome */) // Add extension functions and properties to Node prototype
681
-
682
- observe(value?: boolean | MutationObserverInit) // Start after DOM and third-party libraries initialization
683
- broadcast(callback: BroadcastMessageCallback, options: FileBroadcastOptions | string) // Redirect stdout messages to DevTools console
684
-
685
- // Promise (Recommended "cache": createElementMap - true)
686
-
687
- getElementById(value: string, sync?: boolean, cache?: boolean) // sync - false | cache - true (default)
688
- querySelector(value: string, sync?: boolean, cache?: boolean)
689
- querySelectorAll(value: string, sync?: boolean, cache?: boolean)
690
-
691
- fromElement(element: HTMLElement | string, sync?: boolean, cache?: boolean) // sync - false | cache - false (default)
692
- fromNode(node: Node, sync?: boolean, cache?: boolean)
693
- findDocumentNode(element: HTMLElement | string /* querySelector | elementId | controlId */, all?: boolean) // Use before saving to modify internal Node attributes
694
-
695
- observeSrc(element: HTMLElement | string /* querySelector */, callback: WebSocketMessageChange, options?: FileObserveOptions) // Can be used to watch any element with externally hosted files (src/href)
696
- observeSrc(element: HTMLElement | string, options: FileObserveOptions) // Uses location.reload (reload - true)
697
- ```
698
-
699
- Packaging methods will return a Promise and requires a squared-express installation. These features are not supported when the framework is VDOM.
700
-
701
- ```javascript
702
- saveAs(filename: string, options?: {}, setting?: string, overwrite?: boolean) // Save current session as a new archive
703
- saveFiles(filename: string, options: {}, setting?: string, overwrite?: boolean) // Create new archive from FileAsset[]
704
-
705
- // Required (local archives): --disk-read | --unc-read | --access-all (command-line)
706
-
707
- appendTo(pathname: string, options?: {}, setting?: string, overwrite?: boolean) // Create new archive from a preexisting archive and current session
708
- appendFiles(pathname: string, options: {}, setting?: string, overwrite?: boolean) // Create new archive from a preexisting archive and FileAsset[]
709
-
710
- // Required (all): --disk-write | --unc-write | --access-all (command-line)
711
-
712
- copyTo(pathname: string | string[], options?: {}, setting?: string, overwrite?: boolean) // Copy current session to local
713
- copyFiles(pathname: string | string[], options: {}, setting?: string, overwrite?: boolean) // Copy FileAsset[] to local
714
-
715
- kill(pid: number, timeout?: number) // Use -1 or options.pid (set by system) + seconds
716
- kill(timeout: string)
717
- kill() // Terminate previous request
718
- kill(0) // By username (auth required)
719
- kill(-1, 10) // Terminate previous request in 10 seconds
720
- kill(NaN, 10) // Terminate in 10 seconds (next request) ("timeout" is required)
721
- kill("10s") // Only "s" + "ms" (next request)
722
- ```
723
-
724
- ## Extending Node object
725
-
726
- You can add functions and initial variables to the Node object including overwriting preexisting class definitions per framework. Accessor properties are also supported using the *get/set* object syntax.
727
-
728
- ```javascript
729
- squared.extend({
730
- _id: 1,
731
- altId: {
732
- get() {
733
- return this._id;
734
- },
735
- set(value) {
736
- this._id += value;
737
- }
738
- },
739
- customId: {
740
- value: 2,
741
- configurable: false,
742
- enumerable: false
743
- },
744
- addEvent(eventName, callback) {
745
- this.element.addEventListener(eventName, callback);
746
- }
747
- });
748
- squared.setFramework(vdom);
749
-
750
- const body = await squared.fromElement(document.body);
751
- body.altId = 2; // body.altId: 3
752
- body.addEvent("click", function (ev) {
753
- this.classList.toggle("example");
754
- });
755
- ```
756
-
757
- ## Forwarding Request
758
-
759
- Using another identical remote server to build the project when performing a `saveAs` or `copyTo` request can be achieved by changing only the origin address.
760
-
761
- ```javascript
762
- squared.setHostname("http://hostname:8000");
763
- // OR
764
- squared.setHostname(); // Reset to window.location (e.g. localhost:3000)
765
-
766
- await squared.saveAs("chrome.zip"); // Current browser
767
- // OR
768
- await squared.copyTo("/path/project"); // Remote server
769
- ```
770
-
771
- ## Broadcasting
772
-
773
- Console messages (stdout) can be sent to the browser console instead through DevTools.
774
-
775
- ```javascript
776
- squared.broadcast(result => { console.log(result.value); }, "111-111-111"); // System messages from squared-express
777
- squared.broadcast(result => { console.log(result.value); }, "222-222-222"); // Messages from "project-1" project
778
- squared.broadcast(result => { console.log(result.value); }, { socketId: "333-333-333", socketKey: "socket_id" }); // Messages sent from another channel (default is "socketId")
779
-
780
- await squared.copyTo("/path/project/project-1", {
781
- projectId: "project-1",
782
- log: { useColor: true }, // Chromium
783
- broadcastId: "222-222-222" // Specific use alias for "socketId"
784
- });
785
- ```
786
-
787
- ## Extension Configuration
788
-
789
- Layout rendering can be customized using extensions as the program was built to be nearly completely modular. Some of the common layouts already have built-in extensions which you can load or unload based on your preference.
790
-
791
- ```typescript
792
- // Create an extension
793
- class Sample extends squared.base.Extension {
794
- options = {
795
- attributeName: [];
796
- };
797
-
798
- constructor(name, framework = 0, options = {}) { // 0 - ALL | 1 - vdom | 2 - android | 4 - chrome (framework)
799
- super(name, framework, options);
800
- }
801
-
802
- processNode(node: NodeUI) {
803
- const data = this.project.get(node.element, node.localSettings.projectId);
804
- if (data) {
805
- node.each((child, index) => child.element.title = data[index]);
806
- }
807
- }
808
- }
809
-
810
- // Install an extension
811
- const sample = new Sample("widget.example.com", 0, {/* Same as configure */});
812
- squared.add(sample);
813
- // OR
814
- squared.add([sample, {/* config */}]);
815
-
816
- // Configure an extension
817
- squared.attr("widget.example.com", "attributeName", ["width", "height"]); // typeof is enforced and will only set existing attributes
818
-
819
- // Add project data
820
- const ext = squared.get("widget.example.com");
821
-
822
- ext.project.set(element, await fetch(url?id=1)); // Map interface with optional "projectId" argument
823
- ext.project.set(element, await fetch(url?id=2), "project-1");
824
-
825
- const data = ext.project.get(element, "project-2"); // Returns data from default project (id=1)
826
- ```
827
-
828
- Some extensions have a few settings which can be configured. The default settings usually achieve the best overall rendering accuracy without noticeably affecting performance.
829
-
830
- ## ANDROID
831
-
832
- ### Public Methods
833
-
834
- - [Read the Docs](https://squared.readthedocs.io/en/latest/methods/android.html)
835
-
836
- ```javascript
837
- android.setViewModel(data: {}, sessionId?: string) // Object data for layout bindings
838
- android.setViewModelByProject(data: {}, projectId?: string)
839
- android.removeObserver(element: HTMLElement) // Disconnect an observed element from "parseDocument"
840
- android.addXmlNs(name: string, uri: string) // Add global namespaces for third-party controls
841
- android.addDependency(group: string, name: string, version?: string, type?: number) // Add application dependency implementation (build.gradle)
842
- android.addDependencyByProject(projectId: string, group: string, name: string, version?: string, type?: number) // DEPENDENCY_TYPE: 0 - implementation 1 - api 2 - compileOnly 3 - compileOnlyApi 4 - runtimeOnly 5 - testImplementation 8 - androidTestImplementation
843
- android.customize(build: number, tagNameOrWidget: string, options: {}) // Global attributes applied to specific views
844
- android.loadCustomizations(name: string) // Load customizations from Local Storage
845
- android.saveCustomizations(name: string) // Save "customize" data into Local Storage (includes xmlns)
846
- android.resetCustomizations() // All session customizations are deleted
847
- android.addFontProvider(authority: string, package: string, certs: string[], webFonts: string | {}) // Add additional Web fonts (Google Fonts already included)
848
- android.setResolutionByDeviceName(value: string) // Settings prefixed with "resolution" (e.g. Pixel C)
849
- android.getLocalSettings() // Modify controller styles and parsing rules
850
- ```
851
-
852
- ```javascript
853
- // NOTE: squared.settings.targetAPI is always parsed (Except: customizationsBaseAPI = -1)
854
-
855
- android.customize(android.lib.constant.BUILD_VERSION.ALL /* 0 */, "Button", {
856
- android: {
857
- minWidth: "35px",
858
- minHeight: "25px"
859
- },
860
- "_": { // Non-namespaced attributes
861
- style: "@style/Widget.Material3.Button.TextButton"
862
- }
863
- });
864
-
865
- android.customize(android.lib.constant.BUILD_VERSION.KITKAT /* 19 */, "svg", {
866
- android: {
867
- "[src]": "app:srcCompat" // Change namespace to "app"
868
- }
869
- });
870
-
871
- // Local Storage
872
- android.saveCustomizations("customize-example"); // Save at least once in one layout
873
-
874
- android.loadCustomizations("customize-example"); // Load in any other layout
875
- ```
876
-
877
- ```javascript
878
- android.addXmlNs("tools", "http://schemas.android.com/tools");
879
-
880
- android.customize(16 /* Jelly Bean */, "ImageView", {
881
- tools: {
882
- ignore: "ContentDescription",
883
- targetApi: "16"
53
+ # REPO_ROOT = /workspaces # Dir.pwd
54
+ # rake = /workspaces/Rakefile #
55
+ # REPO_HOME = /workspaces/squared # main: "squared"
56
+
57
+ # pathname = /workspaces/pathname
58
+ # optparse = /workspaces/optparse
59
+ # log = /workspaces/logger
60
+ # emc = /workspaces/e-mc
61
+ # pir = /workspaces/pi-r
62
+ # squared = /workspaces/squared
63
+ # cli = /workspaces/squared/publish/sqd-cli
64
+ # sqd-serve = /workspaces/squared/publish/sqd-serve
65
+ # sqd = /workspaces/squared/sqd
66
+
67
+ Workspace::Application
68
+ .new(Dir.pwd, main: "squared") # Dir.pwd? (main? is implicitly basename)
69
+ .banner("group", "project", styles: ["yellow", "black"], border: "bold") # name | project | path | ref | group? | parent? | version?
70
+ .repo("https://github.com/anpham6/squared-repo", "nightly", script: ["build:dev", "build:prod"], ref: :node) # Repo (optional)
71
+ .run("rake install", ref: :ruby)
72
+ .depend(false, group: "default")
73
+ .clean("rake clean", group: "default")
74
+ .clean(["build/"], group: "app")
75
+ .log({ file: "tmp/%Y-%m-%d.log", level: "debug" }, group: "app")
76
+ .add("pathname", run: "rake compile", copy: "rake install", test: "rake test", group: "default", env: { # Ruby (with C extensions)
77
+ "CFLAGS" => "-fPIC -O1"
78
+ })
79
+ .add("optparse", doc: "rake rdoc", group: "default") # Uses bundler/gem_tasks (without C extensions)
80
+ .add("logger", copy: { from: "lib", glob: "**/*.rb", into: "~/.rvm/gems/ruby-3.3.5/gems/logger-1.6.1" }, clean: ["tmp/"]) # autodetect: true
81
+ .add("e-mc", "emc", copy: { from: "publish", scope: "@e-mc", also: [:pir, "squared-express/"] }, ref: :node) # Node
82
+ .add("pi-r", "pir", copy: { from: "publish", scope: "@pi-r" }, clean: ["publish/**/*.js", "tmp/"]) # Trailing slash required for directories
83
+ .add("squared", script: ["build:stage1", "build:stage2"], group: "app") do # Copy target (main)
84
+ add("publish/sqd-cli", "cli", exclude: [:git]) # rake cli:build
85
+ add("publish/sqd-serve") # rake sqd-serve:build
86
+ add("publish/sqd-admin", group: "sqd", exclude: [:base])
87
+ # OR
88
+ with(exclude: [:base]) { add("publish/*", "packages") } # rake packages:sqd-serve:build
89
+ # OR
90
+ add(["publish/sqd-cli", "publish/sqd-serve", "publish/sqd-admin"], true, exclude: [:base]) # rake squared:sqd-serve:build
91
+ end
92
+ .add("squared/sqd", exclude: [:git]) do
93
+ variable_set :script, "build:sqd" # Override detection
94
+ variable_set :depend, false
95
+ variable_set :clean, ["build/sqd/"]
96
+ end
97
+ .style("banner", 255.255) # 256 colors (fg | fg.bg | -0.bg)
98
+ .build(default: "build", parallel: ["pull", "fetch", "rebase", "copy", "clean", /^outdated:/]) do |workspace|
99
+ workspace
100
+ .enable_aixterm
101
+ .style({
102
+ banner: ["bright_cyan", "bold", "bright_black!"],
103
+ border: "bright_white"
104
+ })
105
+ end
106
+
107
+ # default = /workspaces/ruby/*
108
+ # pathname = /workspaces/ruby/pathname
109
+ # optparse = /workspaces/ruby/optparse
110
+ # logger = /workspaces/ruby/logger
111
+ # android = /workspaces/android-docs
112
+ # chrome = /workspaces/chrome-docs
113
+
114
+ Workspace::Application
115
+ .new(ENV["SQUARED_HOME"], prefix: "rb", common: false) # Local styles
116
+ .group("ruby", "default", run: "rake build", copy: "rake install", clean: "rake clean", ref: :ruby, override: {
117
+ pathname: {
118
+ run: "rake compile" # rake rb:pathname:build
884
119
  }
885
- });
886
- ```
887
-
888
- ### Static Methods
889
-
890
- Project resources can include additional values that are required during compilation. TypeScript definitions are available in the `types/android` directory.
891
-
892
- ```javascript
893
- squared.parseDocument().then(node => {
894
- const resourceId = node.localSettings.resourceId;
895
- android.base.Resource.addString(resourceId, value, /* name */);
896
- android.base.Resource.addArray(resourceId, name, items);
897
- android.base.Resource.addColor(resourceId, color);
898
- android.base.Resource.addDimen(resourceId, name, value);
899
- android.base.Resource.addTheme(resourceId, theme);
900
- squared.save();
901
- });
120
+ })
121
+ .with(:python) do # ref=Symbol | group=String
122
+ banner([:name, ": ", :version], "path") # chrome-docs: 0.1.0 | /workspaces/chrome-docs
123
+ doc("make html") # rake rb:doc:python
124
+ run(false) # rake rb:build:python (disabled)
125
+ exclude(%i[base git]) # Project::Git.ref (superclass)
126
+ add("android-docs", "android") # rake rb:android:doc
127
+ add("chrome-docs", "chrome") # rake rb:chrome:doc
128
+ end #
129
+ .style("inline", "bold")
130
+ .build
131
+ ```
132
+
133
+ **NOTE**: The use of "**ref**" (class name) is only necessary when initializing an empty directory (e.g. *rake repo:init*).
134
+
135
+ ### Graph
136
+
137
+ ```ruby
138
+ Workspace::Application
139
+ .new(main: "squared")
140
+ .graph(["depend"], ref: :git) # Optional
141
+ .with(:python) do
142
+ add("android-docs", "android")
143
+ add("chrome-docs", "chrome", graph: "android")
144
+ end
145
+ .with(:node) do
146
+ graph(["build", "copy"]) # Overrides "git"
147
+ add("e-mc", "emc")
148
+ add("pi-r", "pir", graph: "emc")
149
+ add("squared-express", "express", graph: "pir")
150
+ add("squared", graph: ["chrome", "express"])
151
+ end
152
+ .with(:ruby) do
153
+ add("pathname")
154
+ add("fileutils", graph: "pathname")
155
+ add("optparse")
156
+ add("rake", graph: ["fileutils", "optparse"])
157
+ end
158
+ .build
902
159
  ```
903
160
 
904
- ### Data Binding
905
-
906
- View model data can be applied to most HTML elements using the dataset attribute. Different view models can be used for every `parseDocument` session.
907
-
908
- Leaving the `sessionId` empty uses the default view model which is searched last for all projects when attempting a bind.
909
-
910
- ```javascript
911
- // NOTE: latest(undefined = 1): string (1: most recent sessionId | -1: first sessionId)
912
-
913
- squared.parseDocument("id-1", "id-2", "id-3").then(nodes => {
914
- const sessions = squared.latest(2); // ["00001", "00002", "00003"] => ["00002", "00003"]
915
- android.setViewModel(
916
- {
917
- import: ["java.util.Map", "java.util.List"],
918
- variable: [
919
- { name: "user", type: "com.example.User" },
920
- { name: "list", type: "List&lt;String>" },
921
- { name: "map", type: "Map&lt;String, String>" },
922
- { name: "index", type: "int" },
923
- { name: "key", type: "String" }
924
- ]
925
- },
926
- sessions[0] // nodes[1].sessionId
927
- );
928
- android.setViewModel(
929
- {
930
- import: ["java.util.Map"],
931
- variable: [
932
- { name: "map", type: "Map&lt;String, String>" }
933
- ]
934
- },
935
- sessions[1] // nodes[2].sessionId
936
- );
937
- });
938
-
939
- squared.parseDocument({
940
- element: "main",
941
- enabledViewModel: true,
942
- dataBindableElements: [
943
- {
944
- selector: "#first_name",
945
- namespace: "android", // "android" is default
946
- attr: "text",
947
- expression: "user.firstName"
948
- },
949
- {
950
- selector: "#last_name",
951
- attr: "text",
952
- expression: "user.lastName"
953
- },
954
- {
955
- selector: "#remember_me",
956
- attr: "checked",
957
- expression: "user.rememberMe",
958
- twoWay: true
959
- }
960
- ],
961
- data: {
962
- viewModel: {
963
- import: ["java.util.Map"],
964
- variable: [
965
- { name: "map", type: "Map&lt;String, String>" }
966
- ]
967
- }
968
- }
969
- });
970
-
971
- squared.save();
972
- ```
973
-
974
- Inlining is also supported and might be more convenient for simple layouts. JavaScript is recommended when you are calling `parseDocument` multiple times.
975
-
976
- ```
977
- data-viewmodel-{namespace}-{attribute} -> data-viewmodel-android-text
978
- ```
979
-
980
- These two additional output parameters are required when using the "**data-viewmodel**" prefix.
981
-
982
- ```html
983
- <div id="main">
984
- <label>Name:</label>
985
- <input id="first_name" type="text" data-viewmodel-android-text="user.firstName" />
986
- <input id="last_name" type="text" data-viewmodel-android-text="user.lastName" />
987
- <input id="remember_me" type="checkbox" data-viewmodel-android-checked="=user.rememberMe" /> <!-- "=" for two-way binding -->
988
- </div>
989
- ```
990
-
991
- ```xml
992
- <layout>
993
- <data>
994
- <import type="java.util.Map" />
995
- <import type="java.util.List" />
996
- <variable name="user" type="com.example.User" />
997
- <variable name="list" type="List&lt;String&gt;" />
998
- <variable name="map" type="Map&lt;String, String&gt;" />
999
- <variable name="index" type="int" />
1000
- <variable name="key" type="String" />
1001
- </data>
1002
- <LinearLayout android:id="@+id/main">
1003
- <TextView android:text="Name:" />
1004
- <EditText
1005
- android:id="@+id/first_name"
1006
- android:inputType="text"
1007
- android:text="@{user.firstName}" />
1008
- <EditText
1009
- android:id="@+id/last_name"
1010
- android:inputType="text"
1011
- android:text="@{user.lastName}" />
1012
- <CheckBox
1013
- android:id="@+id/remember_me"
1014
- android:checked="@={user.rememberMe}" />
1015
- </LinearLayout>
1016
- </layout>
1017
- ```
1018
-
1019
- ### Layout Includes / Merge Tag
1020
-
1021
- Some applications can benefit from using includes or merge tags to share common templates. Nested includes is supported.
1022
-
1023
- ```html
1024
- <div>
1025
- <div id="item1">Item 1</div>
1026
- <div id="item2" data-android-include-start="true" data-android-include-merge="true" data-pathname-android="app/src/main/res/layout-land" data-filename-android="filename1.xml">Item 2</div>
1027
- <div id="item3">Item 3</div>
1028
- <div id="item4" data-android-include-end="true">Item 4</div>
1029
- <div id="item5" data-android-include="filename2" data-android-include-end="true" data-android-include-viewmodel="exampleData">Item 5</div> <!-- viewModel -->
1030
- </div>
1031
- ```
1032
-
1033
- ```javascript
1034
- android.setViewModelByProject({ variable: [{ name: "exampleData", type: "com.example.ExampleData" }] }, "project-1"); // Default is "_"
1035
-
1036
- squared.parseDocument({
1037
- element: document.body,
1038
- projectId: "project-1", // Affects all layouts in same project
1039
- enabledIncludes: true,
1040
- includableElements: [
1041
- {
1042
- selectorStart: "#item2",
1043
- selectorEnd: "#item4",
1044
- pathname: "app/src/main/res/layout-land",
1045
- filename: "filename1.xml",
1046
- merge: true // Multiple elements will auto-merge
1047
- },
1048
- {
1049
- selectorStart: "#item5",
1050
- selectorEnd: "#item5",
1051
- filename: "filename2",
1052
- viewModel: "exampleData" // One element only (merge=false)
1053
- }
1054
- ]
1055
- });
161
+ ```sh
162
+ rake pir:graph # emc + pir
163
+ rake express:graph # emc + pir + express
164
+ rake chrome:graph # android + chrome
165
+ rake graph:python # same
166
+ rake squared:graph # android + chrome + emc + pir + express + squared
167
+ rake graph:node # same
168
+ rake rake:graph # pathname + fileutils + optparse + rake
169
+ rake graph:ruby # same
170
+ rake graph # graph:node + graph:ruby
1056
171
  ```
1057
- > [!NOTE]
1058
- > By sessionId has precedence when associating a view model.
1059
172
 
1060
- ```xml
1061
- <LinearLayout>
1062
- <TextView>Item 1</TextView>
1063
- <include layout="@layout/filename1" />
1064
- <include layout="@layout/filename2" app:exampleData="@{exampleData}" />
1065
- </LinearLayout>
1066
- <!-- res/layout/activity_main.xml -->
173
+ ### Batch
1067
174
 
1068
- <merge>
1069
- <TextView>Item 2</TextView>
1070
- <TextView>Item 3</TextView>
1071
- <TextView>Item 4</TextView>
1072
- </merge>
1073
- <!-- res/layout-land/filename1.xml -->
1074
-
1075
- <layout>
1076
- <data>
1077
- <variable name="exampleData" type="com.example.ExampleData" />
1078
- </data>
1079
- <TextView>Item 5</TextView>
1080
- </layout>
1081
- <!-- res/layout/filename2.xml -->
175
+ ```ruby
176
+ Workspace::Series.batch(:ruby, :node, {
177
+ stage: %i[graph test],
178
+ reset: %i[stash pull]
179
+ })
1082
180
  ```
1083
181
 
1084
- The attributes "**data-android-include-start**" and "**data-android-include-end**" can only be applied to elements which share the same parent container. See `/demos/gradient.html` for usage instructions.
1085
-
1086
- > [!TIP]
1087
- > "**data-pathname-android**" AND "**data-filename-android**" can also be used with any `parseDocument` base element.
1088
-
1089
- ### Redirecting Output Location
1090
-
1091
- Sometimes it is necessary to extract elements and append them into other containers for it to look identical on the Android device. Redirection will fail if the *target location* is not a block/container element.
182
+ ### Rename
1092
183
 
1093
- ```html
1094
- <div>
1095
- <span>Item 1</span>
1096
- <span data-android-target="location">Item 2</span>
1097
- <span data-android-target="location" data-android-target-index="1">Item 3</span>
1098
- <div>
1099
- <ul id="location">
1100
- <li>Item 4</li>
1101
- <li>Item 5</li>
1102
- <!-- span -->
1103
- </ul>
184
+ ```ruby
185
+ Workspace::Series.rename("depend", "install")
1104
186
  ```
1105
187
 
1106
- ```xml
1107
- <LinearLayout>
1108
- <TextView>Item 1</TextView>
1109
- </LinearLayout>
1110
- <LinearLayout>
1111
- <TextView>Item 4</TextView>
1112
- <TextView>Item 3</TextView>
1113
- <TextView>Item 5</TextView>
1114
- <TextView>Item 2</TextView>
1115
- </LinearLayout>
1116
- ```
1117
-
1118
- Using `target` into a ConstraintLayout or RelativeLayout container will not include automatic positioning.
1119
-
1120
- ### Custom Attributes
1121
-
1122
- System or extension generated attributes can be overridden preceding finalization. They will only be visible on the declared framework.
1123
-
1124
- ```
1125
- data-android-attr-{namespace}? -> Default is "android"
1126
- ```
1127
-
1128
- ```html
1129
- <div id="customId"
1130
- data-android-attr="layout_width::match_parent;layout_height::match_parent"
1131
- data-android-attr-app="layout_scrollFlags::scroll|exitUntilCollapsed">
1132
- </div>
1133
- ```
1134
-
1135
- ```xml
1136
- <LinearLayout
1137
- android:id="@+id/customId"
1138
- android:layout_width="match_parent"
1139
- android:layout_height="match_parent"
1140
- app:layout_scrollFlags="scroll|exitUntilCollapsed" />
1141
- ```
188
+ ## Usage
1142
189
 
1143
- ```javascript
1144
- const node = squared.findDocumentNode("customId"); // querySelector is supported
1145
- node.android("layout_width", "match_parent");
1146
- node.android("layout_height", "match_parent");
1147
- node.app("layout_scrollFlags", "scroll|exitUntilCollapsed");
1148
- ```
190
+ ```sh
191
+ rake -T # List tasks
192
+ rake # rake status (usually "build")
1149
193
 
1150
- ### SVG animations
194
+ # GIT_OPTIONS=rebase
195
+ rake pull # All except "default" + "app"
196
+ rake pull:ruby # pathname + optparse + logger
197
+ rake pull:default # pathname + optparse
198
+ rake pull:app # squared
199
+ rake pull:node # emc + pir + squared
1151
200
 
1152
- Only the XML based layout and resource files can be viewed on the Android device/emulator without any Java/Kotlin backend code. To play animations in the emulator you also have to `start` the animation in *MainActivity.java*.
201
+ rake build # All except "android"
202
+ rake doc # optparse + android
203
+ rake depend # All except "default"
1153
204
 
1154
- ```java
1155
- import android.graphics.drawable.Animatable;
205
+ rake build:ruby # rake compile + rake install + rake install
1156
206
 
1157
- android.widget.ImageView imageView1 = findViewById(R.id.imageview_1);
1158
- if (imageView1 != null) {
1159
- Animatable animatable = (Animatable) imageView1.getDrawable();
1160
- animatable.start();
1161
- }
207
+ rake clean # All except "default" + "app"
208
+ rake clean:ruby # rake clean + rake clean + ["tmp/"]
209
+ rake clean:default # rake clean + rake clean + skip
210
+ rake clean:app # none + skip + ["build/"]
211
+ rake clean:node # none + ["publish/**/*.js", "tmp/"] + ["build/"]
1162
212
  ```
1163
213
 
1164
- ### Jetpack Compose
1165
-
1166
- Most mobile applications do not have a deeply nested hierarchy and are generally better to implement using declarative programming.
1167
-
1168
- ```javascript
1169
- squared.settings.composableElements = ["main", "#content", "--boxShadow", "--height=300px", {
1170
- selector: "main",
1171
- android: {
1172
- layout_height: "match_parent"
1173
- },
1174
- tools: {
1175
- composableName: "com.example.compose.Preview"
1176
- }
1177
- }];
1178
- squared.settings.createBuildDependencies = true; // Optional
214
+ ```sh
215
+ rake build:app # squared + cli + sqd-serve
216
+ rake squared:build:workspace # cli + sqd-serve
217
+ rake pull:sqd # sqd-admin
218
+ rake squared:pull:workspace # sqd-serve + sqd-admin
219
+ rake squared:outdated:workspace # cli + sqd-serve + sqd-admin
1179
220
  ```
1180
221
 
1181
- You can also do it using the "**android.substitute**" extension directly inside the HTML element.
222
+ ## Methods
1182
223
 
1183
- ```javascript
1184
- // android.substitute is only used here to demonstrate using extensions
224
+ Task:
1185
225
 
1186
- squared.add(["android.substitute", {
1187
- element: {
1188
- content: { android: { layout_width: "match_parent" } }
1189
- }
1190
- }]);
226
+ * run
227
+ * depend
228
+ * graph
229
+ * test
230
+ * doc
231
+ * clean
1191
232
 
1192
- const items = squared.attr("android.substitute", "viewAttributes");
1193
- items.push("hint", "buttonTint");
1194
- /* OR */
1195
- squared.attr("android.substitute", "viewAttributes", items.concat(["hint", "buttonTint"])); // Attributes to preserve (default is "android.view.View")
1196
- squared.attr("android.substitute", "attributeMapping", { "android:src": "app:srcCompat", "icon": "navigationIcon" /* android */});
233
+ Non-task:
1197
234
 
1198
- squared.parseDocument({
1199
- element: document.body,
1200
- substitutableElements: [{
1201
- selector: "#content",
1202
- tag: "androidx.compose.ui.platform.ComposeView",
1203
- renderChildren: false
1204
- }],
235
+ * log
236
+ * exclude
1205
237
 
1206
- // Some extensions have convenience properties
1207
- enabledSubstitute: true,
1208
- /* OR */
1209
- include: ["android.substitute"]
1210
- });
1211
- ```
238
+ ## Styles
1212
239
 
1213
- ```html
1214
- <body>
1215
- <header style="height: 100px"></header>
1216
- <main id="content"
1217
- data-use="android.substitute"
1218
- data-android-substitute-tag="androidx.compose.ui.platform.ComposeView"
1219
- style="height: 300px; box-shadow: 10px 5px 5px black;">
1220
- <!-- Interior elements are not rendered -->
1221
- </main>
1222
- <footer style="height: 80px"></footer>
1223
- </body>
1224
- ```
1225
-
1226
- Compose will remove child elements by default. You can preserve them by explictly using the renderChildren property. (data-android-substitute-render-children="true")
1227
-
1228
- ```html
1229
- <div id="fragment"
1230
- data-use="android.substitute"
1231
- data-android-substitute-tag="androidx.fragment.app.FragmentContainerView"
1232
- data-android-substitute-render-children="false"
1233
- data-android-attr="name::com.github.fragment;tag::example">
1234
- <!-- Interior elements are not rendered -->
1235
- </div>
1236
- ```
240
+ * banner
241
+ * border
242
+ * header
243
+ * active
244
+ * inline
245
+ * major
246
+ * red
247
+ * yellow
248
+ * green
1237
249
 
1238
- You can also use "**android.substitute**" to create fragments within a layout similar to Compose.
250
+ ## Environment
1239
251
 
1240
- Usually you do not render child elements when using Compose View. There are some cases where it can be used effectively to reproduce the desired layout.
252
+ ### Build
1241
253
 
1242
- ```javascript
1243
- squared.parseDocument({
1244
- element: document.body,
1245
- include: ["android.substitute"], // OR: settings.enabledSubstitute
1246
- substitutableElements: [{
1247
- selector: "#navigation",
1248
- tag: "com.google.android.material.tabs.TabLayout",
1249
- tagChild: "com.google.android.material.tabs.TabItem",
1250
- tagChildAttr: {
1251
- android: {
1252
- layout_height: "match_parent"
1253
- }
1254
- },
1255
- renderChildren: true,
1256
- autoLayout: true
1257
- }]
1258
- });
1259
- ```
254
+ ```ruby
255
+ # :env :run :opts
256
+ # LD_LIBRARY_PATH="path/to/lib" CFLAGS="-Wall" gcc a.c -o a.o -c
257
+ BUILD_${NAME} # gcc a.c -o a.o
258
+ BUILD_${NAME}_OPTS # -c
259
+ BUILD_${NAME}_ENV # {"LD_LIBRARY_PATH":"path/to/lib","CFLAGS":"-Wall"} (hash/json)
1260
260
 
1261
- ```html
1262
- <ul id="navigation"
1263
- data-use-android="android.substitute"
1264
- data-android-attr="layout_height::match_parent"
1265
- data-android-substitute-tag="com.google.android.material.tabs.TabLayout"
1266
- data-android-substitute-tag-child="com.google.android.material.tabs.TabItem"
1267
- data-android-substitute-tag-child-attr="layout_height::match_parent"
1268
- data-android-substitute-auto-layout="true">
1269
- <li>TAB 1</li>
1270
- <li>TAB 2</li>
1271
- <li>TAB 3</li>
1272
- </ul>
1273
- ```
261
+ # :env :opts :script
262
+ # NODE_ENV="production" NO_COLOR="1" npm run --loglevel=error --workspaces=false build:dev
263
+ BUILD_${NAME} # build:dev
264
+ BUILD_${NAME}_OPTS # --loglevel=error --workspaces=false
265
+ BUILD_${NAME}_ENV # {"NODE_ENV":"production","NO_COLOR":"1"} (hash/json)
266
+ BUILD_${NAME}_DEV # pattern,0,1 (:dev)
267
+ BUILD_${NAME}_PROD # pattern,0,1 (:prod)
1274
268
 
1275
- ```xml
1276
- <com.google.android.material.tabs.TabLayout
1277
- android:id="@+id/navigation"
1278
- android:layout_height="match_parent"
1279
- android:layout_width="wrap_content">
1280
- <com.google.android.material.tabs.TabItem
1281
- android:layout_height="match_parent"
1282
- android:layout_width="wrap_content"
1283
- android:text="@string/tab_1" />
1284
- <com.google.android.material.tabs.TabItem
1285
- android:layout_height="match_parent"
1286
- android:layout_width="wrap_content"
1287
- android:text="@string/tab_2" />
1288
- <com.google.android.material.tabs.TabItem
1289
- android:layout_height="match_parent"
1290
- android:layout_width="wrap_content"
1291
- android:text="@string/tab_3" />
1292
- </com.google.android.material.tabs.TabLayout>
269
+ BUILD_${NAME}=0 # skip project
1293
270
  ```
1294
271
 
1295
- ### Downloadable Fonts
1296
-
1297
- Google Fonts are pre-installed and can be used without any additional configuration.
1298
-
1299
- * [Guide](https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts)
272
+ These options also support the project specific suffix `${NAME}`. (e.g. LOG_FILE_SQUARED)
1300
273
 
1301
- ```xml
1302
- <!-- build.gradle -->
1303
- dependencies {
1304
- implementation 'androidx.appcompat:appcompat:1.6.0' <!-- createBuildDependencies = true -->
1305
- <!-- OR -->
1306
- implementation 'com.android.support:appcompat-v7:28.0.0'
1307
- }
274
+ ### Logger
1308
275
 
1309
- <!-- AndroidManifest.xml -->
1310
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <!-- createManifest = true -->
1311
- <application android:theme="@style/AppTheme">
1312
- <meta-data android:name="preloaded_fonts" android:resource="@array/preloaded_fonts" />
1313
- </application>
1314
- </manifest>
1315
- ```
1316
-
1317
- ```javascript
1318
- // https://developers.google.com/fonts/docs/developer_api
1319
-
1320
- await android.addFontProvider(
1321
- "com.google.android.gms.fonts",
1322
- "com.google.android.gms",
1323
- ["MIIEqDCCA5CgAwIBAgIJANWFuGx9007...", "MIIEQzCCAyugAwIBAgIJAMLgh0Zk..."],
1324
- "https://www.googleapis.com/webfonts/v1/webfonts?key=1234567890" // JSON object is synchronous
1325
- );
1326
- /* OR */
1327
- squared.attr("android.resource.fonts", "installGoogleFonts", false); // Use browser and local fonts only
276
+ ```ruby
277
+ LOG_FILE # %Y-%m-%d.log
278
+ # OR
279
+ LOG_AUTO # year,y,month,m,day,d,1
280
+ # Optional
281
+ LOG_DIR # exist?
282
+ LOG_LEVEL # See gem "logger"
283
+ LOG_COLUMNS # terminal width (default: 80)
1328
284
  ```
1329
285
 
1330
- ### Excluding Procedures / Applied Attributes
1331
-
1332
- Most attributes can be excluded from the generated XML using the dataset feature in HTML. One or more can be applied to any tag using the OR "**|**" operator. These may cause warnings when you compile your project and should only be used when an extension has their custom attributes overwritten.
1333
-
1334
- NOTE: Defining an element "**id**" will prevent it from being removed during the optimization phase.
286
+ ### Repo
1335
287
 
1336
- ```html
1337
- <div data-exclude-section="DOM_TRAVERSE | EXTENSION | RENDER | ALL"
1338
- data-exclude-procedure="CONSTRAINT | LAYOUT | ALIGNMENT | ACCESSIBILITY | LOCALIZATION | CUSTOMIZATION | OPTIMIZATION | ALL"
1339
- data-exclude-resource="BOX_STYLE | BOX_SPACING | FONT_STYLE | VALUE_STRING | IMAGE_SOURCE | ASSET | ALL"
1340
- data-exclude-optimization="EXCLUDE | INHERIT | ALIGNMENT | POSITION | DIMENSION | MARGIN | PADDING | BASELINE | WHITESPACE | TRANSLATE | TRANSFORM | SCALING">
1341
- </div>
1342
- <div>
1343
- <span data-exclude-resource="FONT_STYLE">content</span>
1344
- <input id="cb1" type="checkbox" data-exclude-procedure="ACCESSIBILITY"><label for="cb1">checkbox text</label>
1345
- </div>
288
+ ```ruby
289
+ REPO_ROOT # parent dir
290
+ REPO_HOME # project dir (main)
291
+ REPO_BUILD # run,script
292
+ REPO_GROUP # string
293
+ REPO_REF # e.g. ruby,node
294
+ REPO_DEV # pattern,0,1
295
+ REPO_PROD # pattern,0,1
296
+ REPO_WARN # 0,1
297
+ REPO_SYNC # 0,1
298
+ REPO_MANIFEST # e.g. latest,nightly,prod
299
+ REPO_TIMEOUT # confirm dialog (seconds)
1346
300
  ```
1347
301
 
1348
302
  ## LICENSE