forms-angular 0.12.0-beta.26 → 0.12.0-beta.261

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