@bennerinformatics/ember-fw-table 2.0.18 → 2.0.19
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/addon/classes/Row.js +74 -73
- package/addon/classes/Table.js +147 -143
- package/addon/components/fw-cell-action.js +15 -14
- package/addon/components/fw-cell-boolean.js +12 -11
- package/addon/components/fw-cell-nullable.js +12 -11
- package/addon/components/fw-cell-permission-icon.js +12 -11
- package/addon/components/fw-column-sortable.js +4 -0
- package/addon/components/fw-column-title.js +13 -10
- package/addon/components/fw-delete-modal.js +61 -58
- package/addon/components/fw-pagination-wrapper.js +681 -470
- package/addon/components/fw-row-toggle-index.js +14 -10
- package/addon/components/fw-row-toggle.js +4 -2
- package/addon/components/fw-table-expanded-row.js +24 -22
- package/addon/components/fw-table-resort.js +13 -4
- package/addon/components/fw-table-sortable.js +389 -390
- package/addon/documentation.js +98 -0
- package/addon/templates/components/fw-pagination-wrapper.hbs +74 -74
- package/addon/templates/components/fw-table-expanded-row.hbs +23 -23
- package/addon/templates/components/fw-table-resort.hbs +1 -1
- package/addon/utils/base-cells.js +40 -35
- package/addon/utils/export.js +76 -72
- package/addon/utils/formats.js +46 -42
- package/addon/utils/table.js +35 -31
- package/app/breakpoints.js +1 -1
- package/app/components/fw-cell-permission-icon.js +1 -1
- package/app/initializers/responsive.js +1 -1
- package/bitbucket-helpers-override.js +240 -0
- package/index.js +10 -9
- package/package.json +67 -63
- package/shippable.yml +28 -0
- package/yuidoc.json +21 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/* Below is the main documentation for the addon. This file is only for documentation, it doesn't actually do anything. */
|
|
2
|
+
/**
|
|
3
|
+
* The primary purpose of ember-fw-table is to make a simplified form of ember-light-table,
|
|
4
|
+
* and which is easier to use than its parent. Within it as well, we have added a few extra
|
|
5
|
+
* things that make more complicated aspects of tables also easier to incorporate (such as
|
|
6
|
+
* paginated tables). For more information on ember-light-table,
|
|
7
|
+
* [see their documentation](https://adopted-ember-addons.github.io/ember-light-table/docs).
|
|
8
|
+
*
|
|
9
|
+
* Because of the design of this addon, it is much simpler than some of Informatics other
|
|
10
|
+
* addons. All of the "internal" elements of this addon, which are used within the addon, but
|
|
11
|
+
* are not designed to be used outside, are in an "Internal" submodule.
|
|
12
|
+
* * [Components](Components.html)
|
|
13
|
+
* - [Main Components](Main.html)
|
|
14
|
+
* - [Internal Components](Internal.html)
|
|
15
|
+
* - [Cell Components](Cell.html)
|
|
16
|
+
* * [Utils](Utils.html)
|
|
17
|
+
*
|
|
18
|
+
* @module Introduction
|
|
19
|
+
* @main Introduction
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Ember-FW-Table defines many different components that can be used throughout the Informatics apps. To understand what a component is,
|
|
23
|
+
* [click here](https://guides.emberjs.com/v2.18.0/components/) for Ember's own documentation on components. The main focus of this app
|
|
24
|
+
* is of course the main table Here contains a list
|
|
25
|
+
* of all of the different components that are defined by ember-fw. Ember-fw also adds the ability for more advanced components
|
|
26
|
+
* (which are components that require more than just a simple call to use), such as [Notifications](../classes/NotificationsService.html)
|
|
27
|
+
* and [Modals](Modals.html).
|
|
28
|
+
*
|
|
29
|
+
* @module Components
|
|
30
|
+
* @main Components
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Since the main component that is imported with this addon is to do with the table,
|
|
34
|
+
* there are many components that can be explained in detail, but are really only internal to
|
|
35
|
+
* the addon itself, and probably shouldn't be used without a serious reason. Those listed below
|
|
36
|
+
* are technically able to be used by any app which import the addon, but will probably only be
|
|
37
|
+
* helpful documentation for the developer who develops the ember-fw-table addon.
|
|
38
|
+
*
|
|
39
|
+
* @module Components
|
|
40
|
+
* @submodule Internal
|
|
41
|
+
* @main Internal
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* There are a few other components which are added in this addon, which are built to be used within
|
|
46
|
+
* the app. Of course the largest of these is the fw-table-sortable, after which the addon derives
|
|
47
|
+
* its name, but there are also other supplemental components designed for use with the app.
|
|
48
|
+
*
|
|
49
|
+
* ***
|
|
50
|
+
*
|
|
51
|
+
* ###Classes
|
|
52
|
+
* * [FW-Table-Sortable](../classes/FW-Table-Sortable.html)
|
|
53
|
+
* * [FW-Table-Resort](../classes/FW-Table-Resort.html)
|
|
54
|
+
* * [FW-Pagination-Wrapper](../classes/FW-Pagination-Wrapper.html)
|
|
55
|
+
* * [FW-Delete-Modal](../classes/FW-Delete-Modal.html)
|
|
56
|
+
*
|
|
57
|
+
* @module Components
|
|
58
|
+
* @submodule Main
|
|
59
|
+
* @main Main
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Some components in this addon were designed to be used with the `cellComponent` value used in the table.
|
|
64
|
+
* For information on how `cellComponent` works, [click here](https://adopted-ember-addons.github.io/ember-light-table/docs/classes/Column.html#property_cellComponent).
|
|
65
|
+
*
|
|
66
|
+
* For each of these cell components, you call them in the following way:
|
|
67
|
+
* ```js
|
|
68
|
+
* column: [
|
|
69
|
+
* {
|
|
70
|
+
* label: 'Actions',
|
|
71
|
+
* cellComponent: 'fw-cell-action'
|
|
72
|
+
* }
|
|
73
|
+
* ]
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* ***
|
|
77
|
+
*
|
|
78
|
+
* ### Classes
|
|
79
|
+
* * [FW-Cell-Action](../classes/FW-Cell-Action.html)
|
|
80
|
+
* * [FW-Cell-Boolean](../classes/FW-Cell-Boolean.html)
|
|
81
|
+
* * [FW-Cell-Nullable](../classes/FW-Cell-Nullable.html)
|
|
82
|
+
* * [FW-Cell-Permission-Icon](../classes/FW-Cell-Permission-Icon.html)
|
|
83
|
+
* * [FW-Row-Toggle](../classes/FW-Row-Toggle.html)
|
|
84
|
+
* * [FW-Row-Toggle-Index](../classes/FW-Row-Toggle-Index.html)
|
|
85
|
+
*
|
|
86
|
+
* @module Components
|
|
87
|
+
* @submodule Cell
|
|
88
|
+
* @main Cell
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Utils is short for Utilities, and they are essentially whatever you need them to be. It is simply a way to import a function that does a certain task.
|
|
93
|
+
* In ember-fw-table, we have a few utils files that have been defined, and each has a couple different functions that are semi-related to each other. So each "class"
|
|
94
|
+
* within the utils module actually is simply a group of related functions exported that can be used after they are imported.
|
|
95
|
+
*
|
|
96
|
+
* @module Utils
|
|
97
|
+
* @main Utils
|
|
98
|
+
*/
|
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
{{!-- Search buttons, whole search component is in block --}}
|
|
2
|
-
{{yield (hash
|
|
3
|
-
search=(action 'search')
|
|
4
|
-
export=(action 'export')
|
|
5
|
-
) false}}
|
|
6
|
-
|
|
7
|
-
{{!-- Table contents, show loading spinner if in progress --}}
|
|
8
|
-
<div class={{tableWrapperClass}}>
|
|
9
|
-
{{#if searchingTable}}
|
|
10
|
-
{{fw-loading-spinner}}
|
|
11
|
-
{{else if pageEntries}}
|
|
12
|
-
{{!-- Page numbers --}}
|
|
13
|
-
{{#if showPages}}
|
|
14
|
-
<div class="text-center" style="overflow:auto">
|
|
15
|
-
{{page-numbers
|
|
16
|
-
content=(hash)
|
|
17
|
-
showFL=true
|
|
18
|
-
currentPage=page
|
|
19
|
-
numPagesToShow=maxPageButtons
|
|
20
|
-
totalPages=totalPages
|
|
21
|
-
action=(action 'setPage')
|
|
22
|
-
}}
|
|
23
|
-
</div>
|
|
24
|
-
{{/if}}
|
|
25
|
-
{{!-- If we are searching a page, show its loading spinner --}}
|
|
26
|
-
{{#if pagesSearching}}
|
|
27
|
-
{{fw-loading-spinner}}
|
|
28
|
-
{{else}}
|
|
29
|
-
{{!-- If given a column getter, use that for columns --}}
|
|
30
|
-
{{#if tableColumns}}
|
|
31
|
-
{{fw-table-sortable
|
|
32
|
-
filteredEntries
|
|
33
|
-
tableColumns
|
|
34
|
-
title=fullTableTitle
|
|
35
|
-
class='sticky-table'
|
|
36
|
-
defaultSort=(array tableSortKey defaultSortKey)
|
|
37
|
-
responsive=true
|
|
38
|
-
empty=emptyText
|
|
39
|
-
hideEmpty=hideEmpty
|
|
40
|
-
canExport=(if showExport 'Export Page' false)
|
|
41
|
-
deleteTable=deletePage
|
|
42
|
-
deleteTablePermission=deletePagePermission
|
|
43
|
-
deleteOverrideTitle='Delete Page'
|
|
44
|
-
onSort=(action 'sortColumn')
|
|
45
|
-
tableActions=tableActions
|
|
46
|
-
}}
|
|
47
|
-
{{else}}
|
|
48
|
-
{{!-- Let the user provide the table --}}
|
|
49
|
-
{{yield (hash
|
|
50
|
-
sort=(action 'sortColumn')
|
|
51
|
-
) (hash
|
|
52
|
-
title=fullTableTitle
|
|
53
|
-
suffix=tableSuffix
|
|
54
|
-
entries=filteredEntries
|
|
55
|
-
sortKey=tableSortKey
|
|
56
|
-
)}}
|
|
57
|
-
{{/if}}
|
|
58
|
-
|
|
59
|
-
{{!-- Second page numbers --}}
|
|
60
|
-
{{#if showPages}}
|
|
61
|
-
<div class="text-center" style="overflow:auto">
|
|
62
|
-
{{page-numbers
|
|
63
|
-
content=(hash)
|
|
64
|
-
showFL=true
|
|
65
|
-
currentPage=page
|
|
66
|
-
numPagesToShow=maxPageButtons
|
|
67
|
-
totalPages=totalPages
|
|
68
|
-
action=(action 'setPage')
|
|
69
|
-
}}
|
|
70
|
-
</div>
|
|
71
|
-
{{/if}}
|
|
72
|
-
{{/if}}
|
|
73
|
-
{{/if}}
|
|
74
|
-
</div>
|
|
1
|
+
{{!-- Search buttons, whole search component is in block --}}
|
|
2
|
+
{{yield (hash
|
|
3
|
+
search=(action 'search')
|
|
4
|
+
export=(action 'export')
|
|
5
|
+
) false}}
|
|
6
|
+
|
|
7
|
+
{{!-- Table contents, show loading spinner if in progress --}}
|
|
8
|
+
<div class={{tableWrapperClass}}>
|
|
9
|
+
{{#if searchingTable}}
|
|
10
|
+
{{fw-loading-spinner}}
|
|
11
|
+
{{else if pageEntries}}
|
|
12
|
+
{{!-- Page numbers --}}
|
|
13
|
+
{{#if (and showPages showPagesTop)}}
|
|
14
|
+
<div class="text-center" style="overflow:auto">
|
|
15
|
+
{{page-numbers
|
|
16
|
+
content=(hash)
|
|
17
|
+
showFL=true
|
|
18
|
+
currentPage=page
|
|
19
|
+
numPagesToShow=maxPageButtons
|
|
20
|
+
totalPages=totalPages
|
|
21
|
+
action=(action 'setPage')
|
|
22
|
+
}}
|
|
23
|
+
</div>
|
|
24
|
+
{{/if}}
|
|
25
|
+
{{!-- If we are searching a page, show its loading spinner --}}
|
|
26
|
+
{{#if pagesSearching}}
|
|
27
|
+
{{fw-loading-spinner}}
|
|
28
|
+
{{else}}
|
|
29
|
+
{{!-- If given a column getter, use that for columns --}}
|
|
30
|
+
{{#if tableColumns}}
|
|
31
|
+
{{fw-table-sortable
|
|
32
|
+
filteredEntries
|
|
33
|
+
tableColumns
|
|
34
|
+
title=fullTableTitle
|
|
35
|
+
class='sticky-table'
|
|
36
|
+
defaultSort=(array tableSortKey defaultSortKey)
|
|
37
|
+
responsive=true
|
|
38
|
+
empty=emptyText
|
|
39
|
+
hideEmpty=hideEmpty
|
|
40
|
+
canExport=(if showExport 'Export Page' false)
|
|
41
|
+
deleteTable=deletePage
|
|
42
|
+
deleteTablePermission=deletePagePermission
|
|
43
|
+
deleteOverrideTitle='Delete Page'
|
|
44
|
+
onSort=(action 'sortColumn')
|
|
45
|
+
tableActions=tableActions
|
|
46
|
+
}}
|
|
47
|
+
{{else}}
|
|
48
|
+
{{!-- Let the user provide the table --}}
|
|
49
|
+
{{yield (hash
|
|
50
|
+
sort=(action 'sortColumn')
|
|
51
|
+
) (hash
|
|
52
|
+
title=fullTableTitle
|
|
53
|
+
suffix=tableSuffix
|
|
54
|
+
entries=filteredEntries
|
|
55
|
+
sortKey=tableSortKey
|
|
56
|
+
)}}
|
|
57
|
+
{{/if}}
|
|
58
|
+
|
|
59
|
+
{{!-- Second page numbers --}}
|
|
60
|
+
{{#if (and showPages showPagesBottom)}}
|
|
61
|
+
<div class="text-center" style="overflow:auto">
|
|
62
|
+
{{page-numbers
|
|
63
|
+
content=(hash)
|
|
64
|
+
showFL=true
|
|
65
|
+
currentPage=page
|
|
66
|
+
numPagesToShow=maxPageButtons
|
|
67
|
+
totalPages=totalPages
|
|
68
|
+
action=(action 'setPage')
|
|
69
|
+
}}
|
|
70
|
+
</div>
|
|
71
|
+
{{/if}}
|
|
72
|
+
{{/if}}
|
|
73
|
+
{{/if}}
|
|
74
|
+
</div>
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
{{!-- If column has a hideLabel set to true, just spit back the value of whatever the user gave it --}}
|
|
2
|
-
{{#if column.hideLabel}}
|
|
3
|
-
{{#if column.cellComponent}}
|
|
4
|
-
{{!-- Pass in all the normal component values, but add an extra boolean so they know it is a hidden row --}}
|
|
5
|
-
{{component column.cellComponent tableActions=tableActions table=table column=column row=row value=value rawValue=rawValue isExpandedRow=true}}
|
|
6
|
-
{{else}}
|
|
7
|
-
{{value}}
|
|
8
|
-
{{/if}}
|
|
9
|
-
{{else}}
|
|
10
|
-
{{!-- Only print the cell if the column label is defined--}}
|
|
11
|
-
{{#if column.label}}
|
|
12
|
-
<dt class="{{column.classNames}}" title="{{column.label}}">{{column.label}}:</dt>
|
|
13
|
-
<dd class="{{column.cellClassNames}}">
|
|
14
|
-
{{!-- If the cell has a custom component, use that --}}
|
|
15
|
-
{{#if column.cellComponent}}
|
|
16
|
-
{{!-- Pass in all the normal component values, but add an extra boolean so they know it is a hidden row --}}
|
|
17
|
-
{{component column.cellComponent tableActions=tableActions table=table column=column row=row value=value rawValue=rawValue isExpandedRow=true}}
|
|
18
|
-
{{else}}
|
|
19
|
-
{{value}}
|
|
20
|
-
{{/if}}
|
|
21
|
-
</dd>
|
|
22
|
-
{{/if}}
|
|
23
|
-
{{/if}}
|
|
1
|
+
{{!-- If column has a hideLabel set to true, just spit back the value of whatever the user gave it --}}
|
|
2
|
+
{{#if column.hideLabel}}
|
|
3
|
+
{{#if column.cellComponent}}
|
|
4
|
+
{{!-- Pass in all the normal component values, but add an extra boolean so they know it is a hidden row --}}
|
|
5
|
+
{{component column.cellComponent tableActions=tableActions table=table column=column row=row value=value rawValue=rawValue isExpandedRow=true}}
|
|
6
|
+
{{else}}
|
|
7
|
+
{{value}}
|
|
8
|
+
{{/if}}
|
|
9
|
+
{{else}}
|
|
10
|
+
{{!-- Only print the cell if the column label is defined--}}
|
|
11
|
+
{{#if column.label}}
|
|
12
|
+
<dt class="{{column.classNames}}" title="{{column.label}}">{{column.label}}:</dt>
|
|
13
|
+
<dd class="{{column.cellClassNames}}">
|
|
14
|
+
{{!-- If the cell has a custom component, use that --}}
|
|
15
|
+
{{#if column.cellComponent}}
|
|
16
|
+
{{!-- Pass in all the normal component values, but add an extra boolean so they know it is a hidden row --}}
|
|
17
|
+
{{component column.cellComponent tableActions=tableActions table=table column=column row=row value=value rawValue=rawValue isExpandedRow=true}}
|
|
18
|
+
{{else}}
|
|
19
|
+
{{value}}
|
|
20
|
+
{{/if}}
|
|
21
|
+
</dd>
|
|
22
|
+
{{/if}}
|
|
23
|
+
{{/if}}
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<span class="input-group-addon"> </span>
|
|
29
29
|
{{else}}
|
|
30
30
|
<span class="input-group-addon clickable" {{action "deleteItem" item}}>
|
|
31
|
-
<i class=
|
|
31
|
+
<i class={{deleteIcon}}></i>
|
|
32
32
|
</span>
|
|
33
33
|
{{/if}}
|
|
34
34
|
{{else}}
|
|
@@ -1,35 +1,40 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* @
|
|
4
|
-
* @
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
/**
|
|
2
|
+
* DESCRIPTION NEEDED
|
|
3
|
+
* @class BaseCells
|
|
4
|
+
* @module Utils
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Creates a generic row toggle object
|
|
8
|
+
* @param {Object} extra Additional values to add to the row toggle. Breakpoints is the most common one
|
|
9
|
+
* @return {Object} Object to use as a row toggle column
|
|
10
|
+
*/
|
|
11
|
+
export function rowToggle(extra = {}) {
|
|
12
|
+
let {valuePath} = extra;
|
|
13
|
+
return Object.assign({
|
|
14
|
+
label: valuePath ? '#' : '',
|
|
15
|
+
width: valuePath ? '40px' : '35px',
|
|
16
|
+
align: valuePath ? 'toggle' : 'center',
|
|
17
|
+
sortable: !!valuePath,
|
|
18
|
+
canExport: false,
|
|
19
|
+
showExpanded: false,
|
|
20
|
+
cellComponent: valuePath ? 'fw-row-toggle-index' : 'fw-row-toggle'
|
|
21
|
+
}, extra);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Creates a generic action cell
|
|
26
|
+
* @param {Object} extra Additional values to add to the action buttons. Small is useful to shrink it with breakpoints
|
|
27
|
+
* @return {Object} Object to use as an actions button column
|
|
28
|
+
*/
|
|
29
|
+
export function actions(extra = {}) {
|
|
30
|
+
let {small} = extra;
|
|
31
|
+
return Object.assign({
|
|
32
|
+
label: 'Actions',
|
|
33
|
+
// if small is set, shrink the width
|
|
34
|
+
width: small ? '95px' : '170px',
|
|
35
|
+
sortable: false,
|
|
36
|
+
canExport: false,
|
|
37
|
+
showExpanded: false,
|
|
38
|
+
cellComponent: 'fw-cell-action'
|
|
39
|
+
}, extra);
|
|
40
|
+
}
|
package/addon/utils/export.js
CHANGED
|
@@ -1,72 +1,76 @@
|
|
|
1
|
-
import EmberObject from '@ember/object';
|
|
2
|
-
import {isEmpty, isNone} from '@ember/utils';
|
|
3
|
-
import Papa from 'papaparse';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*
|
|
7
|
-
* @
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
link.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
1
|
+
import EmberObject from '@ember/object';
|
|
2
|
+
import {isEmpty, isNone} from '@ember/utils';
|
|
3
|
+
import Papa from 'papaparse';
|
|
4
|
+
/**
|
|
5
|
+
* Used internally only. DESCRIPTION NEEDED
|
|
6
|
+
* @class Export
|
|
7
|
+
* @module Utils
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Creates a CSV file from a data array and a title
|
|
11
|
+
* @param {Array} data Array of table cells
|
|
12
|
+
* @param {Title} [name=null] Name to export
|
|
13
|
+
*/
|
|
14
|
+
export function createCSV(data, name = null) {
|
|
15
|
+
// first step, we need to extra the cells into "Cell","Cell 2" format, use JSON.stringify as it makes most escapes
|
|
16
|
+
// regex removes the brackets, as its an array we are calling stringify on
|
|
17
|
+
let rows = Papa.unparse(data);
|
|
18
|
+
|
|
19
|
+
// next, join that using newlines and export as data CSV
|
|
20
|
+
let encodedUri = `data:text/csv;charset=utf-8,${encodeURIComponent(rows)}`;
|
|
21
|
+
|
|
22
|
+
// downloading is a bit weird. We create a link element with the name and URL then click the element
|
|
23
|
+
let link = document.createElement('a');
|
|
24
|
+
link.setAttribute('href', encodedUri);
|
|
25
|
+
link.setAttribute('download', `${name || 'Export'}.csv`);
|
|
26
|
+
document.body.appendChild(link); // Required for FF
|
|
27
|
+
link.click(); // This will download the data file
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Exports an Ember Light Table to CSV
|
|
32
|
+
* @param {Table} table Table class, just needs to include rows and columns
|
|
33
|
+
* @param {String} [title='Export'] Title to use for exporting
|
|
34
|
+
*/
|
|
35
|
+
export default function exportTable(table, title = 'Export') {
|
|
36
|
+
// start by filtering out columns which opted out of exporting. Examples include action buttons and the row toggle
|
|
37
|
+
let columns = table.get('columns').filter(({canExport}) => {
|
|
38
|
+
// if canExport is defined, require it to be true
|
|
39
|
+
return isNone(canExport) || canExport;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// ensure we have columns and data
|
|
43
|
+
if (isEmpty(columns)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// start the data with just the labels from the columns
|
|
48
|
+
let data = [columns.map(({exportLabel, label}) => exportLabel || label)];
|
|
49
|
+
|
|
50
|
+
// next, populate data by iterating through the current rows
|
|
51
|
+
table.get('rows').forEach((row) => {
|
|
52
|
+
// in each row, iterate through the columns
|
|
53
|
+
let rowData = columns.map((column) => {
|
|
54
|
+
let {valuePath, format} = column;
|
|
55
|
+
// flat value pulled from the model
|
|
56
|
+
let rawValue = valuePath ? row.get(valuePath) : '';
|
|
57
|
+
let value = rawValue;
|
|
58
|
+
// if we have a format function and a value, run the function
|
|
59
|
+
if (format && typeof format === 'function') {
|
|
60
|
+
// so, typically there is a cell object which contains data as the functions "this"
|
|
61
|
+
// but we are in a action so simulate it by passing in the data we expect the function to have
|
|
62
|
+
// while we are here, might as well pass in an export parameter so they can modify behavior for export if desired
|
|
63
|
+
value = format.call(EmberObject.create({column, row, table, rawValue, export: true}), rawValue);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// return the value, though convert null/undefined into a string
|
|
67
|
+
return isNone(value) ? '' : value;
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// add that data into the main array
|
|
71
|
+
data.pushObject(rowData);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// finally, pass our 2 dimensional array to the function to convert to a file download
|
|
75
|
+
createCSV(data, title);
|
|
76
|
+
}
|
package/addon/utils/formats.js
CHANGED
|
@@ -1,42 +1,46 @@
|
|
|
1
|
-
/* global moment */
|
|
2
|
-
import {htmlSafe} from '@ember/string';
|
|
3
|
-
import {isNone} from '@ember/utils';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* Format
|
|
7
|
-
* @
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
1
|
+
/* global moment */
|
|
2
|
+
import {htmlSafe} from '@ember/string';
|
|
3
|
+
import {isNone} from '@ember/utils';
|
|
4
|
+
/**
|
|
5
|
+
* DESCRIPTION NEEDED
|
|
6
|
+
* @class Format
|
|
7
|
+
* @module Utils
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Format function which replaces the value with a basic Yes/No format for if its true or false
|
|
11
|
+
* @param {Any} value Value to test
|
|
12
|
+
* @return {String} "Yes" if the value is truthy, "No" otherwise
|
|
13
|
+
*/
|
|
14
|
+
export function formatBoolean(value) {
|
|
15
|
+
return value ? 'Yes' : 'No';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generates a format function which returns the value or an italic default text
|
|
20
|
+
* @param {String} [nullText='None'] Text if the value is null
|
|
21
|
+
* @return {Function} Function to pass into the column format
|
|
22
|
+
*/
|
|
23
|
+
export function formatNullable(nullText = 'None') {
|
|
24
|
+
return function(value) {
|
|
25
|
+
if (isNone(value)) {
|
|
26
|
+
return this.get('export') ? '' : htmlSafe(`<i>${nullText}</i>`);
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Generates a function which formats a moment based on the specified format
|
|
34
|
+
* @param {String} format moment format
|
|
35
|
+
* @param {String} exportFormat moment format used on exporting
|
|
36
|
+
* @return {Function} Function to pass into a column which formats by a moment
|
|
37
|
+
*/
|
|
38
|
+
export function formatMoment(format, exportFormat = null) {
|
|
39
|
+
return function(date) {
|
|
40
|
+
if (moment.isMoment(date)) {
|
|
41
|
+
// if we are exporting and have an export format, use that
|
|
42
|
+
let useFormat = exportFormat && this.get('export') ? exportFormat : format;
|
|
43
|
+
return date.format(useFormat);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|