diff --git a/src/Opten.Umbraco.Localization.Web.UI/App_Data/Umbraco.sdf b/src/Opten.Umbraco.Localization.Web.UI/App_Data/Umbraco.sdf
index 6db9dfa..8a539f6 100644
Binary files a/src/Opten.Umbraco.Localization.Web.UI/App_Data/Umbraco.sdf and b/src/Opten.Umbraco.Localization.Web.UI/App_Data/Umbraco.sdf differ
diff --git a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/directives/headerLocalizedName.html b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/directives/headerLocalizedName.html
new file mode 100644
index 0000000..3fcbdaa
--- /dev/null
+++ b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/directives/headerLocalizedName.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
{{ name }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/opten.localization.controller.js b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/opten.localization.controller.js
new file mode 100644
index 0000000..6871fe7
--- /dev/null
+++ b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/opten.localization.controller.js
@@ -0,0 +1,258 @@
+; (function () {
+ 'use strict';
+
+ angular.module("umbraco").controller("OPTEN.Backoffice.HeaderLocalizedName.Controller", headerLocalizedNameController);
+
+ headerLocalizedNameController.$inject = ["$scope", "$rootScope", "editorState", "languageResource"];
+
+ function headerLocalizedNameController($scope, $rootScope, editorState, languageResource) {
+ var vm = this,
+ errors = [];
+
+ $scope.model = []; //remove this or change
+ $scope.model.value = null;//remove this or change
+
+ vm.loadings = [];
+
+ vm.checkAvailability = checkAvailability;
+ vm.getIndex = getIndex;
+
+ // We set a scope with the value otherwise we have a "empty" JSON saved.
+ $scope.urls = $scope.model.value || [];
+
+ // Legacy fix if json doesn't contain "name"
+ legacy();
+
+ $scope.states = {
+ isEnabled: false,
+ hasHostnames: false,
+ isPublished: false,
+ hasLanguages: false
+ };
+
+ $scope.$watchCollection("states", function (oldValue, newValue) {
+ // Try enable the localizer (set JSON to $scope.model.value)
+ enable(newValue);
+ });
+
+ $rootScope.$watchCollection("languages", function (oldValue, newValue) {
+ if (newValue && newValue.length && vm.loadings.length < 2) {
+ vm.loadings.push("languages");
+
+ $scope.states.hasLanguages = newValue.length > 0;
+ }
+ });
+
+ activate();
+
+ $scope.$on("formSubmitting", function () {
+ //TODO: If we have a valid state the json get's created but could be "empty"
+ // don't know if this is a problem or we have to check each input if it has a value
+ // and then create the json? => this code here don't work if it's a directive...
+
+ if ($scope.states.isPublished == false || ($scope.states.isEnabled && $scope.states.hasHostnames)) {
+ // Delete all urls if has hostnames!
+ $scope.model.value = null;
+ }
+ else if ($scope.urls && $scope.urls.length) {
+ // Check if we have any localized url
+ // Only set the JSON to the $scope.model.value if we really have something.
+ if (hasAnyLocalized()) {
+ $scope.model.value = $scope.urls;
+ }
+ else {
+ $scope.model.value = null;
+ }
+ }
+ });
+
+
+ // Private functions
+
+ function activate() {
+
+ //TODO: Is there a way to get the hostnames on the node by angular?
+ // so we don't have to pass in the current node id
+
+ var contentId = !editorState.current ? 0 : editorState.current.id;
+
+ //TODO: Only call this when published?
+ languageResource.getState(contentId).then(function (state) {
+ vm.loadings.push("isEnabled");
+ vm.loadings.push("hasHostnames");
+
+ $scope.states.isEnabled = state.isEnabled;
+ $scope.states.hasHostnames = state.hasHostnames;
+ });
+
+ $scope.states.isPublished = editorState.current.published;
+ };
+
+ function enable(state) {
+ // We wait until everything is loaded
+ if (state.isPublished && vm.loadings.length >= 3) {
+
+ // Only set the languages if the states are valid
+ if (state.isEnabled &&
+ state.hasHostnames == false &&
+ state.isPublished &&
+ state.hasLanguages) {
+ setLanguages($rootScope.languages);
+ }
+ else {
+ $scope.model.value = null;
+ }
+ }
+ };
+
+ function setLanguages(languages) {
+ // We have to set the json with the languages if never set
+ // or add the new one's but don't delete the old ones
+ var found = false;
+ for (var i = 0; i < languages.length; i++) {
+ found = false;
+
+ for (var y = 0; y < $scope.urls.length; y++) {
+ if (languages[i].isoCode == $scope.urls[y].isoCode) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ $scope.urls.push({
+ isoCode: languages[i].isoCode,
+ url: '',
+ name: '',
+ hasError: false
+ });
+ }
+ }
+
+ // If the languages are equal we check the availability
+ angular.forEach(languages, function (language, index) {
+ checkAvailability(index);
+ });
+ };
+
+ function getNodeLevel() {
+ if (!editorState.current.path || editorState.current.path == null) return -1;
+ return (editorState.current.path.split(',').length - 1);
+ };
+
+ function getUrlSegment(name, success) {
+ if (!name || name.length == 0) {
+ success("");
+ }
+ else {
+ languageResource.getUrlSegment(name).then(function (segment) {
+ success(JSON.parse(segment)); //TODO: Why JSON.parse() somewhow angular returns string in extra quotes
+ });
+ }
+ };
+
+ function getIndex(isoCode) {
+ for (var i = 0; i < $scope.urls.length; i++) {
+ if ($scope.urls[i].isoCode.toLowerCase() == isoCode.toLowerCase()) {
+ return i;
+ }
+ }
+
+ return -1;
+ };
+
+ function checkAvailability(index) {
+ var name = $scope.urls[index].name;
+
+ errors = [];
+
+ if (name == "" || name.length < 1) {
+
+ // Set the semgent to empty
+ $scope.urls[index].url = "";
+
+ // Hide errors because url is empty...
+ setError(index, false);
+ }
+ else if (name != "" && name.length) {
+
+ // Transform name into segment by Umbraco
+ getUrlSegment(name, function (segment) {
+
+ // Set the semgent
+ $scope.urls[index].url = segment;
+
+ // Then check if the current url has the same segment
+ if (editorState.current.urls && editorState.current.urls.length) {
+ var currentSegment = editorState.current.urls[0].split('/');
+ currentSegment = currentSegment[currentSegment.length - 2];
+
+ setError(index, (segment.toLowerCase() == currentSegment.toLowerCase()));
+ }
+
+ // Then if other in the same node has the same url
+ angular.forEach($scope.urls, function (language, i) {
+ if (index != i && hasError(index) == false) {
+
+ if (setError(index, (language.url.toLowerCase() == $scope.urls[index].url.toLowerCase())) == false) {
+
+ //TODO: This could be slow so maybe load all first and then check it against this?
+ // or if a node in the same level has the same url
+ languageResource.getUrlAvailability(editorState.current.id, segment, getNodeLevel()).then(function (isAvailable) {
+
+ setError(index, (isAvailable.toString().toLowerCase() == "false"));
+ });
+ }
+ }
+ });
+ });
+ }
+
+ function setError(index, hasError) {
+ if (hasError) {
+ errors.push(index);
+ } else {
+ for (var i = 0; i < errors.length; i++) {
+ if (errors[i] == index) errors.splice(i, 1);
+ }
+ }
+
+ $scope.urls[index].hasError = hasError;
+ $scope.urlAliasForm.$setValidity("isValid", !hasError);
+
+ return hasError;
+ };
+
+ function hasError(index) {
+ for (var i = 0; i < errors.length; i++) {
+ if (errors[i] == index) return true;
+ }
+ return false;
+ };
+ };
+
+ function hasAnyLocalized() {
+ var anyLocalized = false;
+ for (var i = 0; i < $scope.urls.length; i++) {
+ if ($scope.urls[i].hasError == false &&
+ $scope.urls[i].url != "") {
+ anyLocalized = true;
+ break;
+ }
+ }
+ return anyLocalized;
+ };
+
+ function legacy() {
+ if ($scope.urls.length) {
+ angular.forEach($scope.urls, function (language, i) {
+ if (!$scope.urls[i].name) {
+ $scope.urls[i].name = $scope.urls[i].url;
+ }
+ });
+ }
+ };
+
+ };
+
+}());
\ No newline at end of file
diff --git a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/opten.localization.directive.js b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/opten.localization.directive.js
index 8e51d97..053485d 100644
--- a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/opten.localization.directive.js
+++ b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/opten.localization.directive.js
@@ -86,4 +86,16 @@
};
};
+ angular.module("umbraco.directives").directive("optenHeaderLocalizedName", optenHeaderLocalizedName);
+
+ function optenHeaderLocalizedName() {
+ return {
+ restrict: "E",
+ replace: true,
+ templateUrl: "/App_Plugins/OPTEN.Localization/directives/headerLocalizedName.html?v=ASSEMBLY_VERSION"
+ };
+ };
+
+
+
}());
\ No newline at end of file
diff --git a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/package.manifest b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/package.manifest
index c735e79..344a2b2 100644
--- a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/package.manifest
+++ b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.Localization/package.manifest
@@ -3,6 +3,7 @@
"~/App_Plugins/OPTEN.Localization/opten.localization.js?v=ASSEMBLY_VERSION",
"~/App_Plugins/OPTEN.Localization/opten.localization.interceptor.js?v=ASSEMBLY_VERSION",
"~/App_Plugins/OPTEN.Localization/opten.localization.resource.js?v=ASSEMBLY_VERSION",
- "~/App_Plugins/OPTEN.Localization/opten.localization.directive.js?v=ASSEMBLY_VERSION"
+ "~/App_Plugins/OPTEN.Localization/opten.localization.directive.js?v=ASSEMBLY_VERSION",
+ "~/App_Plugins/OPTEN.Localization/opten.localization.controller.js?v=ASSEMBLY_VERSION"
]
}
\ No newline at end of file
diff --git a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/opten-generate-url.html b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/opten-generate-url.html
new file mode 100644
index 0000000..70ff218
--- /dev/null
+++ b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/opten-generate-url.html
@@ -0,0 +1,10 @@
+
+ {{ alias }}
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/opten.urlAlias.controller.js b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/opten.urlAlias.controller.js
index f7b59d7..c8d8582 100644
--- a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/opten.urlAlias.controller.js
+++ b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/opten.urlAlias.controller.js
@@ -6,12 +6,10 @@
urlAliasController.$inject = ["$scope", "$rootScope", "editorState", "languageResource"];
function urlAliasController($scope, $rootScope, editorState, languageResource) {
- var vm = this,
- errors = [];
+ var vm = this;
vm.loadings = [];
- vm.checkAvailability = checkAvailability;
vm.getIndex = getIndex;
// We set a scope with the value otherwise we have a "empty" JSON saved.
@@ -27,12 +25,11 @@
hasLanguages: false
};
- $scope.$watchCollection("states", function (oldValue, newValue) {
- // Try enable the localizer (set JSON to $scope.model.value)
+ $scope.$watchCollection("states", function (newValue, oldValue) {
enable(newValue);
});
- $rootScope.$watchCollection("languages", function (oldValue, newValue) {
+ $rootScope.$watchCollection("languages", function (newValue, oldValue) {
if (newValue && newValue.length && vm.loadings.length < 2) {
vm.loadings.push("languages");
@@ -40,6 +37,48 @@
}
});
+ $scope.$watch('urls', function (newValue, oldValue) {
+
+ var errors = [];
+
+ for (var index = 0; index < newValue.length; index++) {
+ var segment = newValue[index].url;
+ newValue[index].hasError = false;
+ validateValidity();
+
+ // check if the current url has the same segment
+ if (editorState.current.urls && editorState.current.urls.length) {
+ var currentSegment = editorState.current.urls[0].split('/');
+ currentSegment = currentSegment[currentSegment.length - 2];
+
+ setError(newValue[index], segment.toLowerCase() === currentSegment.toLowerCase());
+ }
+
+ // Then if other in the same node has the same url
+ angular.forEach(newValue, function (language, i) {
+ if (index != i) {
+ setError(newValue[index], language.url.toLowerCase() === segment.toLowerCase());
+ }
+ });
+
+ (function (index2) {
+ languageResource.getUrlAvailability(editorState.current.id, segment, getNodeLevel())
+ .then(function (isAvailable) {
+ setError(newValue[index2], (isAvailable.toString().toLowerCase() == "false"));
+ });
+ }(index));
+
+
+ function setError(language, hasError) {
+ if (hasError) {
+ language.hasError = true;
+ }
+ validateValidity();
+ };
+ }
+
+ }, true);
+
activate();
$scope.$on("formSubmitting", function () {
@@ -102,6 +141,14 @@
}
};
+ function validateValidity() {
+ var isValid = $scope.urls.filter(function (url) {
+ return url.hasError;
+ }).length === 0;
+
+ $scope.urlAliasForm.$setValidity("isValid", isValid);
+ }
+
function setLanguages(languages) {
// We have to set the json with the languages if never set
// or add the new one's but don't delete the old ones
@@ -126,10 +173,6 @@
}
}
- // If the languages are equal we check the availability
- angular.forEach(languages, function (language, index) {
- checkAvailability(index);
- });
};
function getNodeLevel() {
@@ -137,17 +180,6 @@
return (editorState.current.path.split(',').length - 1);
};
- function getUrlSegment(name, success) {
- if (!name || name.length == 0) {
- success("");
- }
- else {
- languageResource.getUrlSegment(name).then(function (segment) {
- success(JSON.parse(segment)); //TODO: Why JSON.parse() somewhow angular returns string in extra quotes
- });
- }
- };
-
function getIndex(isoCode) {
for (var i = 0; i < $scope.urls.length; i++) {
if ($scope.urls[i].isoCode.toLowerCase() == isoCode.toLowerCase()) {
@@ -158,76 +190,6 @@
return -1;
};
- function checkAvailability(index) {
- var name = $scope.urls[index].name;
-
- errors = [];
-
- if (name == "" || name.length < 1) {
-
- // Set the semgent to empty
- $scope.urls[index].url = "";
-
- // Hide errors because url is empty...
- setError(index, false);
- }
- else if (name != "" && name.length) {
-
- // Transform name into segment by Umbraco
- getUrlSegment(name, function (segment) {
-
- // Set the semgent
- $scope.urls[index].url = segment;
-
- // Then check if the current url has the same segment
- if (editorState.current.urls && editorState.current.urls.length) {
- var currentSegment = editorState.current.urls[0].split('/');
- currentSegment = currentSegment[currentSegment.length - 2];
-
- setError(index, (segment.toLowerCase() == currentSegment.toLowerCase()));
- }
-
- // Then if other in the same node has the same url
- angular.forEach($scope.urls, function (language, i) {
- if (index != i && hasError(index) == false) {
-
- if (setError(index, (language.url.toLowerCase() == $scope.urls[index].url.toLowerCase())) == false) {
-
- //TODO: This could be slow so maybe load all first and then check it against this?
- // or if a node in the same level has the same url
- languageResource.getUrlAvailability(editorState.current.id, segment, getNodeLevel()).then(function (isAvailable) {
-
- setError(index, (isAvailable.toString().toLowerCase() == "false"));
- });
- }
- }
- });
- });
- }
-
- function setError(index, hasError) {
- if (hasError) {
- errors.push(index);
- } else {
- for (var i = 0; i < errors.length; i++) {
- if (errors[i] == index) errors.splice(i, 1);
- }
- }
-
- $scope.urls[index].hasError = hasError;
- $scope.urlAliasForm.$setValidity("isValid", !hasError);
-
- return hasError;
- };
-
- function hasError(index) {
- for (var i = 0; i < errors.length; i++) {
- if (errors[i] == index) return true;
- }
- return false;
- };
- };
-
function hasAnyLocalized() {
var anyLocalized = false;
for (var i = 0; i < $scope.urls.length; i++) {
diff --git a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/opten.urlAlias.directive.js b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/opten.urlAlias.directive.js
new file mode 100644
index 0000000..71d9756
--- /dev/null
+++ b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/opten.urlAlias.directive.js
@@ -0,0 +1,91 @@
+; (function () {
+ 'use strict';
+
+
+ angular.module("umbraco.directives").directive('optenGenerateUrl', optenGenerateUrl);
+
+
+ function optenGenerateUrl($timeout, languageResource) {
+ return {
+ restrict: 'E',
+ templateUrl: '/App_Plugins/OPTEN.UrlAlias/opten-generate-url.html',
+ replace: true,
+ scope: {
+ alias: '=',
+ aliasFrom: '=',
+ enableLock: '=?',
+ serverValidationField: '@'
+ },
+ link: function (scope, element, attrs, ctrl) {
+
+ var eventBindings = [];
+ var bindWatcher = true;
+ var generateAliasTimeout = "";
+ var updateAlias = false;
+
+ scope.locked = true;
+ scope.placeholderText = "Enter alias...";
+
+ function generateAlias(value) {
+
+ if (generateAliasTimeout) {
+ $timeout.cancel(generateAliasTimeout);
+ }
+
+ if (value !== undefined && value !== "" && value !== null) {
+
+ scope.alias = "";
+ scope.placeholderText = "Generating Alias...";
+
+ generateAliasTimeout = $timeout(function () {
+ updateAlias = true;
+ languageResource.getUrlSegment(value).then(function (segment) {
+ if (updateAlias) {
+ scope.alias = JSON.parse(segment); //TODO: Why JSON.parse() somewhow angular returns string in extra quotes
+ }
+
+ });
+ }, 500);
+
+ } else {
+ updateAlias = true;
+ scope.alias = "";
+ scope.placeholderText = "Enter alias...";
+ }
+
+ }
+
+ // if alias gets unlocked - stop watching alias
+ eventBindings.push(scope.$watch('locked', function (newValue, oldValue) {
+ if (newValue === false) {
+ bindWatcher = false;
+ } else {
+ generateAlias(scope.alias);
+ }
+ }));
+
+ // validate custom entered alias
+ eventBindings.push(scope.$watch('alias', function (newValue, oldValue) {
+
+ if (scope.alias === "" && bindWatcher === true || scope.alias === null && bindWatcher === true) {
+ // add watcher
+ eventBindings.push(scope.$watch('aliasFrom', function (newValue, oldValue) {
+ if (bindWatcher) {
+ generateAlias(newValue);
+ }
+ }));
+ }
+ }));
+
+ // clean up
+ scope.$on('$destroy', function () {
+ // unbind watchers
+ for (var e in eventBindings) {
+ eventBindings[e]();
+ }
+ });
+
+ }
+ };
+ }
+}());
\ No newline at end of file
diff --git a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/opten.urlalias.css b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/opten.urlalias.css
new file mode 100644
index 0000000..885c983
--- /dev/null
+++ b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/opten.urlalias.css
@@ -0,0 +1,28 @@
+.url-alias-wrapper {
+ position: relative;
+ display: flex;
+ margin-bottom: 10px;
+}
+
+.url-alias-iso-code {
+ padding-right: 10px;
+ display: block;
+ width: 60px;
+ line-height: 30px;
+ text-align: right;
+ color: #a2a1a6;
+ flex: 1 1 60px;
+}
+
+.url-alias-alias {
+ text-align: right;
+ width: auto;
+ font-size: 13px;
+ color: #a2a1a6;
+ line-height: 30px;
+ display: block;
+}
+
+.url-alias-alias-wrapper {
+ top: 0;
+}
\ No newline at end of file
diff --git a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/package.manifest b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/package.manifest
index c6be474..03f5172 100644
--- a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/package.manifest
+++ b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/package.manifest
@@ -8,6 +8,10 @@
}
}],
"javascript": [
- "~/App_Plugins/OPTEN.UrlAlias/opten.urlAlias.controller.js?v=ASSEMBLY_VERSION"
+ "~/App_Plugins/OPTEN.UrlAlias/opten.urlAlias.controller.js?v=ASSEMBLY_VERSION",
+ "~/App_Plugins/OPTEN.UrlAlias/opten.urlAlias.directive.js?v=ASSEMBLY_VERSION"
+ ],
+ "css": [
+ "~/App_Plugins/OPTEN.UrlAlias/opten.urlalias.css?v=ASSEMBLY_VERSION"
]
}
\ No newline at end of file
diff --git a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/urlAlias.html b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/urlAlias.html
index f6b881c..d55f414 100644
--- a/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/urlAlias.html
+++ b/src/Opten.Umbraco.Localization.Web.UI/App_Plugins/OPTEN.UrlAlias/urlAlias.html
@@ -1,31 +1,23 @@