clickgo 3.9.1 → 3.10.0

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/README.md CHANGED
@@ -28,7 +28,7 @@ Load the module loader first, and then load it using the module loader.
28
28
  **index.html**
29
29
 
30
30
  ```html
31
- <script src="https://cdn.jsdelivr.net/npm/@litert/loader@3.5.0/dist/loader.min.js?path=index&npm={'clickgo':'3.9.1'}"></script>
31
+ <script src="https://cdn.jsdelivr.net/npm/@litert/loader@3.5.0/dist/loader.min.js?path=index&npm={'clickgo':'3.10.0'}"></script>
32
32
  ```
33
33
 
34
34
  **index.js**
@@ -31,6 +31,7 @@ class default_1 extends clickgo.form.AbstractForm {
31
31
  this.multi = 'false';
32
32
  this.dir = 'false';
33
33
  this.list = [];
34
+ this.fd = new FormData();
34
35
  }
35
36
  select() {
36
37
  this.refs.file.select();
@@ -42,6 +43,7 @@ class default_1 extends clickgo.form.AbstractForm {
42
43
  }
43
44
  for (const file of files) {
44
45
  this.list.push((file.webkitRelativePath || file.name) + ' (' + file.size.toString() + ')');
46
+ this.fd.append('file', file, file.name);
45
47
  }
46
48
  }
47
49
  }
@@ -235,5 +235,34 @@ class default_1 extends clickgo.form.AbstractForm {
235
235
  yield clickgo.form.dialog('onGesture: ' + dir);
236
236
  });
237
237
  }
238
+ onGAdd(e) {
239
+ clickgo.form.notify({
240
+ 'type': 'info',
241
+ 'title': 'Greatlist @add',
242
+ 'content': 'value: ' + e.detail.value.toString()
243
+ });
244
+ }
245
+ onGRemove(e) {
246
+ clickgo.form.notify({
247
+ 'type': 'info',
248
+ 'title': 'Greatlist @remove',
249
+ 'content': 'value: ' + e.detail.value.toString()
250
+ });
251
+ }
252
+ onLAdd(e) {
253
+ console.log('x', e.detail);
254
+ clickgo.form.notify({
255
+ 'type': 'info',
256
+ 'title': 'List @add',
257
+ 'content': 'value: ' + e.detail.value
258
+ });
259
+ }
260
+ onLRemove(e) {
261
+ clickgo.form.notify({
262
+ 'type': 'info',
263
+ 'title': 'List @remove',
264
+ 'content': 'value: ' + e.detail.value
265
+ });
266
+ }
238
267
  }
239
268
  exports.default = default_1;
@@ -3,7 +3,7 @@
3
3
  <tab v-model="ntab" :tabs="['greatlist', 'adaptation', 'beyond', 'list', 'object', 'async']" style="flex: 1; height: 0;">
4
4
  <!-- 默认 -->
5
5
  <layout v-if="ntab === 'greatlist'" direction="v" style="flex: 1; width: 0; padding: 10px;">
6
- <greatlist v-model="select" :data="slist" :disabled="disabled" :must="must" :multi="multi" :ctrl="ctrl" :selection="selection" :gesture="gesture ? ['top', 'bottom'] : []" @gesture="onGesture" :scroll="scroll" :sizes="sizes" @select="onSelect" style="line-height: 1.3; flex: 1; height: 0;">
6
+ <greatlist v-model="select" :data="slist" :disabled="disabled" :must="must" :multi="multi" :ctrl="ctrl" :selection="selection" :gesture="gesture ? ['top', 'bottom'] : []" @gesture="onGesture" @add="onGAdd" @Remove="onGRemove" :scroll="scroll" :sizes="sizes" @select="onSelect" style="line-height: 1.3; flex: 1; height: 0;">
7
7
  <template v-slot="data">
8
8
  <layout v-if="data.row.type === 0" align-v="center" gutter="5" style="flex: 1;">
9
9
  <img :src="data.row.src" style="width: 32px; height: 32px;"></img>
@@ -51,7 +51,7 @@
51
51
  <label>Raw data:</label>
52
52
  <flow direction="v" style="border: solid 1px #b3b3b3; line-height: 1.5; height: 50px; padding: 5px;">{{listData}}</flow>
