@itrocks/list 0.1.4 → 0.2.1

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/build.js CHANGED
@@ -6,7 +6,7 @@ import { TableFreezeInheritBorder } from '../table/freeze/inherit-border.js';
6
6
  import { TableLink } from '../table/link.js';
7
7
  import { tableByElement } from '../table/table.js';
8
8
  import { xTargetCall } from '../xtarget/xtarget.js';
9
- build('article[data-action="list"] > form > table.objects', element => {
9
+ build('article[data-action="list"] > form > table.objects', table => {
10
10
  const tableLink = new TableLink({
11
11
  call: url => xTargetCall(url, 'main'),
12
12
  href: 'action',
@@ -16,17 +16,34 @@ build('article[data-action="list"] > form > table.objects', element => {
16
16
  return { element: input, value: input.value };
17
17
  }
18
18
  });
19
- tableByElement(element, {
19
+ tableByElement(table, {
20
20
  plugins: [TableFeed, TableFreeze, TableFreezeInheritBackground, TableFreezeInheritBorder, tableLink]
21
21
  });
22
- element.addEventListener('click', event => {
22
+ table.addEventListener('click', event => {
23
23
  const element = event.target;
24
- if (!(element instanceof HTMLTableCellElement) || !element.classList.contains('select'))
24
+ if (!(element instanceof HTMLElement))
25
25
  return;
26
- const input = element.querySelector('input[type=checkbox]');
26
+ const cell = element.closest('table, th');
27
+ if (!(cell instanceof HTMLTableCellElement) || !cell.classList.contains('select'))
28
+ return;
29
+ const input = cell.querySelector('input[type=checkbox]');
27
30
  if (!input)
28
31
  return;
29
32
  input.click();
30
33
  input.focus();
31
34
  });
35
+ table.tHead?.addEventListener('click', event => {
36
+ const element = event.target;
37
+ if (!(element instanceof HTMLElement))
38
+ return;
39
+ const cell = element.closest('table, th');
40
+ if (!(cell instanceof HTMLTableCellElement) || !cell.dataset.property)
41
+ return;
42
+ const form = cell.closest('form');
43
+ if (!form)
44
+ return;
45
+ const reverse = (cell.dataset.sort === '1') ? !cell.dataset.reverse : !!cell.dataset.reverse;
46
+ const url = form.action + '?sort=' + cell.dataset.property + (reverse ? '&reverse' : '');
47
+ xTargetCall(url, 'main');
48
+ });
32
49
  });
package/cjs/columns.d.ts CHANGED
@@ -1,10 +1,18 @@
1
+ import { KeyOf } from '@itrocks/class-type';
1
2
  import { Type } from '@itrocks/class-type';
2
3
  import { ReflectProperty } from '@itrocks/reflect';
3
4
  import { Request } from '@itrocks/request-response';
4
5
  import { Option } from '@itrocks/storage';
5
- export declare class Columns<T extends object> implements Iterable<ReflectProperty<T>> {
6
+ import { Parameter } from './parameter';
7
+ export declare class Columns<T extends object> extends Parameter implements Iterable<ReflectProperty<T>> {
6
8
  properties: ReflectProperty<T>[];
7
9
  [Symbol.iterator](): ArrayIterator<ReflectProperty<T>>;
8
10
  getParams(_request: Request, type: Type<T>): void;
11
+ get length(): number;
12
+ map(callback: (value: ReflectProperty<T>) => any): any[];
9
13
  readOptions(options?: Option[]): Option[];
14
+ remove(propertyName: string): void;
15
+ serialize(): Extract<keyof T, string>[];
16
+ unserialize(data: KeyOf<T>[], type: Type<T>): void;
17
+ unshift(property: ReflectProperty<T>): number;
10
18
  }
package/cjs/columns.js CHANGED
@@ -2,17 +2,44 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Columns = void 0;
4
4
  const list_properties_1 = require("@itrocks/list-properties");
5
- class Columns {
5
+ const reflect_1 = require("@itrocks/reflect");
6
+ const parameter_1 = require("./parameter");
7
+ class Columns extends parameter_1.Parameter {
6
8
  properties = new Array;
7
9
  [Symbol.iterator]() {
8
10
  return this.properties[Symbol.iterator]();
9
11
  }
10
12
  getParams(_request, type) {
11
- this.properties = new list_properties_1.ListReflectClass(type).listProperties();
13
+ if (!this.length) {
14
+ this.properties = new list_properties_1.ListReflectClass(type).listProperties();
15
+ }
16
+ }
17
+ get length() {
18
+ return this.properties.length;
19
+ }
20
+ map(callback) {
21
+ return this.properties.map(callback);
12
22
  }
13
23
  readOptions(options = new Array) {
14
24
  return options;
15
25
  }
26
+ remove(propertyName) {
27
+ for (const property of this.properties) {
28
+ if (property.name !== propertyName)
29
+ continue;
30
+ this.properties.splice(this.properties.indexOf(property), 1);
31
+ return;
32
+ }
33
+ }
34
+ serialize() {
35
+ return this.properties.map(property => property.name);
36
+ }
37
+ unserialize(data, type) {
38
+ this.properties = data.map(property => new reflect_1.ReflectProperty(type, property));
39
+ }
40
+ unshift(property) {
41
+ return this.properties.unshift(property);
42
+ }
16
43
  }
17
44
  exports.Columns = Columns;
18
45
  //# sourceMappingURL=columns.js.map
package/cjs/feed.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Request } from '@itrocks/request-response';
2
2
  import { Option } from '@itrocks/storage';
3
- export declare class Feed {
3
+ import { Parameter } from './parameter';
4
+ export declare class Feed extends Parameter {
4
5
  static DEFAULT_LIMIT: number;
5
6
  static DEFAULT_LINE_HEIGHT: number;
6
7
  static DEFAULT_OFFSET: number;
package/cjs/feed.js CHANGED
@@ -2,7 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Feed = void 0;
4
4
  const storage_1 = require("@itrocks/storage");
5
- class Feed {
5
+ const parameter_1 = require("./parameter");
6
+ class Feed extends parameter_1.Parameter {
6
7
  static DEFAULT_LIMIT = 50;
7
8
  static DEFAULT_LINE_HEIGHT = 30;
8
9
  static DEFAULT_OFFSET = 0;
package/cjs/filter.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { Type } from '@itrocks/class-type';
2
2
  import { Request } from '@itrocks/request-response';
3
3
  import { Option } from '@itrocks/storage';
4
- export declare class Filter {
4
+ import { Parameter } from './parameter';
5
+ export declare class Filter extends Parameter {
5
6
  getParams(_request: Request): void;
6
7
  readOptions(options?: Option[]): Option[];
7
8
  searchObject(type: Type): any;
package/cjs/filter.js CHANGED
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Filter = void 0;
4
- class Filter {
4
+ const parameter_1 = require("./parameter");
5
+ class Filter extends parameter_1.Parameter {
5
6
  getParams(_request) {
6
7
  }
7
8
  readOptions(options = new Array) {
package/cjs/list.html CHANGED
@@ -30,7 +30,7 @@
30
30
  <tr class="properties">
31
31
  <th class="select"><input name="select" type="checkbox" value="all"></th>
32
32
  <!--columns-->
33
- <th data-property="{name}">{@display}</th>
33
+ <th data-property="{name}" data-reverse="{?reverse}" data-sort="{?sort}">{@display}</th>
34
34
  <!--end-->
35
35
  </tr>
36
36
  </thead>
package/cjs/list.js CHANGED
@@ -44,6 +44,8 @@ const storage_1 = require("@itrocks/storage");
44
44
  const columns_1 = require("./columns");
45
45
  const feed_1 = require("./feed");
46
46
  const filter_1 = require("./filter");
47
+ const persist_1 = require("./persist");
48
+ const persist_2 = require("./persist");
47
49
  const sort_1 = require("./sort");
48
50
  let List = (() => {
49
51
  let _classDecorators = [(0, action_3.Need)('Store', 'new'), (0, route_1.Route)('/list')];
@@ -63,17 +65,19 @@ let List = (() => {
63
65
  columns = new columns_1.Columns;
64
66
  feed = new feed_1.Feed;
65
67
  filter = new filter_1.Filter;
66
- sort = new sort_1.Sort;
68
+ sort = new sort_1.Sort(this.columns);
67
69
  async html(request) {
68
70
  const columns = this.columns;
69
71
  const feed = this.feed;
70
72
  const filter = this.filter;
71
73
  const sort = this.sort;
72
74
  const type = request.type;
75
+ (0, persist_1.load)(this, request.request, type);
73
76
  columns.getParams(request.request, type);
74
77
  feed.getParams(request.request);
75
78
  filter.getParams(request.request);
76
- sort.getParams(request.request, type, columns);
79
+ sort.getParams(request.request, type);
80
+ (0, persist_2.save)(this, request.request, type);
77
81
  const objects = await (0, storage_1.dataSource)().search(type, filter.searchObject(type), feed.readOptions(filter.readOptions(sort.readOptions())));
78
82
  if (feed.offset) {
79
83
  return this.htmlTemplateResponse({ objects, type }, request, feed.template);
@@ -0,0 +1,9 @@
1
+ import { Request } from '@itrocks/request-response';
2
+ import { Option } from '@itrocks/storage';
3
+ import { Type } from '@itrocks/class-type';
4
+ export declare abstract class Parameter {
5
+ abstract getParams(request: Request, type?: Type): void;
6
+ readOptions(options?: Option[]): Option[];
7
+ serialize(): any;
8
+ unserialize(_data: any, _type: Type): void;
9
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Parameter = void 0;
4
+ class Parameter {
5
+ readOptions(options = new Array) {
6
+ return options;
7
+ }
8
+ serialize() { }
9
+ unserialize(_data, _type) { }
10
+ }
11
+ exports.Parameter = Parameter;
12
+ //# sourceMappingURL=parameter.js.map
@@ -0,0 +1,8 @@
1
+ import { Type } from '@itrocks/class-type';
2
+ import { Request } from '@itrocks/request-response';
3
+ interface Container {
4
+ [s: string]: any;
5
+ }
6
+ export declare function load(list: Container, request: Request, type: Type): {} | undefined;
7
+ export declare function save(list: Container, request: Request, type: Type): void;
8
+ export {};
package/cjs/persist.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.load = load;
4
+ exports.save = save;
5
+ const route_1 = require("@itrocks/route");
6
+ const parameter_1 = require("./parameter");
7
+ function load(list, request, type) {
8
+ if (!request.session.list)
9
+ return {};
10
+ const serialized = request.session.list[(0, route_1.routeOf)(type)];
11
+ if (!serialized)
12
+ return {};
13
+ for (const key of Object.keys(list)) {
14
+ const parameter = list[key];
15
+ if (!(parameter instanceof parameter_1.Parameter) || !serialized[key])
16
+ continue;
17
+ parameter.unserialize(serialized[key], type);
18
+ }
19
+ }
20
+ function save(list, request, type) {
21
+ if (!request.session.list) {
22
+ request.session.list = {};
23
+ }
24
+ const serialized = {};
25
+ for (const key of Object.keys(list)) {
26
+ const parameter = list[key];
27
+ if (!(parameter instanceof parameter_1.Parameter))
28
+ continue;
29
+ serialized[key] = parameter.serialize();
30
+ }
31
+ request.session.list[(0, route_1.routeOf)(type)] = serialized;
32
+ }
33
+ //# sourceMappingURL=persist.js.map
package/cjs/sort.d.ts CHANGED
@@ -2,7 +2,21 @@ import { Type } from '@itrocks/class-type';
2
2
  import { Request } from '@itrocks/request-response';
3
3
  import { Option } from '@itrocks/storage';
4
4
  import { Columns } from './columns';
5
- export declare class Sort<T extends object> {
6
- getParams(_request: Request, _type: Type, _columns: Columns<T>): void;
5
+ import { Parameter } from './parameter';
6
+ interface Serialized {
7
+ [key: string]: boolean;
8
+ }
9
+ interface Sortable {
10
+ reverse: boolean;
11
+ sort?: number;
12
+ }
13
+ export declare class Sort<T extends object> extends Parameter {
14
+ columns: Columns<T> & Sortable[];
15
+ sorted?: Serialized;
16
+ constructor(columns: Columns<T>);
17
+ getParams(request: Request, type: Type<T>): void;
7
18
  readOptions(options?: Option[]): Option[];
19
+ serialize(): Serialized | undefined;
20
+ unserialize(data: Serialized): void;
8
21
  }
22
+ export {};
package/cjs/sort.js CHANGED
@@ -1,14 +1,70 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Sort = void 0;
4
+ const sort_1 = require("@itrocks/sort");
5
+ const sort_2 = require("@itrocks/sort");
4
6
  const storage_1 = require("@itrocks/storage");
5
- class Sort {
6
- getParams(_request, _type, _columns) {
7
+ const parameter_1 = require("./parameter");
8
+ class Sort extends parameter_1.Parameter {
9
+ columns;
10
+ sorted;
11
+ constructor(columns) {
12
+ super();
13
+ this.columns = columns;
14
+ }
15
+ getParams(request, type) {
16
+ let sortProperties;
17
+ let sortReverse;
18
+ if (this.sorted) {
19
+ sortProperties = Object.keys(this.sorted);
20
+ sortReverse = Object.values(this.sorted);
21
+ }
22
+ else {
23
+ for (const option of this.readOptions()) {
24
+ if (option instanceof storage_1.Sort) {
25
+ sortProperties = option.properties.map(property => '' + property);
26
+ sortReverse = option.properties.map(property => property instanceof sort_1.Reverse);
27
+ }
28
+ }
29
+ if (!sortProperties || !sortReverse) {
30
+ sortProperties = (0, sort_2.sortOf)(type).map(property => '' + property);
31
+ sortReverse = (0, sort_2.sortOf)(type).map(property => property instanceof sort_1.Reverse);
32
+ }
33
+ }
34
+ if (typeof request.data.sort === 'string') {
35
+ const reverse = 'reverse' in request.data;
36
+ const sort = request.data.sort;
37
+ const index = sortProperties.indexOf(sort);
38
+ if (index < 0)
39
+ return;
40
+ sortProperties.splice(index, 1);
41
+ sortProperties.unshift(sort);
42
+ sortReverse.splice(index, 1);
43
+ sortReverse.unshift(reverse);
44
+ this.sorted = undefined;
45
+ }
46
+ if (!this.sorted) {
47
+ this.sorted = {};
48
+ for (const index in sortProperties) {
49
+ this.sorted[sortProperties[index]] = sortReverse[index];
50
+ }
51
+ }
52
+ for (const column of this.columns) {
53
+ const sortIndex = sortProperties.indexOf(column.name);
54
+ column.reverse = sortReverse[sortIndex];
55
+ column.sort = (sortIndex > -1) ? (sortIndex + 1) : undefined;
56
+ }
7
57
  }
8
58
  readOptions(options = new Array) {
9
59
  options.push(storage_1.Sort);
10
60
  return options;
11
61
  }
62
+ serialize() {
63
+ return this.sorted;
64
+ }
65
+ unserialize(data) {
66
+ this.sorted = data;
67
+ }
12
68
  }
13
69
  exports.Sort = Sort;
14
70
  //# sourceMappingURL=sort.js.map
package/list.css CHANGED
@@ -56,6 +56,33 @@ table.objects > tbody:first-child > tr:nth-child(even) > td {
56
56
  table.objects > tbody:first-child > tr:nth-child(odd) > td {
57
57
  background: #f8f8f8;
58
58
  }
59
+ table.objects > thead > tr > th[data-property] {
60
+ cursor: pointer;
61
+ }
62
+ table.objects > thead > tr > th[data-sort] {
63
+ padding-right: calc(0.6em + 16px);
64
+ }
65
+ table.objects > thead > tr > th[data-sort]::after {
66
+ content: "";
67
+ height: 24px;
68
+ mask: url("sort.svg") right center/24px 24px no-repeat;
69
+ position: absolute;
70
+ right: 0;
71
+ top: calc(50% - 12px);
72
+ width: 24px;
73
+ }
74
+ table.objects > thead > tr > th[data-sort][data-reverse]::after {
75
+ transform: scaleY(-1);
76
+ }
77
+ table.objects > thead > tr > th[data-sort][data-sort="1"]::after {
78
+ background-color: #444;
79
+ }
80
+ table.objects > thead > tr > th[data-sort][data-sort="2"]::after {
81
+ background-color: #888;
82
+ }
83
+ table.objects > thead > tr > th[data-sort][data-sort="3"]::after {
84
+ background-color: #ccc;
85
+ }
59
86
  table.objects > thead + tbody > tr:nth-child(even) > td {
60
87
  background: #f8f8f8;
61
88
  }
package/package.json CHANGED
@@ -30,6 +30,7 @@
30
30
  "LICENSE",
31
31
  "README.md",
32
32
  "cjs/*",
33
+ "/*.svg",
33
34
  "*.css",
34
35
  "*.d.ts",
35
36
  "*.js",
@@ -67,9 +68,9 @@
67
68
  "scripts": {
68
69
  "build": "npm run build:cjs && npm run build:css && npm run build:front",
69
70
  "build:cjs": "tsc -p tsconfig.cjs.json && cp src/*.html cjs/",
70
- "build:css": "sass --no-source-map src/list.scss:list.css",
71
+ "build:css": "sass --no-source-map src/list.scss:list.css && cp src/*.svg ./",
71
72
  "build:front": "tsc -p esm/tsconfig.json && ../prepare-module/prepare-module.js esm"
72
73
  },
73
74
  "types": "./cjs/list.d.ts",
74
- "version": "0.1.4"
75
+ "version": "0.2.1"
75
76
  }
package/sort.svg ADDED
@@ -0,0 +1 @@
1
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M7 15l10 0-5-5z"/></svg>