Fixes some property editors ensuring ngModelController(#10013)
Co-authored-by: Niels Lyngsø <nsl@umbraco.com>
This commit is contained in:
376
src/Umbraco.Web.UI.Client/package-lock.json
generated
376
src/Umbraco.Web.UI.Client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -129,6 +129,8 @@
|
||||
replace: true,
|
||||
templateUrl: 'views/components/buttons/umb-toggle.html',
|
||||
scope: {
|
||||
// TODO: This should have required ngModel so we can track and validate user input correctly
|
||||
// https://docs.angularjs.org/api/ng/type/ngModel.NgModelController#custom-control-example
|
||||
checked: "=",
|
||||
disabled: "=",
|
||||
inputId: "@",
|
||||
|
||||
@@ -35,6 +35,12 @@
|
||||
|
||||
vm.$onInit = onInit;
|
||||
|
||||
vm.setDirty = function () {
|
||||
// NOTE: We need to use scope because we haven't changd it to vm.propertyForm in the html and that
|
||||
// might mean a breaking change.
|
||||
$scope.propertyForm.$setDirty();
|
||||
}
|
||||
|
||||
vm.setPropertyError = function (errorMsg) {
|
||||
vm.property.propertyErrorMessage = errorMsg;
|
||||
};
|
||||
|
||||
@@ -44,9 +44,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location
|
||||
|
||||
this.isShowingValidation = () => $scope.showValidation === true;
|
||||
|
||||
this.notify = function () {
|
||||
notify($scope);
|
||||
}
|
||||
this.notify = notify;
|
||||
|
||||
this.isValid = function () {
|
||||
return !$scope.formCtrl.$invalid;
|
||||
@@ -112,6 +110,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location
|
||||
});
|
||||
|
||||
//watch the list of validation errors to notify the application of any validation changes
|
||||
// TODO: Wouldn't it be easier/faster to watch formCtrl.$invalid ?
|
||||
scope.$watch(() => angularHelper.countAllFormErrors(formCtrl),
|
||||
function (e) {
|
||||
|
||||
|
||||
@@ -177,8 +177,9 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
|
||||
watcher = scope.$watchCollection(
|
||||
() => formCtrl,
|
||||
function (updatedFormController) {
|
||||
var ngModels = [];
|
||||
collectAllNgModelControllersRecursively(updatedFormController.$getControls(), ngModels);
|
||||
let childControls = updatedFormController.$getControls();
|
||||
let ngModels = [];
|
||||
collectAllNgModelControllersRecursively(childControls, ngModels);
|
||||
ngModels.forEach(x => {
|
||||
if (!x.$validators.serverValidityResetter) {
|
||||
x.$validators.serverValidityResetter = resetServerValidityValidator(x);
|
||||
@@ -201,7 +202,7 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
|
||||
hasError = false;
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
scope.errorMsg = "";
|
||||
|
||||
|
||||
}
|
||||
|
||||
// This deals with client side validation changes and is executed anytime validators change on the containing
|
||||
@@ -264,6 +265,8 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
|
||||
//listen for form validation changes.
|
||||
//The alternative is to add a watch to formCtrl.$invalid but that would lead to many more watches then
|
||||
// subscribing to this single watch.
|
||||
// TODO: Really? Since valFormManager is watching a countof all errors which is more overhead than watching formCtrl.$invalid
|
||||
// and there's a TODO there that it should just watch formCtrl.$invalid
|
||||
valFormManager.onValidationStatusChanged(function (evt, args) {
|
||||
checkValidationStatus();
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function booleanEditorController($scope, angularHelper) {
|
||||
function booleanEditorController($scope) {
|
||||
|
||||
// Setup the default config
|
||||
// This allow to overwrite the configuration when property editor is re-used
|
||||
@@ -36,6 +36,12 @@ function booleanEditorController($scope, angularHelper) {
|
||||
}
|
||||
}
|
||||
|
||||
function setDirty() {
|
||||
if ($scope.modelValueForm) {
|
||||
$scope.modelValueForm.modelValue.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
setupViewModel();
|
||||
|
||||
if ($scope.model && !$scope.model.value) {
|
||||
@@ -51,7 +57,7 @@ function booleanEditorController($scope, angularHelper) {
|
||||
|
||||
// Update the value when the toggle is clicked
|
||||
$scope.toggle = function(){
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
setDirty();
|
||||
if ($scope.renderModel.value){
|
||||
$scope.model.value = $scope.model.config.falsevalue;
|
||||
setupViewModel();
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
<div class="umb-property-editor umb-boolean" ng-controller="Umbraco.PropertyEditors.BooleanController">
|
||||
<umb-toggle
|
||||
input-id="{{model.alias}}"
|
||||
checked="renderModel.value"
|
||||
on-click="toggle()"
|
||||
show-labels="{{model.config.showLabels}}"
|
||||
label-position="right"
|
||||
label-on="{{model.config.labelOn}}"
|
||||
label-off="{{model.config.labelOff}}">
|
||||
</umb-toggle>
|
||||
|
||||
<ng-form name="modelValueForm">
|
||||
|
||||
<umb-toggle input-id="{{model.alias}}"
|
||||
checked="renderModel.value"
|
||||
on-click="toggle()"
|
||||
show-labels="{{model.config.showLabels}}"
|
||||
label-position="right"
|
||||
label-on="{{model.config.labelOn}}"
|
||||
label-off="{{model.config.labelOff}}">
|
||||
</umb-toggle>
|
||||
|
||||
<input type="hidden" name="modelValue" ng-model="renderModel.value" />
|
||||
</ng-form>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -63,7 +63,7 @@ function ColorPickerController($scope, $timeout) {
|
||||
// this is required to re-validate
|
||||
$timeout(function () {
|
||||
var newColor = color ? color.value : null;
|
||||
$scope.propertyForm.selectedColor.$setViewValue(newColor);
|
||||
vm.modelValueForm.selectedColor.$setViewValue(newColor);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.ColorPickerController as vm">
|
||||
|
||||
<div ng-if="!isConfigured">
|
||||
<localize key="colorpicker_noColors">You haven't defined any colors</localize>
|
||||
</div>
|
||||
<ng-form name="vm.modelValueForm">
|
||||
<div ng-if="!isConfigured">
|
||||
<localize key="colorpicker_noColors">You haven't defined any colors</localize>
|
||||
</div>
|
||||
|
||||
<umb-color-swatches
|
||||
colors="model.config.items"
|
||||
selected-color="model.value"
|
||||
size="m"
|
||||
use-label="model.useLabel"
|
||||
on-select="vm.selectColor(color)">
|
||||
</umb-color-swatches>
|
||||
<umb-color-swatches colors="model.config.items"
|
||||
selected-color="model.value"
|
||||
size="m"
|
||||
use-label="model.useLabel"
|
||||
on-select="vm.selectColor(color)">
|
||||
</umb-color-swatches>
|
||||
|
||||
<input type="hidden" name="selectedColor" ng-model="model.selectedColor" val-property-validator="validateMandatory" />
|
||||
|
||||
<input type="hidden" name="selectedColor" ng-model="model.selectedColor" val-property-validator="validateMandatory" />
|
||||
</ng-form>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
return x.value === item.value && x.label === item.label;
|
||||
});
|
||||
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
setDirty();
|
||||
}
|
||||
|
||||
function add(evt) {
|
||||
@@ -130,7 +130,7 @@
|
||||
$scope.newLabel = "";
|
||||
$scope.hasError = false;
|
||||
$scope.focusOnNew = true;
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
setDirty();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -156,6 +156,12 @@
|
||||
$scope.newLabel = defaultLabel;
|
||||
}
|
||||
|
||||
function setDirty() {
|
||||
if (vm.modelValueForm) {
|
||||
vm.modelValueForm.selectedColor.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.sortableOptions = {
|
||||
axis: 'y',
|
||||
containment: 'parent',
|
||||
@@ -164,7 +170,7 @@
|
||||
items: '> div.control-group',
|
||||
tolerance: 'pointer',
|
||||
update: function (e, ui) {
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* @param {any} editorService
|
||||
* @param {any} userService
|
||||
*/
|
||||
function contentPickerController($scope, $q, $routeParams, $location, entityResource, editorState, iconHelper, angularHelper, navigationService, localizationService, editorService, userService, overlayService) {
|
||||
function contentPickerController($scope, $q, $routeParams, $location, entityResource, editorState, iconHelper, navigationService, localizationService, editorService, userService, overlayService) {
|
||||
|
||||
var vm = {
|
||||
labels: {
|
||||
@@ -112,7 +112,7 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
|
||||
scroll: true,
|
||||
zIndex: 6000,
|
||||
update: function (e, ui) {
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -180,7 +180,7 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
|
||||
$scope.clear();
|
||||
$scope.add(data);
|
||||
}
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
setDirty();
|
||||
},
|
||||
treeAlias: $scope.model.config.startNode.type,
|
||||
section: $scope.model.config.startNode.type,
|
||||
@@ -257,9 +257,9 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
|
||||
_.each(model.selection, function (item, i) {
|
||||
$scope.add(item);
|
||||
});
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
setDirty();
|
||||
}
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
setDirty();
|
||||
editorService.close();
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
|
||||
var currIds = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
if (currIds.length > 0) {
|
||||
currIds.splice(index, 1);
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
setDirty();
|
||||
$scope.model.value = currIds.join();
|
||||
}
|
||||
|
||||
@@ -375,6 +375,12 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
|
||||
}
|
||||
});
|
||||
|
||||
function setDirty() {
|
||||
if ($scope.contentPickerForm && $scope.contentPickerForm.modelValue) {
|
||||
$scope.contentPickerForm.modelValue.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/** Syncs the renderModel based on the actual model.value and returns a promise */
|
||||
function syncRenderModel(doValidation) {
|
||||
|
||||
|
||||
@@ -19,14 +19,12 @@
|
||||
</umb-node-preview>
|
||||
</div>
|
||||
|
||||
<button
|
||||
ng-show="model.config.multiPicker === true && renderModel.length < model.config.maxNumber || renderModel.length === 0 || !model.config.maxNumber"
|
||||
type="button"
|
||||
class="umb-node-preview-add"
|
||||
ng-click="openCurrentPicker()"
|
||||
id="{{model.alias}}"
|
||||
aria-label="{{model.label}}: {{labels.general_add}}"
|
||||
>
|
||||
<button ng-show="model.config.multiPicker === true && renderModel.length < model.config.maxNumber || renderModel.length === 0 || !model.config.maxNumber"
|
||||
type="button"
|
||||
class="umb-node-preview-add"
|
||||
ng-click="openCurrentPicker()"
|
||||
id="{{model.alias}}"
|
||||
aria-label="{{model.label}}: {{labels.general_add}}">
|
||||
<localize key="general_add">Add</localize>
|
||||
<span class="sr-only">...</span>
|
||||
</button>
|
||||
@@ -64,16 +62,18 @@
|
||||
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="modelValue" ng-model="model.value" />
|
||||
|
||||
<!--These are here because we need ng-form fields to validate against-->
|
||||
<input type="hidden" name="minCount" ng-model="renderModel" />
|
||||
<input type="hidden" name="maxCount" ng-model="renderModel" />
|
||||
|
||||
<div ng-messages="contentPickerForm.minCount.$error" show-validation-on-submit >
|
||||
<div ng-messages="contentPickerForm.minCount.$error" show-validation-on-submit>
|
||||
<div class="help-inline" ng-message="minCount">
|
||||
<localize key="validation_minCount">You need to add at least</localize> {{model.config.minNumber}} <localize key="validation_items">items</localize>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-messages="contentPickerForm.maxCount.$error" show-validation-on-submit >
|
||||
<div ng-messages="contentPickerForm.maxCount.$error" show-validation-on-submit>
|
||||
<div class="help-inline" ng-message="maxCount">
|
||||
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected">items selected</localize>
|
||||
</div>
|
||||
|
||||
@@ -161,7 +161,14 @@ function dateTimePickerController($scope, angularHelper, dateHelper, validationM
|
||||
else {
|
||||
$scope.model.value = null;
|
||||
}
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
|
||||
setDirty();
|
||||
}
|
||||
|
||||
function setDirty() {
|
||||
if ($scope.datePickerForm) {
|
||||
$scope.datePickerForm.datepicker.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the value of the date picker control adn associated viewModel objects based on the model value */
|
||||
|
||||
@@ -31,7 +31,7 @@ angular.module('umbraco')
|
||||
};
|
||||
|
||||
//set form to dirty to track changes
|
||||
$scope.imageCropperForm.$setDirty();
|
||||
setDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,7 +67,13 @@ angular.module('umbraco')
|
||||
function onFileSelected(value, files) {
|
||||
setModelValueWithSrc(value);
|
||||
//set form to dirty to track changes
|
||||
$scope.imageCropperForm.$setDirty();
|
||||
setDirty();
|
||||
}
|
||||
|
||||
function setDirty() {
|
||||
if ($scope.imageCropperForm) {
|
||||
$scope.imageCropperForm.modelValue.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
function imageLoaded(isCroppable, hasDimensions) {
|
||||
@@ -84,7 +90,7 @@ angular.module('umbraco')
|
||||
if (files && files[0]) {
|
||||
$scope.imageSrc = files[0].fileSrc;
|
||||
//set form to dirty to track changes
|
||||
$scope.imageCropperForm.$setDirty();
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +144,7 @@ angular.module('umbraco')
|
||||
$scope.currentPoint = null;
|
||||
|
||||
//set form to dirty to track changes
|
||||
$scope.imageCropperForm.$setDirty();
|
||||
setDirty();
|
||||
}
|
||||
else {
|
||||
// we have a crop open already - close the crop (this will discard any changes made)
|
||||
@@ -168,7 +174,7 @@ angular.module('umbraco')
|
||||
$scope.close();
|
||||
|
||||
//set form to dirty to track changes
|
||||
$scope.imageCropperForm.$setDirty();
|
||||
setDirty();
|
||||
};
|
||||
|
||||
function reset() {
|
||||
@@ -201,7 +207,7 @@ angular.module('umbraco')
|
||||
}
|
||||
|
||||
//set form to dirty to track changes
|
||||
$scope.imageCropperForm.$setDirty();
|
||||
setDirty();
|
||||
};
|
||||
|
||||
function isCustomCrop(crop) {
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
ng-controller="Umbraco.PropertyEditors.ImageCropperController">
|
||||
|
||||
<ng-form name="imageCropperForm">
|
||||
|
||||
<input type="hidden" name="modelValue" ng-model="model.value" />
|
||||
|
||||
<umb-property-file-upload culture="{{model.culture}}"
|
||||
segment="{{model.segment}}"
|
||||
property-alias="{{model.alias}}"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//inject umbracos assetsServce and dialog service
|
||||
function MarkdownEditorController($scope, $element, assetsService, editorService, angularHelper, $timeout) {
|
||||
function MarkdownEditorController($scope, $element, assetsService, editorService, $timeout) {
|
||||
|
||||
//tell the assets service to load the markdown.editor libs from the markdown editors
|
||||
//plugin folder
|
||||
@@ -41,6 +41,12 @@ function MarkdownEditorController($scope, $element, assetsService, editorService
|
||||
editorService.linkPicker(linkPicker);
|
||||
}
|
||||
|
||||
function setDirty() {
|
||||
if ($scope.modelValueForm) {
|
||||
$scope.modelValueForm.modelValue.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
assetsService
|
||||
.load([
|
||||
"lib/markdown/markdown.converter.js",
|
||||
@@ -78,7 +84,7 @@ function MarkdownEditorController($scope, $element, assetsService, editorService
|
||||
if ($scope.model.value !== $("textarea", $element).val()) {
|
||||
if ($scope.markdownEditorInitComplete) {
|
||||
//only set dirty after init load to avoid "unsaved" dialogue when we don't want it
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
setDirty();
|
||||
} else {
|
||||
$scope.markdownEditorInitComplete = true;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<div class="wmd-panel" ng-controller="Umbraco.PropertyEditors.MarkdownEditorController">
|
||||
<div id="wmd-button-bar-{{editorId}}"></div>
|
||||
|
||||
<textarea class="wmd-input" id="wmd-input-{{editorId}}" ng-model="model.value" ng-required="model.validation.mandatory"></textarea>
|
||||
<ng-form name="modelValueForm">
|
||||
<div id="wmd-button-bar-{{editorId}}"></div>
|
||||
|
||||
<div class="wmd-panel wmd-preview" id="wmd-preview-{{editorId}}" ng-show="model.config.preview"></div>
|
||||
<textarea name="modelValue" class="wmd-input" id="wmd-input-{{editorId}}" ng-model="model.value" ng-required="model.validation.mandatory"></textarea>
|
||||
|
||||
<div class="wmd-panel wmd-preview" id="wmd-preview-{{editorId}}" ng-show="model.config.preview"></div>
|
||||
</ng-form>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//this controller simply tells the dialogs service to open a mediaPicker window
|
||||
//with a specified callback, this callback will receive an object with a selection on it
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerController",
|
||||
function ($scope, entityResource, mediaHelper, $timeout, userService, localizationService, editorService, angularHelper, overlayService) {
|
||||
function ($scope, entityResource, mediaHelper, $timeout, userService, localizationService, editorService, overlayService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -13,6 +13,9 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
vm.editItem = editItem;
|
||||
vm.showAdd = showAdd;
|
||||
|
||||
vm.mediaItems = [];
|
||||
let selectedIds = [];
|
||||
|
||||
//check the pre-values for multi-picker
|
||||
var multiPicker = $scope.model.config.multiPicker && $scope.model.config.multiPicker !== '0' ? true : false;
|
||||
var onlyImages = $scope.model.config.onlyImages && $scope.model.config.onlyImages !== '0' ? true : false;
|
||||
@@ -22,9 +25,6 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
$scope.allowAddMedia = false;
|
||||
|
||||
function setupViewModel() {
|
||||
$scope.mediaItems = [];
|
||||
$scope.ids = [];
|
||||
|
||||
$scope.isMultiPicker = multiPicker;
|
||||
|
||||
if ($scope.model.value) {
|
||||
@@ -77,12 +77,12 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
media.thumbnail = mediaHelper.resolveFileFromEntity(media, true);
|
||||
}
|
||||
|
||||
$scope.mediaItems.push(media);
|
||||
vm.mediaItems.push(media);
|
||||
|
||||
if ($scope.model.config.idType === "udi") {
|
||||
$scope.ids.push(media.udi);
|
||||
selectedIds.push(media.udi);
|
||||
} else {
|
||||
$scope.ids.push(media.id);
|
||||
selectedIds.push(media.id);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -92,12 +92,14 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
}
|
||||
|
||||
function sync() {
|
||||
$scope.model.value = $scope.ids.join();
|
||||
removeAllEntriesAction.isDisabled = $scope.ids.length === 0;
|
||||
$scope.model.value = selectedIds.join();
|
||||
removeAllEntriesAction.isDisabled = selectedIds.length === 0;
|
||||
}
|
||||
|
||||
function setDirty() {
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
if (vm.modelValueForm) {
|
||||
vm.modelValueForm.modelValue.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
function reloadUpdatedMediaItems(updatedMediaNodes) {
|
||||
@@ -105,7 +107,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
// reload. We only reload the images that is already picked but has been updated.
|
||||
// We have to get the entities from the server because the media
|
||||
// can be edited without being selected
|
||||
$scope.mediaItems.forEach(media => {
|
||||
vm.mediaItems.forEach(media => {
|
||||
if (updatedMediaNodes.indexOf(media.udi) !== -1) {
|
||||
media.loading = true;
|
||||
entityResource.getById(media.udi, "Media")
|
||||
@@ -155,8 +157,8 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
}
|
||||
|
||||
function remove(index) {
|
||||
$scope.mediaItems.splice(index, 1);
|
||||
$scope.ids.splice(index, 1);
|
||||
vm.mediaItems.splice(index, 1);
|
||||
selectedIds.splice(index, 1);
|
||||
sync();
|
||||
setDirty();
|
||||
}
|
||||
@@ -174,7 +176,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
.then(function (mediaEntity) {
|
||||
// if an image is selecting more than once
|
||||
// we need to update all the media items
|
||||
$scope.mediaItems.forEach(media => {
|
||||
vm.mediaItems.forEach(media => {
|
||||
if (media.id === model.mediaNode.id) {
|
||||
angular.extend(media, mediaEntity);
|
||||
media.thumbnail = mediaHelper.resolveFileFromEntity(media, true);
|
||||
@@ -208,13 +210,13 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
media.thumbnail = mediaHelper.resolveFileFromEntity(media, true);
|
||||
}
|
||||
|
||||
$scope.mediaItems.push(media);
|
||||
vm.mediaItems.push(media);
|
||||
|
||||
if ($scope.model.config.idType === "udi") {
|
||||
$scope.ids.push(media.udi);
|
||||
selectedIds.push(media.udi);
|
||||
}
|
||||
else {
|
||||
$scope.ids.push(media.id);
|
||||
selectedIds.push(media.id);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -250,8 +252,8 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
overlayService.close();
|
||||
},
|
||||
submit: function () {
|
||||
$scope.mediaItems.length = 0;// AngularJS way to empty the array.
|
||||
$scope.ids.length = 0;// AngularJS way to empty the array.
|
||||
vm.mediaItems.length = 0;// AngularJS way to empty the array.
|
||||
selectedIds.length = 0;// AngularJS way to empty the array.
|
||||
sync();
|
||||
setDirty();
|
||||
overlayService.close();
|
||||
@@ -291,7 +293,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
// TODO: Instead of doing this with a timeout would be better to use a watch like we do in the
|
||||
// content picker. Then we don't have to worry about setting ids, render models, models, we just set one and let the
|
||||
// watch do all the rest.
|
||||
$scope.ids = $scope.mediaItems.map(media => $scope.model.config.idType === "udi" ? media.udi : media.id);
|
||||
selectedIds = vm.mediaItems.map(media => $scope.model.config.idType === "udi" ? media.udi : media.id);
|
||||
|
||||
sync();
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<div class="umb-property-editor umb-mediapicker" ng-class="{'umb-mediapicker-multi':isMultiPicker, 'umb-mediapicker-single':!isMultiPicker}" ng-controller="Umbraco.PropertyEditors.MediaPickerController as vm">
|
||||
|
||||
<p ng-if="(mediaItems|filter:{trashed:true}).length == 1"><localize key="mediaPicker_pickedTrashedItem"></localize></p>
|
||||
<p ng-if="(mediaItems|filter:{trashed:true}).length > 1"><localize key="mediaPicker_pickedTrashedItems"></localize></p>
|
||||
<p ng-if="(vm.mediaItems|filter:{trashed:true}).length == 1"><localize key="mediaPicker_pickedTrashedItem"></localize></p>
|
||||
<p ng-if="(vm.mediaItems|filter:{trashed:true}).length > 1"><localize key="mediaPicker_pickedTrashedItems"></localize></p>
|
||||
|
||||
<div data-element="sortable-thumbnails" class="umb-sortable-thumbnails-container error">
|
||||
<ul ui-sortable="sortableOptions" ng-model="mediaItems" class="umb-sortable-thumbnails">
|
||||
<li data-element="sortable-thumbnail-{{$index}}" class="umb-sortable-thumbnails__wrapper" ng-repeat="media in mediaItems track by $index">
|
||||
<ul ui-sortable="sortableOptions" ng-model="vm.mediaItems" class="umb-sortable-thumbnails">
|
||||
<li data-element="sortable-thumbnail-{{$index}}" class="umb-sortable-thumbnails__wrapper" ng-repeat="media in vm.mediaItems track by $index">
|
||||
|
||||
<p class="label label__trashed" ng-if="media.trashed">
|
||||
<localize key="mediaPicker_trashed"></localize>
|
||||
@@ -46,13 +46,15 @@
|
||||
</div>
|
||||
</li>
|
||||
<li style="border: none;" class="add-wrapper unsortable" ng-if="vm.showAdd() && allowAddMedia">
|
||||
<button type="button" aria-label="Open media picker" data-element="sortable-thumbnails-add" class="add-link btn-reset umb-outline umb-outline--surrounding" ng-click="vm.add()" ng-class="{'add-link-square': (mediaItems.length === 0 || isMultiPicker)}">
|
||||
<button type="button" aria-label="Open media picker" data-element="sortable-thumbnails-add" class="add-link btn-reset umb-outline umb-outline--surrounding" ng-click="vm.add()" ng-class="{'add-link-square': (vm.mediaItems.length === 0 || isMultiPicker)}">
|
||||
<i class="icon icon-add large" aria-hidden="true"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="mandatory" ng-model="model.mandatory" ng-required="model.validation.mandatory && !mediaItems.length" />
|
||||
<ng-form name="vm.modelValueForm">
|
||||
<input type="hidden" name="modelValue" ng-model="vm.mediaItems.length" ng-required="model.validation.mandatory && !vm.mediaItems.length" />
|
||||
</ng-form>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,12 @@ function memberGroupPicker($scope, editorService, memberGroupResource){
|
||||
});
|
||||
}
|
||||
|
||||
function setDirty() {
|
||||
if ($scope.modelValueForm) {
|
||||
$scope.modelValueForm.modelValue.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.openMemberGroupPicker = function() {
|
||||
var memberGroupPicker = {
|
||||
multiPicker: true,
|
||||
@@ -32,6 +38,7 @@ function memberGroupPicker($scope, editorService, memberGroupResource){
|
||||
if (newGroupIds && newGroupIds.length) {
|
||||
memberGroupResource.getByIds(newGroupIds).then(function (groups) {
|
||||
$scope.renderModel = _.union($scope.renderModel, groups);
|
||||
setDirty();
|
||||
editorService.close();
|
||||
});
|
||||
}
|
||||
@@ -47,10 +54,13 @@ function memberGroupPicker($scope, editorService, memberGroupResource){
|
||||
editorService.memberGroupPicker(memberGroupPicker);
|
||||
};
|
||||
|
||||
$scope.remove =function(index){
|
||||
// TODO: I don't believe this is used
|
||||
$scope.remove = function(index){
|
||||
$scope.renderModel.splice(index, 1);
|
||||
setDirty();
|
||||
};
|
||||
|
||||
// TODO: I don't believe this is used
|
||||
$scope.add = function (item) {
|
||||
var currIds = _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
@@ -58,11 +68,14 @@ function memberGroupPicker($scope, editorService, memberGroupResource){
|
||||
|
||||
if (currIds.indexOf(item) < 0) {
|
||||
$scope.renderModel.push({ name: item, id: item, icon: 'icon-users' });
|
||||
setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: I don't believe this is used
|
||||
$scope.clear = function() {
|
||||
$scope.renderModel = [];
|
||||
setDirty();
|
||||
};
|
||||
|
||||
function renderModelIds() {
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.MemberGroupPickerController" class="umb-property-editor umb-membergrouppicker">
|
||||
|
||||
<div ng-model="renderModel">
|
||||
<umb-node-preview
|
||||
ng-repeat="node in renderModel | orderBy:'name'"
|
||||
icon="node.icon"
|
||||
name="node.name"
|
||||
allow-remove="allowRemove"
|
||||
on-remove="remove($index)">
|
||||
<umb-node-preview ng-repeat="node in renderModel | orderBy:'name'"
|
||||
icon="node.icon"
|
||||
name="node.name"
|
||||
allow-remove="allowRemove"
|
||||
on-remove="remove($index)">
|
||||
</umb-node-preview>
|
||||
</div>
|
||||
|
||||
<button type="button"
|
||||
class="umb-node-preview-add"
|
||||
ng-click="openMemberGroupPicker()">
|
||||
class="umb-node-preview-add"
|
||||
ng-click="openMemberGroupPicker()">
|
||||
<localize key="general_add">Add</localize>
|
||||
</button>
|
||||
|
||||
<input type="hidden" name="mandatory" ng-model="model.mandatory" ng-required="model.validation.mandatory && !renderModel.length" />
|
||||
<ng-form name="modelValueForm">
|
||||
<input type="hidden" name="modelValue" ng-model="renderModel.length" ng-required="model.validation.mandatory && !renderModel.length" />
|
||||
</ng-form>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
return selected;
|
||||
};
|
||||
|
||||
function setDirty() {
|
||||
if ($scope.modelValueForm) {
|
||||
$scope.modelValueForm.modelValue.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.pickGroup = function() {
|
||||
editorService.memberGroupPicker({
|
||||
multiPicker: true,
|
||||
@@ -24,6 +30,7 @@
|
||||
$scope.model.value[group.name] = true;
|
||||
});
|
||||
});
|
||||
setDirty();
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
@@ -34,6 +41,7 @@
|
||||
|
||||
$scope.removeGroup = function (group) {
|
||||
$scope.model.value[group] = false;
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.MemberGroupController", memberGroupController);
|
||||
|
||||
@@ -12,4 +12,9 @@
|
||||
ng-click="pickGroup()">
|
||||
<localize key="general_add">Add</localize>
|
||||
</button>
|
||||
|
||||
<ng-form name="modelValueForm">
|
||||
<input type="hidden" name="modelValue" ng-model="model.value" />
|
||||
</ng-form>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//this controller simply tells the dialogs service to open a memberPicker window
|
||||
//with a specified callback, this callback will receive an object with a selection on it
|
||||
function memberPickerController($scope, entityResource, iconHelper, angularHelper, editorService){
|
||||
function memberPickerController($scope, entityResource, iconHelper, editorService){
|
||||
|
||||
function trim(str, chr) {
|
||||
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
|
||||
@@ -27,11 +27,16 @@ function memberPickerController($scope, entityResource, iconHelper, angularHelpe
|
||||
} else {
|
||||
$scope.clear();
|
||||
$scope.add(data);
|
||||
}
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function setDirty() {
|
||||
if ($scope.modelValueForm) {
|
||||
$scope.modelValueForm.modelValue.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
//since most of the pre-value config's are used in the dialog options (i.e. maxNumber, minNumber, etc...) we'll merge the
|
||||
// pre-value config on to the dialog options
|
||||
if ($scope.model.config) {
|
||||
@@ -60,6 +65,7 @@ function memberPickerController($scope, entityResource, iconHelper, angularHelpe
|
||||
|
||||
$scope.remove = function (index) {
|
||||
$scope.renderModel.splice(index, 1);
|
||||
setDirty();
|
||||
};
|
||||
|
||||
$scope.add = function (item) {
|
||||
@@ -76,7 +82,8 @@ function memberPickerController($scope, entityResource, iconHelper, angularHelpe
|
||||
|
||||
if (currIds.indexOf(itemId) < 0) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, udi: item.udi, icon: item.icon});
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, udi: item.udi, icon: item.icon });
|
||||
setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.MemberPickerController" class="umb-property-editor umb-memberpicker">
|
||||
|
||||
<div>
|
||||
<umb-node-preview
|
||||
ng-repeat="node in renderModel"
|
||||
icon="node.icon"
|
||||
name="node.name"
|
||||
allow-remove="allowRemove"
|
||||
on-remove="remove($index)">
|
||||
<umb-node-preview ng-repeat="node in renderModel"
|
||||
icon="node.icon"
|
||||
name="node.name"
|
||||
allow-remove="allowRemove"
|
||||
on-remove="remove($index)">
|
||||
</umb-node-preview>
|
||||
</div>
|
||||
|
||||
<button type="button"
|
||||
class="umb-node-preview-add"
|
||||
ng-show="model.config.multiPicker === true || renderModel.length === 0"
|
||||
ng-click="openMemberPicker()">
|
||||
class="umb-node-preview-add"
|
||||
ng-show="model.config.multiPicker === true || renderModel.length === 0"
|
||||
ng-click="openMemberPicker()">
|
||||
<localize key="general_add">Add</localize>
|
||||
</button>
|
||||
|
||||
<input type="hidden" name="mandatory" ng-model="model.mandatory" ng-required="model.validation.mandatory && !renderModel.length" />
|
||||
<ng-form name="modelValueForm">
|
||||
<input type="hidden" name="modelValue" ng-model="renderModel.length" ng-required="model.validation.mandatory && !renderModel.length" />
|
||||
</ng-form>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function multiUrlPickerController($scope, angularHelper, localizationService, entityResource, iconHelper, editorService) {
|
||||
function multiUrlPickerController($scope, localizationService, entityResource, iconHelper, editorService) {
|
||||
|
||||
var vm = {
|
||||
labels: {
|
||||
@@ -16,8 +16,6 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
|
||||
$scope.model.value = [];
|
||||
}
|
||||
|
||||
var currentForm = angularHelper.getCurrentForm($scope);
|
||||
|
||||
$scope.sortableOptions = {
|
||||
axis: "y",
|
||||
containment: "parent",
|
||||
@@ -27,7 +25,7 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
|
||||
scroll: true,
|
||||
zIndex: 6000,
|
||||
update: function () {
|
||||
currentForm.$setDirty();
|
||||
setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -66,7 +64,7 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
|
||||
$scope.remove = function ($index) {
|
||||
$scope.renderModel.splice($index, 1);
|
||||
|
||||
currentForm.$setDirty();
|
||||
setDirty();
|
||||
};
|
||||
|
||||
$scope.openLinkPicker = function (link, $index) {
|
||||
@@ -122,7 +120,7 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
|
||||
link.published = true;
|
||||
}
|
||||
|
||||
currentForm.$setDirty();
|
||||
setDirty();
|
||||
}
|
||||
editorService.close();
|
||||
},
|
||||
@@ -133,6 +131,12 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
|
||||
editorService.linkPicker(linkPicker);
|
||||
};
|
||||
|
||||
function setDirty() {
|
||||
if ($scope.multiUrlPickerForm) {
|
||||
$scope.multiUrlPickerForm.modelValue.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
localizationService.localizeMany(["general_recycleBin"])
|
||||
.then(function (data) {
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
</div>
|
||||
|
||||
<button ng-show="!model.config.maxNumber || renderModel.length < model.config.maxNumber"
|
||||
type="button"
|
||||
class="umb-node-preview-add"
|
||||
ng-click="openLinkPicker()">
|
||||
type="button"
|
||||
class="umb-node-preview-add"
|
||||
ng-click="openLinkPicker()">
|
||||
<span class="sr-only">{{ model.label }}:</span>
|
||||
<localize key="general_add">Add</localize>
|
||||
<span class="sr-only">url</span>
|
||||
@@ -60,6 +60,8 @@
|
||||
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="modelValue" ng-model="renderModel.length" />
|
||||
|
||||
<!--These are here because we need ng-form fields to validate against-->
|
||||
<input type="hidden" name="minCount" ng-model="renderModel" />
|
||||
<input type="hidden" name="maxCount" ng-model="renderModel" />
|
||||
|
||||
@@ -169,11 +169,14 @@
|
||||
method: removeAllEntries,
|
||||
isDisabled: true
|
||||
};
|
||||
|
||||
// helper to force the current form into the dirty state
|
||||
function setDirty() {
|
||||
if ($scope.$parent.$parent.propertyForm) {
|
||||
$scope.$parent.$parent.propertyForm.$setDirty();
|
||||
|
||||
if (vm.umbProperty) {
|
||||
vm.umbProperty.setDirty();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function addNode(alias) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function sliderController($scope, angularHelper) {
|
||||
function sliderController($scope) {
|
||||
|
||||
let sliderRef = null;
|
||||
|
||||
@@ -14,7 +14,13 @@
|
||||
|
||||
function setModelValue(values) {
|
||||
$scope.model.value = values ? values.toString() : null;
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
setDirty();
|
||||
}
|
||||
|
||||
function setDirty() {
|
||||
if ($scope.modelValueForm) {
|
||||
$scope.modelValueForm.modelValue.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.setup = function(slider) {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<div class="umb-property-editor umb-slider" ng-controller="Umbraco.PropertyEditors.SliderController">
|
||||
|
||||
<div style="padding-top: 50px; padding-bottom: 40px;">
|
||||
<umb-range-slider
|
||||
ng-model="sliderValue"
|
||||
options="sliderOptions"
|
||||
on-setup="setup(slider)"
|
||||
on-change="change(values)">
|
||||
</umb-range-slider>
|
||||
</div>
|
||||
<ng-form name="modelValueForm">
|
||||
<div style="padding-top: 50px; padding-bottom: 40px;">
|
||||
<umb-range-slider ng-model="sliderValue"
|
||||
options="sliderOptions"
|
||||
on-setup="setup(slider)"
|
||||
on-change="change(values)">
|
||||
</umb-range-slider>
|
||||
</div>
|
||||
<input type="hidden" name="modelValue" ng-model="model.value" />
|
||||
</ng-form>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,12 @@ function userPickerController($scope, iconHelper, editorService, overlayService,
|
||||
|
||||
var multiPicker = $scope.model.config.multiPicker && $scope.model.config.multiPicker !== '0' ? true : false;
|
||||
|
||||
function setDirty() {
|
||||
if ($scope.modelValueForm) {
|
||||
$scope.modelValueForm.modelValue.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.openUserPicker = function () {
|
||||
|
||||
var currentSelection = [];
|
||||
@@ -42,7 +48,7 @@ function userPickerController($scope, iconHelper, editorService, overlayService,
|
||||
submit: function () {
|
||||
$scope.renderModel.splice(index, 1);
|
||||
$scope.userName = '';
|
||||
|
||||
setDirty();
|
||||
overlayService.close();
|
||||
},
|
||||
close: function () {
|
||||
@@ -68,11 +74,13 @@ function userPickerController($scope, iconHelper, editorService, overlayService,
|
||||
if (currIds.indexOf(itemId) < 0) {
|
||||
item.icon = item.icon ? iconHelper.convertFromLegacyIcon(item.icon) : "icon-user";
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, udi: item.udi, icon: item.icon, avatars: item.avatars });
|
||||
setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.clear = function() {
|
||||
$scope.renderModel = [];
|
||||
setDirty();
|
||||
};
|
||||
|
||||
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.UserPickerController" class="umb-property-editor umb-userpicker">
|
||||
|
||||
<div>
|
||||
<umb-user-preview
|
||||
ng-repeat="user in renderModel"
|
||||
name="user.name"
|
||||
avatars="user.avatars"
|
||||
allow-remove="allowRemove"
|
||||
on-remove="remove($index)">
|
||||
<div>
|
||||
<umb-user-preview ng-repeat="user in renderModel"
|
||||
name="user.name"
|
||||
avatars="user.avatars"
|
||||
allow-remove="allowRemove"
|
||||
on-remove="remove($index)">
|
||||
</umb-user-preview>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" ng-show="model.config.multiPicker === true || renderModel.length === 0"
|
||||
class="umb-node-preview-add"
|
||||
ng-click="openUserPicker()">
|
||||
<localize key="general_add">Add</localize>
|
||||
</button>
|
||||
<button type="button" ng-show="model.config.multiPicker === true || renderModel.length === 0"
|
||||
class="umb-node-preview-add"
|
||||
ng-click="openUserPicker()">
|
||||
<localize key="general_add">Add</localize>
|
||||
</button>
|
||||
|
||||
<input type="hidden" name="mandatory" ng-model="model.mandatory" ng-required="model.validation.mandatory && !renderModel.length" />
|
||||
<ng-form name="modelValueForm">
|
||||
<input type="hidden" name="modelValue" ng-model="renderModel.length" ng-required="model.validation.mandatory && !renderModel.length" />
|
||||
</ng-form>
|
||||
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user