53
53
  <layout gutter="10" style="flex: 1; height: 0;">
54
- <list v-model="select2" :disabled="disabled" :must="must" :multi="multi" :ctrl="ctrl" :selection="selection" :gesture="gesture ? ['top', 'bottom'] : []" @gesture="onGesture" :scroll="scroll" :data="listData" @label="label2 = $event" style="flex: 2; width: 0;" :tree="tree" :async="async" :icon="icon" icon-default="../../../res/txt.svg" @load="onSelectLoad">
54
+ <list v-model="select2" :disabled="disabled" :must="must" :multi="multi" :ctrl="ctrl" :selection="selection" :gesture="gesture ? ['top', 'bottom'] : []" @gesture="onGesture" :scroll="scroll" :data="listData" @label="label2 = $event" style="flex: 2; width: 0;" :tree="tree" :async="async" :icon="icon" icon-default="../../../res/txt.svg" @load="onSelectLoad" @add="onLAdd" @Remove="onLRemove">
55
55
  <menulist>
56
56
  <menulist-item alt="I" @click="showIndex2">Show select</menulist-item>
57
57
  </menulist>
@@ -153,11 +153,7 @@ class default_1 extends clickgo.form.AbstractForm {
153
153
  onRemote(value, resolve) {
154
154
  return __awaiter(this, void 0, void 0, function* () {
155
155
  yield clickgo.tool.sleep(300);
156
- if (value === '') {
157
- resolve(['1', '3', '5']);
158
- return;
159
- }
160
- if (value === '8') {
156
+ if (!value || value === '8') {
161
157
  resolve();
162
158
  return;
163
159
  }
@@ -170,11 +166,37 @@ class default_1 extends clickgo.form.AbstractForm {
170
166
  }]);
171
167
  });
172
168
  }
