element.
5 | */
6 | angular.module('ui.codemirror', [])
7 | .constant('uiCodemirrorConfig', {})
8 | .directive('uiCodemirror', uiCodemirrorDirective);
9 |
10 | /**
11 | * @ngInject
12 | */
13 | function uiCodemirrorDirective($timeout, uiCodemirrorConfig) {
14 |
15 | return {
16 | restrict: 'EA',
17 | require: '?ngModel',
18 | compile: function compile() {
19 |
20 | // Require CodeMirror
21 | if (angular.isUndefined(window.CodeMirror)) {
22 | throw new Error('ui-codemirror needs CodeMirror to work... (o rly?)');
23 | }
24 |
25 | return postLink;
26 | }
27 | };
28 |
29 | function postLink(scope, iElement, iAttrs, ngModel) {
30 |
31 | var codemirrorOptions = angular.extend(
32 | { value: iElement.text() },
33 | uiCodemirrorConfig.codemirror || {},
34 | scope.$eval(iAttrs.uiCodemirror),
35 | scope.$eval(iAttrs.uiCodemirrorOpts)
36 | );
37 |
38 | var codemirror = newCodemirrorEditor(iElement, codemirrorOptions);
39 |
40 | configOptionsWatcher(
41 | codemirror,
42 | iAttrs.uiCodemirror || iAttrs.uiCodemirrorOpts,
43 | scope
44 | );
45 |
46 | configNgModelLink(codemirror, ngModel, scope);
47 |
48 | configUiRefreshAttribute(codemirror, iAttrs.uiRefresh, scope);
49 |
50 | // Allow access to the CodeMirror instance through a broadcasted event
51 | // eg: $broadcast('CodeMirror', function(cm){...});
52 | scope.$on('CodeMirror', function(event, callback) {
53 | if (angular.isFunction(callback)) {
54 | callback(codemirror);
55 | } else {
56 | throw new Error('the CodeMirror event requires a callback function');
57 | }
58 | });
59 |
60 | // onLoad callback
61 | if (angular.isFunction(codemirrorOptions.onLoad)) {
62 | codemirrorOptions.onLoad(codemirror);
63 | }
64 | }
65 |
66 | function newCodemirrorEditor(iElement, codemirrorOptions) {
67 | var codemirrot;
68 |
69 | if (iElement[0].tagName === 'TEXTAREA') {
70 | // Might bug but still ...
71 | codemirrot = window.CodeMirror.fromTextArea(iElement[0], codemirrorOptions);
72 | } else {
73 | iElement.html('');
74 | codemirrot = new window.CodeMirror(function(cm_el) {
75 | iElement.append(cm_el);
76 | }, codemirrorOptions);
77 | }
78 |
79 | return codemirrot;
80 | }
81 |
82 | function configOptionsWatcher(codemirrot, uiCodemirrorAttr, scope) {
83 | if (!uiCodemirrorAttr) { return; }
84 |
85 | var codemirrorDefaultsKeys = Object.keys(window.CodeMirror.defaults);
86 | scope.$watch(uiCodemirrorAttr, updateOptions, true);
87 | function updateOptions(newValues, oldValue) {
88 | if (!angular.isObject(newValues)) { return; }
89 | codemirrorDefaultsKeys.forEach(function(key) {
90 | if (newValues.hasOwnProperty(key)) {
91 |
92 | if (oldValue && newValues[key] === oldValue[key]) {
93 | return;
94 | }
95 |
96 | codemirrot.setOption(key, newValues[key]);
97 | }
98 | });
99 | }
100 | }
101 |
102 | function configNgModelLink(codemirror, ngModel, scope) {
103 | if (!ngModel) { return; }
104 | // CodeMirror expects a string, so make sure it gets one.
105 | // This does not change the model.
106 | ngModel.$formatters.push(function(value) {
107 | if (angular.isUndefined(value) || value === null) {
108 | return '';
109 | } else if (angular.isObject(value) || angular.isArray(value)) {
110 | throw new Error('ui-codemirror cannot use an object or an array as a model');
111 | }
112 | return value;
113 | });
114 |
115 |
116 | // Override the ngModelController $render method, which is what gets called when the model is updated.
117 | // This takes care of the synchronizing the codeMirror element with the underlying model, in the case that it is changed by something else.
118 | ngModel.$render = function() {
119 | //Code mirror expects a string so make sure it gets one
120 | //Although the formatter have already done this, it can be possible that another formatter returns undefined (for example the required directive)
121 | var safeViewValue = ngModel.$viewValue || '';
122 | codemirror.setValue(safeViewValue);
123 | };
124 |
125 |
126 | // Keep the ngModel in sync with changes from CodeMirror
127 | codemirror.on('change', function(instance) {
128 | var newValue = instance.getValue();
129 | if (newValue !== ngModel.$viewValue) {
130 | scope.$evalAsync(function() {
131 | ngModel.$setViewValue(newValue);
132 | });
133 | }
134 | });
135 | }
136 |
137 | function configUiRefreshAttribute(codeMirror, uiRefreshAttr, scope) {
138 | if (!uiRefreshAttr) { return; }
139 |
140 | scope.$watch(uiRefreshAttr, function(newVal, oldVal) {
141 | // Skip the initial watch firing
142 | if (newVal !== oldVal) {
143 | $timeout(function() {
144 | codeMirror.refresh();
145 | });
146 | }
147 | });
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/example/partials/additional_filters.html:
--------------------------------------------------------------------------------
1 | Additional filters
2 | add filtering by controller variables
3 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
29 |
30 |
31 |
32 | In template:
33 |
63 |
64 |
Notice:
65 | $owner
is a link to Controller
66 |
67 |
68 |
--------------------------------------------------------------------------------
/example/partials/attributes.html:
--------------------------------------------------------------------------------
1 | Possible attrributes:
2 |
3 | Required:
4 |
5 |
6 | -
7 |
data="controllerArray"
8 | Data source (array of objects) in your Controller. But if 'fromUrl' is present 'data' atribute will contain controller link to empty array( will be fill up after receiving data ).
9 |
10 | -
11 |
headers="headerName1,headerName1,headerName3"
12 | Array of table header names
13 |
14 | -
15 |
fields="Property1, Property2"
16 | Array of displayed properties of object. This option allows you to display only certain fields of the object. Number of fields must be equal number of headers.
17 |
18 |
19 |
20 | Optional:
21 |
22 |
23 |
24 | -
25 |
fromUrl="URL"
26 | Load data from external URL.
27 |
28 | -
29 |
display="N"
30 | Display N records per page.
31 |
32 | -
33 |
search="true | false | separate"
34 | Display search input. Value "separate" is allows you search by columns.
35 |
36 | -
37 |
paging="true | false"
38 | Use paging to present data.
39 |
40 | -
41 |
sorting="simple | compound | false"
42 | Use sorting. 'simple' - by single column (property), 'compound' - by few columns.
43 |
44 | -
45 |
select="multiply"
46 | Allows to select more than one row. Selected rows are accessible.
47 |
48 | -
49 |
editable="all"
50 | Allows to edit content inside cells. Edit uptates your angular model.
51 |
52 | -
53 |
selected-model="model"
54 | It exports selected model to controller variable.
55 |
56 | -
57 |
resize="true"
58 | Use column resizing.
59 |
60 | -
61 |
drag-columns="true"
62 | It allows to reorder your columns using drag-n-drop.
63 |
64 |
65 |
66 | Default values:
67 |
68 |
69 |
70 | -
71 |
display="5"
72 |
73 | -
74 |
paging="true"
75 |
76 | -
77 |
sorting="simple"
78 |
79 |
80 | -
81 |
resize="false"
82 |
83 | -
84 |
drag-columns="false"
85 |
86 |
87 |
--------------------------------------------------------------------------------
/example/partials/basic.html:
--------------------------------------------------------------------------------
1 | Bacis
2 |
3 |
12 |
13 |
14 |
15 | In template:
16 |
27 |
28 | In controller:
29 |
30 |
49 |
50 |
--------------------------------------------------------------------------------
/example/partials/column_highlighting.html:
--------------------------------------------------------------------------------
1 | Column highlighting
2 |
3 |
13 |
14 |
15 |
16 |
17 | In template:
18 |
27 |
28 |
29 |
Notice:
30 | just add class class="hover-column"
to add CSS column highlighting
31 |
32 |
--------------------------------------------------------------------------------
/example/partials/compound_resize.html:
--------------------------------------------------------------------------------
1 | Resizable table columns
2 |
3 |
10 |
11 |
12 |
13 |
14 |
Example
15 | Just add attribute resize
to the table
16 |
17 |
18 |
19 | In template:
20 |
29 |
30 |
31 |
Notice
32 | If you want to change in the size of the cell was changed and the length of the table, just add a CSS class with style width:auto
to the table. Example:
33 | .object-table-module table{ width:auto; }
34 |
35 |
36 | If you are using custom header:
37 | 1) Add ng-mousedown="resizeStart($event)"
and ng-mouseup="resizeEnd($event)"
to your <thead>
tag.
38 | 2) Add <div class="resize"></div>
to resized headers (<td>
tag)
39 |
40 |
46 |
47 |
48 |
49 |
50 | Name of Person
51 | |
52 |
53 |
54 | Eye |
55 |
56 |
57 | Age |
58 |
59 |
60 |
61 |
62 |
63 | In template:
64 |
88 |
--------------------------------------------------------------------------------
/example/partials/compound_sorting.html:
--------------------------------------------------------------------------------
1 | Compound sorting
2 |
3 |
10 |
11 |
12 |
Example
13 | First try sort by 'Full Name' , then by 'Money'
14 |
15 |
24 |
--------------------------------------------------------------------------------
/example/partials/custom_headers.html:
--------------------------------------------------------------------------------
1 | Custom headers pattern
2 |
3 |
10 |
11 |
12 | Personal information |
13 | Additional information |
14 |
15 |
16 | Name |
17 | Eye color |
18 | Age |
19 | Balance |
20 | Company |
21 | Address |
22 | Favorite Fruit |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | In template:
33 |
78 |
79 |
80 |
Notice:
81 | If you want to allow sorting you need to add attributes to header (th):
82 | ng-click="sortBy('object.property')"
and
83 | ng-class="headerIsSortedClass('Header Name')"
84 |
85 |
--------------------------------------------------------------------------------
/example/partials/custom_rows.html:
--------------------------------------------------------------------------------
1 | Rows pattern
2 |
3 |
11 |
12 |
13 | {{::item.name}} |
14 |
15 | {{::item.eyeColor}}
16 | |
17 | {{::item.age}} |
18 | {{::item.balance}} |
19 | {{::item.company}} |
20 | {{::item.address}} |
21 | {{::item.favoriteFruit}} |
22 |
23 |
24 |
25 |
26 |
27 |
28 | In template:
29 |
54 |
55 |
56 |
Warning:
57 | If you want to use ng-attributes (like ng-if
, ng-repeat
,...) inside your template - please add to your <body>
ng-non-bindable
attribute to prevent Angular engine to compile attributes before table render.
58 |
59 |
60 | Example:
61 |
62 |
67 |
68 |
69 | {{::item.name}} |
70 |
71 | {{::item.eyeColor}}
72 | |
73 | {{::item.address}} |
74 |
75 |
76 | {{::friend.name}}
77 |
78 | |
79 |
80 |
81 |
82 |
83 |
84 | In template:
85 |
107 |
--------------------------------------------------------------------------------
/example/partials/custom_rows_headers.html:
--------------------------------------------------------------------------------
1 | Custom rows and headers pattern:
2 |
3 |
10 |
11 |
12 | Name..(click me) |
13 | Age |
14 | Money $ |
15 |
16 |
17 |
18 |
19 |
20 | {{::item.name}} |
21 | {{::item.age}} |
22 | {{::item.money}} USD |
23 |
24 |
25 |
26 |
27 |
28 |
29 | In template:
30 |
56 |
57 |
58 |
Notice:
59 | $owner
is a link to Controller
60 |
--------------------------------------------------------------------------------
/example/partials/draggable_headers.html:
--------------------------------------------------------------------------------
1 | Draggable headers
2 |
3 |
12 |
13 |
14 | In template:
15 |
26 |
27 |
Example
28 | Working perfect with resize
resizing columns
29 |
30 |
31 | If you are using custom templates:
32 | add allow-drag
attribute to draggable header
33 |
39 |
40 |
41 | Name |
42 | Eye color |
43 | Age |
44 | Balance |
45 | Company |
46 | Favorite Fruit |
47 |
48 |
49 |
50 |
51 | {{::item.name}} |
52 |
53 | {{::item.eyeColor}}
54 | |
55 | {{::item.age}} |
56 | {{::item.balance}} |
57 | {{::item.balance}} |
58 | {{::item.favoriteFruit}} |
59 |
60 |
61 |
62 |
63 |
64 | In template:
65 |
96 |
--------------------------------------------------------------------------------
/example/partials/editable_cells.html:
--------------------------------------------------------------------------------
1 | Editable cells (all)
2 |
3 |
13 |
14 |
15 |
16 | In template:
17 |
28 |
29 |
30 |
Notice:
31 | Add attribute editable = "true"
to allow to edit all cells.
32 |
33 |
34 | Editable single column (Eye color)
35 |
36 |
44 |
45 |
46 | {{::item.name}} |
47 | {{item.eyeColor}} |
48 | {{::item.age}} |
49 | {{::item.balance}} |
50 | {{::item.company}} |
51 | {{::item.address}} |
52 | {{::item.favoriteFruit}} |
53 |
54 |
55 |
56 |
57 |
58 |
59 | In template:
60 |
81 |
82 |
83 |
Notice:
84 | Add attribute editable
to cell for editing.
85 |
86 |
87 |
--------------------------------------------------------------------------------
/example/partials/external.html:
--------------------------------------------------------------------------------
1 | External resource
2 |
3 |
10 |
11 |
12 |
13 | In template:
14 |
23 |
24 |
25 |
Notice
26 | Directive exports all data to controller variable.
27 |
28 |
29 | In controller:
30 |
34 |
--------------------------------------------------------------------------------
/example/partials/footer_expression.html:
--------------------------------------------------------------------------------
1 | Footer expressions
2 | aggregate functions in footer
3 |
4 |
11 |
12 |
13 | Total users:{{$filtered.length}} |
14 | |
15 | Total balance:{{ $owner.getTotalBalance($filtered) }} $ |
16 |
17 |
18 |
19 |
20 | {{::item.name}} |
21 | {{::item.age}} |
22 | {{item.money}} |
23 |
24 |
25 |
26 |
27 |
28 |
Please try to edit money
column
29 |
30 |
31 |
32 | In template:
33 |
56 |
57 |
58 |
Notice:
59 |
variable $filtered
contains displayed array (It depends on the filters like search or your custom filters);
60 |
If you want to apply your aggregate function for all data array despite filters, please use getTotalBalance(data)
. In this case returned of function value won't be changed during search.
61 |
62 |
63 |
64 |
Notice:
65 |
The <tfoot>
tag must be used in the following context: As a child of a <table>
element, after any <caption>
, <colgroup>
, and <thead>
elements and before any <tbody>
and <tr>
elements.
66 |
67 |
68 |
69 |
70 |
71 | Method getTotalBalance
in controller:
72 |