forms-angular 0.12.0-beta.24 → 0.12.0-beta.240

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.
@@ -1,15 +1,63 @@
1
1
  declare module fng {
2
- var formsAngular: angular.IModule;
2
+ export interface IFng extends angular.IModule {
3
+ beforeProcess?: (scope: IFormScope, cb: (err?: Error) => void) => void;
4
+ title?: { prefix?: string; suffix?: string };
5
+ // when provided, the named function (assumed to be present on $rootscope) will be used to determine the visibility
6
+ // of menu items and control groups
7
+ hiddenSecurityFuncName?: string;
8
+ // when provided, the named function (assumed to be present on $rootscope) will be used to determine the disabled
9
+ // state of menu items and individual form input controls
10
+ disabledSecurityFuncName?: string;
11
+ // when provided, the named function (assumed to be present on $rootscope) will be called each time a new page
12
+ // or popup is accessed, providing the host app with the opportunity to confirm whether there are ANY hidden elements
13
+ // at all on that page. where there are not, we can optimise by skipping logic relating to DOM element visibility.
14
+ skipHiddenSecurityFuncName?: string;
15
+ // when provided, the named function (assumed to be present on $rootscope) will be called each time a new page
16
+ // or popup is accessed, providing the host app with the opportunity to confirm whether there are ANY disabled elements
17
+ // at all on that page. where there are not, we can optimise by skipping logic relating to disabling DOM elements.
18
+ skipDisabledSecurityFuncName?: string;
19
+ // when provided, the named function (assumed to be present on $rootscope) will be called each time a new page
20
+ // or popup is accessed, providing the host app with the opportunity to confirm whether there are ANY elements on that
21
+ // page that require their child elements to be disabled. where there are not, we can optimise by skipping
22
+ // disabled ancestor checks.
23
+ skipDisabledAncestorSecurityFuncName?: string;
24
+ // how the function identified by elemSecurityFuncName should be bound. "instant" means that it will be called
25
+ // as the markup is being constructed, with 'hidden' elements not included in the markup at all, and disabled elements
26
+ // given a simple DISABLED attribute. this is the most efficient approach. "one-time" will add ng-hide and
27
+ // ng-disabled directives to the relevant elements, with one-time binding to the security function. this is
28
+ // also reasonably efficient (but not as efficient as "instant", due to the need for watches). "normal" will not use
29
+ // one-time binding, which has the potential to be highly resource-intensive on large forms. which
30
+ // option is chosen will depend upon when the function identified by elemSecurityFuncName will be ready to
31
+ // make the necessary determination.
32
+ elemSecurityFuncBinding?: "instant" | "one-time" | "normal";
33
+ hideableAttr?: string; // an attribute to mark all elements that can be hidden using security
34
+ disableableAttr?: string; // an attribute to mark all elements that can be disabled using security
35
+ disableableAncestorAttr?: string; // an attribute to mark all elements whose children can all be disabled using "disabled + children" security
36
+ // if an element's id is a partial match on any of this array's contents, it will never be marked with hideableAttr/disableableAttr
37
+ ignoreIdsForHideableOrDisableableAttrs?: string[];
38
+ keyboardShortCuts? : {
39
+ letter: string;
40
+ keycode: number;
41
+ id: string;
42
+ desc: string;
43
+ } [];
44
+ }
45
+ var formsAngular: IFng;
3
46
 
4
47
  /*
5
48
  Type definitions for types that are used on both the client and the server
6
49
  */
50
+ type formStyle = "inline" | "vertical" | "horizontal" | "horizontalCompact" | "stacked";
7
51
 
8
- export interface IFngLookupReference {
9
- type: 'lookup';
10
- collection: string
52
+ export interface IBaseArrayLookupReference {
53
+ property: string;
54
+ value: string;
11
55
  }
12
56
 
57
+ interface ILookupItem {
58
+ id: string;
59
+ text: string;
60
+ }
13
61
  /*
14
62
  IInternalLookupreference makes it possible to look up from a list (of key / value pairs) in the current record. For example
15
63
 
@@ -20,13 +68,11 @@ declare module fng {
20
68
  var ESchema = new Schema({
21
69
  warehouse_name: {type: String, list: {}},
22
70
  shelves: {type: [ShelfSchema]},
23
- favouriteShelf: {type: Schema.Types.ObjectId, ref: {type: 'internal', property: 'shelves', value:'location'};
71
+ favouriteShelf: {type: Schema.Types.ObjectId, internalRef: {property: 'shelves', value:'location'};
24
72
  });
25
73
  */
26
- export interface IFngInternalLookupReference {
27
- type: 'internal';
28
- property: string;
29
- value: string;
74
+ export interface IFngInternalLookupReference extends IBaseArrayLookupReference {
75
+ noConvert?: boolean; // can be used by a tricksy hack to get around nesting limitations
30
76
  }
31
77
 
32
78
  /*
@@ -36,18 +82,15 @@ declare module fng {
36
82
  const LSchemaDef : IFngSchemaDefinition = {
37
83
  descriptin: {type: String, required: true, list: {}},
38
84
  warehouse: {type: Schema.Types.ObjectId, ref:'k_referencing_self_collection', form: {directive: 'fng-ui-select', fngUiSelect: {fngAjax: true}}},
39
- shelf: {type: Schema.Types.ObjectId, ref: {type: 'lookupList', collection:'k_referencing_self_collection', id:'$warehouse', property: 'shelves', value:'location'}},
85
+ shelf: {type: Schema.Types.ObjectId, lookupListRef: {collection:'k_referencing_self_collection', id:'$warehouse', property: 'shelves', value:'location'}},
40
86
  };
41
87
  */
42
- export interface IFngLookupListReference {
43
- type: 'lookupList';
44
- collection: string; // collection that contains the list
88
+ export interface IFngLookupListReference extends IBaseArrayLookupReference {
89
+ collection: string; // collection that contains the list
45
90
  /*
46
91
  Some means of calculating _id in collection. If it starts with $ then it is property in record
47
92
  */
48
93
  id: string;
49
- property: string;
50
- value: string;
51
94
  }
52
95
 
53
96
  /*
@@ -66,7 +109,7 @@ declare module fng {
66
109
  */
67
110
  export interface IFngShowWhen {
68
111
  lhs: any;
69
- comp: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte';
112
+ comp: "eq" | "ne" | "gt" | "gte" | "lt" | "lte";
70
113
  rhs: any;
71
114
  }
72
115
 
@@ -74,11 +117,15 @@ declare module fng {
74
117
  link allows the setting up of hyperlinks for lookup reference fields
75
118
  */
76
119
  export interface IFngLinkSetup {
77
- linkOnly?: boolean; // if true (which at the time of writing is the only option supported) then the input element is not generated.
78
- form?: string; // can be used to generate a link to a custom schema
79
- text?: string; // the literal value used for the link. If this property is omitted then text is generated from the field values of the document referred to by the link.
120
+ linkOnly?: boolean; // if true then the input element is not generated (this overrides label)
121
+ label?: boolean; // Make a link out of the label (causes text to be overridden) (this overrides text)
122
+ form?: string; // can be used to generate a link to a custom schema
123
+ linktab?: string; // can be used to generate a link to a tab on a form
124
+ text?: string; // the literal value used for the link. If this property is omitted then text is generated from the field values of the document referred to by the link.
80
125
  }
81
126
 
127
+ export type FieldSizeString = "mini" | "small" | "medium" | "large" | "xlarge" | "xxlarge" | "block-level"; // sets control width. Default is 'medium''
128
+
82
129
  export interface IFngSchemaTypeFormOpts {
83
130
  /*
84
131
  The input type to be generated - which must be compatible with the Mongoose type.
@@ -97,33 +144,36 @@ declare module fng {
97
144
  */
98
145
  type?: string;
99
146
 
100
- hidden?: boolean; // inhibits this schema key from appearing on the generated form.
101
- label?: string | null; // overrides the default input label. label:null suppresses the label altogether.
102
- ref?: IFngLookupReference | IFngInternalLookupReference;
103
-
147
+ hidden?: boolean; // inhibits this schema key from appearing on the generated form.
148
+ label?: string | null; // overrides the default input label. label:null suppresses the label altogether.
149
+ ref?: string; // reference to another collection
150
+ internalRef?: IFngInternalLookupReference;
151
+ lookupListRef?: IFngLookupListReference;
104
152
  id?: string; // specifies the id of the input field (which defaults to f_name)
105
153
 
106
- placeHolder?: string // adds placeholder text to the input (depending on data type).
107
- help?: string; // adds help text under the input.
108
- helpInline?: string; // adds help to the right of the input.
109
- popup?: string; // adds popup help as specified.
110
- order?: number; // allows user to specify the order / tab order of this field in the form. This overrides the position in the Mongoose schema.
111
- size?: 'mini' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | 'block-level'; // sets control width. Default is 'medium''
112
- readonly?: boolean; // adds the readonly attribute to the generated input (currently doesn't work with date - and perhaps other types).
113
- rows?: number | 'auto'; // sets the number of rows in inputs (such as textarea) that support this. Setting rows to "auto" makes the textarea expand to fit the content, rather than create a scrollbar.
114
- tab?: string; // Used to divide a large form up into a tabset with multiple tabs
115
- showWhen?: IFngShowWhen | string; // allows conditional display of fields based on values elsewhere. string must be an abular expression.
154
+ placeHolder?: string; // adds placeholder text to the input (depending on data type).
155
+ help?: string; // adds help text under the input.
156
+ helpInline?: string; // adds help to the right of the input.
157
+ popup?: string; // adds title (popup help) as specified.
158
+ ariaLabel?: string; // adds aria-label as specified.
159
+ order?: number; // allows user to specify the order / tab order of this field in the form. This overrides the position in the Mongoose schema.
160
+ size?: FieldSizeString;
161
+ readonly?: boolean | string; // adds the readonly or ng-readonly attribute to the generated input (currently doesn't work with date - and perhaps other types).
162
+ rows?: number | "auto"; // sets the number of rows in inputs (such as textarea) that support this. Setting rows to "auto" makes the textarea expand to fit the content, rather than create a scrollbar.
163
+ tab?: string; // Used to divide a large form up into a tabset with multiple tabs
164
+ showWhen?: IFngShowWhen | string; // allows conditional display of fields based on values elsewhere. string must be an abular expression.
116
165
 
117
166
  /*
118
167
  add: 'class="myClass"' allows custom styling of a specific input
119
168
  Angular model options can be used - for example add: 'ng-model-options="{updateOn: \'default blur\', debounce: { \'default\': 500, \'blur\': 0 }}" '
120
169
  custom validation directives, such as the timezone validation in this schema
121
170
  */
122
- add?: string; // allows arbitrary attributes to be added to the input tag.
171
+ add?: string; // allows arbitrary attributes to be added to the input tag.
123
172
 
124
- class?: string; // allows arbitrary classes to be added to the input tag.
125
- inlineRadio?: boolean; // (only valid when type is radio) should be set to true to present all radio button options in a single line
126
- link?: IFngLinkSetup; // handles displaying links for IFngLookupReference lookups
173
+ class?: string; // allows arbitrary classes to be added to the input tag.
174
+ inlineRadio?: boolean; // (only valid when type is radio) should be set to true to present all radio button options in a single line
175
+ link?: IFngLinkSetup; // handles displaying links for ref lookups
176
+ asText?: boolean; // (only valid when type is ObjectId) should be set to true to force a simple text input rather than a select. presumed for advanced cases where the objectid is going to be pasted in.
127
177
 
128
178
  /*
129
179
  With a select / radio type you can specify the options.
@@ -146,17 +196,35 @@ declare module fng {
146
196
  /*
147
197
  The next few options relate to the handling and display of arrays (including arrays of subdocuments)
148
198
  */
149
- noAdd?: boolean; // inhibits an Add button being generated for arrays.
199
+ noAdd?: boolean | string; // inhibits an Add button being generated for arrays.
200
+ noneIndicator?: boolean; // show "None" where there's no add button and no array items
150
201
  unshift?: boolean; // (for arrays of sub documents) puts an add button in the sub schema header which allows insertion of new sub documents at the beginning of the array.
151
- noRemove?: boolean; // inhibits a Remove button being generated for array elements.
152
- formstyle?: 'inline' | 'vertical' | 'horizontal' | 'horizontalCompact'; // (only valid on a sub schema) sets style of sub form.
153
- sortable? : boolean; // Allows drag and drop sorting of arrays - requires angular-ui-sortable
202
+ noRemove?: boolean | string; // inhibits a Remove button being generated for array elements.
203
+ formstyle?: formStyle; // (only valid on a sub schema) sets style of sub form.
204
+ sortable?: boolean | string; // Allows drag and drop sorting of arrays - requires angular-ui-sortable
205
+ ngClass?: string; // Allows for conditional per-item styling through the addition of an ng-class expression to the class list of li elements created for each item in the array
206
+ filterable?: boolean; // Add a data-ng-hide to all array elements, referring to subDoc._hidden. Does not actually (yet) provide a UI for managing this property, however (which needs to be done via an external directive)
207
+ subDocContainerType?:
208
+ | "fieldset"
209
+ | "well"
210
+ | "well-large"
211
+ | "well-small"
212
+ | string
213
+ | ((info) => { before: ""; after: "" }); // allows each element in the array to be nested in a container
214
+ subDocContainerProps?: any; // the parameters that will be passed if subDocContainerType is a function
154
215
 
155
216
  /*
156
217
  The next section relates to the display of sub documents
157
218
  */
158
219
  customSubDoc?: string; // Allows you to specify custom HTML (which may include directives) for the sub doc
220
+ customHeader?: string; // Allows you to specify custom HTML (which may include directives) for the header of a group of sub docs
159
221
  customFooter?: string; // Allows you to specify custom HTML (which may include directives) for the footer of a group of sub docs
222
+
223
+ /*
224
+ Suppresses warnings about attenpting deep nesting which would be logged to console in some circumstances when a
225
+ directive fakes deep nesting
226
+ */
227
+ suppressNestingWarning?: boolean;
160
228
  }
161
229
 
162
230
  // Schema passed from server - derived from Mongoose schema
@@ -164,83 +232,167 @@ declare module fng {
164
232
  name: string;
165
233
  schema?: Array<IFieldViewInfo>;
166
234
  array?: boolean;
167
- showIf? : any;
235
+ showIf?: any;
168
236
  required?: boolean;
169
- step? : number;
237
+ step?: number;
170
238
  }
171
239
 
240
+ export type fieldType =
241
+ | "string"
242
+ | "text"
243
+ | "textarea"
244
+ | "number"
245
+ | "select"
246
+ | "link"
247
+ | "date"
248
+ | "checkbox"
249
+ | "password"
250
+ | "radio";
251
+
172
252
  // Schema used internally on client - often derived from IFieldViewInfo passed from server
173
253
  export interface IFormInstruction extends IFieldViewInfo {
174
- id? : string; // id of generated DOM element
175
- type?: 'string' | 'text' | 'textarea' | 'number' | 'select' | 'link' | 'date' | 'checkbox' | 'password';
176
- rows? : number
177
- label: string;
254
+ id?: string; // id of generated DOM element
255
+ nonUniqueId?: string; // where this field is part of a sub-sub-schema, id is likely to include $index from the sub-schema, to ensure uniqueness. provide it here without reference to $parent.$index for use in security evaluations.
256
+ type?: fieldType;
257
+ defaultValue?: any;
258
+ rows?: number;
259
+ label?: string;
178
260
  options?: any;
179
261
  ids?: any;
180
262
  hidden?: boolean;
181
263
  tab?: string;
182
- add? : string;
183
- ref? : any;
184
- link? : any;
185
- linkText?: string;
186
- form?: string; // the form that is linked to
187
- select2? : any; // deprecated
264
+ add?: string;
265
+ ref?: any;
266
+ link?: any;
267
+ linktext?: string;
268
+ linklabel?: boolean;
269
+ form?: string; // the form that is linked to
270
+ select2?: any; // deprecated
271
+ schema?: IFormInstruction[]; // If the field is an array of fields
272
+ intType?: "date";
273
+ [directiveOptions: string]: any;
188
274
  }
189
275
 
276
+ interface IContainerInstructions {
277
+ before?: string;
278
+ after?: string;
279
+ omit?: boolean;
280
+ }
281
+
282
+ export type HiddenTabReintroductionMethod = "none" | "tab";
283
+
284
+ export interface IContainer {
285
+ /*
286
+ Type of container, which determines markup. This is currently only available when the schema is generated by
287
+ the client for use independent of the BaseController
288
+ In the case of a string which does not match one of the predefined options
289
+ the generated container div is given the class of the name
290
+ */
291
+ containerType: "fieldset" | "well" | "tabset" | "tab" | "+tab" | "well-large" | "well-small" | string | ((info: IContainer) => IContainerInstructions);
292
+ title?: string;
293
+ /*
294
+ Applies only to tabs - causing them to be rendered with a x for closing ('hiding') the tab in question.
295
+ Where hideable is true, hiddenTabArrayProp can be used to specify a property name (which can include ".", and which
296
+ will be assumed to identiy an array) that should be used to store the ids of closed ('hidden') tabs.
297
+ Where this is not specified, record.hiddenTabs will be used.
298
+ If hiddenTabReintroductionMethod is set to "tab", an additional tab will be added to the end of the tabset
299
+ with a + heading, and clicking on this will provide a UI for re-introducing hidden tabs.
300
+ */
301
+ hideable?: boolean;
302
+ hiddenTabArrayProp?: string;
303
+ hiddenTabReintroductionMethod?: HiddenTabReintroductionMethod;
304
+ /*
305
+ h1...h6 will use a header style
306
+ anything else will be used as a paragraph stype
307
+ */
308
+ titleTagOrClass?: string;
309
+ content: IFormInstruction[];
310
+ }
311
+
312
+ export type IFormSchemaElement = IFormInstruction | IContainer;
313
+
314
+ export type IFormSchema = IFormSchemaElement[];
315
+ export type IControlledFormSchema = IFormInstruction[];
316
+
190
317
  export interface IEnumInstruction {
191
318
  repeat: string;
192
319
  value: string;
193
- label? : string;
320
+ label?: string;
194
321
  }
195
322
 
196
323
  export interface IFngCtrlState {
197
324
  master: any;
198
- allowLocationChange: boolean; // Do we allow location change or prompt for permission
325
+ allowLocationChange: boolean; // Do we allow location change or prompt for permission
199
326
  }
200
- export interface IRecordHandler {
201
- convertToMongoModel(schema: Array<IFieldViewInfo>, anObject: any, prefixLength: number, scope: IFormScope): any;
327
+ export interface IRecordHandlerService {
328
+ convertToMongoModel(schema: IControlledFormSchema, anObject: any, prefixLength: number, scope: IFormScope): any;
202
329
  createNew(dataToSave: any, options: any, scope: IFormScope, ctrlState: IFngCtrlState): void;
203
- deleteRecord(model: any, id: any, scope: IFormScope, ctrlState: any): void;
204
- updateDocument(dataToSave : any, options: any, scope: IFormScope, ctrlState: IFngCtrlState) : void;
330
+ deleteRecord(id: string, scope: IFormScope, ctrlState: IFngCtrlState): void;
331
+ updateDocument(dataToSave: any, options: any, scope: IFormScope, ctrlState: IFngCtrlState): void;
205
332
  readRecord($scope: IFormScope, ctrlState);
206
333
  scrollTheList($scope: IFormScope);
207
- getListData($scope: IFormScope, record, fieldName, listSchema);
334
+ getListData(record, fieldName, listSchema?, $scope?: IFormScope);
208
335
  suffixCleanId(inst, suffix);
209
- setData(object, fieldname, element, value);
336
+ setData(object, fieldname: string, element, value);
337
+ getData(object, fieldname: string, element?: any);
210
338
  setUpLookupOptions(lookupCollection, schemaElement, $scope: IFormScope, ctrlState, handleSchema);
211
- setUpLookupListOptions: (ref: IFngLookupListReference, formInstructions: IFormInstruction, $scope: IFormScope, ctrlState: IFngCtrlState) => void;
339
+ setUpLookupListOptions: (
340
+ ref: IFngLookupListReference,
341
+ formInstructions: IFormInstruction,
342
+ $scope: IFormScope,
343
+ ctrlState: IFngCtrlState
344
+ ) => void;
212
345
  handleInternalLookup($scope: IFormScope, formInstructions, ref): void;
213
346
  preservePristine(element, fn): void;
214
347
  convertIdToListValue(id, idsArray, valuesArray, fname);
215
- decorateScope($scope:IFormScope, $uibModal, recordHandlerInstance : IRecordHandler, ctrlState);
216
- fillFormFromBackendCustomSchema(schema, $scope:IFormScope, formGeneratorInstance, recordHandlerInstance, ctrlState);
348
+ decorateScope($scope: IFormScope, $uibModal, recordHandlerInstance: IRecordHandlerService, ctrlState);
349
+ fillFormFromBackendCustomSchema(
350
+ schema,
351
+ $scope: IFormScope,
352
+ formGeneratorInstance,
353
+ recordHandlerInstance,
354
+ ctrlState
355
+ );
217
356
  fillFormWithBackendSchema($scope: IFormScope, formGeneratorInstance, recordHandlerInstance, ctrlState);
218
357
  handleError($scope: IFormScope);
219
358
  }
220
359
 
221
- export interface IFormGenerator {
222
- generateEditUrl(obj, $scope:IFormScope): string;
360
+ export interface IFormGeneratorService {
361
+ generateEditUrl(obj, $scope: IFormScope): string;
362
+ generateViewUrl(obj, $scope: IFormScope): string;
223
363
  generateNewUrl($scope: IFormScope): string;
224
364
  handleFieldType(formInstructions, mongooseType, mongooseOptions, $scope: IFormScope, ctrlState);
225
- handleSchema(description: string, source, destForm, destList, prefix, doRecursion: boolean, $scope: IFormScope, ctrlState);
365
+ handleSchema(
366
+ description: string,
367
+ source,
368
+ destForm,
369
+ destList,
370
+ prefix,
371
+ doRecursion: boolean,
372
+ $scope: IFormScope,
373
+ ctrlState
374
+ );
226
375
  updateDataDependentDisplay(curValue, oldValue, force, $scope: IFormScope);
227
- add(fieldName, $event, $scope: IFormScope);
228
- unshift(fieldName, $event, $scope: IFormScope);
229
- remove(fieldName, value, $event, $scope: IFormScope);
376
+ add(fieldName: string, $event, $scope: IFormScope, modelOverride?: any);
377
+ unshift(fieldName: string, $event, $scope: IFormScope, modelOverride?: any);
378
+ remove(fieldName: string, value, $event, $scope: IFormScope, modelOverride?: any);
230
379
  hasError(formName, name, index, $scope: IFormScope);
231
- decorateScope($scope: IFormScope, formGeneratorInstance, recordHandlerInstance: IRecordHandler, sharedStuff);
380
+ decorateScope($scope: IFormScope, formGeneratorInstance: IFormGeneratorService, recordHandlerInstance: IRecordHandlerService, sharedStuff, pseudoUrl?: string);
232
381
  }
233
382
 
234
383
  export interface IFngSingleLookupHandler {
235
384
  formInstructions: IFormInstruction;
236
385
  lastPart: string;
237
386
  possibleArray: string;
387
+ // If the looked-up record changes, we use these fields to see if the old lookup value also exists in the new lookup record
388
+ oldValue?: string | string[];
389
+ oldId?: string | string[];
238
390
  }
239
391
 
240
392
  export interface IFngLookupHandler {
241
393
  lookupOptions: string[];
242
394
  lookupIds: string[];
243
- handlers: IFngSingleLookupHandler[]
395
+ handlers: IFngSingleLookupHandler[];
244
396
  }
245
397
 
246
398
  export interface IFngInternalLookupHandlerInfo extends IFngLookupHandler {
@@ -251,16 +403,32 @@ declare module fng {
251
403
  ref: IFngLookupListReference;
252
404
  }
253
405
 
406
+ // we cannot use an enum here, so this will have to do. these are the values expected to be returned by the
407
+ // function on $rootScope with the name formsAngular.disabledSecurityFuncName.
408
+ // false = not disabled,
409
+ // true = disabled,
410
+ // "+" = this and all child elements disabled
411
+ export type DisabledOutcome = boolean | "+";
412
+
413
+ export interface ISecurableScope extends angular.IScope {
414
+ // added by ISecurityService
415
+ isSecurelyHidden: (elemId: string) => boolean;
416
+ isSecurelyDisabled: (elemId: string) => boolean;
417
+ requiresDisabledChildren: (elemId: string) => boolean;
418
+ }
419
+
254
420
  /*
255
421
  The scope which contains form data
256
422
  */
257
- export interface IFormScope extends angular.IScope {
423
+ export interface IFormScope extends ISecurableScope {
258
424
  sharedData: any;
259
- modelNameDisplay : string;
425
+ modelNameDisplay: string;
260
426
  modelName: string;
261
427
  formName: string;
262
428
  alertTitle: any;
429
+ errorVisible: boolean;
263
430
  errorMessage: any;
431
+ errorHideTimer: number;
264
432
  save: any;
265
433
  newRecord: boolean;
266
434
  initialiseNewRecord?: any;
@@ -271,17 +439,16 @@ declare module fng {
271
439
  isCancelDisabled: any;
272
440
  isNewDisabled: any;
273
441
  isSaveDisabled: any;
274
- disabledText: any;
442
+ whyDisabled: string;
275
443
  unconfirmedDelete: boolean;
276
444
  getVal: any;
277
445
  sortableOptions: any;
278
- tabDeselect: any;
279
- tabs?: Array<any>; // In the case of forms that contain a tab set
280
- tab?: string; // title of the active tab - from the route
446
+ tabs?: Array<any>; // In the case of forms that contain a tab set
447
+ tab?: string; // title of the active tab - from the route
281
448
  activeTabNo?: number;
282
- topLevelFormName: string; // The name of the form
449
+ topLevelFormName: string; // The name of the form
283
450
  record: any;
284
- originalData: any; // the unconverted data read from the server
451
+ originalData: any; // the unconverted data read from the server
285
452
  phase: any;
286
453
  disableFunctions: any;
287
454
  dataEventFunctions: any;
@@ -293,13 +460,17 @@ declare module fng {
293
460
  conversions: any;
294
461
  pageSize: any;
295
462
  pagesLoaded: any;
463
+ redirectOptions?: { redirect?: string; allowChange?: boolean };
296
464
  cancel: () => any;
297
- showError: (error: any, alertTitle? : string) => void;
465
+ showError: (error: any, alertTitle?: string) => void;
298
466
  prepareForSave: (cb: (error: string, dataToSave?: any) => void) => void;
299
- formSchema: IFormInstruction[];
467
+ setDefaults: (formSchema: IFormSchema, base?: string) => any;
468
+ formSchema: IControlledFormSchema;
300
469
  baseSchema: () => Array<any>;
301
470
  setFormDirty: any;
302
471
  add: any;
472
+ hideTab: (event, tabTitle: string, hiddenTabArrayProp: string) => void;
473
+ addTab: (event, tabTitle: string, hiddenTabArrayProp: string) => void;
303
474
  hasError: any;
304
475
  unshift: any;
305
476
  remove: any;
@@ -308,23 +479,44 @@ declare module fng {
308
479
  skipCols: any;
309
480
  setPristine: any;
310
481
  generateEditUrl: any;
482
+ generateViewUrl: any;
311
483
  generateNewUrl: any;
312
484
  scrollTheList: any;
313
485
  getListData: any;
314
- dismissError: any;
486
+ phaseWatcher: any;
487
+ dismissError: () => void;
488
+ stickError: () => void;
489
+ clearTimeout: () => void;
315
490
  handleHttpError: (response: any) => void;
316
491
  dropConversionWatcher: () => void;
492
+ readingRecord?: angular.IPromise<any>;
493
+ onSchemaFetch?: (description: string, source: IFieldViewInfo[]) => void;
494
+ onSchemaProcessed?: (description: string, formSchema: IFormInstruction[]) => void;
495
+ updateQueryForTab?: (tab: string) => void;
496
+ showLoading? : boolean;
497
+ tabDeselect?: ($event: any, $selectedIndex: number) => void;
498
+ setUpCustomLookupOptions?: (
499
+ schemaElement: IFormInstruction,
500
+ ids: string[],
501
+ options: string[],
502
+ baseScope: any
503
+ ) => void;
317
504
  }
318
505
 
319
506
  export interface IContextMenuDivider {
320
507
  divider: boolean;
321
508
  }
322
509
  export interface IContextMenuOption {
323
- // For it to make any sense, a menu option needs one of the next two properties
510
+ // For it to make any sense, a menu option needs one of the next three properties
324
511
  url?: string;
325
512
  fn?: () => void;
513
+ urlFunc?: () => string;
326
514
 
327
- text: string;
515
+ // provided to the security hook (see elemSecurityFuncName) - optional where that is not being used
516
+ id?: string;
517
+
518
+ text?: string;
519
+ textFunc?: () => string;
328
520
  isDisabled?: () => boolean;
329
521
  isHidden?: () => boolean;
330
522
 
@@ -334,10 +526,15 @@ declare module fng {
334
526
  editing: boolean;
335
527
  }
336
528
 
529
+ export interface IModelCtrlService {
530
+ loadControllerAndMenu: (sharedData: any, titleCaseModelName: string, level: number, needDivider: boolean, scope: angular.IScope) => void;
531
+ }
532
+
337
533
  export interface IModelController extends IFormScope {
338
- onBaseCtrlReady? : (baseScope: IFormScope) => void; // Optional callback after form is instantiated
339
- onAllReady? : (baseScope: IFormScope) => void; // Optional callback after form is instantiated and populated
340
- contextMenu? : Array<IContextMenuOption | IContextMenuDivider>
534
+ onBaseCtrlReady?: (baseScope: IFormScope) => void; // Optional callback after form is instantiated
535
+ onAllReady?: (baseScope: IFormScope) => void; // Optional callback after form is instantiated and populated
536
+ contextMenu?: Array<IContextMenuOption | IContextMenuDivider>;
537
+ contextMenuPromise?: Promise<Array<IContextMenuOption | IContextMenuDivider>>;
341
538
  }
342
539
 
343
540
  export interface IBaseFormOptions {
@@ -345,13 +542,13 @@ declare module fng {
345
542
  * The style of the form layout. Supported values are horizontalcompact, horizontal, vertical, inline
346
543
  */
347
544
  //TODO supported values should be in an enum
348
- formstyle?: string;
545
+ formstyle?: formStyle;
349
546
  /**
350
547
  * Model on form scope (defaults to record).
351
548
  * <li><strong>model</strong> the object in the scope to be bound to the model controller. Specifying
352
549
  * the model inhibits the generation of the <strong>form</strong> tag unless the <strong>forceform</strong> attribute is set to true</li>
353
550
  */
354
- model? : string;
551
+ model?: string;
355
552
  /**
356
553
  * The name to be given to the form - defaults to myForm
357
554
  */
@@ -360,60 +557,270 @@ declare module fng {
360
557
  * Normally first field in a form gets autofocus set. Use this to prevent this
361
558
  */
362
559
  noautofocus?: string;
560
+ /*
561
+ Suppress the generation of element ids
562
+ (sometimes required when using nested form-inputs in a directive)
563
+ */
564
+ noid?: boolean;
363
565
  }
364
566
 
365
567
  export interface IFormAttrs extends IFormOptions, angular.IAttributes {
366
568
  /**
367
569
  * Schema used by the form
368
570
  */
369
- schema : string;
370
- forceform?: string; // Must be true or omitted. Forces generation of the <strong>form</strong> tag when model is specified
571
+ schema: string;
572
+ forceform?: string; // Must be true or omitted. Forces generation of the <strong>form</strong> tag when model is specified
573
+ noid?: boolean;
371
574
  }
372
575
 
373
576
  export interface IFormOptions extends IBaseFormOptions {
374
- schema? : string;
577
+ schema?: string;
375
578
  subkey?: string;
376
579
  subkeyno?: number;
377
- subschema? : string;
378
- subschemaroot? : string;
580
+ subschema?: string;
581
+ subschemaroot?: string;
582
+ viewform?: boolean;
583
+ suppressNestingWarning?: boolean;
379
584
  }
380
585
 
381
586
  export interface IBuiltInRoute {
382
587
  route: string;
383
- state: string;
384
- templateUrl: string;
385
- options? : any;
588
+ state?: string;
589
+ templateUrl?: string;
590
+ options?: {
591
+ authenticate?: boolean;
592
+ templateUrl?: string | (() => void);
593
+ template?: string;
594
+ controller?: string;
595
+ }
386
596
  }
387
597
 
388
598
  export interface IRoutingConfig {
389
- hashPrefix: string;
599
+ hashPrefix?: string;
390
600
  html5Mode: boolean;
391
- routing: string; // What sort of routing do we want? ngroute or uirouter.
392
- // TODO Should be enum
393
- prefix: string; // How do we want to prefix out routes? If not empty string then first character must be slash (which is added if not)
394
- // for example '/db' that gets prepended to all the generated routes. This can be used to
395
- // prevent generated routes (which have a lot of parameters) from clashing with other routes in
396
- // the web app that have nothing to do with CRUD forms
601
+ routing: string; // What sort of routing do we want? ngroute or uirouter.
602
+ // TODO Should be enum
603
+ prefix: string; // How do we want to prefix out routes? If not empty string then first character must be slash (which is added if not)
604
+ // for example '/db' that gets prepended to all the generated routes. This can be used to
605
+ // prevent generated routes (which have a lot of parameters) from clashing with other routes in
606
+ // the web app that have nothing to do with CRUD forms
397
607
  fixedRoutes?: Array<IBuiltInRoute>;
398
- templateFolder?: string; // The folder where the templates for base-list, base-edit and base-analysis live. Internal templates used by default. For pre 0.7.0 behaviour use 'partials/'
399
- add2fngRoutes?: any; // An object to add to the generated routes. One use case would be to add {authenticate: true}
400
- // so that the client authenticates for certain routes
608
+ templateFolder?: string; // The folder where the templates for base-list, base-edit and base-analysis live. Internal templates used by default. For pre 0.7.0 behaviour use 'partials/'
609
+ add2fngRoutes?: any; // An object to add to the generated routes. One use case would be to add {authenticate: true}
610
+ // so that the client authenticates for certain routes
401
611
 
402
- variantsForDemoWebsite? : any; // Just for demo website
403
- variants?: any; // Just for demo website
612
+ variantsForDemoWebsite?: any; // Just for demo website
613
+ variants?: any; // Just for demo website
614
+ onDelete?: string; // Supports literal (such as '/') or 'new' (which will go to a /new of the model) default is to go to the list view
404
615
  }
405
616
 
406
617
  export interface IFngRoute {
407
- newRecord?: boolean;
408
- analyse?: boolean;
409
- modelName?: string;
410
- reportSchemaName? : string;
411
- id? : string;
412
- formName? : string;
413
- tab? : string;
414
- variant? : string; // TODO should be enum of supported frameworks
618
+ newRecord?: boolean;
619
+ analyse?: boolean;
620
+ modelName?: string;
621
+ reportSchemaName?: string;
622
+ id?: string;
623
+ formName?: string;
624
+ tab?: string;
625
+ variant?: string; // TODO should be enum of supported frameworks
626
+ }
627
+
628
+ interface IBuildingBlocks {
629
+ common: string;
630
+ sizeClassBS3: string;
631
+ sizeClassBS2: string;
632
+ compactClass: string;
633
+ formControl: string;
634
+ modelString: string;
635
+ disableableAncestorStr: string;
636
+ }
637
+
638
+ interface IProcessedAttrs {
639
+ info: IFormInstruction;
640
+ options: IFormOptions;
641
+ directiveOptions: any;
415
642
  }
416
643
 
644
+ interface IGenDisableStrParams {
645
+ forceNg?: boolean;
646
+ nonUniqueIdSuffix?: string;
647
+ }
648
+
649
+
650
+ interface IPluginHelperService {
651
+ extractFromAttr: (
652
+ attr: any,
653
+ directiveName: string
654
+ ) => { info: IFormInstruction; options: IFormOptions; directiveOptions: any };
655
+ buildInputMarkup: (
656
+ scope: angular.IScope,
657
+ attrs: any,
658
+ params: {
659
+ processedAttrs?: IProcessedAttrs;
660
+ fieldInfoOverrides?: Partial<IFormInstruction>;
661
+ optionOverrides?: Partial<IFormOptions>;
662
+ addButtons?: boolean;
663
+ needsX?: boolean;
664
+ },
665
+ generateInputControl: (buildingBlocks: IBuildingBlocks) => string
666
+ ) => string;
667
+ genIdString: (scope: angular.IScope, processedAttrs: IProcessedAttrs, idSuffix: string) => string;
668
+ genDisabledStr: (
669
+ scope: angular.IScope,
670
+ processedAttrs: IProcessedAttrs,
671
+ idSuffix: string,
672
+ params?: fng.IGenDisableStrParams
673
+ ) => string;
674
+ genIdAndDisabledStr: (
675
+ scope: angular.IScope,
676
+ processedAttrs: IProcessedAttrs,
677
+ idSuffix: string,
678
+ params?: fng.IGenDisableStrParams
679
+ ) => string;
680
+ genDateTimePickerDisabledStr: (scope: angular.IScope, processedAttrs: IProcessedAttrs, idSuffix: string) => string;
681
+ genDateTimePickerIdAndDisabledStr: (
682
+ scope: angular.IScope,
683
+ processedAttrs: IProcessedAttrs,
684
+ idSuffix: string
685
+ ) => string;
686
+ genUiSelectIdAndDisabledStr: (
687
+ scope: angular.IScope,
688
+ processedAttrs: IProcessedAttrs,
689
+ idSuffix: string
690
+ ) => string;
691
+ handlePseudos: (str: string) => string;
692
+ genDisableableAncestorStr: (processedAttrs: IProcessedAttrs) => string;
693
+ }
694
+
695
+ interface ISecurityVisibility {
696
+ omit?: boolean;
697
+ visibilityAttr?: string;
698
+ }
699
+
700
+ interface IGenerateDisableAttrParams {
701
+ attr?: string;
702
+ attrRequiresValue?: boolean;
703
+ forceNg?: boolean;
704
+ }
705
+
706
+ type SecurityType = "hidden" | "disabled";
707
+
708
+ interface ISecurityService {
709
+ canDoSecurity: (type: SecurityType) => boolean;
710
+ canDoSecurityNow: (scope: fng.ISecurableScope, type: SecurityType) => boolean;
711
+ isSecurelyHidden: (elemId: string, pseudoUrl?: string) => boolean;
712
+ isSecurelyDisabled: (elemId: string, pseudoUrl?: string) => boolean;
713
+ decorateSecurableScope: (securableScope: ISecurableScope, params?: { pseudoUrl?: string, overrideSkipping?: boolean }) => void;
714
+ doSecurityWhenReady: (cb: () => void) => void;
715
+ considerVisibility: (id: string, scope: fng.ISecurableScope) => ISecurityVisibility;
716
+ considerContainerVisibility: (contentIds: string[], scope: fng.ISecurableScope) => fng.ISecurityVisibility;
717
+ getDisableableAttrs: (id: string) => string;
718
+ getHideableAttrs: (id: string) => string;
719
+ getDisableableAncestorAttrs: (id: string) => string;
720
+ generateDisabledAttr: (id: string, scope: fng.ISecurableScope, params?: IGenerateDisableAttrParams) => string;
721
+ }
722
+
723
+ interface IListQueryOptions {
724
+ limit?: number;
725
+ find?: any; // e.g., { "careWorker.isCareWorker": true }
726
+ aggregate?: any;
727
+ projection?: any;
728
+ order?: any; // e.g., { familyName: -1, givenName: -1 }
729
+ skip?: number;
730
+ concatenate?: boolean; // whether the list fields should be concatenated into a single .text property
731
+ }
732
+
733
+ interface ISubmissionsService {
734
+ // return all of the list attributes of the record from db.<modelName>.<id>
735
+ // where returnRaw is true, the document (albeit with only its list attributes present) will be returned without transformation
736
+ // otherwise, the list fields will be concatenated (space-seperated) and returned as the list property of a record { list: string }
737
+ // e.g., "John Doe", in the case of a person
738
+ getListAttributes: (
739
+ modelName: string,
740
+ id: string,
741
+ returnRaw?: boolean
742
+ ) => angular.IHttpPromise<{ list: string } | any>;
743
+ readRecord: (modelName: string, id: string, formName?: string) => angular.IHttpPromise<any>;
744
+ getAll: (modelName: string, _options: any) => angular.IHttpPromise<any[]>;
745
+ getAllListAttributes: (ref: string) => angular.IHttpPromise<ILookupItem[]>;
746
+ getPagedAndFilteredList: (
747
+ modelName: string,
748
+ options: IListQueryOptions
749
+ ) => angular.IHttpPromise<any[]>;
750
+ getPagedAndFilteredListFull: (
751
+ modelName: string,
752
+ options: IListQueryOptions
753
+ ) => angular.IHttpPromise<any[]>;
754
+ deleteRecord: (model: string, id: string, formName: string) => angular.IHttpPromise<void>;
755
+ updateRecord: (modelName: string, id: string, dataToSave: any, formName?: string) => angular.IHttpPromise<any>;
756
+ createRecord: (modelName: string, dataToSave: any, formName?: string) => angular.IHttpPromise<any>;
757
+ useCache: (val: boolean) => void;
758
+ clearCache: () => void;
759
+ getCache: () => boolean;
760
+ }
761
+
762
+ interface IRoutingServiceProvider {
763
+ start: (options: IRoutingConfig) => void;
764
+ addRoutes: (fixedRoutes: Array<IBuiltInRoute>, fngRoutes:Array<IBuiltInRoute>) => void;
765
+ registerAction: (action: string) => void;
766
+ $get: () => IRoutingService;
767
+ }
768
+
769
+ interface IRoutingService {
770
+ router: () => string;
771
+ prefix: () => string;
772
+ parsePathFunc: () => (location: string) => void;
773
+ html5hash: () => string;
774
+ buildUrl: (path: string) => string;
775
+ buildOperationUrl: (
776
+ prefix: string,
777
+ operation: string,
778
+ modelName: string,
779
+ formName: string,
780
+ id: string,
781
+ tabName?: string
782
+ ) => string;
783
+ redirectTo: () => (operation: string, scope: IFormScope, LocationService: angular.ILocationService, id?: string, tab?: string) => void;
784
+ }
785
+
786
+ interface ICssFrameworkServiceProvider {
787
+ setOptions: (options: { framework: string }) => void;
788
+ $get: () => ICssFrameworkService;
789
+ }
790
+
791
+ interface ICssFrameworkService {
792
+ framework: () => string;
793
+ span: (cols: number) => string;
794
+ offset: (cols: number) => string;
795
+ rowFluid: () => string;
796
+ }
797
+
798
+ interface IFngUiSelectHelperService {
799
+ windowChanged: (width: number, height: number) => boolean;
800
+ addClientLookup: (lkpName: string, lkpData: any) => void;
801
+ clearCache: () => void;
802
+ lookupFunc: (value: string, formSchema: IFormInstruction, cb: (formSchema: IFormInstruction, value: ILookupItem ) => void) => void;
803
+ doOwnConversion: (scope: IFormScope, processedAttrs: any, ref: string) => void;
804
+ }
805
+
806
+ interface IFormMarkupHelperService {
807
+ isHorizontalStyle: (formStyle: string, includeStacked: boolean) => boolean;
808
+ isArrayElement: (scope: angular.IScope, info: fng.IFormInstruction, options: fng.IFormOptions) => boolean;
809
+ fieldChrome: (scope: fng.IFormScope, info: fng.IFormInstruction, options: fng.IFormOptions) => { omit?: boolean, template?: string, closeTag?: string };
810
+ label: (scope: fng.IFormScope, fieldInfo: fng.IFormInstruction, addButtonMarkup: boolean, options: fng.IFormOptions) => string;
811
+ glyphClass: () => string;
812
+ allInputsVars: (scope: angular.IScope, fieldInfo: fng.IFormInstruction, options: fng.IFormOptions, modelString: string, idString: string, nameString: string) => Partial<fng.IBuildingBlocks>;
813
+ inputChrome: (value: string, fieldInfo: fng.IFormInstruction, options: fng.IFormOptions, markupVars) => string;
814
+ generateSimpleInput: (common: string, fieldInfo: fng.IFormInstruction, options: fng.IFormOptions) => string;
815
+ controlDivClasses: (options: fng.IFormOptions) => string[];
816
+ handleInputAndControlDiv: (inputMarkup: string, controlDivClasses: string[]) => string;
817
+ handleArrayInputAndControlDiv: (inputMarkup: string, controlDivClasses: string[], scope: fng.IFormScope, info: fng.IFormInstruction, options: fng.IFormOptions) => string;
818
+ addTextInputMarkup: (allInputsVars: Partial<fng.IBuildingBlocks>, fieldInfo: fng.IFormInstruction, requiredStr: string) => string;
819
+ handleReadOnlyDisabled: (partialFieldInfo: { name: string, id?: string, nonUniqueId?: string, readonly?: boolean | string }, scope: fng.IFormScope) => string[];
820
+ generateArrayElementIdString: (idString: string, info: fng.IFormInstruction, options: fng.IFormOptions) => string;
821
+ genDisableableAncestorStr: (id: string) => string;
822
+ generateNgShow(showWhen: IFngShowWhen, model: string): string;
823
+ }
417
824
  }
418
825
 
419
- declare var formsAngular: angular.IModule;
826
+ declare var formsAngular: fng.IFng;