fit-ui 2.5.4 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Documentation.html +3 -3
- package/dist/Fit.UI.css +102 -6
- package/dist/Fit.UI.js +986 -132
- package/dist/Fit.UI.min.css +1 -1
- package/dist/Fit.UI.min.js +1 -1
- package/dist/Resources/CKEditor/CHANGES.md +107 -0
- package/dist/Resources/CKEditor/LICENSE.md +1 -0
- package/dist/Resources/CKEditor/build-config.js +7 -3
- package/dist/Resources/CKEditor/ckeditor.js +638 -538
- package/dist/Resources/CKEditor/contents.css +208 -208
- package/dist/Resources/CKEditor/index.html +8 -0
- package/dist/Resources/CKEditor/lang/da.js +2 -2
- package/dist/Resources/CKEditor/lang/de.js +2 -2
- package/dist/Resources/CKEditor/lang/en.js +2 -2
- package/dist/Resources/CKEditor/plugins/autocomplete/skins/default.css +38 -0
- package/dist/Resources/CKEditor/plugins/base64image/dialogs/base64image.js +38 -33
- package/dist/Resources/CKEditor/plugins/base64image/plugin.js +1 -1
- package/dist/Resources/CKEditor/plugins/emoji/assets/iconsall.png +0 -0
- package/dist/Resources/CKEditor/plugins/emoji/assets/iconsall.svg +58 -0
- package/dist/Resources/CKEditor/plugins/emoji/emoji.json +1 -0
- package/dist/Resources/CKEditor/plugins/emoji/skins/default.css +237 -0
- package/dist/Resources/CKEditor/plugins/icons.png +0 -0
- package/dist/Resources/CKEditor/plugins/icons_hidpi.png +0 -0
- package/dist/Resources/CKEditor/plugins/link/dialogs/anchor.js +4 -4
- package/dist/Resources/CKEditor/skins/moono-lisa/dialog.css +5 -5
- package/dist/Resources/CKEditor/skins/moono-lisa/dialog_ie.css +5 -5
- package/dist/Resources/CKEditor/skins/moono-lisa/dialog_ie8.css +5 -5
- package/dist/Resources/CKEditor/skins/moono-lisa/dialog_iequirks.css +5 -5
- package/dist/Resources/CKEditor/skins/moono-lisa/editor.css +1 -1
- package/dist/Resources/CKEditor/skins/moono-lisa/editor_gecko.css +1 -1
- package/dist/Resources/CKEditor/skins/moono-lisa/editor_ie.css +1 -1
- package/dist/Resources/CKEditor/skins/moono-lisa/editor_ie8.css +1 -1
- package/dist/Resources/CKEditor/skins/moono-lisa/editor_iequirks.css +1 -1
- package/dist/Resources/CKEditor/skins/moono-lisa/icons.png +0 -0
- package/dist/Resources/CKEditor/skins/moono-lisa/icons_hidpi.png +0 -0
- package/dist/Resources/CKEditor/styles.js +137 -137
- package/package.json +1 -1
- package/types/index.d.ts +417 -38
- package/dist/Resources/CKEditor/plugins/resize/plugin.js +0 -187
package/dist/Fit.UI.js
CHANGED
|
@@ -648,7 +648,7 @@ Fit._internal =
|
|
|
648
648
|
{
|
|
649
649
|
Core:
|
|
650
650
|
{
|
|
651
|
-
VersionInfo: { Major: 2, Minor:
|
|
651
|
+
VersionInfo: { Major: 2, Minor: 6, Patch: 0 } // Do NOT modify format - version numbers are programmatically changed when releasing new versions - MUST be on a separate line!
|
|
652
652
|
}
|
|
653
653
|
};
|
|
654
654
|
|
|
@@ -4281,6 +4281,7 @@ Fit.Controls.ControlBase = function(controlId)
|
|
|
4281
4281
|
|
|
4282
4282
|
var onChangeHandler = me._internal.FireOnChange;
|
|
4283
4283
|
me._internal.FireOnChange = function() {};
|
|
4284
|
+
me._internal.FireOnChangeSuppressed = true; // Allow specialized controls to detect when OnChange event will be suppressed for performance optimizations
|
|
4284
4285
|
|
|
4285
4286
|
var error = null;
|
|
4286
4287
|
|
|
@@ -4294,10 +4295,12 @@ Fit.Controls.ControlBase = function(controlId)
|
|
|
4294
4295
|
}
|
|
4295
4296
|
|
|
4296
4297
|
me._internal.FireOnChange = onChangeHandler;
|
|
4298
|
+
me._internal.FireOnChangeSuppressed = false;
|
|
4297
4299
|
|
|
4298
4300
|
if (error !== null)
|
|
4299
4301
|
Fit.Validation.ThrowError(error);
|
|
4300
4302
|
}
|
|
4303
|
+
this._internal.FireOnChangeSuppressed = false;
|
|
4301
4304
|
|
|
4302
4305
|
this._internal.Data = function(key, val)
|
|
4303
4306
|
{
|
|
@@ -9264,6 +9267,7 @@ Fit.Http.JsonpRequest = function(uri, jsonpCallbackName)
|
|
|
9264
9267
|
var timeout = 30000;
|
|
9265
9268
|
var timer = -1;
|
|
9266
9269
|
var response = null;
|
|
9270
|
+
var aborted = false;
|
|
9267
9271
|
|
|
9268
9272
|
var onRequestHandlers = [];
|
|
9269
9273
|
var onSuccessHandlers = [];
|
|
@@ -9321,6 +9325,14 @@ Fit.Http.JsonpRequest = function(uri, jsonpCallbackName)
|
|
|
9321
9325
|
return timeout;
|
|
9322
9326
|
}
|
|
9323
9327
|
|
|
9328
|
+
/// <function container="Fit.Http.JsonpRequest" name="Abort" access="public">
|
|
9329
|
+
/// <description> Abort request </description>
|
|
9330
|
+
/// </function>
|
|
9331
|
+
this.Abort = function()
|
|
9332
|
+
{
|
|
9333
|
+
aborted = true;
|
|
9334
|
+
}
|
|
9335
|
+
|
|
9324
9336
|
/// <function container="Fit.Http.JsonpRequest" name="SetParameter" access="public">
|
|
9325
9337
|
/// <description> Set URL parameter </description>
|
|
9326
9338
|
/// <param name="key" type="string"> URL parameter key </param>
|
|
@@ -9370,6 +9382,8 @@ Fit.Http.JsonpRequest = function(uri, jsonpCallbackName)
|
|
|
9370
9382
|
/// </function>
|
|
9371
9383
|
this.Start = function()
|
|
9372
9384
|
{
|
|
9385
|
+
aborted = false;
|
|
9386
|
+
|
|
9373
9387
|
// Fire OnRequest handlers
|
|
9374
9388
|
|
|
9375
9389
|
if (fireEvent(onRequestHandlers) === false)
|
|
@@ -9403,7 +9417,10 @@ Fit.Http.JsonpRequest = function(uri, jsonpCallbackName)
|
|
|
9403
9417
|
response = resp;
|
|
9404
9418
|
delete Fit._internal.Http.JsonpRequest.Callbacks[cbId];
|
|
9405
9419
|
|
|
9406
|
-
|
|
9420
|
+
if (aborted === false)
|
|
9421
|
+
{
|
|
9422
|
+
fireEvent(onSuccessHandlers);
|
|
9423
|
+
}
|
|
9407
9424
|
}
|
|
9408
9425
|
|
|
9409
9426
|
// Configure timeout
|
|
@@ -9416,7 +9433,10 @@ Fit.Http.JsonpRequest = function(uri, jsonpCallbackName)
|
|
|
9416
9433
|
// NOTICE: Do not remove callback - it would cause a JavaScript error if the situation described above occures.
|
|
9417
9434
|
Fit._internal.Http.JsonpRequest.Callbacks[cbId] = function(response) { };
|
|
9418
9435
|
|
|
9419
|
-
|
|
9436
|
+
if (aborted === false)
|
|
9437
|
+
{
|
|
9438
|
+
fireEvent(onTimeoutHandlers);
|
|
9439
|
+
}
|
|
9420
9440
|
}, timeout);
|
|
9421
9441
|
|
|
9422
9442
|
// Construct request URL
|
|
@@ -14230,6 +14250,11 @@ Fit.Controls.DatePicker = function(ctlId)
|
|
|
14230
14250
|
|
|
14231
14251
|
function moveCalenderWidgetLocally()
|
|
14232
14252
|
{
|
|
14253
|
+
if (Fit._internal.ControlBase.ReduceDocumentRootPollution !== true)
|
|
14254
|
+
{
|
|
14255
|
+
return;
|
|
14256
|
+
}
|
|
14257
|
+
|
|
14233
14258
|
// We want the benefits of a connected calendar control (connected to input control),
|
|
14234
14259
|
// but do not want it rendered in the root of the document. It pollutes the global scope,
|
|
14235
14260
|
// and it doesn't work with dialogs with light dismiss, since interacting with the calendar
|
|
@@ -14305,6 +14330,11 @@ Fit.Controls.DatePicker = function(ctlId)
|
|
|
14305
14330
|
|
|
14306
14331
|
function moveCalenderWidgetGlobally() // Undo everything done in moveCalenderWidgetLocally()
|
|
14307
14332
|
{
|
|
14333
|
+
if (Fit._internal.ControlBase.ReduceDocumentRootPollution !== true)
|
|
14334
|
+
{
|
|
14335
|
+
return;
|
|
14336
|
+
}
|
|
14337
|
+
|
|
14308
14338
|
var calendarWidget = document.getElementById("fitui-datepicker-div");
|
|
14309
14339
|
Fit.Dom.Add(document.body, calendarWidget);
|
|
14310
14340
|
|
|
@@ -15795,6 +15825,7 @@ Fit.Controls.DropDown = function(ctlId)
|
|
|
15795
15825
|
var detectBoundariesRelToViewPort = false; // Flag indicating whether drop down menu should be positioned relative to viewport (true) or scroll parent (false)
|
|
15796
15826
|
var persistView = false; // Flag indicating whether picker controls should remember and restore its scroll position and highlighted item when reopened
|
|
15797
15827
|
var highlightFirst = false; // Flag indicating whether picker controls should focus its first node automatically when opened
|
|
15828
|
+
var searchModeOnFocus = false; // Flag indicating whether control goes into search mode when it is focused (search mode clears input field and displays "search.." placeholder)
|
|
15798
15829
|
|
|
15799
15830
|
var onInputChangedHandlers = []; // Invoked when input value is changed - takes two arguments (sender (this), text value)
|
|
15800
15831
|
var onPasteHandlers = []; // Invoked when a value is pasted - takes two arguments (sender (this), text value)
|
|
@@ -16040,6 +16071,53 @@ Fit.Controls.DropDown = function(ctlId)
|
|
|
16040
16071
|
}
|
|
16041
16072
|
});
|
|
16042
16073
|
|
|
16074
|
+
// Support for SearchModeOnFocus
|
|
16075
|
+
|
|
16076
|
+
me.OnFocus(function(sender)
|
|
16077
|
+
{
|
|
16078
|
+
if (searchModeOnFocus === true)
|
|
16079
|
+
{
|
|
16080
|
+
searchModeOnFocus = false; // Temporarily disable searchModeOnFocus to allow setInputEditing(..) (which is called by ClearInputForSearch(..)) to change editing state for txtPrimary
|
|
16081
|
+
me._internal.ClearInputForSearch(true); // True = keep DropDown open - do not auto close it
|
|
16082
|
+
searchModeOnFocus = true;
|
|
16083
|
+
}
|
|
16084
|
+
});
|
|
16085
|
+
|
|
16086
|
+
me.OnBlur(function()
|
|
16087
|
+
{
|
|
16088
|
+
if (searchModeOnFocus === true)
|
|
16089
|
+
{
|
|
16090
|
+
searchModeOnFocus = false; // Temporarily disable searchModeOnFocus to allow setInputEditing(..) to change editing state for txtPrimary
|
|
16091
|
+
me._internal.UndoClearInputForSearch();
|
|
16092
|
+
searchModeOnFocus = true;
|
|
16093
|
+
}
|
|
16094
|
+
});
|
|
16095
|
+
|
|
16096
|
+
me.OnChange(function()
|
|
16097
|
+
{
|
|
16098
|
+
// Determine whether value was changed by user or programmatically,
|
|
16099
|
+
// so placeholder is not set when value is assigned programmatically.
|
|
16100
|
+
// Control might not be focused on mobile if opened using arrow icon.
|
|
16101
|
+
// In this case we simply use the DropDown's opened state instead.
|
|
16102
|
+
var controlIsActive = me.Focused() === true || me.IsDropDownOpen() === true;
|
|
16103
|
+
|
|
16104
|
+
if (searchModeOnFocus === true && controlIsActive === true)
|
|
16105
|
+
{
|
|
16106
|
+
if (me.GetSelections().length === 0)
|
|
16107
|
+
{
|
|
16108
|
+
// DropDown has a synthetic placeholder which is displayed
|
|
16109
|
+
// when no items are selected. Remove placeholder from input
|
|
16110
|
+
// field so we do not get two placeholders on top of each other.
|
|
16111
|
+
txtPrimary.placeholder = "";
|
|
16112
|
+
}
|
|
16113
|
+
else
|
|
16114
|
+
{
|
|
16115
|
+
// Display placeholder in input field when items are selected
|
|
16116
|
+
txtPrimary.placeholder = me.Placeholder();
|
|
16117
|
+
}
|
|
16118
|
+
}
|
|
16119
|
+
});
|
|
16120
|
+
|
|
16043
16121
|
// PickerBase - make picker aware of focused state of host control
|
|
16044
16122
|
|
|
16045
16123
|
me.OnFocus(function()
|
|
@@ -16270,7 +16348,7 @@ Fit.Controls.DropDown = function(ctlId)
|
|
|
16270
16348
|
itemDropZones[key].Dispose();
|
|
16271
16349
|
});
|
|
16272
16350
|
|
|
16273
|
-
me = itemContainer = itemCollection = itemDropZones = arrow = txtPrimary = txtActive = txtEnabled = dropDownMenu = picker = orgSelections = invalidMessage = invalidMessageChanged = initialFocus = maxHeight = prevValue = focusAssigned = closeHandlers = dropZone = isMobile = focusInputOnMobile = detectBoundaries = detectBoundariesRelToViewPort = persistView = highlightFirst = onInputChangedHandlers = onPasteHandlers = onOpenHandlers = onCloseHandlers = suppressUpdateItemSelectionState = suppressOnItemSelectionChanged = clearTextSelectionOnInputChange = prevTextSelection = textSelectionCallback = cmdToggleTextMode = null;
|
|
16351
|
+
me = itemContainer = itemCollection = itemDropZones = arrow = txtPrimary = txtActive = txtEnabled = dropDownMenu = picker = orgSelections = invalidMessage = invalidMessageChanged = initialFocus = maxHeight = prevValue = focusAssigned = closeHandlers = dropZone = isMobile = focusInputOnMobile = detectBoundaries = detectBoundariesRelToViewPort = persistView = highlightFirst = searchModeOnFocus = onInputChangedHandlers = onPasteHandlers = onOpenHandlers = onCloseHandlers = suppressUpdateItemSelectionState = suppressOnItemSelectionChanged = clearTextSelectionOnInputChange = prevTextSelection = textSelectionCallback = cmdToggleTextMode = null;
|
|
16274
16352
|
|
|
16275
16353
|
base();
|
|
16276
16354
|
});
|
|
@@ -17261,9 +17339,30 @@ Fit.Controls.DropDown = function(ctlId)
|
|
|
17261
17339
|
if (Fit._internal.DropDown.Current !== null && Fit._internal.DropDown.Current !== me)
|
|
17262
17340
|
Fit._internal.DropDown.Current.CloseDropDown();
|
|
17263
17341
|
|
|
17264
|
-
if (txtActive === txtPrimary && me.GetInputValue() === "")
|
|
17342
|
+
if (searchModeOnFocus === false && me.TextSelectionMode() === false && txtActive === txtPrimary && me.GetInputValue() === "")
|
|
17265
17343
|
{
|
|
17266
|
-
|
|
17344
|
+
// Visual Selection Mode with SearchModeOnFocus (which keeps txtPrimary locked in place) disabled:
|
|
17345
|
+
|
|
17346
|
+
// When placing the control in search mode temporarily (not "locked" by
|
|
17347
|
+
// SearchModeOnFocus) via me._internal.ClearInputForSearch() or by entering a value
|
|
17348
|
+
// in txtPrimary, the input control "word wraps" to a new line. When it lose focus,
|
|
17349
|
+
// it returns to its normal position if it is empty.
|
|
17350
|
+
// In Visual Selection Mode with SearchModeOnFocus disabled this poses a problem
|
|
17351
|
+
// since interacting with the picker control results in the input control losing
|
|
17352
|
+
// focus.
|
|
17353
|
+
// So, if the user clicks on an item in the picker control while the control
|
|
17354
|
+
// is temporarily in search mode (remember, SearchModeOnFocus is not enabled),
|
|
17355
|
+
// txtPrimary lose focus, the control's height is changed because the input
|
|
17356
|
+
// control returns to its normal position (it no longer "word wraps"), the picker
|
|
17357
|
+
// control moves up, and the mouse button is released on another element than the
|
|
17358
|
+
// one the user initially clicked on.
|
|
17359
|
+
// OnClick does not fire unless the mouse button is clicked and released
|
|
17360
|
+
// on the same element. So in this situation the picker control would not cause
|
|
17361
|
+
// the given item to be selected. The user would have to try again.
|
|
17362
|
+
// To avoid this, we exit search mode to force txtPrimary back into place when
|
|
17363
|
+
// re-opening the DropDown control.
|
|
17364
|
+
|
|
17365
|
+
me._internal.UndoClearInputForSearch(); // Undo/exit search mode to return txtPrimary to its normal position
|
|
17267
17366
|
}
|
|
17268
17367
|
|
|
17269
17368
|
// Do this before displaying drop down to prevent dropdown with position:absolute
|
|
@@ -17446,8 +17545,10 @@ Fit.Controls.DropDown = function(ctlId)
|
|
|
17446
17545
|
|
|
17447
17546
|
this._internal = (this._internal ? this._internal : {});
|
|
17448
17547
|
|
|
17449
|
-
this._internal.ClearInputForSearch = function()
|
|
17548
|
+
this._internal.ClearInputForSearch = function(keepDropDownOpen) // Put input in search mode
|
|
17450
17549
|
{
|
|
17550
|
+
Fit.Validation.ExpectBoolean(keepDropDownOpen, true);
|
|
17551
|
+
|
|
17451
17552
|
if (me.TextSelectionMode() === true)
|
|
17452
17553
|
{
|
|
17453
17554
|
forceFocusInput(txtPrimary);
|
|
@@ -17471,10 +17572,13 @@ Fit.Controls.DropDown = function(ctlId)
|
|
|
17471
17572
|
// event to register interactions, which doesn't fire unless the mouse button is released
|
|
17472
17573
|
// on the same object it was pressed down on. We avoid this by closing the control.
|
|
17473
17574
|
// We close it in both Text Selection Mode and Visual Selection Mode for consistency.
|
|
17474
|
-
|
|
17575
|
+
if (keepDropDownOpen !== true)
|
|
17576
|
+
{
|
|
17577
|
+
me.CloseDropDown();
|
|
17578
|
+
}
|
|
17475
17579
|
}
|
|
17476
17580
|
|
|
17477
|
-
this._internal.UndoClearInputForSearch = function()
|
|
17581
|
+
this._internal.UndoClearInputForSearch = function() // Undo/exit search mode for input field
|
|
17478
17582
|
{
|
|
17479
17583
|
if (me.TextSelectionMode() === true)
|
|
17480
17584
|
{
|
|
@@ -17947,12 +18051,45 @@ Fit.Controls.DropDown = function(ctlId)
|
|
|
17947
18051
|
focusInputOnMobile = orgFocusInputOnMobile;
|
|
17948
18052
|
}
|
|
17949
18053
|
|
|
17950
|
-
function
|
|
18054
|
+
/// <function container="Fit.Controls.DropDown" name="SearchModeOnFocus" access="public" returns="boolean">
|
|
18055
|
+
/// <description>
|
|
18056
|
+
/// Clear input and display "Search.." placeholder when control receives focus.
|
|
18057
|
+
/// If SearchModeOnFocus is enabled, InputEnabled will also be enabled. Disabling
|
|
18058
|
+
/// SearchModeOnFocus does not disable InputEnabled.
|
|
18059
|
+
/// </description>
|
|
18060
|
+
/// <param name="val" type="boolean" default="undefined"> If defined, True enables search mode on focus, False disables it </param>
|
|
18061
|
+
/// </function>
|
|
18062
|
+
this.SearchModeOnFocus = function(val)
|
|
18063
|
+
{
|
|
18064
|
+
Fit.Validation.ExpectBoolean(val, true);
|
|
18065
|
+
|
|
18066
|
+
if (Fit.Validation.IsSet(val) === true)
|
|
18067
|
+
{
|
|
18068
|
+
searchModeOnFocus = val;
|
|
18069
|
+
|
|
18070
|
+
if (me.InputEnabled() === false && val === true)
|
|
18071
|
+
{
|
|
18072
|
+
me.InputEnabled(true);
|
|
18073
|
+
}
|
|
18074
|
+
}
|
|
18075
|
+
|
|
18076
|
+
return searchModeOnFocus;
|
|
18077
|
+
}
|
|
18078
|
+
|
|
18079
|
+
function setInputEditing(input, val, keepStateOnParent) // Input being edited "word wraps" to separate line
|
|
17951
18080
|
{
|
|
17952
18081
|
Fit.Validation.ExpectInstance(input, HTMLInputElement);
|
|
17953
18082
|
Fit.Validation.ExpectBoolean(val);
|
|
17954
18083
|
Fit.Validation.ExpectBoolean(keepStateOnParent, true);
|
|
17955
18084
|
|
|
18085
|
+
// Do not change editing state for txtPrimary when SearchModeOnFocus is enabled.
|
|
18086
|
+
// In this case txtPrimary remains locked in editing mode so it remains visible,
|
|
18087
|
+
// even when changing focus within the control and when adding or removing items.
|
|
18088
|
+
if (searchModeOnFocus === true && input === txtPrimary)
|
|
18089
|
+
{
|
|
18090
|
+
return;
|
|
18091
|
+
}
|
|
18092
|
+
|
|
17956
18093
|
if (keepStateOnParent !== true)
|
|
17957
18094
|
{
|
|
17958
18095
|
Fit.Dom.Data(input.parentElement, "editing", val === true ? "true" : null);
|
|
@@ -19432,7 +19569,7 @@ Fit.Controls.WSDropDown = function(ctlId)
|
|
|
19432
19569
|
}
|
|
19433
19570
|
else if (item.Value === "ShowAll")
|
|
19434
19571
|
{
|
|
19435
|
-
me._internal.UndoClearInputForSearch(); // In case user first picked SearchMore, changed their mind, and then selected ShowAll
|
|
19572
|
+
me._internal.UndoClearInputForSearch(); // In case user first picked SearchMore, entered a search value, changed their mind, and then selected ShowAll
|
|
19436
19573
|
|
|
19437
19574
|
useActionMenuAfterLoad = false;
|
|
19438
19575
|
|
|
@@ -19850,6 +19987,19 @@ Fit.Controls.WSDropDown = function(ctlId)
|
|
|
19850
19987
|
return me.InputEnabled(val);
|
|
19851
19988
|
}
|
|
19852
19989
|
|
|
19990
|
+
this.SearchModeOnFocus = Fit.Core.CreateOverride(this.SearchModeOnFocus, function(val)
|
|
19991
|
+
{
|
|
19992
|
+
Fit.Validation.ExpectBoolean(val, true);
|
|
19993
|
+
|
|
19994
|
+
if (Fit.Validation.IsSet(val) === true && val !== base())
|
|
19995
|
+
{
|
|
19996
|
+
base(val);
|
|
19997
|
+
updateActionMenu(); // Add/remove search option depending on whether SearchModeOnFocus is enabled or not
|
|
19998
|
+
}
|
|
19999
|
+
|
|
20000
|
+
return base();
|
|
20001
|
+
});
|
|
20002
|
+
|
|
19853
20003
|
this.Placeholder = function(val)
|
|
19854
20004
|
{
|
|
19855
20005
|
Fit.Validation.ExpectString(val, true);
|
|
@@ -20170,7 +20320,7 @@ Fit.Controls.WSDropDown = function(ctlId)
|
|
|
20170
20320
|
|
|
20171
20321
|
actionMenu.RemoveItems();
|
|
20172
20322
|
|
|
20173
|
-
if (me.InputEnabled() === true)
|
|
20323
|
+
if (me.InputEnabled() === true && me.SearchModeOnFocus() === false)
|
|
20174
20324
|
{
|
|
20175
20325
|
actionMenu.AddItem(searchIcon + translations.SearchMore, "SearchMore");
|
|
20176
20326
|
}
|
|
@@ -20183,7 +20333,7 @@ Fit.Controls.WSDropDown = function(ctlId)
|
|
|
20183
20333
|
}
|
|
20184
20334
|
else //if (nodesPopulated === true && tree.GetChildren().length === 0)
|
|
20185
20335
|
{
|
|
20186
|
-
actionMenu.AddItem(showAllIcon + "<i>" + translations.NoneAvailable + "
|
|
20336
|
+
actionMenu.AddItem(showAllIcon + "<i>" + translations.NoneAvailable + "</i>", "ShowAllNoneFound");
|
|
20187
20337
|
}
|
|
20188
20338
|
}
|
|
20189
20339
|
|
|
@@ -20301,7 +20451,7 @@ Fit.Controls.WSDropDown = function(ctlId)
|
|
|
20301
20451
|
ShowAllOptions : "Show available options",
|
|
20302
20452
|
RemoveAll : "Remove all selected",
|
|
20303
20453
|
Remove : "Remove",
|
|
20304
|
-
NoneAvailable : "
|
|
20454
|
+
NoneAvailable : "List with options is empty"
|
|
20305
20455
|
}
|
|
20306
20456
|
},
|
|
20307
20457
|
"da":
|
|
@@ -20316,7 +20466,7 @@ Fit.Controls.WSDropDown = function(ctlId)
|
|
|
20316
20466
|
ShowAllOptions : "Vis tilgængelige valgmuligheder",
|
|
20317
20467
|
RemoveAll : "Fjern alle valgte",
|
|
20318
20468
|
Remove : "Fjern",
|
|
20319
|
-
NoneAvailable : "
|
|
20469
|
+
NoneAvailable : "Liste med valgmuligheder er tom"
|
|
20320
20470
|
}
|
|
20321
20471
|
},
|
|
20322
20472
|
"de":
|
|
@@ -20331,7 +20481,7 @@ Fit.Controls.WSDropDown = function(ctlId)
|
|
|
20331
20481
|
ShowAllOptions : "Verfügbare Optionen anzeigen",
|
|
20332
20482
|
RemoveAll : "Alle ausgewählten entfernen",
|
|
20333
20483
|
Remove : "Entfernen",
|
|
20334
|
-
NoneAvailable : "
|
|
20484
|
+
NoneAvailable : "Liste der Optionen ist leer"
|
|
20335
20485
|
}
|
|
20336
20486
|
}
|
|
20337
20487
|
}
|
|
@@ -21455,12 +21605,17 @@ Fit.Controls.Input = function(ctlId)
|
|
|
21455
21605
|
Fit.Core.Extend(this, Fit.Controls.ControlBase).Apply(ctlId);
|
|
21456
21606
|
|
|
21457
21607
|
var me = this;
|
|
21458
|
-
var orgVal = "";
|
|
21459
|
-
var preVal = "";
|
|
21608
|
+
var orgVal = ""; // Holds initial value used to determine IsDirty state
|
|
21609
|
+
var preVal = ""; // Holds latest change made by user - used to determine whether OnChange needs to be fired
|
|
21460
21610
|
var input = null;
|
|
21461
21611
|
var cmdResize = null;
|
|
21462
21612
|
var designEditor = null;
|
|
21463
|
-
var
|
|
21613
|
+
var designEditorDirty = false;
|
|
21614
|
+
var designEditorDirtyPending = false;
|
|
21615
|
+
var designEditorConfig = null;
|
|
21616
|
+
var designEditorRestoreButtonState = null;
|
|
21617
|
+
var designEditorSuppressPaste = false;
|
|
21618
|
+
//var htmlWrappedInParagraph = false;
|
|
21464
21619
|
var wasAutoChangedToMultiLineMode = false; // Used to revert to single line if multi line was automatically enabled along with DesignMode(true), Maximizable(true), or Resizable(true)
|
|
21465
21620
|
var minimizeHeight = -1;
|
|
21466
21621
|
var maximizeHeight = -1;
|
|
@@ -21553,6 +21708,21 @@ Fit.Controls.Input = function(ctlId)
|
|
|
21553
21708
|
}
|
|
21554
21709
|
|
|
21555
21710
|
fireOnChange(); // Only fires OnChange if value has actually changed
|
|
21711
|
+
|
|
21712
|
+
// Restore editor's toolbar buttons in case they were temporarily disabled
|
|
21713
|
+
|
|
21714
|
+
if (designEditor !== null)
|
|
21715
|
+
{
|
|
21716
|
+
restoreDesignEditorButtons();
|
|
21717
|
+
}
|
|
21718
|
+
});
|
|
21719
|
+
|
|
21720
|
+
Fit.Events.AddHandler(me.GetDomElement(), "paste", true, function(e)
|
|
21721
|
+
{
|
|
21722
|
+
if (designEditor !== null && designEditorSuppressPaste === true)
|
|
21723
|
+
{
|
|
21724
|
+
Fit.Events.Stop(e);
|
|
21725
|
+
}
|
|
21556
21726
|
});
|
|
21557
21727
|
|
|
21558
21728
|
try
|
|
@@ -21698,20 +21868,34 @@ Fit.Controls.Input = function(ctlId)
|
|
|
21698
21868
|
|
|
21699
21869
|
if (Fit.Validation.IsSet(val) === true)
|
|
21700
21870
|
{
|
|
21701
|
-
var fireOnChange = (
|
|
21871
|
+
var fireOnChange = (me.Value() !== val);
|
|
21702
21872
|
|
|
21703
21873
|
orgVal = (preserveDirtyState !== true ? val : orgVal);
|
|
21704
21874
|
preVal = val;
|
|
21875
|
+
designEditorDirty = designEditorDirtyPending === true ? true : false;
|
|
21876
|
+
designEditorDirtyPending = false;
|
|
21705
21877
|
|
|
21706
|
-
if (val.indexOf("<p>") === 0)
|
|
21707
|
-
htmlWrappedInParagraph = true; // Indicates that val is comparable with value from CKEditor which wraps content in paragraphs
|
|
21878
|
+
/*if (val.indexOf("<p>") === 0)
|
|
21879
|
+
htmlWrappedInParagraph = true; // Indicates that val is comparable with value from CKEditor which wraps content in paragraphs*/
|
|
21708
21880
|
|
|
21709
21881
|
if (designEditor !== null)
|
|
21710
|
-
|
|
21882
|
+
{
|
|
21883
|
+
// NOTICE: Invalid HTML is removed, so an all invalid HTML string will be discarded
|
|
21884
|
+
// by the editor, resulting in the editor's getData() function returning an empty string.
|
|
21885
|
+
|
|
21886
|
+
// Calling setData(..) fires CKEditor's onchange event which in turn fires
|
|
21887
|
+
// Input's OnChange event. Suppress OnChange which is fired further down.
|
|
21888
|
+
me._internal.ExecuteWithNoOnChange(function()
|
|
21889
|
+
{
|
|
21890
|
+
CKEDITOR.instances[me.GetId() + "_DesignMode"].setData(val);
|
|
21891
|
+
});
|
|
21892
|
+
}
|
|
21711
21893
|
else
|
|
21894
|
+
{
|
|
21712
21895
|
input.value = val;
|
|
21896
|
+
}
|
|
21713
21897
|
|
|
21714
|
-
if (
|
|
21898
|
+
if (designEditorConfig !== null && designEditorConfig.Plugins && designEditorConfig.Plugins.Images && designEditorConfig.Plugins.Images.RevokeExternalBlobUrlsOnDispose === true)
|
|
21715
21899
|
{
|
|
21716
21900
|
// Keep track of image blobs added via Value(..) so we can dispose them automatically.
|
|
21717
21901
|
// When RevokeExternalBlobUrlsOnDispose is True it basically means that the Input control
|
|
@@ -21736,14 +21920,69 @@ Fit.Controls.Input = function(ctlId)
|
|
|
21736
21920
|
}
|
|
21737
21921
|
|
|
21738
21922
|
if (designEditor !== null)
|
|
21739
|
-
|
|
21923
|
+
{
|
|
21924
|
+
// If user has not changed value, then return the value initially set.
|
|
21925
|
+
// CKEditor may change (optimize) HTML when applied, but we always want
|
|
21926
|
+
// the value initially set when no changes have been made by the user.
|
|
21927
|
+
// See additional comments regarding this in the IsDirty() implementation.
|
|
21928
|
+
if (designEditorDirty === false)
|
|
21929
|
+
{
|
|
21930
|
+
return orgVal;
|
|
21931
|
+
}
|
|
21932
|
+
|
|
21933
|
+
var curVal = CKEDITOR.instances[me.GetId() + "_DesignMode"].getData();
|
|
21934
|
+
|
|
21935
|
+
// Remove extra line break added by htmlwriter plugin at the end: <p>Hello world</p>\n
|
|
21936
|
+
curVal = curVal.replace(/<\/p>\n$/, "</p>");
|
|
21937
|
+
|
|
21938
|
+
// Remove empty class attribute on <img> tags which may be temporarily set when selecting
|
|
21939
|
+
// an image using the dragresize plugin. This plugin adds a CSS class (ckimgrsz) to the image
|
|
21940
|
+
// tag while being selected, although the class name is removed when calling getData() above.
|
|
21941
|
+
// However, the empty class attribute is useless, so we remove it. It also results in IsDirty()
|
|
21942
|
+
// returning True while the image is selected if we keep it. Actually the class attribute should
|
|
21943
|
+
// never have been returned since the allowedContent option does not allow it - might be a minor bug.
|
|
21944
|
+
curVal = curVal.replace(/(<img.*?) class=""(.*?>)/, "$1$2"); // Not using /g switch as only one image can be selected
|
|
21945
|
+
|
|
21946
|
+
return curVal;
|
|
21947
|
+
}
|
|
21740
21948
|
|
|
21741
21949
|
return input.value;
|
|
21742
21950
|
}
|
|
21743
21951
|
|
|
21952
|
+
// See documentation on ControlBase
|
|
21953
|
+
this.UserValue = Fit.Core.CreateOverride(this.UserValue, function(val)
|
|
21954
|
+
{
|
|
21955
|
+
if (Fit.Validation.IsSet(val) === true && designEditor !== null)
|
|
21956
|
+
{
|
|
21957
|
+
designEditorDirtyPending = true;
|
|
21958
|
+
}
|
|
21959
|
+
|
|
21960
|
+
return base(val);
|
|
21961
|
+
});
|
|
21962
|
+
|
|
21744
21963
|
// See documentation on ControlBase
|
|
21745
21964
|
this.IsDirty = function()
|
|
21746
21965
|
{
|
|
21966
|
+
if (designEditor !== null)
|
|
21967
|
+
{
|
|
21968
|
+
// Never do value comparison in DesignMode.
|
|
21969
|
+
// A value such as "Hello world" could have been provided,
|
|
21970
|
+
// which by CKEditor would be returned as "<p>Hello world</p>".
|
|
21971
|
+
// A value such as '<p style="text-align: center;">Hello</p>' could
|
|
21972
|
+
// also have been set, which by CKEditor would be optimized to
|
|
21973
|
+
// '<p style="text-align:center">Hello</p>' via ACF (Advanced Content Filter):
|
|
21974
|
+
// https://ckeditor.com/docs/ckeditor4/latest/guide/dev_advanced_content_filter.html
|
|
21975
|
+
// Furthermore invalid HTML is removed while valid HTML is kept.
|
|
21976
|
+
// All this makes it very difficult to reliably determine dirty state
|
|
21977
|
+
// by comparing values. Therefore, if the user changed anything by interacting
|
|
21978
|
+
// with the editor, or UserValue(..) was called, always consider the value dirty.
|
|
21979
|
+
|
|
21980
|
+
// Another positive of avoiding value comparison to determine dirty state
|
|
21981
|
+
// is that retrieving the value from CKEditor is fairly expensive.
|
|
21982
|
+
|
|
21983
|
+
return designEditorDirty;
|
|
21984
|
+
}
|
|
21985
|
+
|
|
21747
21986
|
return (orgVal !== me.Value());
|
|
21748
21987
|
}
|
|
21749
21988
|
|
|
@@ -21758,7 +21997,7 @@ Fit.Controls.Input = function(ctlId)
|
|
|
21758
21997
|
{
|
|
21759
21998
|
// This will destroy control - it will no longer work!
|
|
21760
21999
|
|
|
21761
|
-
var curVal =
|
|
22000
|
+
var curVal = designEditorConfig !== null && designEditorConfig.Plugins && designEditorConfig.Plugins.Images && designEditorConfig.Plugins.Images.RevokeBlobUrlsOnDispose === "UnreferencedOnly" ? me.Value() : null;
|
|
21762
22001
|
|
|
21763
22002
|
if (Fit._internal.Controls.Input.ActiveEditorForDialog === me)
|
|
21764
22003
|
{
|
|
@@ -21826,7 +22065,7 @@ Fit.Controls.Input = function(ctlId)
|
|
|
21826
22065
|
debouncedOnChange.Cancel();
|
|
21827
22066
|
}
|
|
21828
22067
|
|
|
21829
|
-
if (
|
|
22068
|
+
if (designEditorConfig === null || !designEditorConfig.Plugins || !designEditorConfig.Plugins.Images || !designEditorConfig.Plugins.Images.RevokeBlobUrlsOnDispose || designEditorConfig.Plugins.Images.RevokeBlobUrlsOnDispose === "All")
|
|
21830
22069
|
{
|
|
21831
22070
|
Fit.Array.ForEach(imageBlobUrls, function(imageUrl)
|
|
21832
22071
|
{
|
|
@@ -21844,7 +22083,7 @@ Fit.Controls.Input = function(ctlId)
|
|
|
21844
22083
|
});
|
|
21845
22084
|
}
|
|
21846
22085
|
|
|
21847
|
-
me = orgVal = preVal = input = cmdResize = designEditor = htmlWrappedInParagraph = wasAutoChangedToMultiLineMode = minimizeHeight = maximizeHeight = minMaxUnit = resizable = nativeResizableAvailable = mutationObserverId = rootedEventId = createWhenReadyIntervalId = isIe8 = debounceOnChangeTimeout = debouncedOnChange = imageBlobUrls = null;
|
|
22086
|
+
me = orgVal = preVal = input = cmdResize = designEditor = designEditorDirty = designEditorDirtyPending = designEditorConfig = designEditorRestoreButtonState = designEditorSuppressPaste /*= htmlWrappedInParagraph*/ = wasAutoChangedToMultiLineMode = minimizeHeight = maximizeHeight = minMaxUnit = resizable = nativeResizableAvailable = mutationObserverId = rootedEventId = createWhenReadyIntervalId = isIe8 = debounceOnChangeTimeout = debouncedOnChange = imageBlobUrls = null;
|
|
21848
22087
|
|
|
21849
22088
|
base();
|
|
21850
22089
|
});
|
|
@@ -22305,16 +22544,220 @@ Fit.Controls.Input = function(ctlId)
|
|
|
22305
22544
|
return (cmdResize !== null && Fit.Dom.HasClass(cmdResize, "fa-chevron-up") === true);
|
|
22306
22545
|
}
|
|
22307
22546
|
|
|
22547
|
+
/// <container name="Fit.Controls.InputTypeDefs.DesignModeConfigPluginsImagesConfig">
|
|
22548
|
+
/// <description> Configuration for image plugins </description>
|
|
22549
|
+
/// <member name="Enabled" type="boolean"> Flag indicating whether to enable image plugins or not (defaults to False) </member>
|
|
22550
|
+
/// <member name="EmbedType" type="'base64' | 'blob'" default="undefined">
|
|
22551
|
+
/// How to store and embed images. Base64 is persistent while blob (default) is temporary
|
|
22552
|
+
/// and must be extracted from memory and uploaded/stored to be permanantly persisted.
|
|
22553
|
+
/// References to blobs can be parsed from the HTML value produced by the editor.
|
|
22554
|
+
/// </member>
|
|
22555
|
+
/// <member name="RevokeBlobUrlsOnDispose" type="'All' | 'UnreferencedOnly'" default="undefined">
|
|
22556
|
+
/// This option is in effect when EmbedType is blob.
|
|
22557
|
+
/// Dispose images from blob storage (revoke blob URLs) added though image plugins when control is disposed.
|
|
22558
|
+
/// If "UnreferencedOnly" is specified, the component using Fit.UI's input control will be responsible for
|
|
22559
|
+
/// disposing referenced blobs. Failing to do so may cause a memory leak. Defaults to All.
|
|
22560
|
+
/// </member>
|
|
22561
|
+
/// <member name="RevokeExternalBlobUrlsOnDispose" type="boolean" default="undefined">
|
|
22562
|
+
/// This option is in effect when EmbedType is blob.
|
|
22563
|
+
/// Dispose images from blob storage (revoke blob URLs) added through Value(..)
|
|
22564
|
+
/// function when control is disposed. Basically ownership of these blobs are handed
|
|
22565
|
+
/// over to the control for the duration of its life time.
|
|
22566
|
+
/// These images are furthermore subject to the rule set in RevokeBlobUrlsOnDispose.
|
|
22567
|
+
/// Defaults to False.
|
|
22568
|
+
/// </member>
|
|
22569
|
+
/// </container>
|
|
22570
|
+
|
|
22571
|
+
/// <container name="Fit.Controls.InputTypeDefs.DesignModeConfigPlugins">
|
|
22572
|
+
/// <description> Additional plugins enabled in DesignMode </description>
|
|
22573
|
+
/// <member name="Emojis" type="boolean" default="undefined"> Plugin(s) related to emoji support (defaults to False) </member>
|
|
22574
|
+
/// <member name="Images" type="Fit.Controls.InputTypeDefs.DesignModeConfigPluginsImagesConfig" default="undefined"> Plugin(s) related to support for images (defaults to False) </member>
|
|
22575
|
+
/// </container>
|
|
22576
|
+
|
|
22577
|
+
/// <container name="Fit.Controls.InputTypeDefs.DesignModeConfigToolbar">
|
|
22578
|
+
/// <description> Toolbar buttons enabled in DesignMode </description>
|
|
22579
|
+
/// <member name="Formatting" type="boolean" default="undefined"> Enable text formatting (bold, italic, underline) (defaults to True) </member>
|
|
22580
|
+
/// <member name="Justify" type="boolean" default="undefined"> Enable text alignment (defaults to True) </member>
|
|
22581
|
+
/// <member name="Lists" type="boolean" default="undefined"> Enable ordered and unordered lists with indentation (defaults to True) </member>
|
|
22582
|
+
/// <member name="Links" type="boolean" default="undefined"> Enable links (defaults to True) </member>
|
|
22583
|
+
/// <member name="Emojis" type="boolean" default="undefined"> Enable emoji button (defaults to False) </member>
|
|
22584
|
+
/// <member name="Images" type="boolean" default="undefined"> Enable image button (defaults to false) </member>
|
|
22585
|
+
/// </container>
|
|
22586
|
+
|
|
22587
|
+
/// <container name="Fit.Controls.InputTypeDefs.DesignModeConfigInfoPanel">
|
|
22588
|
+
/// <description> Information panel at the bottom of the editor </description>
|
|
22589
|
+
/// <member name="Text" type="string" default="undefined"> Text to display </member>
|
|
22590
|
+
/// <member name="Alignment" type="'Left' | 'Center' | 'Right'" default="undefined"> Text alignment - defaults to Center </member>
|
|
22591
|
+
/// </container>
|
|
22592
|
+
|
|
22593
|
+
/// <container name="Fit.Controls.InputTypeDefs.DesignModeTagsOnRequestEventHandlerArgs">
|
|
22594
|
+
/// <description> Request handler event arguments </description>
|
|
22595
|
+
/// <member name="Sender" type="Fit.Controls.Input"> Instance of control </member>
|
|
22596
|
+
/// <member name="Request" type="Fit.Http.JsonRequest | Fit.Http.JsonpRequest"> Instance of JsonRequest or JsonpRequest </member>
|
|
22597
|
+
/// <member name="Query" type="{ Marker: string, Query: string }"> Query information </member>
|
|
22598
|
+
/// </container>
|
|
22599
|
+
/// <function container="Fit.Controls.InputTypeDefs" name="DesignModeTagsOnRequest" returns="boolean | void">
|
|
22600
|
+
/// <description> Cancelable request event handler </description>
|
|
22601
|
+
/// <param name="sender" type="Fit.Controls.Input"> Instance of control </param>
|
|
22602
|
+
/// <param name="eventArgs" type="Fit.Controls.InputTypeDefs.DesignModeTagsOnRequestEventHandlerArgs"> Event arguments </param>
|
|
22603
|
+
/// </function>
|
|
22604
|
+
|
|
22605
|
+
/// <container name="Fit.Controls.InputTypeDefs.DesignModeTagsOnResponseJsonTag">
|
|
22606
|
+
/// <description> JSON object representing tag </description>
|
|
22607
|
+
/// <member name="Value" type="string"> Unique value </member>
|
|
22608
|
+
/// <member name="Title" type="string"> Title </member>
|
|
22609
|
+
/// <member name="Icon" type="string" default="undefined"> Optional URL to icon/image </member>
|
|
22610
|
+
/// <member name="Url" type="string" default="undefined"> Optional URL to associate with tag </member>
|
|
22611
|
+
/// <member name="Data" type="string" default="undefined"> Optional data to associate with tag </member>
|
|
22612
|
+
/// </container>
|
|
22613
|
+
/// <container name="Fit.Controls.InputTypeDefs.DesignModeTagsOnResponseEventHandlerArgs">
|
|
22614
|
+
/// <description> Response handler event arguments </description>
|
|
22615
|
+
/// <member name="Sender" type="Fit.Controls.Input"> Instance of control </member>
|
|
22616
|
+
/// <member name="Request" type="Fit.Http.JsonRequest | Fit.Http.JsonpRequest"> Instance of JsonRequest or JsonpRequest </member>
|
|
22617
|
+
/// <member name="Query" type="{ Marker: string, Query: string }"> Query information </member>
|
|
22618
|
+
/// <member name="Tags" type="Fit.Controls.InputTypeDefs.DesignModeTagsOnResponseJsonTag[]"> Tags received from WebService </member>
|
|
22619
|
+
/// </container>
|
|
22620
|
+
/// <function container="Fit.Controls.InputTypeDefs" name="DesignModeTagsOnResponse">
|
|
22621
|
+
/// <description> Response event handler </description>
|
|
22622
|
+
/// <param name="sender" type="Fit.Controls.Input"> Instance of control </param>
|
|
22623
|
+
/// <param name="eventArgs" type="Fit.Controls.InputTypeDefs.DesignModeTagsOnResponseEventHandlerArgs"> Event arguments </param>
|
|
22624
|
+
/// </function>
|
|
22625
|
+
|
|
22626
|
+
/// <container name="Fit.Controls.InputTypeDefs.DesignModeTagsTagCreatorReturnType">
|
|
22627
|
+
/// <description> JSON object representing tag to be inserted into editor </description>
|
|
22628
|
+
/// <member name="Title" type="string"> Tag title </member>
|
|
22629
|
+
/// <member name="Value" type="string"> Tag value (ID) </member>
|
|
22630
|
+
/// <member name="Type" type="string"> Tag type (marker) </member>
|
|
22631
|
+
/// <member name="Url" type="string" default="undefined"> Optional tag URL </member>
|
|
22632
|
+
/// <member name="Data" type="string" default="undefined"> Optional tag data </member>
|
|
22633
|
+
/// </container>
|
|
22634
|
+
/// <container name="Fit.Controls.InputTypeDefs.DesignModeTagsTagCreatorCallbackArgs">
|
|
22635
|
+
/// <description> TagCreator event arguments </description>
|
|
22636
|
+
/// <member name="Sender" type="Fit.Controls.Input"> Instance of control </member>
|
|
22637
|
+
/// <member name="QueryMarker" type="string"> Query marker </member>
|
|
22638
|
+
/// <member name="Tag" type="Fit.Controls.InputTypeDefs.DesignModeTagsOnResponseJsonTag"> Tag received from WebService </member>
|
|
22639
|
+
/// </container>
|
|
22640
|
+
/// <function container="Fit.Controls.InputTypeDefs" name="DesignModeTagsTagCreator" returns="Fit.Controls.InputTypeDefs.DesignModeTagsTagCreatorReturnType | null | void">
|
|
22641
|
+
/// <description>
|
|
22642
|
+
/// Function producing JSON object representing tag to be inserted into editor.
|
|
22643
|
+
/// Returning nothing or Null results in default tag being inserted into editor.
|
|
22644
|
+
/// </description>
|
|
22645
|
+
/// <param name="sender" type="Fit.Controls.Input"> Instance of control </param>
|
|
22646
|
+
/// <param name="eventArgs" type="Fit.Controls.InputTypeDefs.DesignModeTagsTagCreatorCallbackArgs"> Event arguments </param>
|
|
22647
|
+
/// </function>
|
|
22648
|
+
|
|
22649
|
+
/// <container name="Fit.Controls.InputTypeDefs.DesignModeConfigTags">
|
|
22650
|
+
/// <description> Configuration for tags in DesignMode </description>
|
|
22651
|
+
/// <member name="Triggers" type="{ Marker: string, MinimumCharacters?: integer, DebounceQuery?: integer }[]"> Markers triggering tags request and context menu </member>
|
|
22652
|
+
/// <member name="QueryUrl" type="string">
|
|
22653
|
+
/// URL to request data from. Endpoint receives the following payload:
|
|
22654
|
+
/// { Marker: "@", Query: "search" }
|
|
22655
|
+
///
|
|
22656
|
+
/// Data is expected to be returned in the following format:
|
|
22657
|
+
/// [
|
|
22658
|
+
/// { Value: "t-1", Title: "Tag 1", Icon: "images/img1.jpeg", Url: "show/1", Data: "..." },
|
|
22659
|
+
/// { Value: "t-2", Title: "Tag 2", Icon: "images/img2.jpeg", Url: "show/2", Data: "..." }, ...
|
|
22660
|
+
/// ]
|
|
22661
|
+
///
|
|
22662
|
+
/// The Value and Title properties are required. The Icon property is optional and must specify the path to an image.
|
|
22663
|
+
/// The Url property is optional and must specify a path to a related page/resource.
|
|
22664
|
+
/// The Data property is optional and allows for additional data to be associated with the tag.
|
|
22665
|
+
/// To hold multiple values, consider using a base64 encoded JSON object:
|
|
22666
|
+
/// btoa(JSON.stringify({ creationDate: new Date(), active: true }))
|
|
22667
|
+
///
|
|
22668
|
+
/// The data eventuelly results in a tag being added to the editor with the following format:
|
|
22669
|
+
/// <a data-tag-type="@" data-tag-id="unique id 1" data-tag-data="..." href="show/1">Tag name 1</a>
|
|
22670
|
+
/// The data-tag-data attribute is only declared if the corresponding Data property is defined in data.
|
|
22671
|
+
/// </member>
|
|
22672
|
+
/// <member name="JsonpCallback" type="string" default="undefined"> Name of URL parameter receiving name of JSONP callback function (only for JSONP services) </member>
|
|
22673
|
+
/// <member name="JsonpTimeout" type="integer" default="undefined"> Number of milliseconds to allow JSONP request to wait for a response before aborting (only for JSONP services) </member>
|
|
22674
|
+
/// <member name="OnRequest" type="Fit.Controls.InputTypeDefs.DesignModeTagsOnRequest" default="undefined">
|
|
22675
|
+
/// Event handler invoked when tags are requested. Request may be canceled by returning False.
|
|
22676
|
+
/// Function receives two arguments:
|
|
22677
|
+
/// Sender (Fit.Controls.Input) and EventArgs object.
|
|
22678
|
+
/// EventArgs object contains the following properties:
|
|
22679
|
+
/// - Sender: Fit.Controls.Input instance
|
|
22680
|
+
/// - Request: Fit.Http.JsonpRequest or Fit.Http.JsonRequest instance
|
|
22681
|
+
/// - Query: Contains query information in its Marker and Query property
|
|
22682
|
+
/// </member>
|
|
22683
|
+
/// <member name="OnResponse" type="Fit.Controls.InputTypeDefs.DesignModeTagsOnResponse" default="undefined">
|
|
22684
|
+
/// Event handler invoked when tags data is received, allowing for data transformation.
|
|
22685
|
+
/// Function receives two arguments:
|
|
22686
|
+
/// Sender (Fit.Controls.Input) and EventArgs object.
|
|
22687
|
+
/// EventArgs object contains the following properties:
|
|
22688
|
+
/// - Sender: Fit.Controls.Input instance
|
|
22689
|
+
/// - Request: Fit.Http.JsonpRequest or Fit.Http.JsonRequest instance
|
|
22690
|
+
/// - Query: Contains query information in its Marker and Query property
|
|
22691
|
+
/// - Tags: JSON tags array received from WebService
|
|
22692
|
+
/// </member>
|
|
22693
|
+
/// <member name="TagCreator" type="Fit.Controls.InputTypeDefs.DesignModeTagsTagCreator" default="undefined">
|
|
22694
|
+
/// Callback invoked when a tag is being inserted into editor, allowing
|
|
22695
|
+
/// for customization to the title and attributes associated with the tag.
|
|
22696
|
+
/// Function receives two arguments:
|
|
22697
|
+
/// Sender (Fit.Controls.Input) and EventArgs object.
|
|
22698
|
+
/// EventArgs object contains the following properties:
|
|
22699
|
+
/// - Sender: Fit.Controls.Input instance
|
|
22700
|
+
/// - QueryMarker: String containing query marker
|
|
22701
|
+
/// - Tag: JSON tag received from WebService
|
|
22702
|
+
/// </member>
|
|
22703
|
+
/// </container>
|
|
22704
|
+
|
|
22705
|
+
/// <container name="Fit.Controls.InputTypeDefs.DesignModeConfig">
|
|
22706
|
+
/// <description> Configuration for DesignMode </description>
|
|
22707
|
+
/// <member name="Plugins" type="Fit.Controls.InputTypeDefs.DesignModeConfigPlugins" default="undefined"> Plugins configuration </member>
|
|
22708
|
+
/// <member name="Toolbar" type="Fit.Controls.InputTypeDefs.DesignModeConfigToolbar" default="undefined"> Toolbar configuration </member>
|
|
22709
|
+
/// <member name="InfoPanel" type="Fit.Controls.InputTypeDefs.DesignModeConfigInfoPanel" default="undefined"> Information panel configuration </member>
|
|
22710
|
+
/// <member name="Tags" type="Fit.Controls.InputTypeDefs.DesignModeConfigTags" default="undefined"> Tags configuration </member>
|
|
22711
|
+
/// </container>
|
|
22712
|
+
|
|
22308
22713
|
/// <function container="Fit.Controls.Input" name="DesignMode" access="public" returns="boolean">
|
|
22309
22714
|
/// <description>
|
|
22310
22715
|
/// Get/set value indicating whether control is in Design Mode allowing for rich HTML content.
|
|
22311
22716
|
/// Notice that this control type requires dimensions (Width/Height) to be specified in pixels.
|
|
22312
22717
|
/// </description>
|
|
22313
22718
|
/// <param name="val" type="boolean" default="undefined"> If defined, True enables Design Mode, False disables it </param>
|
|
22719
|
+
/// <param name="editorConfig" type="Fit.Controls.InputTypeDefs.DesignModeConfig" default="undefined">
|
|
22720
|
+
/// If provided and DesignMode is enabled, configuration is applied when editor is created.
|
|
22721
|
+
/// </param>
|
|
22314
22722
|
/// </function>
|
|
22315
|
-
this.DesignMode = function(val)
|
|
22723
|
+
this.DesignMode = function(val, editorConfig)
|
|
22316
22724
|
{
|
|
22317
22725
|
Fit.Validation.ExpectBoolean(val, true);
|
|
22726
|
+
Fit.Validation.ExpectObject(editorConfig, true);
|
|
22727
|
+
Fit.Validation.ExpectObject((editorConfig || {}).Plugins, true);
|
|
22728
|
+
Fit.Validation.ExpectBoolean(((editorConfig || {}).Plugins || {}).Emojis, true);
|
|
22729
|
+
Fit.Validation.ExpectObject(((editorConfig || {}).Plugins || {}).Images, true);
|
|
22730
|
+
Fit.Validation.ExpectBoolean((((editorConfig || {}).Plugins || {}).Images || {}).Enabled, true);
|
|
22731
|
+
Fit.Validation.ExpectStringValue((((editorConfig || {}).Plugins || {}).Images || {}).EmbedType, true);
|
|
22732
|
+
Fit.Validation.ExpectStringValue((((editorConfig || {}).Plugins || {}).Images || {}).RevokeBlobUrlsOnDispose, true);
|
|
22733
|
+
Fit.Validation.ExpectBoolean((((editorConfig || {}).Plugins || {}).Images || {}).RevokeExternalBlobUrlsOnDispose, true);
|
|
22734
|
+
Fit.Validation.ExpectObject((editorConfig || {}).Toolbar, true);
|
|
22735
|
+
Fit.Validation.ExpectBoolean(((editorConfig || {}).Toolbar || {}).Formatting, true);
|
|
22736
|
+
Fit.Validation.ExpectBoolean(((editorConfig || {}).Toolbar || {}).Justify, true);
|
|
22737
|
+
Fit.Validation.ExpectBoolean(((editorConfig || {}).Toolbar || {}).Lists, true);
|
|
22738
|
+
Fit.Validation.ExpectBoolean(((editorConfig || {}).Toolbar || {}).Links, true);
|
|
22739
|
+
Fit.Validation.ExpectBoolean(((editorConfig || {}).Toolbar || {}).Emojis, true);
|
|
22740
|
+
Fit.Validation.ExpectBoolean(((editorConfig || {}).Toolbar || {}).Images, true);
|
|
22741
|
+
Fit.Validation.ExpectObject((editorConfig || {}).InfoPanel, true);
|
|
22742
|
+
Fit.Validation.ExpectString(((editorConfig || {}).InfoPanel || {}).Text, true);
|
|
22743
|
+
Fit.Validation.ExpectString(((editorConfig || {}).InfoPanel || {}).Alignment, true);
|
|
22744
|
+
Fit.Validation.ExpectObject((editorConfig || {}).Tags, true);
|
|
22745
|
+
|
|
22746
|
+
if (editorConfig && editorConfig.Tags)
|
|
22747
|
+
{
|
|
22748
|
+
Fit.Validation.ExpectTypeArray(editorConfig.Tags.Triggers, function(trigger)
|
|
22749
|
+
{
|
|
22750
|
+
Fit.Validation.ExpectStringValue(trigger.Marker);
|
|
22751
|
+
Fit.Validation.ExpectInteger(trigger.MinimumCharacters, true);
|
|
22752
|
+
Fit.Validation.ExpectInteger(trigger.DebounceQuery, true);
|
|
22753
|
+
});
|
|
22754
|
+
Fit.Validation.ExpectStringValue(editorConfig.Tags.QueryUrl);
|
|
22755
|
+
Fit.Validation.ExpectStringValue(editorConfig.Tags.JsonpCallback, true);
|
|
22756
|
+
Fit.Validation.ExpectInteger(editorConfig.Tags.JsonpTimeout, true);
|
|
22757
|
+
Fit.Validation.ExpectFunction(editorConfig.Tags.OnRequest, true);
|
|
22758
|
+
Fit.Validation.ExpectFunction(editorConfig.Tags.OnResponse, true);
|
|
22759
|
+
Fit.Validation.ExpectFunction(editorConfig.Tags.TagCreator, true);
|
|
22760
|
+
}
|
|
22318
22761
|
|
|
22319
22762
|
if (Fit.Validation.IsSet(val) === true)
|
|
22320
22763
|
{
|
|
@@ -22325,6 +22768,11 @@ Fit.Controls.Input = function(ctlId)
|
|
|
22325
22768
|
|
|
22326
22769
|
if (val === true && designMode === false)
|
|
22327
22770
|
{
|
|
22771
|
+
if (Fit.Validation.IsSet(editorConfig) === true)
|
|
22772
|
+
{
|
|
22773
|
+
designEditorConfig = editorConfig;
|
|
22774
|
+
}
|
|
22775
|
+
|
|
22328
22776
|
if (Fit._internal.Controls.Input.ActiveEditorForDialog === me)
|
|
22329
22777
|
{
|
|
22330
22778
|
// Control is actually already in Design Mode, but waiting
|
|
@@ -22356,6 +22804,16 @@ Fit.Controls.Input = function(ctlId)
|
|
|
22356
22804
|
CKEDITOR.config.skin = Fit._internal.Controls.Input.Editor.Skin;
|
|
22357
22805
|
}
|
|
22358
22806
|
|
|
22807
|
+
CKEDITOR.on("instanceReady", function(ev)
|
|
22808
|
+
{
|
|
22809
|
+
// Do not produce XHTML self-closing tags such as <br /> and <img src="img.jpg" />
|
|
22810
|
+
// https://ckeditor.com/docs/ckeditor4/latest/features/output_format.html
|
|
22811
|
+
// NOTICE: The htmlwriter plugin is required for this to work!
|
|
22812
|
+
// Output produced is now both HTML4 and HTML5 compatible, but is not valid
|
|
22813
|
+
// XHTML anymore! Self-closing tags are allowed in HTML5 but not valid in HTML4.
|
|
22814
|
+
ev.editor.dataProcessor.writer.selfClosingEnd = ">"; // Defaults to ' />'
|
|
22815
|
+
});
|
|
22816
|
+
|
|
22359
22817
|
// Register OnShow and OnHide event handlers when a dialog is opened for the first time.
|
|
22360
22818
|
// IMPORTANT: These event handlers are shared by all input control instances in Design Mode,
|
|
22361
22819
|
// so we cannot use 'me' to access the current control for which a dialog is opened.
|
|
@@ -22429,23 +22887,26 @@ Fit.Controls.Input = function(ctlId)
|
|
|
22429
22887
|
return;
|
|
22430
22888
|
}
|
|
22431
22889
|
|
|
22432
|
-
|
|
22433
|
-
|
|
22434
|
-
|
|
22435
|
-
|
|
22436
|
-
|
|
22437
|
-
|
|
22438
|
-
|
|
22439
|
-
|
|
22440
|
-
|
|
22441
|
-
|
|
22442
|
-
|
|
22443
|
-
|
|
22444
|
-
|
|
22445
|
-
|
|
22446
|
-
|
|
22447
|
-
|
|
22448
|
-
|
|
22890
|
+
if (Fit._internal.ControlBase.ReduceDocumentRootPollution === true)
|
|
22891
|
+
{
|
|
22892
|
+
// Move dialog to control - otherwise placed in the root of the document where it pollutes,
|
|
22893
|
+
// and makes it impossible to interact with the dialog in light dismissable panels and callouts.
|
|
22894
|
+
// Dialog is placed alongside control and not within the control's container, to prevent Fit.UI
|
|
22895
|
+
// styling from affecting the dialog.
|
|
22896
|
+
// DISABLED: It breaks file picker controls in dialogs which are hosted in iframes.
|
|
22897
|
+
// When an iframe is re-rooted in DOM it reloads, and any dynamically created content is lost.
|
|
22898
|
+
// We will have to increase the z-index to make sure dialogs open on top of modal layers.
|
|
22899
|
+
// EDIT 2021-08-20: Enabled again. The base64image plugin has now been altered so it no longer
|
|
22900
|
+
// uses CKEditor's built-in file picker which is wrapped in an iFrame. Therefore the dialog can
|
|
22901
|
+
// once again be mounted next to the Input control.
|
|
22902
|
+
|
|
22903
|
+
var ckeDialogElement = this.getElement().$;
|
|
22904
|
+
Fit.Dom.InsertAfter(Fit._internal.Controls.Input.ActiveEditorForDialog.GetDomElement(), ckeDialogElement);
|
|
22905
|
+
|
|
22906
|
+
// 2nd+ time dialog is opened it remains invisible - make it appear and position it
|
|
22907
|
+
ckeDialogElement.style.display = !CKEDITOR.env.ie || CKEDITOR.env.edge ? "flex" : ""; // https://github.com/ckeditor/ckeditor4/blob/8b208d05d1338d046cdc8f971c9faf21604dd75d/plugins/dialog/plugin.js#L152
|
|
22908
|
+
this.layout(); // 'this' is the dialog instance - layout() positions dialog
|
|
22909
|
+
}
|
|
22449
22910
|
});
|
|
22450
22911
|
|
|
22451
22912
|
dialog.on("hide", function(ev) // Fires when user closes dialog, or when hide() is called on dialog, or if destroy() is called on editor instance from Dispose() or DesignMode(false)
|
|
@@ -22717,6 +23178,277 @@ Fit.Controls.Input = function(ctlId)
|
|
|
22717
23178
|
var langSupport = ["da", "de", "en"];
|
|
22718
23179
|
var locale = Fit.Internationalization.Locale().length === 2 ? Fit.Internationalization.Locale() : Fit.Internationalization.Locale().substring(0, 2);
|
|
22719
23180
|
var lang = Fit.Array.Contains(langSupport, locale) === true ? locale : "en";
|
|
23181
|
+
var plugins = [];
|
|
23182
|
+
var toolbar = [];
|
|
23183
|
+
var mentions = [];
|
|
23184
|
+
|
|
23185
|
+
var config = designEditorConfig || {};
|
|
23186
|
+
|
|
23187
|
+
// Enable additional plugins not compiled into CKEditor by default
|
|
23188
|
+
|
|
23189
|
+
if ((config.Plugins && config.Plugins.Emojis === true) || (config.Toolbar && config.Toolbar.Emojis === true))
|
|
23190
|
+
{
|
|
23191
|
+
Fit.Array.Add(plugins, "emoji");
|
|
23192
|
+
}
|
|
23193
|
+
|
|
23194
|
+
if ((config.Plugins && config.Plugins.Images && config.Plugins.Images.Enabled === true) || (config.Toolbar && config.Toolbar.Images === true))
|
|
23195
|
+
{
|
|
23196
|
+
if (config.Toolbar && config.Toolbar.Images === true)
|
|
23197
|
+
{
|
|
23198
|
+
Fit.Array.Add(plugins, "base64image");
|
|
23199
|
+
}
|
|
23200
|
+
|
|
23201
|
+
plugins = Fit.Array.Merge(plugins, ["base64imagepaste", "dragresize"]);
|
|
23202
|
+
}
|
|
23203
|
+
|
|
23204
|
+
// Add toolbar buttons
|
|
23205
|
+
|
|
23206
|
+
if (!config.Toolbar || config.Toolbar.Formatting !== false)
|
|
23207
|
+
{
|
|
23208
|
+
Fit.Array.Add(toolbar,
|
|
23209
|
+
{
|
|
23210
|
+
name: "BasicFormatting",
|
|
23211
|
+
items: [ "Bold", "Italic", "Underline" ]
|
|
23212
|
+
});
|
|
23213
|
+
}
|
|
23214
|
+
|
|
23215
|
+
if (!config.Toolbar || config.Toolbar.Justify !== false)
|
|
23216
|
+
{
|
|
23217
|
+
Fit.Array.Add(toolbar,
|
|
23218
|
+
{
|
|
23219
|
+
name: "Justify",
|
|
23220
|
+
items: [ "JustifyLeft", "JustifyCenter", "JustifyRight" ]
|
|
23221
|
+
});
|
|
23222
|
+
}
|
|
23223
|
+
|
|
23224
|
+
if (!config.Toolbar || config.Toolbar.Lists !== false)
|
|
23225
|
+
{
|
|
23226
|
+
Fit.Array.Add(toolbar,
|
|
23227
|
+
{
|
|
23228
|
+
name: "Lists",
|
|
23229
|
+
items: [ "NumberedList", "BulletedList", "Indent", "Outdent" ]
|
|
23230
|
+
});
|
|
23231
|
+
}
|
|
23232
|
+
|
|
23233
|
+
if (!config.Toolbar || config.Toolbar.Links !== false)
|
|
23234
|
+
{
|
|
23235
|
+
Fit.Array.Add(toolbar,
|
|
23236
|
+
{
|
|
23237
|
+
name: "Links",
|
|
23238
|
+
items: [ "Link", "Unlink" ]
|
|
23239
|
+
});
|
|
23240
|
+
}
|
|
23241
|
+
|
|
23242
|
+
if (config.Toolbar)
|
|
23243
|
+
{
|
|
23244
|
+
var insert = [];
|
|
23245
|
+
|
|
23246
|
+
if (config.Toolbar.Emojis === true)
|
|
23247
|
+
{
|
|
23248
|
+
Fit.Array.Add(insert, "EmojiPanel");
|
|
23249
|
+
}
|
|
23250
|
+
|
|
23251
|
+
if (config.Toolbar.Images === true)
|
|
23252
|
+
{
|
|
23253
|
+
Fit.Array.Add(insert, "base64image");
|
|
23254
|
+
}
|
|
23255
|
+
|
|
23256
|
+
if (insert.length > 0)
|
|
23257
|
+
{
|
|
23258
|
+
Fit.Array.Add(toolbar,
|
|
23259
|
+
{
|
|
23260
|
+
name: "Insert",
|
|
23261
|
+
items: insert
|
|
23262
|
+
});
|
|
23263
|
+
}
|
|
23264
|
+
}
|
|
23265
|
+
|
|
23266
|
+
// Configure tags/mentions plugin
|
|
23267
|
+
|
|
23268
|
+
if (config.Tags)
|
|
23269
|
+
{
|
|
23270
|
+
var requestAwaiting = null;
|
|
23271
|
+
|
|
23272
|
+
var createEventArgs = function(marker, query, request) // EventsArgs for OnRequest and OnResponse
|
|
23273
|
+
{
|
|
23274
|
+
return { Sender: me, Query: { Marker: marker, Query: query }, Request: request };
|
|
23275
|
+
};
|
|
23276
|
+
|
|
23277
|
+
Fit.Array.ForEach(config.Tags.Triggers, function(trigger)
|
|
23278
|
+
{
|
|
23279
|
+
var mention =
|
|
23280
|
+
{
|
|
23281
|
+
marker: trigger.Marker,
|
|
23282
|
+
minChars: trigger.MinimumCharacters || 0,
|
|
23283
|
+
throttle: 0, // Throttling is not debouncing - it merely ensures that no more than 1 request is made every X milliseconds when value is changed (defaults to 200ms) - real debouncing implemented further down, which reduce and cancel network calls as user types - also a work around for https://github.com/ckeditor/ckeditor4/issues/5036
|
|
23284
|
+
feed: function(args, resolve)
|
|
23285
|
+
{
|
|
23286
|
+
// WebService is expected to return tag items in an array like so:
|
|
23287
|
+
// [ { Title: string, Value: string, Icon?: string, Url?: string, Data?: string }, { ... }, ... ]
|
|
23288
|
+
|
|
23289
|
+
var req = null;
|
|
23290
|
+
|
|
23291
|
+
if (config.Tags.JsonpCallback)
|
|
23292
|
+
{
|
|
23293
|
+
req = new Fit.Http.JsonpRequest(config.Tags.QueryUrl, config.Tags.JsonpCallback);
|
|
23294
|
+
config.Tags.JsonpTimeout && req.Timeout(config.Tags.JsonpTimeout);
|
|
23295
|
+
req.SetParameter("Marker", args.marker);
|
|
23296
|
+
req.SetParameter("Query", args.query);
|
|
23297
|
+
}
|
|
23298
|
+
else
|
|
23299
|
+
{
|
|
23300
|
+
req = new Fit.Http.JsonRequest(config.Tags.QueryUrl);
|
|
23301
|
+
req.SetData({ Marker: args.marker, Query: args.query });
|
|
23302
|
+
}
|
|
23303
|
+
|
|
23304
|
+
if (config.Tags.OnRequest)
|
|
23305
|
+
{
|
|
23306
|
+
var eventArgs = createEventArgs(args.marker, args.query, req);
|
|
23307
|
+
|
|
23308
|
+
if (config.Tags.OnRequest(me, eventArgs) === false)
|
|
23309
|
+
{
|
|
23310
|
+
resolve([]);
|
|
23311
|
+
return;
|
|
23312
|
+
}
|
|
23313
|
+
|
|
23314
|
+
if (eventArgs.Request !== req)
|
|
23315
|
+
{
|
|
23316
|
+
// Support for changing request instans to
|
|
23317
|
+
// take control over webservice communication.
|
|
23318
|
+
|
|
23319
|
+
// Restrict to support for Fit.Http.Request or classes derived from this
|
|
23320
|
+
Fit.Validation.ExpectInstance(eventArgs.Request, Fit.Http.Request);
|
|
23321
|
+
|
|
23322
|
+
req = eventArgs.Request;
|
|
23323
|
+
}
|
|
23324
|
+
}
|
|
23325
|
+
|
|
23326
|
+
var processDataAndResolve = function(items)
|
|
23327
|
+
{
|
|
23328
|
+
if (config.Tags.OnResponse) // OnResponse is allowed to manipulate tags
|
|
23329
|
+
{
|
|
23330
|
+
var eventArgs = Fit.Core.Merge(createEventArgs(args.marker, args.query, req), { Tags: items });
|
|
23331
|
+
config.Tags.OnResponse(me, eventArgs);
|
|
23332
|
+
|
|
23333
|
+
items = eventArgs.Tags; // In case OnResponse event handler assigned new collection
|
|
23334
|
+
}
|
|
23335
|
+
|
|
23336
|
+
Fit.Array.ForEach(items, function(item)
|
|
23337
|
+
{
|
|
23338
|
+
// Set properties required by mentions plugin
|
|
23339
|
+
item.id = item.Value;
|
|
23340
|
+
item.name = item.Title;
|
|
23341
|
+
});
|
|
23342
|
+
|
|
23343
|
+
resolve(items);
|
|
23344
|
+
|
|
23345
|
+
if (Fit._internal.ControlBase.ReduceDocumentRootPollution === true)
|
|
23346
|
+
{
|
|
23347
|
+
// Calling resolve(..) above immediately opens the context menu from which
|
|
23348
|
+
// a tag can be selected. However, it is placed in the root of the document
|
|
23349
|
+
// where it pollutes the global scope. Move it next to the Fit.UI control.
|
|
23350
|
+
// We do not mount it within the Fit.UI control as it could cause Fit.UI styles
|
|
23351
|
+
// to take effect on the context menu.
|
|
23352
|
+
|
|
23353
|
+
// Get the autocomplete context menu currently open. There can be only one
|
|
23354
|
+
// such menu open at any time. Each editor can declare multiple autocomplete
|
|
23355
|
+
// context menus since each tag marker is associated with its own context menu.
|
|
23356
|
+
var ctm = document.querySelector("ul.cke_autocomplete_opened");
|
|
23357
|
+
Fit.Dom.InsertAfter(me.GetDomElement(), ctm);
|
|
23358
|
+
}
|
|
23359
|
+
};
|
|
23360
|
+
|
|
23361
|
+
if (Fit.Core.InstanceOf(req, Fit.Http.JsonpRequest) === true)
|
|
23362
|
+
{
|
|
23363
|
+
req.OnSuccess(function(sender)
|
|
23364
|
+
{
|
|
23365
|
+
var response = req.GetResponse();
|
|
23366
|
+
var items = ((response instanceof Array) ? response : []);
|
|
23367
|
+
|
|
23368
|
+
processDataAndResolve(items);
|
|
23369
|
+
});
|
|
23370
|
+
|
|
23371
|
+
req.OnTimeout(function(sender)
|
|
23372
|
+
{
|
|
23373
|
+
resolve([]);
|
|
23374
|
+
Fit.Validation.ThrowError("Unable to get tags - request did not return data in time (JSONP timeout reached)");
|
|
23375
|
+
});
|
|
23376
|
+
}
|
|
23377
|
+
else
|
|
23378
|
+
{
|
|
23379
|
+
req.OnSuccess(function(sender)
|
|
23380
|
+
{
|
|
23381
|
+
var response = req.GetResponseJson();
|
|
23382
|
+
var items = ((response instanceof Array) ? response : []);
|
|
23383
|
+
|
|
23384
|
+
processDataAndResolve(items);
|
|
23385
|
+
});
|
|
23386
|
+
|
|
23387
|
+
req.OnFailure(function(sender)
|
|
23388
|
+
{
|
|
23389
|
+
resolve([]);
|
|
23390
|
+
Fit.Validation.ThrowError("Unable to get tags - request failed with HTTP Status code " + req.GetHttpStatus());
|
|
23391
|
+
});
|
|
23392
|
+
}
|
|
23393
|
+
|
|
23394
|
+
if (requestAwaiting !== null)
|
|
23395
|
+
{
|
|
23396
|
+
requestAwaiting.Abort();
|
|
23397
|
+
}
|
|
23398
|
+
|
|
23399
|
+
requestAwaiting = req;
|
|
23400
|
+
req.Start();
|
|
23401
|
+
},
|
|
23402
|
+
itemTemplate: function(item) // Item must define "name" and "id" properties - the {name} placeholder is replaced by "@" + the value of the "name" property - to get rid of "@" simply use an alternative property such as nameWithoutTag:"Some username"
|
|
23403
|
+
{
|
|
23404
|
+
if (item.Icon)
|
|
23405
|
+
{
|
|
23406
|
+
return '<li data-id="' + item.Value + '"><img src="' + item.Icon + '" style="width: 24px; height: 24px; border-radius: 24px; vertical-align: middle" alt=""><span style="display: inline-block; width: 150px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: middle; margin-left: 5px">' + item.Title + '</span></li>';
|
|
23407
|
+
}
|
|
23408
|
+
else
|
|
23409
|
+
{
|
|
23410
|
+
return '<li data-id="' + item.Value + '">' + item.Title + '</li>';
|
|
23411
|
+
}
|
|
23412
|
+
},
|
|
23413
|
+
outputTemplate: function(item)
|
|
23414
|
+
{
|
|
23415
|
+
// IMPORTANT: Output produced must respect ACF (Advanced Content Filter).
|
|
23416
|
+
// So the tag produced must be allowed, and any attributes contained must be allowed.
|
|
23417
|
+
|
|
23418
|
+
var alternativeItem = null;
|
|
23419
|
+
|
|
23420
|
+
if (config.Tags.TagCreator)
|
|
23421
|
+
{
|
|
23422
|
+
var callbackArgs = { Sender: me, QueryMarker: trigger.Marker, Tag: Fit.Core.Clone(item) };
|
|
23423
|
+
alternativeItem = config.Tags.TagCreator(me, callbackArgs) || null;
|
|
23424
|
+
}
|
|
23425
|
+
|
|
23426
|
+
// Function should return a link for tags to "just work". Returning a <span> requires the span to be whitelisted in
|
|
23427
|
+
// extraAllowedContent configuration, but even then the editor will continue writing text within the <span> element,
|
|
23428
|
+
// rather than next to it. So one would expect something like: We will assign <span data-tag-type="@" ..>@James Bond</span> to this mission.
|
|
23429
|
+
// But what we get instead is something like: We will assign <span data-tag-type="@" ..>@James Bond to this mission</span>.
|
|
23430
|
+
// The same happens to link tags if the href attribute is removed, which is why we always add it, even when no URL is defined.
|
|
23431
|
+
|
|
23432
|
+
if (alternativeItem !== null)
|
|
23433
|
+
{
|
|
23434
|
+
return '<a data-tag-type="' + (alternativeItem.Type || trigger.Marker) + '" data-tag-id="' + (alternativeItem.Value || item.Value) + '"' + (alternativeItem.Data || item.Data ? ' data-tag-data="' + (alternativeItem.Data || item.Data) + '"' : '') + (alternativeItem.Url || item.Url ? ' href="' + (alternativeItem.Url || item.Url) + '"' : 'href=""') + '>' + (alternativeItem.Title || (trigger.Marker + item.Title)) + '</a>';
|
|
23435
|
+
}
|
|
23436
|
+
else
|
|
23437
|
+
{
|
|
23438
|
+
return '<a data-tag-type="' + trigger.Marker + '" data-tag-id="' + item.Value + '"' + (item.Data ? ' data-tag-data="' + item.Data + '"' : '') + (item.Url ? ' href="' + item.Url + '"' : 'href=""') + '>' + trigger.Marker + item.Title + '</a>';
|
|
23439
|
+
}
|
|
23440
|
+
}
|
|
23441
|
+
};
|
|
23442
|
+
|
|
23443
|
+
if (trigger.DebounceQuery !== 0) // A value of 0 (zero) disables debouncing
|
|
23444
|
+
{
|
|
23445
|
+
// Wrap feed handler in debounce function so that every time it gets invoked, it cancels the previous invocation
|
|
23446
|
+
mention.feed = Fit.Core.CreateDebouncer(mention.feed, trigger.DebounceQuery || 300).Invoke;
|
|
23447
|
+
}
|
|
23448
|
+
|
|
23449
|
+
Fit.Array.Add(mentions, mention)
|
|
23450
|
+
});
|
|
23451
|
+
}
|
|
22720
23452
|
|
|
22721
23453
|
// Prevent control from losing focus when HTML editor is initialized,
|
|
22722
23454
|
// e.g. if Design Mode is enabled when ordinary input control gains focus.
|
|
@@ -22770,49 +23502,30 @@ Fit.Controls.Input = function(ctlId)
|
|
|
22770
23502
|
designEditor = CKEDITOR.replace(me.GetId() + "_DesignMode",
|
|
22771
23503
|
{
|
|
22772
23504
|
//allowedContent: true, // http://docs.ckeditor.com/#!/guide/dev_allowed_content_rules and http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-allowedContent
|
|
23505
|
+
extraAllowedContent: "a[data-tag-type,data-tag-id,data-tag-data]", // https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_config.html#cfg-extraAllowedContent
|
|
22773
23506
|
language: lang,
|
|
22774
23507
|
disableNativeSpellChecker: me.CheckSpelling() === false,
|
|
22775
23508
|
readOnly: me.Enabled() === false,
|
|
22776
23509
|
tabIndex: me.Enabled() === false ? -1 : 0,
|
|
22777
23510
|
title: "",
|
|
22778
23511
|
startupFocus: focused === true ? "end" : false,
|
|
22779
|
-
extraPlugins:
|
|
23512
|
+
extraPlugins: plugins.join(","),
|
|
23513
|
+
clipboard_handleImages: false, // Disable native support for image pasting - allow base64imagepaste plugin to handle image data if loaded
|
|
22780
23514
|
base64image: // Custom property used by base64image plugin if loaded
|
|
22781
23515
|
{
|
|
22782
|
-
storage: "blob", // "base64" (default) or "blob" - base64 will always be provided by browsers not supporting blob storage
|
|
23516
|
+
storage: designEditorConfig !== null && designEditorConfig.Plugins && designEditorConfig.Plugins.Images && designEditorConfig.Plugins.Images.EmbedType === "blob" ? "blob" : "base64", // "base64" (default) or "blob" - base64 will always be provided by browsers not supporting blob storage
|
|
22783
23517
|
onImageAdded: onImageAdded
|
|
22784
23518
|
},
|
|
22785
23519
|
base64imagepaste: // Custom property used by base64imagepaste plugin if loaded - notice that IE has native support for image pasting as base64 so plugin is not triggered in IE
|
|
22786
23520
|
{
|
|
22787
|
-
storage: "blob", // "base64" (default) or "blob" - base64 will always be provided by browsers not supporting blob storage
|
|
23521
|
+
storage: designEditorConfig !== null && designEditorConfig.Plugins && designEditorConfig.Plugins.Images && designEditorConfig.Plugins.Images.EmbedType === "blob" ? "blob" : "base64", // "base64" (default) or "blob" - base64 will always be provided by browsers not supporting blob storage
|
|
22788
23522
|
onImageAdded: onImageAdded
|
|
22789
23523
|
},
|
|
22790
23524
|
resize_enabled: resizable !== Fit.Controls.InputResizing.Disabled,
|
|
22791
23525
|
resize_dir: resizable === Fit.Controls.InputResizing.Enabled ? "both" : resizable === Fit.Controls.InputResizing.Vertical ? "vertical" : resizable === Fit.Controls.InputResizing.Horizontal ? "horizontal" : "none", // Specific to resize plugin (horizontal | vertical | both - https://ckeditor.com/docs/ckeditor4/latest/features/resize.html)
|
|
22792
|
-
toolbar:
|
|
22793
|
-
/*[
|
|
22794
|
-
{
|
|
22795
|
-
name: "BasicFormatting",
|
|
22796
|
-
items: [ "Bold", "Italic", "Underline" ]
|
|
22797
|
-
},
|
|
22798
|
-
{
|
|
22799
|
-
name: "Justify",
|
|
22800
|
-
items: [ "JustifyLeft", "JustifyCenter", "JustifyRight" ]
|
|
22801
|
-
},
|
|
22802
|
-
{
|
|
22803
|
-
name: "Lists",
|
|
22804
|
-
items: [ "NumberedList", "BulletedList", "Indent", "Outdent" ]
|
|
22805
|
-
},
|
|
22806
|
-
{
|
|
22807
|
-
name: "Links",
|
|
22808
|
-
items: [ "Link", "Unlink" ]
|
|
22809
|
-
},
|
|
22810
|
-
{
|
|
22811
|
-
name: "Insert",
|
|
22812
|
-
items: [ "base64image" ]
|
|
22813
|
-
}
|
|
22814
|
-
],*/
|
|
23526
|
+
toolbar: toolbar,
|
|
22815
23527
|
removeButtons: "", // Set to empty string to prevent CKEditor from removing buttons such as Underline
|
|
23528
|
+
mentions: mentions,
|
|
22816
23529
|
on:
|
|
22817
23530
|
{
|
|
22818
23531
|
instanceReady: function()
|
|
@@ -22857,6 +23570,60 @@ Fit.Controls.Input = function(ctlId)
|
|
|
22857
23570
|
me.Maximized(true);
|
|
22858
23571
|
}
|
|
22859
23572
|
|
|
23573
|
+
if (config.InfoPanel && config.InfoPanel.Text)
|
|
23574
|
+
{
|
|
23575
|
+
var infoPanel = document.createElement("div");
|
|
23576
|
+
infoPanel.className = "FitUiControlInputInfoPanel";
|
|
23577
|
+
infoPanel.innerHTML = config.InfoPanel.Text;
|
|
23578
|
+
infoPanel.style.cssText = "text-align: " + (config.InfoPanel.Alignment ? config.InfoPanel.Alignment.toLowerCase() : "center");
|
|
23579
|
+
|
|
23580
|
+
var ckEditorInner = designEditor.container.$.querySelector(".cke_inner"); // Div in modern browsers, span in legacy IE
|
|
23581
|
+
var ckEditorBottom = designEditor.container.$.querySelector(".cke_inner span.cke_bottom"); // Only present if resize handle is enable
|
|
23582
|
+
|
|
23583
|
+
if (ckEditorInner !== null)
|
|
23584
|
+
{
|
|
23585
|
+
if (ckEditorBottom !== null)
|
|
23586
|
+
{
|
|
23587
|
+
Fit.Dom.InsertBefore(ckEditorBottom, infoPanel);
|
|
23588
|
+
}
|
|
23589
|
+
else
|
|
23590
|
+
{
|
|
23591
|
+
Fit.Dom.Add(ckEditorInner, infoPanel);
|
|
23592
|
+
}
|
|
23593
|
+
}
|
|
23594
|
+
}
|
|
23595
|
+
|
|
23596
|
+
// DISABLED: Doesn't work! Emoji panel contains an iFrame. When it is re-mounted
|
|
23597
|
+
// in DOM, the iframe reloads, and dynamically added content is lost. Also, this makes
|
|
23598
|
+
// CKEditor throw errors and the dialog never appears.
|
|
23599
|
+
/*if (Fit._internal.ControlBase.ReduceDocumentRootPollution === true)
|
|
23600
|
+
{
|
|
23601
|
+
// Move emoji dialog to control - otherwise placed in the root of the document where it pollutes,
|
|
23602
|
+
// and makes it impossible to interact with the dialog in light dismissable panels and callouts.
|
|
23603
|
+
// Dialog is placed alongside control and not within the control's container, to prevent Fit.UI
|
|
23604
|
+
// styling from affecting the dialog.
|
|
23605
|
+
if (config.Toolbar && config.Toolbar.Emojis === true)
|
|
23606
|
+
{
|
|
23607
|
+
var emojiButton = designEditor.container.$.querySelector("a.cke_button__emojipanel");
|
|
23608
|
+
|
|
23609
|
+
if (emojiButton !== null)
|
|
23610
|
+
{
|
|
23611
|
+
Fit.Events.AddHandler(emojiButton, "click", function(e)
|
|
23612
|
+
{
|
|
23613
|
+
setTimeout(function() // Postpone - made visible after click event
|
|
23614
|
+
{
|
|
23615
|
+
var emojiPanel = document.querySelector("div.cke_emoji-panel:not([style*='display: none'])");
|
|
23616
|
+
|
|
23617
|
+
if (emojiPanel !== null)
|
|
23618
|
+
{
|
|
23619
|
+
Fit.Dom.InsertAfter(me.GetDomElement(), emojiPanel);
|
|
23620
|
+
}
|
|
23621
|
+
}, 0);
|
|
23622
|
+
});
|
|
23623
|
+
}
|
|
23624
|
+
}
|
|
23625
|
+
}*/
|
|
23626
|
+
|
|
22860
23627
|
designEditor._isReadyForInteraction = true;
|
|
22861
23628
|
|
|
22862
23629
|
// Make editor assume configured width and height.
|
|
@@ -22868,6 +23635,21 @@ Fit.Controls.Input = function(ctlId)
|
|
|
22868
23635
|
},
|
|
22869
23636
|
change: function() // CKEditor bug: not fired in Opera 12 (possibly other old versions as well)
|
|
22870
23637
|
{
|
|
23638
|
+
if (me._internal.FireOnChangeSuppressed === true)
|
|
23639
|
+
{
|
|
23640
|
+
// Do not process event - it has been fired by CKEditor when HTML
|
|
23641
|
+
// value was initially assigned in Value(..) which happend through
|
|
23642
|
+
// me._internal.ExecuteWithNoOnChange(function() { .. }).
|
|
23643
|
+
// See Value(..) implementation for details.
|
|
23644
|
+
return;
|
|
23645
|
+
}
|
|
23646
|
+
|
|
23647
|
+
// Assume value was changed by user if control has focus
|
|
23648
|
+
if (designEditorDirty === false && me.Focused() === true)
|
|
23649
|
+
{
|
|
23650
|
+
designEditorDirty = true;
|
|
23651
|
+
}
|
|
23652
|
+
|
|
22871
23653
|
input.onkeyup();
|
|
22872
23654
|
},
|
|
22873
23655
|
resize: function() // Fires when size is changed, not just when resized using resize handle in lower right cornor
|
|
@@ -22875,8 +23657,73 @@ Fit.Controls.Input = function(ctlId)
|
|
|
22875
23657
|
me._internal.Data("resized", "true");
|
|
22876
23658
|
repaint();
|
|
22877
23659
|
},
|
|
23660
|
+
selectionChange: function(ev)
|
|
23661
|
+
{
|
|
23662
|
+
// Disable/enable toolbar buttons, depending on whether a tag/mention is selected
|
|
23663
|
+
|
|
23664
|
+
var elm = ev.data.selection.getStartElement().$;
|
|
23665
|
+
|
|
23666
|
+
if (elm.tagName === "A" && Fit.Dom.Data(elm, "tag-id") !== null)
|
|
23667
|
+
{
|
|
23668
|
+
designEditorSuppressPaste = true;
|
|
23669
|
+
setTimeout(function() // Postpone - otherwise we won't be able to temporarily disable some of the buttons (https://jsfiddle.net/ymv56znq/14/)
|
|
23670
|
+
{
|
|
23671
|
+
disableDesignEditorButtons();
|
|
23672
|
+
}, 0);
|
|
23673
|
+
}
|
|
23674
|
+
else
|
|
23675
|
+
{
|
|
23676
|
+
designEditorSuppressPaste = false;
|
|
23677
|
+
restoreDesignEditorButtons();
|
|
23678
|
+
}
|
|
23679
|
+
},
|
|
23680
|
+
doubleclick: function(ev)
|
|
23681
|
+
{
|
|
23682
|
+
// Suppress link dialog for tags (similar code found in beforeCommandExec handler below)
|
|
23683
|
+
if (Fit.Dom.Data(ev.data.element.$, "tag-id") !== null)
|
|
23684
|
+
{
|
|
23685
|
+
ev.cancel();
|
|
23686
|
+
return;
|
|
23687
|
+
}
|
|
23688
|
+
},
|
|
23689
|
+
paste: function(ev)
|
|
23690
|
+
{
|
|
23691
|
+
// Prevent pasting (especially images) into tags.
|
|
23692
|
+
// OnPaste is suppressed using an OnPaste handler in capture phase, which will prevent the operation entirely
|
|
23693
|
+
// on supported browsers. On legacy browsers we handle this by invoking undo on the editor instance instead.
|
|
23694
|
+
//var path = ev.editor.elementPath(); // Null if dialog button is triggered without placing text cursor in editor first
|
|
23695
|
+
//if (Fit.Dom.Data(path.lastElement.$, "tag-id") !== null)
|
|
23696
|
+
if (designEditorSuppressPaste === true) // Also handled in a native OnPaste event handler (capture phase) for supported browsers, which suppresses the event entirely
|
|
23697
|
+
{
|
|
23698
|
+
setTimeout(function() // Postpone - allow editor to create snapshot
|
|
23699
|
+
{
|
|
23700
|
+
ev.editor.execCommand("undo"); // Undo change - paste event cannot be canceled, as it has already happened
|
|
23701
|
+
}, 0);
|
|
23702
|
+
return;
|
|
23703
|
+
}
|
|
23704
|
+
},
|
|
22878
23705
|
beforeCommandExec: function(ev)
|
|
22879
23706
|
{
|
|
23707
|
+
// Suppress any command (formatting, link dialog etc.) for tags (similar code found in doubleclick handler above).
|
|
23708
|
+
// Commmands can be triggered in multiple ways, e.g. using toolbar buttons, using keyboard shortcuts, and programmatically.
|
|
23709
|
+
var path = ev.editor.elementPath(); // Null if dialog button is triggered without placing text cursor in editor first
|
|
23710
|
+
if (path === null && ev.editor.getData().indexOf("<p><a data-tag-id=") === 0)
|
|
23711
|
+
{
|
|
23712
|
+
// Text cursor has not been placed in editor, but a command such as Bold or "insert image"
|
|
23713
|
+
// has been triggered, and editor content starts with a tag. This results in command being
|
|
23714
|
+
// applied to the tag, which we do not want. Usually this is prevented by the toolbar being
|
|
23715
|
+
// disabled when a tag is selected (see selectionChange event handler further up), but that
|
|
23716
|
+
// is not the case when the user has not yet placed the cursor in the editor.
|
|
23717
|
+
ev.cancel();
|
|
23718
|
+
return;
|
|
23719
|
+
}
|
|
23720
|
+
else if (path !== null && Fit.Dom.Data(path.lastElement.$, "tag-id") !== null && ev.data.name !== "undo") // Allow undo within tag, in case user typed something by mistake
|
|
23721
|
+
{
|
|
23722
|
+
// Cursor is currently placed in a tag - do not allow formatting
|
|
23723
|
+
ev.cancel();
|
|
23724
|
+
return;
|
|
23725
|
+
}
|
|
23726
|
+
|
|
22880
23727
|
if (ev && ev.data && ev.data.command && ev.data.command.dialogName)
|
|
22881
23728
|
{
|
|
22882
23729
|
// Command triggered was a dialog
|
|
@@ -22933,6 +23780,68 @@ Fit.Controls.Input = function(ctlId)
|
|
|
22933
23780
|
});
|
|
22934
23781
|
}
|
|
22935
23782
|
|
|
23783
|
+
function disableDesignEditorButtons() // Might be called multiple times, e.g. if navigating from one tag/mention to another - buttons must be disabled every time since CKEditor itself re-enable buttons when navigating elements in editor
|
|
23784
|
+
{
|
|
23785
|
+
var preserveButtonState = designEditorRestoreButtonState === null;
|
|
23786
|
+
|
|
23787
|
+
if (preserveButtonState === true)
|
|
23788
|
+
{
|
|
23789
|
+
designEditorRestoreButtonState = {};
|
|
23790
|
+
}
|
|
23791
|
+
|
|
23792
|
+
Fit.Array.ForEach(designEditor.toolbar, function(toolbarGroup)
|
|
23793
|
+
{
|
|
23794
|
+
var items = toolbarGroup.items;
|
|
23795
|
+
|
|
23796
|
+
Fit.Array.ForEach(toolbarGroup.items, function(item)
|
|
23797
|
+
{
|
|
23798
|
+
if (item.command) // Buttons have a command identifier which can be used to resolve the actual command instance
|
|
23799
|
+
{
|
|
23800
|
+
var cmd = designEditor.getCommand(item.command);
|
|
23801
|
+
|
|
23802
|
+
if (preserveButtonState === true && cmd.state !== CKEDITOR.TRISTATE_DISABLED) // https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_command.html#property-state
|
|
23803
|
+
{
|
|
23804
|
+
designEditorRestoreButtonState[item.command] = true;
|
|
23805
|
+
}
|
|
23806
|
+
|
|
23807
|
+
cmd.disable();
|
|
23808
|
+
}
|
|
23809
|
+
else if (item.setState) // MenuButtons allow for direct manipulation of enabled/disabled state
|
|
23810
|
+
{
|
|
23811
|
+
if (preserveButtonState === true && item.getState() !== CKEDITOR.TRISTATE_DISABLED) // https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_command.html#property-state
|
|
23812
|
+
{
|
|
23813
|
+
designEditorRestoreButtonState[item.name] = item;
|
|
23814
|
+
}
|
|
23815
|
+
|
|
23816
|
+
item.setState(CKEDITOR.TRISTATE_DISABLED);
|
|
23817
|
+
}
|
|
23818
|
+
});
|
|
23819
|
+
});
|
|
23820
|
+
}
|
|
23821
|
+
|
|
23822
|
+
function restoreDesignEditorButtons()
|
|
23823
|
+
{
|
|
23824
|
+
console.log("RESTORING toolbar buttons");
|
|
23825
|
+
|
|
23826
|
+
if (designEditorRestoreButtonState !== null)
|
|
23827
|
+
{
|
|
23828
|
+
Fit.Array.ForEach(designEditorRestoreButtonState, function(commandKey)
|
|
23829
|
+
{
|
|
23830
|
+
if (designEditorRestoreButtonState[commandKey] === true) // Command button
|
|
23831
|
+
{
|
|
23832
|
+
var cmd = designEditor.getCommand(commandKey);
|
|
23833
|
+
cmd.enable();
|
|
23834
|
+
}
|
|
23835
|
+
else // MenuButton
|
|
23836
|
+
{
|
|
23837
|
+
designEditorRestoreButtonState[commandKey].setState(CKEDITOR.TRISTATE_OFF); // Enabled but not highlighted/activated like e.g. a bold button would be when selecting bold text
|
|
23838
|
+
}
|
|
23839
|
+
});
|
|
23840
|
+
|
|
23841
|
+
designEditorRestoreButtonState = null;
|
|
23842
|
+
}
|
|
23843
|
+
};
|
|
23844
|
+
|
|
22936
23845
|
function updateDesignEditorSize()
|
|
22937
23846
|
{
|
|
22938
23847
|
if (designEditor !== null)
|
|
@@ -23004,7 +23913,9 @@ Fit.Controls.Input = function(ctlId)
|
|
|
23004
23913
|
|
|
23005
23914
|
if (newVal !== preVal)
|
|
23006
23915
|
{
|
|
23007
|
-
|
|
23916
|
+
// DISABLED: No longer necessary with the introduction of designEditorDirty which ensures
|
|
23917
|
+
// that we get the initial value set from Value(), unless changed by the user using the editor.
|
|
23918
|
+
/*if (designEditor !== null && htmlWrappedInParagraph === false) // A value not wrapped in paragraph(s) was assigned to HTML editor
|
|
23008
23919
|
{
|
|
23009
23920
|
// Do not trigger OnChange if the only difference is that CKEditor
|
|
23010
23921
|
// wrapped the value initially assigned to control in a paragraph.
|
|
@@ -23020,7 +23931,7 @@ Fit.Controls.Input = function(ctlId)
|
|
|
23020
23931
|
{
|
|
23021
23932
|
return; // Do not fire OnChange
|
|
23022
23933
|
}
|
|
23023
|
-
}
|
|
23934
|
+
}*/
|
|
23024
23935
|
|
|
23025
23936
|
preVal = newVal;
|
|
23026
23937
|
me._internal.FireOnChange();
|
|
@@ -23149,66 +24060,9 @@ Fit._internal.Controls.Input.Editor =
|
|
|
23149
24060
|
/// <member container="Fit._internal.Controls.Input.Editor" name="Skin" access="public" static="true" type="'bootstrapck' | 'moono-lisa' | null">
|
|
23150
24061
|
/// <description> Skin used with DesignMode - must be set before an editor is created and cannot be changed for each individual control </description>
|
|
23151
24062
|
/// </member>
|
|
23152
|
-
Skin: null
|
|
23153
|
-
|
|
23154
|
-
/// <member container="Fit._internal.Controls.Input.Editor" name="Plugins" access="public" static="true" type="('justify' | 'pastefromword' | 'resize' | 'base64image' | 'base64imagepaste' | 'dragresize')[]">
|
|
23155
|
-
/// <description> Additional plugins used with DesignMode </description>
|
|
23156
|
-
/// </member>
|
|
23157
|
-
Plugins: ["justify", "pastefromword", "resize" /*"base64image", "base64imagepaste", "dragresize"*/], // Regarding base64imagepaste and dragresize: IE11 has native support for pasting images as base64 and IE8+ has native support for image resizing, so plugins are not in effect in IE, even when enabled
|
|
23158
|
-
|
|
23159
|
-
/// <member container="Fit._internal.Controls.Input.Editor" name="Toolbar" access="public" static="true" type="( { name: 'BasicFormatting', items: ('Bold' | 'Italic' | 'Underline')[] } | { name: 'Justify', items: ('JustifyLeft' | 'JustifyCenter' | 'JustifyRight')[] } | { name: 'Lists', items: ('NumberedList' | 'BulletedList' | 'Indent' | 'Outdent')[] } | { name: 'Links', items: ('Link' | 'Unlink')[] } | { name: 'Insert', items: ('base64image')[] } )[]">
|
|
23160
|
-
/// <description> Toolbar buttons used with DesignMode - make sure necessary plugins are loaded (see Fit._internal.Controls.Input.EditorPlugins) </description>
|
|
23161
|
-
/// </member>
|
|
23162
|
-
Toolbar:
|
|
23163
|
-
[
|
|
23164
|
-
{
|
|
23165
|
-
name: "BasicFormatting",
|
|
23166
|
-
items: [ "Bold", "Italic", "Underline" ]
|
|
23167
|
-
},
|
|
23168
|
-
{
|
|
23169
|
-
name: "Justify",
|
|
23170
|
-
items: [ "JustifyLeft", "JustifyCenter", "JustifyRight" ]
|
|
23171
|
-
},
|
|
23172
|
-
{
|
|
23173
|
-
name: "Lists",
|
|
23174
|
-
items: [ "NumberedList", "BulletedList", "Indent", "Outdent" ]
|
|
23175
|
-
},
|
|
23176
|
-
{
|
|
23177
|
-
name: "Links",
|
|
23178
|
-
items: [ "Link", "Unlink" ]
|
|
23179
|
-
}/*,
|
|
23180
|
-
{
|
|
23181
|
-
name: "Insert",
|
|
23182
|
-
items: [ "base64image" ]
|
|
23183
|
-
}*/
|
|
23184
|
-
]
|
|
24063
|
+
Skin: null // Notice: CKEditor does not support multiple different skins on the same page - do not change value once an editor has been created
|
|
23185
24064
|
};
|
|
23186
24065
|
|
|
23187
|
-
/// <container name="Fit._internal.Controls.Input.BlobManager">
|
|
23188
|
-
/// Internal settings related to blob storage management in HTML Editor (Design Mode)
|
|
23189
|
-
/// </container>
|
|
23190
|
-
Fit._internal.Controls.Input.BlobManager =
|
|
23191
|
-
{
|
|
23192
|
-
/// <member container="Fit._internal.Controls.Input.BlobManager" name="RevokeBlobUrlsOnDispose" access="public" static="true" type="'All' | 'UnreferencedOnly'">
|
|
23193
|
-
/// <description>
|
|
23194
|
-
/// Dispose images from blob storage (revoke blob URLs) added though image plugins when control is disposed.
|
|
23195
|
-
/// If "UnreferencedOnly" is specified, the component using Fit.UI's input control will be responsible for
|
|
23196
|
-
/// disposing referenced blobs. Failing to do so may cause a memory leak.
|
|
23197
|
-
/// </description>
|
|
23198
|
-
/// </member>
|
|
23199
|
-
RevokeBlobUrlsOnDispose: "All", // "All" | "UnreferencedOnly"
|
|
23200
|
-
|
|
23201
|
-
/// <member container="Fit._internal.Controls.Input.BlobManager" name="RevokeExternalBlobUrlsOnDispose" access="public" static="true" type="boolean">
|
|
23202
|
-
/// <description>
|
|
23203
|
-
/// Dispose images from blob storage (revoke blob URLs) added through Value(..)
|
|
23204
|
-
/// function when control is disposed. Basically ownership of these blobs are handed
|
|
23205
|
-
/// over to the control for the duration of its life time.
|
|
23206
|
-
/// These images are furthermore subject to the rule set in RevokeBlobUrlsOnDispose.
|
|
23207
|
-
/// </description>
|
|
23208
|
-
/// </member>
|
|
23209
|
-
RevokeExternalBlobUrlsOnDispose: false
|
|
23210
|
-
}
|
|
23211
|
-
|
|
23212
24066
|
/// <container name="Fit.Controls.InputResizing">
|
|
23213
24067
|
/// <description> Resizing options </description>
|
|
23214
24068
|
/// <member name="Enabled" access="public" static="true" type="string" default="Enabled"> Allow for resizing both vertically and horizontally </member>
|