alchemymvc 1.3.6 → 1.3.8
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.
- package/lib/app/helper/alchemy_helper.js +12 -6
- package/lib/app/helper/breadcrumb.js +156 -0
- package/lib/app/helper/router_helper.js +115 -31
- package/lib/app/helper_field/boolean_field.js +21 -1
- package/lib/app/helper_field/schema_field.js +3 -5
- package/lib/app/helper_model/model.js +3 -3
- package/lib/class/field.js +30 -0
- package/lib/class/model.js +1 -1
- package/lib/class/path_param_definition.js +36 -2
- package/lib/class/route.js +110 -0
- package/lib/class/router.js +3 -1
- package/lib/core/client_alchemy.js +62 -35
- package/package.json +1 -1
|
@@ -290,16 +290,18 @@ Alchemy.setMethod(function group(name, id, callback) {
|
|
|
290
290
|
/**
|
|
291
291
|
* Print a segment
|
|
292
292
|
*
|
|
293
|
-
* @author Jelle De Loecker <jelle@
|
|
293
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
294
294
|
* @since 0.5.0
|
|
295
|
-
* @version 1.
|
|
295
|
+
* @version 1.3.7
|
|
296
296
|
*
|
|
297
297
|
* @param {String|Object} options
|
|
298
298
|
* @param {Object} data
|
|
299
|
+
*
|
|
300
|
+
* @return {HePlaceholder}
|
|
299
301
|
*/
|
|
300
302
|
Alchemy.setMethod(function segment(options, data) {
|
|
301
303
|
|
|
302
|
-
|
|
304
|
+
const that = this;
|
|
303
305
|
|
|
304
306
|
if (typeof options == 'string') {
|
|
305
307
|
options = {
|
|
@@ -307,10 +309,14 @@ Alchemy.setMethod(function segment(options, data) {
|
|
|
307
309
|
};
|
|
308
310
|
}
|
|
309
311
|
|
|
310
|
-
let
|
|
312
|
+
let print_placeholder = options.print;
|
|
313
|
+
|
|
314
|
+
if (print_placeholder == null) {
|
|
315
|
+
print_placeholder = true;
|
|
316
|
+
}
|
|
311
317
|
|
|
312
318
|
// Prints a placeholder
|
|
313
|
-
this.view.async(function doAsync(next) {
|
|
319
|
+
return this.view.async(function doAsync(next) {
|
|
314
320
|
|
|
315
321
|
var conduit,
|
|
316
322
|
route;
|
|
@@ -354,7 +360,7 @@ Alchemy.setMethod(function segment(options, data) {
|
|
|
354
360
|
|
|
355
361
|
next(null, block);
|
|
356
362
|
});
|
|
357
|
-
});
|
|
363
|
+
}, {print: print_placeholder});
|
|
358
364
|
});
|
|
359
365
|
|
|
360
366
|
/**
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Breadcrumb class
|
|
3
|
+
*
|
|
4
|
+
* @constructor
|
|
5
|
+
*
|
|
6
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
7
|
+
* @since 1.3.8
|
|
8
|
+
* @version 1.3.8
|
|
9
|
+
*
|
|
10
|
+
* @param {String} input
|
|
11
|
+
*/
|
|
12
|
+
const Breadcrumb = Function.inherits('Alchemy.Base', function Breadcrumb(input) {
|
|
13
|
+
|
|
14
|
+
this.trails = [];
|
|
15
|
+
|
|
16
|
+
if (input) {
|
|
17
|
+
this.addTrail(input);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get the number of trails
|
|
23
|
+
*
|
|
24
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
25
|
+
* @since 1.3.8
|
|
26
|
+
* @version 1.3.8
|
|
27
|
+
*
|
|
28
|
+
* @return {Number}
|
|
29
|
+
*/
|
|
30
|
+
Breadcrumb.setProperty(function length() {
|
|
31
|
+
return this.trails.length;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Add a breadcrumb trail
|
|
36
|
+
*
|
|
37
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
38
|
+
* @since 1.3.8
|
|
39
|
+
* @version 1.3.8
|
|
40
|
+
*
|
|
41
|
+
* @param {String} input
|
|
42
|
+
*/
|
|
43
|
+
Breadcrumb.setMethod(function addTrail(input) {
|
|
44
|
+
|
|
45
|
+
let trails;
|
|
46
|
+
|
|
47
|
+
if (!input) {
|
|
48
|
+
input = '';
|
|
49
|
+
} else if (typeof input == 'object') {
|
|
50
|
+
if (input instanceof Breadcrumb) {
|
|
51
|
+
trails = input.trails;
|
|
52
|
+
} else if (input.nodeType === 1) {
|
|
53
|
+
// Simple way to see if it's an HTMLElement
|
|
54
|
+
|
|
55
|
+
let element = input;
|
|
56
|
+
input = '';
|
|
57
|
+
|
|
58
|
+
let crumb = element.getAttribute('data-breadcrumb');
|
|
59
|
+
|
|
60
|
+
if (crumb) {
|
|
61
|
+
input = crumb;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
crumb = element.getAttribute('data-breadcrumbs');
|
|
65
|
+
|
|
66
|
+
if (crumb) {
|
|
67
|
+
input += ' ' + crumb;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!trails) {
|
|
73
|
+
// Split the string why whitespaces
|
|
74
|
+
trails = input.trim().split(/\s+|\|+/);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (trails?.length) {
|
|
78
|
+
for (let trail of trails) {
|
|
79
|
+
|
|
80
|
+
if (!trail) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// The trail has to end with a dot
|
|
85
|
+
if (!trail.endsWith('.')) {
|
|
86
|
+
trail += '.';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.trails.push(trail);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Do these 2 breadcrumbs match loosely?
|
|
96
|
+
*
|
|
97
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
98
|
+
* @since 1.3.8
|
|
99
|
+
* @version 1.3.8
|
|
100
|
+
*
|
|
101
|
+
* @param {Alchemy.Breadcrumb} other
|
|
102
|
+
*/
|
|
103
|
+
Breadcrumb.setMethod(function matches(other) {
|
|
104
|
+
return this.matchLevel(other) > 0;
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* What leven of match is there between these 2 breadcrumbs?
|
|
109
|
+
*
|
|
110
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
111
|
+
* @since 1.3.8
|
|
112
|
+
* @version 1.3.8
|
|
113
|
+
*
|
|
114
|
+
* @param {Alchemy.Breadcrumb} other
|
|
115
|
+
*
|
|
116
|
+
* @return {Number} 1 for a strict match, 2 for a loose match
|
|
117
|
+
*/
|
|
118
|
+
Breadcrumb.setMethod(function matchLevel(other) {
|
|
119
|
+
|
|
120
|
+
if (!other || !this.trails.length) {
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!(other instanceof Breadcrumb)) {
|
|
125
|
+
other = new Breadcrumb(other);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
let their_trail,
|
|
129
|
+
our_trail;
|
|
130
|
+
|
|
131
|
+
for (our_trail of this.trails) {
|
|
132
|
+
for (their_trail of other.trails) {
|
|
133
|
+
// Strict matches are always true
|
|
134
|
+
if (our_trail == their_trail) {
|
|
135
|
+
return 1;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (our_trail.startsWith(their_trail)) {
|
|
139
|
+
return 2;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return 0;
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Turn it into a string
|
|
149
|
+
*
|
|
150
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
151
|
+
* @since 1.3.8
|
|
152
|
+
* @version 1.3.8
|
|
153
|
+
*/
|
|
154
|
+
Breadcrumb.setMethod(function toString() {
|
|
155
|
+
return this.trails.join(' ');
|
|
156
|
+
});
|
|
@@ -147,14 +147,24 @@ Router.setMethod(function applyDirective(element, name, options) {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
let breadcrumb = config.breadcrumb;
|
|
151
|
+
|
|
152
|
+
if (options.breadcrumb) {
|
|
153
|
+
if (!breadcrumb) {
|
|
154
|
+
breadcrumb = options.breadcrumb;
|
|
155
|
+
} else {
|
|
156
|
+
breadcrumb += ' ' + options.breadcrumb;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (config.breadcrumb || options.breadcrumb) {
|
|
161
|
+
let link_breadcrumb = this.getTrail(name, {...params}, options);
|
|
152
162
|
element.setAttribute('data-breadcrumb', link_breadcrumb);
|
|
153
163
|
|
|
154
164
|
if (this.renderer && link_breadcrumb) {
|
|
155
|
-
let page_breadcrumb = this.renderer.internal('breadcrumb');
|
|
165
|
+
let page_breadcrumb = new Classes.Alchemy.Breadcrumb(this.renderer.internal('breadcrumb'));
|
|
156
166
|
|
|
157
|
-
if (page_breadcrumb
|
|
167
|
+
if (page_breadcrumb.matches(link_breadcrumb)) {
|
|
158
168
|
|
|
159
169
|
if (element.parentElement) {
|
|
160
170
|
// @TODO: We need to make sure the options (classnames & such)
|
|
@@ -223,7 +233,7 @@ Router.setMethod(function applyDirective(element, name, options) {
|
|
|
223
233
|
*
|
|
224
234
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
225
235
|
* @since 0.2.0
|
|
226
|
-
* @version 1.3.
|
|
236
|
+
* @version 1.3.7
|
|
227
237
|
*
|
|
228
238
|
* @param {String} name
|
|
229
239
|
* @param {Boolean} socket_route Look in the socket routes
|
|
@@ -288,22 +298,17 @@ Router.setMethod(function routeConfig(name, socket_route) {
|
|
|
288
298
|
if (routes[section] != null && routes[section][name] != null) {
|
|
289
299
|
let route = routes[section][name];
|
|
290
300
|
|
|
291
|
-
let result
|
|
292
|
-
section : section,
|
|
293
|
-
name : name
|
|
294
|
-
};
|
|
301
|
+
let result;
|
|
295
302
|
|
|
296
303
|
if (socket_route) {
|
|
297
|
-
result
|
|
304
|
+
result = {
|
|
305
|
+
section : section,
|
|
306
|
+
name : name,
|
|
307
|
+
socket_route : true,
|
|
308
|
+
};
|
|
298
309
|
} else {
|
|
310
|
+
result = Object.create(route);
|
|
299
311
|
result.socket_route = false;
|
|
300
|
-
result.paths = route.paths;
|
|
301
|
-
result.breadcrumb = route.breadcrumb;
|
|
302
|
-
result.has_breadcrumb_assignments = route.has_breadcrumb_assignments;
|
|
303
|
-
result.keys = route.keys;
|
|
304
|
-
result.methods = route.methods;
|
|
305
|
-
result.permission = route.permission;
|
|
306
|
-
result.has_permission_assignments = route.has_permission_assignments;
|
|
307
312
|
}
|
|
308
313
|
|
|
309
314
|
let router_options;
|
|
@@ -329,9 +334,9 @@ Router.setMethod(function routeConfig(name, socket_route) {
|
|
|
329
334
|
/**
|
|
330
335
|
* Return the plain url for the given url name & parameters object
|
|
331
336
|
*
|
|
332
|
-
* @author Jelle De Loecker <jelle@
|
|
337
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
333
338
|
* @since 0.2.0
|
|
334
|
-
* @version 1.3.
|
|
339
|
+
* @version 1.3.7
|
|
335
340
|
*
|
|
336
341
|
* @param {String} name
|
|
337
342
|
* @param {Object} parameters
|
|
@@ -392,6 +397,33 @@ Router.setMethod(function routeUrl(name, parameters, options) {
|
|
|
392
397
|
return '#url_config_' + name + '_notfound';
|
|
393
398
|
}
|
|
394
399
|
|
|
400
|
+
if (config.param_definitions) {
|
|
401
|
+
|
|
402
|
+
let documents = {},
|
|
403
|
+
definition,
|
|
404
|
+
key;
|
|
405
|
+
|
|
406
|
+
for (key in config.param_definitions) {
|
|
407
|
+
definition = config.param_definitions[key];
|
|
408
|
+
|
|
409
|
+
// If this definition has a specific model name,
|
|
410
|
+
// try to get it from the parameters (and also remove it from there)
|
|
411
|
+
if (definition.type_class_name) {
|
|
412
|
+
if (!documents[definition.type_class_name]) {
|
|
413
|
+
documents[definition.type_class_name] = parameters[definition.type_class_name];
|
|
414
|
+
|
|
415
|
+
if (documents[definition.type_class_name]) {
|
|
416
|
+
delete parameters[definition.type_class_name];
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (!parameters[definition.name] && documents[definition.type_class_name]) {
|
|
422
|
+
parameters[definition.name] = documents[definition.type_class_name][definition.type_field_name];
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
395
427
|
// Remove [brackets]
|
|
396
428
|
url = url.replace(/\[.*?\]/g, '');
|
|
397
429
|
url = url.assign(parameters, true, RURL.encodeUriQuery);
|
|
@@ -470,28 +502,72 @@ Router.setMethod(function routeUrl(name, parameters, options) {
|
|
|
470
502
|
*
|
|
471
503
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
472
504
|
* @since 0.3.0
|
|
473
|
-
* @version
|
|
505
|
+
* @version 1.3.8
|
|
474
506
|
*
|
|
475
507
|
* @param {String} name
|
|
476
508
|
* @param {Object} parameters
|
|
509
|
+
* @param {Object} options
|
|
477
510
|
*
|
|
478
|
-
* @return {
|
|
511
|
+
* @return {Alchemy.Breadcrumb}
|
|
479
512
|
*/
|
|
480
|
-
Router.setMethod(function getTrail(name, parameters) {
|
|
513
|
+
Router.setMethod(function getTrail(name, parameters, options) {
|
|
481
514
|
|
|
482
|
-
|
|
515
|
+
let can_have_assignments,
|
|
516
|
+
trails = [],
|
|
483
517
|
config;
|
|
518
|
+
|
|
519
|
+
if (options?.breadcrumb) {
|
|
520
|
+
can_have_assignments = true;
|
|
521
|
+
trails.push(options.breadcrumb);
|
|
522
|
+
}
|
|
484
523
|
|
|
485
524
|
config = this.routeConfig(name);
|
|
486
525
|
|
|
487
|
-
if (!config || !config.breadcrumb) {
|
|
526
|
+
if (!trails.length && (!config || !config.breadcrumb)) {
|
|
488
527
|
return;
|
|
489
528
|
}
|
|
490
529
|
|
|
491
|
-
breadcrumb =
|
|
530
|
+
let breadcrumb = new Classes.Alchemy.Breadcrumb();
|
|
531
|
+
|
|
532
|
+
if (config?.breadcrumb) {
|
|
533
|
+
trails.push(config.breadcrumb);
|
|
534
|
+
}
|
|
492
535
|
|
|
493
|
-
if (
|
|
494
|
-
|
|
536
|
+
if (!can_have_assignments) {
|
|
537
|
+
can_have_assignments = config?.has_breadcrumb_assignments;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (can_have_assignments) {
|
|
541
|
+
let key;
|
|
542
|
+
parameters = {...parameters};
|
|
543
|
+
|
|
544
|
+
for (key in parameters) {
|
|
545
|
+
if (key[0] == key[0].toUpperCase()) {
|
|
546
|
+
let value = parameters[key];
|
|
547
|
+
|
|
548
|
+
if (value && typeof value == 'object') {
|
|
549
|
+
let subkey;
|
|
550
|
+
|
|
551
|
+
let context = value?.$main || value;
|
|
552
|
+
|
|
553
|
+
for (subkey in context) {
|
|
554
|
+
if (parameters[subkey] == null) {
|
|
555
|
+
parameters[subkey] = context[subkey];
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
let trail;
|
|
564
|
+
|
|
565
|
+
for (trail of trails) {
|
|
566
|
+
if (can_have_assignments) {
|
|
567
|
+
trail = Blast.Bound.String.assign(trail, parameters).toLowerCase();
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
breadcrumb.addTrail(trail);
|
|
495
571
|
}
|
|
496
572
|
|
|
497
573
|
return breadcrumb;
|
|
@@ -505,9 +581,6 @@ Router.setMethod(function getTrail(name, parameters) {
|
|
|
505
581
|
* @version 0.3.0
|
|
506
582
|
*/
|
|
507
583
|
Router.setMethod(function printBreadcrumb() {
|
|
508
|
-
|
|
509
|
-
var that = this;
|
|
510
|
-
|
|
511
584
|
this.view.print_partial('breadcrumb/wrapper');
|
|
512
585
|
});
|
|
513
586
|
|
|
@@ -717,7 +790,7 @@ Router.setMethod(function updateLanguageSwitcher(element, variables) {
|
|
|
717
790
|
*
|
|
718
791
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
719
792
|
* @since 1.2.5
|
|
720
|
-
* @version 1.3.
|
|
793
|
+
* @version 1.3.8
|
|
721
794
|
*
|
|
722
795
|
* @param {String} prefix The prefix to use
|
|
723
796
|
* @param {Object} variables
|
|
@@ -739,6 +812,15 @@ Router.setMethod(function translateCurrentRoute(prefix, variables) {
|
|
|
739
812
|
return;
|
|
740
813
|
}
|
|
741
814
|
|
|
815
|
+
// Don't just translate the last rendered route, make sure it's the current one
|
|
816
|
+
if (info.url && Blast.isBrowser) {
|
|
817
|
+
let url = RURL.parse(info.url);
|
|
818
|
+
|
|
819
|
+
if (url && !url.matchesPath(window.location)) {
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
742
824
|
let config = this.routeConfig(info.route);
|
|
743
825
|
|
|
744
826
|
if (!config) {
|
|
@@ -762,6 +844,8 @@ Router.setMethod(function translateCurrentRoute(prefix, variables) {
|
|
|
762
844
|
|
|
763
845
|
// Add the get queries
|
|
764
846
|
if (info.url && info.url.search) {
|
|
847
|
+
let key;
|
|
848
|
+
|
|
765
849
|
for (key in info.url.query) {
|
|
766
850
|
|
|
767
851
|
if (key == 'hajax' || key == 'h_diversion' || key == 'htop') {
|
|
@@ -33,4 +33,24 @@ BooleanField.setDatatype('boolean');
|
|
|
33
33
|
*/
|
|
34
34
|
BooleanField.setMethod(function cast(value) {
|
|
35
35
|
return Boolean(value);
|
|
36
|
-
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* See if the given vlaue is considered not-empty for this field
|
|
40
|
+
*
|
|
41
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
42
|
+
* @since 1.3.7
|
|
43
|
+
* @version 1.3.7
|
|
44
|
+
*
|
|
45
|
+
* @param {Mixed} value
|
|
46
|
+
*
|
|
47
|
+
* @return {Boolean}
|
|
48
|
+
*/
|
|
49
|
+
BooleanField.setMethod(function valueHasContent(value) {
|
|
50
|
+
|
|
51
|
+
if (value === undefined) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return true;
|
|
56
|
+
});
|
|
@@ -89,13 +89,11 @@ SchemaField.setProperty(function requires_translating() {
|
|
|
89
89
|
/**
|
|
90
90
|
* Get the subschema of this field
|
|
91
91
|
*
|
|
92
|
-
* @
|
|
93
|
-
*
|
|
94
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
92
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
95
93
|
* @since 0.2.0
|
|
96
|
-
* @version 1.3.
|
|
94
|
+
* @version 1.3.7
|
|
97
95
|
*
|
|
98
|
-
* @param {Object} record
|
|
96
|
+
* @param {Object} record This *should* be the schema context (might not be the root)
|
|
99
97
|
* @param {String} some_path Some path to a field in the wanted schema
|
|
100
98
|
*
|
|
101
99
|
* @return {Schema}
|
|
@@ -597,9 +597,9 @@ Model.setMethod(function getAliasModel(alias) {
|
|
|
597
597
|
/**
|
|
598
598
|
* Query the database
|
|
599
599
|
*
|
|
600
|
-
* @author Jelle De Loecker <jelle@
|
|
600
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
601
601
|
* @since 0.0.1
|
|
602
|
-
* @version 1.3.
|
|
602
|
+
* @version 1.3.8
|
|
603
603
|
*
|
|
604
604
|
* @param {String} type The type of find (first, all)
|
|
605
605
|
* @param {Criteria} criteria The criteria object
|
|
@@ -660,7 +660,7 @@ Model.setMethod(function find(type, criteria, callback) {
|
|
|
660
660
|
}
|
|
661
661
|
|
|
662
662
|
if (!criteria.options.locale && this.conduit) {
|
|
663
|
-
criteria.setOption('locale', this.conduit.
|
|
663
|
+
criteria.setOption('locale', this.conduit.active_prefix);
|
|
664
664
|
}
|
|
665
665
|
|
|
666
666
|
let that = this,
|
package/lib/class/field.js
CHANGED
|
@@ -1078,6 +1078,36 @@ Field.setMethod(function getRules() {
|
|
|
1078
1078
|
return result;
|
|
1079
1079
|
});
|
|
1080
1080
|
|
|
1081
|
+
/**
|
|
1082
|
+
* See if the given vlaue is considered not-empty for this field
|
|
1083
|
+
*
|
|
1084
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1085
|
+
* @since 1.3.7
|
|
1086
|
+
* @version 1.3.7
|
|
1087
|
+
*
|
|
1088
|
+
* @param {Mixed} value
|
|
1089
|
+
*
|
|
1090
|
+
* @return {Boolean}
|
|
1091
|
+
*/
|
|
1092
|
+
Field.setMethod(function valueHasContent(value) {
|
|
1093
|
+
|
|
1094
|
+
if (value == null) {
|
|
1095
|
+
return false;
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
if (value === '') {
|
|
1099
|
+
return false;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
if (Array.isArray(value)) {
|
|
1103
|
+
if (value.length === 0) {
|
|
1104
|
+
return false;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
return true;
|
|
1109
|
+
});
|
|
1110
|
+
|
|
1081
1111
|
/**
|
|
1082
1112
|
* Translate the given value
|
|
1083
1113
|
*
|
package/lib/class/model.js
CHANGED
|
@@ -5,7 +5,7 @@ const PathDefinition = Classes.Alchemy.PathDefinition;
|
|
|
5
5
|
*
|
|
6
6
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
7
7
|
* @since 1.3.0
|
|
8
|
-
* @version 1.3.
|
|
8
|
+
* @version 1.3.7
|
|
9
9
|
*/
|
|
10
10
|
const PathParamDefinition = Function.inherits('Alchemy.Base', function PathParamDefinition(config) {
|
|
11
11
|
|
|
@@ -41,6 +41,9 @@ const PathParamDefinition = Function.inherits('Alchemy.Base', function PathParam
|
|
|
41
41
|
// The optional type class constructor
|
|
42
42
|
this.type_class_constructor = null;
|
|
43
43
|
|
|
44
|
+
// Is this a model type?
|
|
45
|
+
this.is_model_type = false;
|
|
46
|
+
|
|
44
47
|
// Has all the config been parsed?
|
|
45
48
|
this.is_parsed = false;
|
|
46
49
|
});
|
|
@@ -79,6 +82,30 @@ PathParamDefinition.setStatic(function from(input) {
|
|
|
79
82
|
return new this(input);
|
|
80
83
|
});
|
|
81
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Get the model constructor
|
|
87
|
+
*
|
|
88
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
89
|
+
* @since 1.3.7
|
|
90
|
+
* @version 1.3.7
|
|
91
|
+
*/
|
|
92
|
+
PathParamDefinition.enforceProperty(function model_constructor(new_value) {
|
|
93
|
+
|
|
94
|
+
if (!this.is_parsed) {
|
|
95
|
+
this.parseTypeDefinition();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!new_value) {
|
|
99
|
+
const constructor = this.type_class_constructor;
|
|
100
|
+
|
|
101
|
+
if (constructor && this.is_model_type) {
|
|
102
|
+
new_value = constructor;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return new_value;
|
|
107
|
+
});
|
|
108
|
+
|
|
82
109
|
/**
|
|
83
110
|
* Parse the type definition
|
|
84
111
|
*
|
|
@@ -131,7 +158,14 @@ PathParamDefinition.setMethod(function parseTypeDefinition() {
|
|
|
131
158
|
this.type_field_name = field_name;
|
|
132
159
|
|
|
133
160
|
const Model = Classes.Alchemy.Model || Classes.Alchemy.Client.Model;
|
|
134
|
-
|
|
161
|
+
|
|
162
|
+
this.type_class_constructor = Object.path(Model, class_name);
|
|
163
|
+
|
|
164
|
+
if (this.type_class_constructor) {
|
|
165
|
+
this.is_model_type = true;
|
|
166
|
+
} else {
|
|
167
|
+
this.type_class_constructor = Object.path(Classes.Alchemy, class_name) || Object.path(Classes, class_name);
|
|
168
|
+
}
|
|
135
169
|
}
|
|
136
170
|
});
|
|
137
171
|
|
package/lib/class/route.js
CHANGED
|
@@ -129,6 +129,116 @@ Route.setProperty(function has_type_class_checks() {
|
|
|
129
129
|
return result;
|
|
130
130
|
});
|
|
131
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Routes with parameters can have schemas
|
|
134
|
+
*
|
|
135
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
136
|
+
* @since 1.3.7
|
|
137
|
+
* @version 1.3.7
|
|
138
|
+
*
|
|
139
|
+
* @return {Schema}
|
|
140
|
+
*/
|
|
141
|
+
Route.enforceProperty(function schema(new_value) {
|
|
142
|
+
|
|
143
|
+
if (new_value) {
|
|
144
|
+
return new_value;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!this.has_path_assignments) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let added_models = {},
|
|
152
|
+
added_fields = {},
|
|
153
|
+
prefix,
|
|
154
|
+
param,
|
|
155
|
+
model_constructor,
|
|
156
|
+
definition;
|
|
157
|
+
|
|
158
|
+
new_value = alchemy.createSchema();
|
|
159
|
+
|
|
160
|
+
for (prefix in this.paths) {
|
|
161
|
+
definition = this.paths[prefix];
|
|
162
|
+
|
|
163
|
+
if (!definition?.param_definitions?.length) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for (param of definition.param_definitions) {
|
|
168
|
+
model_constructor = param.model_constructor;
|
|
169
|
+
|
|
170
|
+
if (model_constructor) {
|
|
171
|
+
|
|
172
|
+
if (added_models[model_constructor.name]) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (added_fields[param.name]) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
added_models[model_constructor.name] = true;
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
new_value.belongsTo(model_constructor.name);
|
|
184
|
+
} catch (err) {
|
|
185
|
+
// Ignored
|
|
186
|
+
alchemy.distinctProblem('route-schema-' + this.name, 'Route schema error', {error: err});
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
new_value.addField(param.name, 'String');
|
|
190
|
+
added_fields[param.name] = true;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return new_value;
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Get all the param definitions
|
|
200
|
+
*
|
|
201
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
202
|
+
* @since 1.3.7
|
|
203
|
+
* @version 1.3.7
|
|
204
|
+
*
|
|
205
|
+
* @return {Object}
|
|
206
|
+
*/
|
|
207
|
+
Route.enforceProperty(function param_definitions(new_value) {
|
|
208
|
+
|
|
209
|
+
if (new_value) {
|
|
210
|
+
return new_value;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let prefix,
|
|
214
|
+
param,
|
|
215
|
+
key,
|
|
216
|
+
definition;
|
|
217
|
+
|
|
218
|
+
new_value = {};
|
|
219
|
+
|
|
220
|
+
for (prefix in this.paths) {
|
|
221
|
+
definition = this.paths[prefix];
|
|
222
|
+
|
|
223
|
+
if (!definition.param_definitions?.length) {
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
for (param of definition.param_definitions) {
|
|
228
|
+
key = prefix + '_' + param.name;
|
|
229
|
+
|
|
230
|
+
new_value[key] = {
|
|
231
|
+
name : param.name,
|
|
232
|
+
type_class_name : param.type_class_name,
|
|
233
|
+
type_field_name : param.type_field_name,
|
|
234
|
+
is_model_type : param.is_model_type,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return new_value;
|
|
240
|
+
});
|
|
241
|
+
|
|
132
242
|
/**
|
|
133
243
|
* Set the breadcrumb for this route
|
|
134
244
|
*
|
package/lib/class/router.js
CHANGED
|
@@ -1163,7 +1163,7 @@ RouterClass.setMethod(function getOptions(result) {
|
|
|
1163
1163
|
*
|
|
1164
1164
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1165
1165
|
* @since 0.2.0
|
|
1166
|
-
* @version 1.3.
|
|
1166
|
+
* @version 1.3.7
|
|
1167
1167
|
*
|
|
1168
1168
|
* @param {Object} result Optional object to store sectioned results in
|
|
1169
1169
|
*
|
|
@@ -1212,6 +1212,8 @@ RouterClass.setMethod(function getRoutes(result) {
|
|
|
1212
1212
|
has_permission_assignments : route.has_permission_assignments || undefined,
|
|
1213
1213
|
title : route.title,
|
|
1214
1214
|
visible_location : route.visible_location,
|
|
1215
|
+
schema : route.schema,
|
|
1216
|
+
param_definitions : route.param_definitions,
|
|
1215
1217
|
};
|
|
1216
1218
|
}
|
|
1217
1219
|
|
|
@@ -519,6 +519,59 @@ Alchemy.setMethod(function routeConfig(name) {
|
|
|
519
519
|
|
|
520
520
|
const markLinkElement = Alchemy.prototype.markLinkElement;
|
|
521
521
|
|
|
522
|
+
/**
|
|
523
|
+
* Get a live map of all the routes
|
|
524
|
+
*
|
|
525
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
526
|
+
* @since 1.3.8
|
|
527
|
+
* @version 1.3.8
|
|
528
|
+
*
|
|
529
|
+
* @return {Develry.BackedMap}
|
|
530
|
+
*/
|
|
531
|
+
Alchemy.setMethod(function getRoutes() {
|
|
532
|
+
return new Classes.Develry.BackedMap(getRoutesDict);
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* The live-map dictionary creator
|
|
537
|
+
*
|
|
538
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
539
|
+
* @since 1.3.8
|
|
540
|
+
* @version 1.3.8
|
|
541
|
+
*
|
|
542
|
+
* @return {Object}
|
|
543
|
+
*/
|
|
544
|
+
function getRoutesDict() {
|
|
545
|
+
let routes;
|
|
546
|
+
|
|
547
|
+
if (Blast.isNode) {
|
|
548
|
+
routes = {};
|
|
549
|
+
|
|
550
|
+
let roots = Router.getRoutes();
|
|
551
|
+
|
|
552
|
+
for (let key in roots) {
|
|
553
|
+
let root = roots[key];
|
|
554
|
+
|
|
555
|
+
for (let name in root) {
|
|
556
|
+
routes[name] = root[name];
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
} else {
|
|
561
|
+
routes = {};
|
|
562
|
+
|
|
563
|
+
for (let root in hawkejs.scene.exposed.routes) {
|
|
564
|
+
let section = hawkejs.scene.exposed.routes[root];
|
|
565
|
+
|
|
566
|
+
for (let key in section) {
|
|
567
|
+
routes[key] = section[key];
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return routes;
|
|
573
|
+
}
|
|
574
|
+
|
|
522
575
|
// From here on, only client-side code is added
|
|
523
576
|
if (Blast.isBrowser) {
|
|
524
577
|
window.alchemy = new Alchemy();
|
|
@@ -582,21 +635,18 @@ Alchemy.setMethod(function linkup(type, data, cb) {
|
|
|
582
635
|
*
|
|
583
636
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
584
637
|
* @since 0.3.0
|
|
585
|
-
* @version 1.3.
|
|
638
|
+
* @version 1.3.8
|
|
586
639
|
*
|
|
587
640
|
* @param {Object} variables
|
|
588
641
|
* @param {Object} render_data
|
|
589
642
|
*/
|
|
590
643
|
Alchemy.setMethod(function markLinks(variables, render_data) {
|
|
591
644
|
|
|
592
|
-
|
|
593
|
-
el_breadcrumbs,
|
|
594
|
-
el_breadcrumb,
|
|
645
|
+
let page_breadcrumb,
|
|
595
646
|
placeholder,
|
|
596
647
|
href_val,
|
|
597
648
|
elements,
|
|
598
649
|
element,
|
|
599
|
-
temp,
|
|
600
650
|
url,
|
|
601
651
|
i;
|
|
602
652
|
|
|
@@ -607,7 +657,7 @@ Alchemy.setMethod(function markLinks(variables, render_data) {
|
|
|
607
657
|
}
|
|
608
658
|
|
|
609
659
|
// Get the newly set breadcrumb
|
|
610
|
-
page_breadcrumb = variables.__breadcrumb;
|
|
660
|
+
page_breadcrumb = new Classes.Alchemy.Breadcrumb(variables.__breadcrumb);
|
|
611
661
|
|
|
612
662
|
// Get all the language switcher anchors
|
|
613
663
|
elements = document.querySelectorAll('[data-alchemy-language-switch]');
|
|
@@ -621,30 +671,7 @@ Alchemy.setMethod(function markLinks(variables, render_data) {
|
|
|
621
671
|
|
|
622
672
|
for (i = 0; i < elements.length; i++) {
|
|
623
673
|
element = elements[i];
|
|
624
|
-
|
|
625
|
-
// Create the breadcrumbs array
|
|
626
|
-
el_breadcrumbs = [];
|
|
627
|
-
|
|
628
|
-
// Get the element's set breadcrumb
|
|
629
|
-
el_breadcrumb = element.getAttribute('data-breadcrumb');
|
|
630
|
-
|
|
631
|
-
if (el_breadcrumb) {
|
|
632
|
-
el_breadcrumbs.push(el_breadcrumb);
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
el_breadcrumb = element.getAttribute('data-breadcrumbs');
|
|
636
|
-
|
|
637
|
-
if (el_breadcrumb) {
|
|
638
|
-
el_breadcrumbs.include(el_breadcrumb.split('|'));
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
if (el_breadcrumbs.indexOf(page_breadcrumb) > -1) {
|
|
642
|
-
markLinkElement(element, 1);
|
|
643
|
-
} else if (page_breadcrumb && page_breadcrumb.startsWithAny(el_breadcrumbs)) {
|
|
644
|
-
markLinkElement(element, 2);
|
|
645
|
-
} else {
|
|
646
|
-
markLinkElement(element, false);
|
|
647
|
-
}
|
|
674
|
+
markLinkElement(element, page_breadcrumb.matchLevel(element));
|
|
648
675
|
}
|
|
649
676
|
|
|
650
677
|
// Get all anchors without breadcrumbs
|
|
@@ -702,9 +729,9 @@ Alchemy.setMethod(function markLinks(variables, render_data) {
|
|
|
702
729
|
/**
|
|
703
730
|
* Reload all stylesheets
|
|
704
731
|
*
|
|
705
|
-
* @author Jelle De Loecker <jelle@
|
|
732
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
706
733
|
* @since 1.0.0
|
|
707
|
-
* @version 1.
|
|
734
|
+
* @version 1.3.8
|
|
708
735
|
*/
|
|
709
736
|
Alchemy.setMethod(function reloadStylesheets() {
|
|
710
737
|
|
|
@@ -718,15 +745,15 @@ Alchemy.setMethod(function reloadStylesheets() {
|
|
|
718
745
|
let url = new RURL(sheet.href);
|
|
719
746
|
url.param('last_reload', Date.now());
|
|
720
747
|
|
|
721
|
-
//sheet.ownerNode.href = String(url);
|
|
722
|
-
|
|
723
748
|
let new_element = alchemy.hawkejs.createElement('link');
|
|
724
749
|
new_element.setAttribute('rel', 'stylesheet');
|
|
725
750
|
new_element.setAttribute('href', String(url));
|
|
726
751
|
document.head.append(new_element);
|
|
727
752
|
|
|
728
753
|
new_element.addEventListener('load', e => {
|
|
729
|
-
sheet.ownerNode
|
|
754
|
+
if (sheet.ownerNode) {
|
|
755
|
+
sheet.ownerNode.remove();
|
|
756
|
+
}
|
|
730
757
|
});
|
|
731
758
|
}
|
|
732
759
|
});
|