173
- onAdd(index, value) {
174
- this.addRemoveList.unshift('@add, index: ' + index.toString() + ', value: ' + value);
169
+ onGAdd(e) {
170
+ clickgo.form.notify({
171
+ 'type': 'info',
172
+ 'title': 'Greatselect @add',
173
+ 'content': 'value: ' + e.detail.value.toString()
174
+ });
175
+ if (this.slist[e.detail.value].type === 1) {
176
+ e.preventDefault();
177
+ }
178
+ }
179
+ onGRemove(e) {
180
+ clickgo.form.notify({
181
+ 'type': 'info',
182
+ 'title': 'Greaselect @remove',
183
+ 'content': 'value: ' + e.detail.value.toString()
184
+ });
185
+ }
186
+ onAdd(e) {
187
+ this.addRemoveList.unshift('@add, index: ' + e.detail.index.toString() + ', value: ' + e.detail.value);
175
188
  }
176
- onRemove(index, value) {
177
- this.addRemoveList.unshift('@remove, index: ' + index.toString() + ', value: ' + value);
189
+ onAdded(e) {
190
+ this.addRemoveList.unshift('@added, index: ' + e.detail.index.toString() + ', value: ' + e.detail.value);
191
+ }
192
+ onRemove(e) {
193
+ this.addRemoveList.unshift('@remove, index: ' + e.detail.index.toString() + ', value: ' + e.detail.value + ', mode: ' + e.detail.mode);
194
+ }
195
+ onRemoved(e) {
196
+ this.addRemoveList.unshift('@removed, index: ' + e.detail.index.toString() + ', value: ' + e.detail.value + ', mode: ' + e.detail.mode);
197
+ }
198
+ onTagclick(e) {
199
+ this.addRemoveList.unshift('@tagclick, index: ' + e.detail.index.toString() + ', value: ' + e.detail.value);
178
200
  }
179
201
  changeArea() {
180
202
  switch (this.area) {
@@ -202,25 +224,13 @@ class default_1 extends clickgo.form.AbstractForm {
202
224
  }
203
225
  onMounted() {
204
226
  this.watch(() => this.select.join(','), (n, o) => {
205
- let select = [];
206
- const now = n.split(',');
207
- const old = o.split(',');
208
- for (const item of now) {
209
- if (this.slist[parseInt(item)].type !== 0) {
210
- continue;
211
- }
212
- select.push(parseInt(item));
213
- }
214
- if (select.length === now.length) {
227
+ if (this.multi) {
215
228
  return;
216
229
  }
217
- select = [];
218
- for (const item of old) {
219
- select.push(parseInt(item));
230
+ if (this.slist[parseInt(n)].type === 0) {
231
+ return;
220
232
  }
221
- this.select = select;
222
- }, {
223
- 'deep': true
233
+ this.select = [parseInt(o)];
224
234
  });
225
235
  }
226
236
  }
@@ -4,7 +4,7 @@
4
4
  <!-- greatselect -->
5
5
  <layout v-if="ntab === 'greatselect'" gutter="10" direction="v" style="flex: 1; width: 0; padding: 10px;">
6
6
  <label>Now select value is {{select}}:</label>
7
- <greatselect v-model="select" :data="slist" :area="area" :disabled="disabled" :multi="multi" :sizes="sizes" :style="{'font-size': fontSize ? '16px' : undefined, 'padding': padding ? '15px' : undefined, 'background': background ? 'red' : undefined, 'color': background ? '#FFF' : undefined}" style="line-height: 1.3;">
7
+ <greatselect v-model="select" :data="slist" :area="area" :disabled="disabled" :multi="multi" :sizes="sizes" :style="{'font-size': fontSize ? '16px' : undefined, 'padding': padding ? '15px' : undefined, 'background': background ? 'red' : undefined, 'color': background ? '#FFF' : undefined}" style="line-height: 1.3;" @add="onGAdd" @remove="onGRemove">
8
8
  <layout align-v="center" gutter="5" style="flex: 1;">
9
9
  <img :src="slist[select[0]] ? slist[select[0]].src : ''" style="width: 32px; height: 32px;"></img>
10
10
  <block>
@@ -45,7 +45,7 @@
45
45
  <layout gutter="10" direction="v" style="padding: 10px;">
46
46
  <label>Now select value is {{select2}}</label>
47
47
  <label>Label: {{label2}}</label>
48
- <select v-model="select2" @label="label2 = $event" :data="slist2" :disabled="disabled" :editable="editable" :multi="multi" :tree="tree" :async="async" :search="search" :remote="remote" :remote-delay="remoteDelay[0]" :icon="icon" icon-default="../../../res/txt.svg" @load="onLoad" @remote="onRemote" @add="onAdd" @remove="onRemove" :style="{'font-size': fontSize ? '16px' : undefined, 'padding': padding ? '15px' : undefined, 'background': background ? 'red' : undefined, 'color': background ? '#FFF' : undefined}"></select>
48
+ <select v-model="select2" @label="label2 = $event" :data="slist2" :disabled="disabled" :editable="editable" :multi="multi" :tree="tree" :async="async" :search="search" :remote="remote" :remote-delay="remoteDelay[0]" :icon="icon" icon-default="../../../res/txt.svg" @load="onLoad" @remote="onRemote" @add="onAdd" @remove="onRemove" @added="onAdded" @removed="onRemoved" @tagclick="onTagclick" :style="{'font-size': fontSize ? '16px' : undefined, 'padding': padding ? '15px' : undefined, 'background': background ? 'red' : undefined, 'color': background ? '#FFF' : undefined}"></select>
49
49
  <list :data="addRemoveList" style="height: 100px;"></list>
50
50
  <label>Custom height:</label>
51
51
  <select :data="['1','2','3','4','5']" :disabled="disabled" :editable="editable" :multi="multi" :tree="tree" :async="async" :search="search" :remote="remote" :remote-delay="remoteDelay[0]" :icon="icon" icon-default="../../../res/txt.svg" style="height: 60px;" @load="onLoad" @remote="onRemote" :style="{'font-size': fontSize ? '16px' : undefined, 'padding': padding ? '15px' : undefined, 'background': background ? 'red' : undefined, 'color': background ? '#FFF' : undefined}"></select>
@@ -48,10 +48,10 @@ class default_1 extends clickgo.form.AbstractForm {
48
48
  this.drag = false;
49
49
  this.cclose = false;
50
50
  }
51
- onClose(e, i, v) {
51
+ onClose(e) {
52
52
  return __awaiter(this, void 0, void 0, function* () {
53
- if (i !== 10) {
54
- yield clickgo.form.dialog('Closed, index: ' + i.toString() + ', value: ' + v);
53
+ if (e.detail.index !== 10) {
54
+ yield clickgo.form.dialog('Closed, index: ' + e.detail.index.toString() + ', value: ' + e.detail.value);
55
55
  return;
56
56
  }
57
57
  e.preventDefault();
package/dist/clickgo.js CHANGED
@@ -24,7 +24,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.zip = exports.tool = exports.theme = exports.task = exports.storage = exports.native = exports.fs = exports.form = exports.dom = exports.core = exports.control = exports.vue = exports.hasFrame = exports.isImmersion = exports.getPlatform = exports.isNative = exports.getVersion = void 0;
27
- const version = '3.9.1';
27
+ const version = '3.10.0';
28
28
  function getVersion() {
29
29
  return version;
30
30
  }
package/dist/clickgo.ts CHANGED
@@ -13,7 +13,7 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- const version = '3.9.1';
16
+ const version = '3.10.0';
17
17
  export function getVersion(): string {
18
18
  return version;
19
19
  }
Binary file
package/dist/index.js CHANGED
@@ -101,7 +101,7 @@ function launcher(boot) {
101
101
  var _a;
102
102
  return __awaiter(this, void 0, void 0, function* () {
103
103
  const paths = [
104
- loader.cdn + '/npm/vue@3.3.13/dist/vue.global.prod.min.js'
104
+ loader.cdn + '/npm/vue@3.4.15/dist/vue.global.prod.min.js'
105
105
  ];
106
106
  let ro = true;
107
107
  if (!(window.ResizeObserver)) {
package/dist/index.ts CHANGED
@@ -176,7 +176,7 @@ export function launcher(boot: AbstractBoot): void {
176
176
  (async function() {
177
177
  // --- 通过标签加载库 ---
178
178
  const paths: string[] = [
179
- loader.cdn + '/npm/vue@3.3.13/dist/vue.global.prod.min.js'
179
+ loader.cdn + '/npm/vue@3.4.15/dist/vue.global.prod.min.js'
180
180
  ];
181
181
  // --- 判断 ResizeObserver 是否存在 ---
182
182
  let ro = true;
@@ -44,6 +44,7 @@ class AbstractControl {
44
44
  constructor() {
45
45
  this.packageFiles = {};
46
46
  this.props = {};
47
+ this.emits = {};
47
48
  this.slots = {};
48
49
  }
49
50
  get filename() {
@@ -272,6 +273,7 @@ function init(taskId, invoke) {
272
273
  'layout': '',
273
274
  'files': item.files,
274
275
  'props': {},
276
+ 'emits': {},
275
277
  'data': {},
276
278
  'access': {},
277
279
  'methods': {},
@@ -353,6 +355,11 @@ function init(taskId, invoke) {
353
355
  };
354
356
  }
355
357
  }
358
+ if (cls.emits) {
359
+ for (const key in cls.emits) {
360
+ t.controls[name].emits[key] = cls.emits[key];
361
+ }
362
+ }
356
363
  const cdata = Object.entries(cls);
357
364
  for (const item of cdata) {
358
365
  if (item[0] === 'files') {
@@ -445,11 +452,15 @@ function buildComponents(taskId, formId, path) {
445
452
  components['cg-' + name] = {
446
453
  'template': control.layout.replace(/{{{formId}}}/g, formId.toString()),
447
454
  'props': control.props,
455
+ 'emits': control.emits,
448
456
  'data': function () {
449
457
  const data = tool.clone(control.data);
450
458
  if (data.props) {
451
459
  delete data.props;
452
460
  }
461
+ if (data.emits) {
462
+ delete data.emits;
463
+ }
453
464
  return data;
454
465
  },
455
466
  'methods': control.methods,
@@ -164,6 +164,9 @@ export abstract class AbstractControl {
164
164
  /** --- 组件参数,由用户定义重写 --- */
165
165
  public readonly props = {};
166
166
 
167
+ /** --- 组件参数,由用户定义重写 --- */
168
+ public readonly emits: Record<string, null | ((payload: any) => boolean)> = {};
169
+
167
170
  /** --- 组件的子插槽 --- */
168
171
  public readonly slots: Record<string, any> = {};
169
172
 
@@ -390,6 +393,7 @@ export async function init(
390
393
 
391
394
  'files': item.files,
392
395
  'props': {},
396
+ 'emits': {},
393
397
  'data': {},
394
398
  'access': {},
395
399
  'methods': {},
@@ -493,6 +497,11 @@ export async function init(
493
497
  };
494
498
  }
495
499
  }
500
+ if (cls.emits) {
501
+ for (const key in cls.emits) {
502
+ t.controls[name].emits[key] = cls.emits[key];
503
+ }
504
+ }
496
505
  // --- DATA ---
497
506
  const cdata = Object.entries(cls);
498
507
  for (const item of cdata) {
@@ -598,12 +607,16 @@ export function buildComponents(
598
607
  components['cg-' + name] = {
599
608
  'template': control.layout.replace(/{{{formId}}}/g, formId.toString()),
600
609
  'props': control.props,
610
+ 'emits': control.emits,
601
611
 
602
612
  'data': function() {
603
613
  const data = tool.clone(control.data);
604
614
  if (data.props) {
605
615
  delete data.props;
606
616
  }
617
+ if (data.emits) {
618
+ delete data.emits;
619
+ }
607
620
  return data;
608
621
  },
609
622
  'methods': control.methods,
package/dist/lib/tool.js CHANGED
@@ -73,6 +73,13 @@ function clone(obj) {
73
73
  if (obj[i] instanceof Date) {
74
74
  newObj[i] = new Date(obj[i].getTime());
75
75
  }
76
+ else if (obj[i] instanceof FormData) {
77
+ const fd = new FormData();
78
+ for (const item of obj[i]) {
79
+ fd.append(item[0], item[1]);
80
+ }
81
+ newObj[i] = fd;
82
+ }
76
83
  else if (typeof obj[i] === 'object') {
77
84
  newObj[i] = clone(obj[i]);
78
85
  }
@@ -86,6 +93,13 @@ function clone(obj) {
86
93
  if (obj[key] instanceof Date) {
87
94
  newObj[key] = new Date(obj[key].getTime());
88
95
  }
96
+ else if (obj[key] instanceof FormData) {
97
+ const fd = new FormData();
98
+ for (const item of obj[key]) {
99
+ fd.append(item[0], item[1]);
100
+ }
101
+ newObj[key] = fd;
102
+ }
89
103
  else if (typeof obj[key] === 'object') {
90
104
  newObj[key] = clone(obj[key]);
91
105
  }
package/dist/lib/tool.ts CHANGED
@@ -102,6 +102,13 @@ export function clone(obj: Record<string, any> | any[]): any[] | any {
102
102
  if (obj[i] instanceof Date) {
103
103
  newObj[i] = new Date(obj[i].getTime());
104
104
  }
105
+ else if (obj[i] instanceof FormData) {
106
+ const fd = new FormData();
107
+ for (const item of obj[i]) {
108
+ fd.append(item[0], item[1]);
109
+ }
110
+ newObj[i] = fd;
111
+ }
105
112
  else if (typeof obj[i] === 'object') {
106
113
  newObj[i] = clone(obj[i]);
107
114
  }
@@ -115,6 +122,13 @@ export function clone(obj: Record<string, any> | any[]): any[] | any {
115
122
  if (obj[key] instanceof Date) {
116
123
  newObj[key] = new Date(obj[key].getTime());
117
124
  }
125
+ else if (obj[key] instanceof FormData) {
126
+ const fd = new FormData();
127
+ for (const item of obj[key]) {
128
+ fd.append(item[0], item[1]);
129
+ }
130
+ newObj[key] = fd;
131
+ }
118
132
  else if (typeof obj[key] === 'object') {
119
133
  newObj[key] = clone(obj[key]);
120
134
  }
@@ -797,7 +811,7 @@ export function execCommand(ac: string): void {
797
811
  * @param before 老值
798
812
  * @param after 新值
799
813
  */
800
- export function compar(before: string[], after: string[]): {
814
+ export function compar(before: Array<string | number>, after: Array<string | number>): {
801
815
  'remove': Record<string, number>;
802
816
  'add': Record<string, number>;
803
817
  'length': {
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clickgo",
3
- "version": "3.9.1",
3
+ "version": "3.10.0",
4
4
  "description": "Background interface, software interface, mobile phone APP interface operation library.",
5
5
  "keywords": [
6
6
  "deskrt",
package/types/index.d.ts CHANGED
@@ -406,6 +406,7 @@ export interface ITask {
406
406
 
407
407
  'files': Record<string, Blob | string>;
408
408
  'props': Record<string, any>;
409
+ 'emits': Record<string, any>;
409
410
  'data': Record<string, any>;
410
411
  'access': Record<string, any>;
411
412
  'methods': Record<string, any>;
@@ -615,6 +616,123 @@ export interface INotifyOptions {
615
616
  'progress'?: boolean;
616
617
  }
617
618
 
619
+ // --- Custom Event Control ---
620
+
621
+ interface ICustomEvent {
622
+ 'go': boolean;
623
+ preventDefault: () => void;
624
+ }
625
+
626
+ // --- Greatlist Control ---
627
+
628
+ export interface IGreatlistRemoveEvent extends ICustomEvent {
629
+ 'detail': {
630
+ 'index': number;
631
+ 'value': number;
632
+ };
633
+ }
634
+
635
+ export interface IGreatlistAddEvent extends ICustomEvent {
636
+ 'detail': {
637
+ 'index': number;
638
+ 'value': number;
639
+ };
640
+ }
641
+
642
+ export interface IGreatlistItemclickedEvent {
643
+ 'detail': {
644
+ 'event': MouseEvent | TouchEvent;
645
+ 'value': number;
646
+ 'arrow': boolean;
647
+ };
648
+ }
649
+
650
+ // --- Greatselect Control ---
651
+
652
+ export interface IGreatselectRemoveEvent extends ICustomEvent {
653
+ 'detail': {
654
+ 'value': number;
655
+ };
656
+ }
657
+
658
+ export interface IGreatselectAddEvent extends ICustomEvent {
659
+ 'detail': {
660
+ 'value': number;
661
+ };
662
+ }
663
+
664
+ // --- List Control ---
665
+
666
+ export interface IListRemoveEvent extends ICustomEvent {
667
+ 'detail': {
668
+ 'index': number;
669
+ 'value': string;
670
+ };
671
+ }
672
+
673
+ export interface IListAddEvent extends ICustomEvent {
674
+ 'detail': {
675
+ 'index': number;
676
+ 'value': string;
677
+ };
678
+ }
679
+
680
+ export interface IListItemclickedEvent {
681
+ 'detail': {
682
+ 'event': MouseEvent | TouchEvent;
683
+ 'value': number;
684
+ 'arrow': boolean;
685
+ };
686
+ }
687
+
688
+ // --- Select Control ---
689
+
690
+ export interface ISelectAddEvent extends ICustomEvent {
691
+ 'detail': {
692
+ 'index': number;
693
+ 'value': string;
694
+ };
695
+ }
696
+
697
+ export interface ISelectRemoveEvent extends ICustomEvent {
698
+ 'detail': {
699
+ 'index': number;
700
+ 'value': string;
701
+ 'mode': 'backspace' | 'tag' | 'list';
702
+ };
703
+ }
704
+
705
+ export interface ISelectAddedEvent {
706
+ 'detail': {
707
+ 'index': number;
708
+ 'value': string;
709
+ };
710
+ }
711
+
712
+ export interface ISelectRemovedEvent {
713
+ 'detail': {
714
+ 'index': number;
715
+ 'value': string;
716
+ 'mode': 'backspace' | 'tag' | 'list';
717
+ };
718
+ }
719
+
720
+ export interface ISelectTagclickEvent {
721
+ 'detail': {
722
+ 'index': number;
723
+ 'value': string;
724
+ };
725
+ }
726
+
727
+ // --- Tab Control ---
728
+
729
+ export interface ITabCloseEvent extends ICustomEvent {
730
+ 'detail': {
731
+ 'index': number;
732
+ 'value': string;
733
+ };
734
+ }
735
+
618
736
  // -------------------------
619
737
  // ---------- vue ----------
620
738
  // -------------------------