"use strict"; /** * Created by sun chu on 02/11/2015. */ (function () { 'use strict'; angular.module('adminModule') .controller('KnowledgeStyleConfigController', ['$scope', 'knowledgeArticleModel', 'systemAlertService', '$filter', function ($scope, knowledgeArticleModel, systemAlertService, $filter) { var state = {}, dirtyState = {}, originalTemplate = {}, originalStyle = {}, styleMetadata = { fontSize: [ { label: '8', value: '8px' }, { label: '9', value: '9px' }, { label: '10', value: '10px' }, { label: '11', value: '11px' }, { label: '12', value: '12px' }, { label: '14', value: '14px' }, { label: '16', value: '16px' }, { label: '18', value: '18px' }, { label: '20', value: '20px' }, { label: '22', value: '22px' }, { label: '24', value: '24px' }, { label: '26', value: '26px' }, { label: '28', value: '28px' }, { label: '36', value: '36px' }, { label: '48', value: '48px' }, { label: '72', value: '72px' } ], font: [ { label: 'Times', value: 'times' }, { label: 'Arial', value: 'arial' }, { label: 'Courier', value: 'courier' } ], element: [ 'span', 'div' ] }, standardStyles = [ { type: 'Header 1', element: 'h1', text: '', styles: '', userStyle: false }, { type: 'Header 2', element: 'h2', text: '', styles: '', userStyle: false }, { type: 'Header 3', element: 'h3', text: '', styles: '', userStyle: false }, { type: 'Header 4', element: 'h4', text: '', styles: '', userStyle: false }, { type: 'Header 5', element: 'h5', text: '', styles: '', userStyle: false }, { type: 'Header 6', element: 'h6', text: '', styles: '', userStyle: false }, { type: 'Paragraph', element: 'p', text: '', styles: '', userStyle: false } ]; $scope.selectedTemplate = {}; $scope.selectedStyle = {}; $scope.selected_css = {}; $scope.additional = { style: '' }; $scope.isDirtyState = false; function init() { state = angular.extend(state, { dataIsLoading: false }); $scope.state = state; $scope.styleMetadata = styleMetadata; clearSelected_css(); loadAvailableTemplates(); } function loadAvailableTemplates() { state.dataIsLoading = true; knowledgeArticleModel.getKnowledgeArticleTemplates().then(function (templates) { $scope.templates = angular.copy(templates); _.remove($scope.templates, { name: 'Decision Tree' }); }).finally(function () { state.dataIsLoading = false; }); } $scope.selectTemplate = function (template) { if (template.name === $scope.selectedTemplate.name) { return; } if ($scope.isDirtyState) { showLeaveDialog().then(function (confirmToDiscard) { if (confirmToDiscard) { originalTemplate = template; setSelectedTemplate(template); } }); } else { originalTemplate = template; setSelectedTemplate(template); } }; $scope.selectStyle = function (style) { if (style.isExpanded) { style.isExpanded = false; $scope.selectedStyle = {}; } else { $scope.selectedStyle.isExpanded = false; $scope.selectedStyle = style; style.isExpanded = true; parse_css(style.styles); formulate_css(); // save a copy for dirty check if (!originalStyle[style.type]) { originalStyle[style.type] = { styles: $scope.selectedStyle.styles, element: $scope.selectedStyle.element }; } } }; $scope.deleteStyle = function (index, $event) { $scope.selectedTemplate.templateObject.styles.splice(index, 1); $scope.isDirtyState = true; $event.stopPropagation(); }; $scope.addStyle = function () { var defaultStyle = { type: '', element: 'span', text: '', styles: '', userStyle: true }; $scope.selectedTemplate.templateObject.styles.push(defaultStyle); $scope.selectStyle(defaultStyle); $scope.isDirtyState = true; }; $scope.updateElement = function (element) { $scope.selectedStyle.element = element || ''; dirtyStateCheck(); }; $scope.updateFont = function (font) { $scope.selected_css.fontFamily.label = font ? font.label : ''; $scope.selected_css.fontFamily.value = font ? font.value : ''; formulate_css(); dirtyStateCheck(); }; $scope.updateFontSize = function (fontSize) { $scope.selected_css.fontSize.label = fontSize ? fontSize.label : ''; $scope.selected_css.fontSize.value = fontSize ? fontSize.value : ''; formulate_css(); dirtyStateCheck(); }; $scope.updateFontWeight = function () { $scope.selected_css.fontWeight.value = $scope.selected_css.fontWeight.bold ? 'bold' : ''; formulate_css(); dirtyStateCheck(); }; $scope.updateFontStyle = function () { $scope.selected_css.fontStyle.value = $scope.selected_css.fontStyle.italic ? 'italic' : ''; formulate_css(); dirtyStateCheck(); }; $scope.updateTextDecoration = function () { $scope.selected_css.textDecoration.value = ''; $scope.selected_css.textDecoration.value += $scope.selected_css.textDecoration.underline ? 'underline ' : ''; $scope.selected_css.textDecoration.value += $scope.selected_css.textDecoration.lineThrough ? 'line-through' : ''; $scope.selected_css.textDecoration.value = $scope.selected_css.textDecoration.value.trim(); formulate_css(); dirtyStateCheck(); }; $scope.update_css = function () { formulate_css(); dirtyStateCheck(); }; $scope.saveStyles = function () { // check to make sure style name is unique var unique = true; _.each($scope.selectedTemplate.templateObject.styles, function (style, index) { if (_.find($scope.selectedTemplate.templateObject.styles.slice(index + 1), { type: style.type })) { var msg = $filter('i18n')('config.kaStyle.nameNotUnique.message', style.type); systemAlertService.error({ text: msg, clear: false }); unique = false; } }); if (!unique) { return; } state.dataIsLoading = true; var nonEmptyStyles = $scope.selectedTemplate.templateObject.styles.slice(); var stylesToBackend = []; // if the style is not defined, don't send it to backend _.remove(nonEmptyStyles, { styles: '' }); // remove the isExpanded attribute that was used only by the UI _.each(nonEmptyStyles, function (nonEmptyStyle) { stylesToBackend.push(_.omit(nonEmptyStyle, 'isExpanded')); }); knowledgeArticleModel.updateTemplateStyles($scope.selectedTemplate.name, stylesToBackend) .then(function (data) { if (data && data.styles && data.styles.length) { originalTemplate.templateObject.styles = data.styles; $scope.selectedTemplate.templateObject.styles = _.cloneDeep(data.styles); mergeWithStandardStyle($scope.selectedTemplate); $scope.selectedStyle = {}; resetDirtyState(); } }, function (error) { systemAlertService.error({ text: error.data && error.data.error, clear: false }); }).finally(function () { state.dataIsLoading = false; }); }; $scope.discard = function () { showLeaveDialog().then(function (result) { if (result) { setSelectedTemplate(originalTemplate); } }); }; function parse_css(styleString) { clearSelected_css(); _.each(styleString.split(';'), function (style) { var css = style.split(':'); var foundMatch = false; _.each($scope.selected_css, function (selected_css) { if (css[0].trim() === selected_css.name) { if (selected_css.name === 'text-decoration') { selected_css.value = css[1]; if (css[1].indexOf('underline') > -1) { selected_css.underline = true; } if (css[1].indexOf('line-through') > -1) { selected_css.lineThrough = true; } } else if (selected_css.name === 'font-weight' && css[1].indexOf('bold') > -1) { selected_css.value = css[1].trim(); selected_css.bold = true; } else if (selected_css.name === 'font-style' && css[1].indexOf('italic') > -1) { selected_css.value = css[1].trim(); selected_css.italic = true; } else { selected_css.value = css[1].trim(); } foundMatch = true; return; } }); if (!foundMatch && style && style.length) { $scope.additional.style += style + ';'; } }); if ($scope.selected_css.fontSize.value.length) { $scope.selected_css.fontSize.label = $scope.selected_css.fontSize.value.replace('px', ''); } if ($scope.selected_css.fontFamily.value.length) { $scope.selected_css.fontFamily.label = _.find(styleMetadata.font, { value: $scope.selected_css.fontFamily.value }).label; } } function formulate_css() { $scope.selectedStyle.text = ''; $scope.selectedStyle.styles = ''; _.each($scope.selected_css, function (selected_css) { if (selected_css.value && selected_css.value.length) { $scope.selectedStyle.text += selected_css.value + ' ,'; $scope.selectedStyle.styles += selected_css.name + ':' + selected_css.value + ';'; } }); if ($scope.additional.style.length) { $scope.selectedStyle.styles += $scope.additional.style; _.each($scope.additional.style.split(';'), function (style) { if (style) { var styleValue = style.split(':'); if (styleValue && styleValue[1]) { $scope.selectedStyle.text += styleValue[1] + ' ,'; } } }); } // remove trailing , and ; if any $scope.selectedStyle.text = $scope.selectedStyle.text.replace(/ ,+$/, ''); $scope.selectedStyle.styles = $scope.selectedStyle.styles.replace(/;+$/, ''); } function clearSelected_css() { $scope.selected_css = { fontWeight: { name: 'font-weight', value: '', bold: false }, fontStyle: { name: 'font-style', value: '', italic: false }, textDecoration: { name: 'text-decoration', value: '', underLine: false, lineThrough: false }, textAlign: { name: 'text-align', value: '' }, fontFamily: { name: 'font-family', value: '', label: '' }, fontSize: { name: 'font-size', value: '', label: '' }, color: { name: 'color', value: '' }, backgroundColor: { name: 'background-color', value: '' } }; $scope.additional.style = ''; } function mergeWithStandardStyle(template) { // make sure all standard styles (H1-H6, P) are presented to user // they cannot be deleted but user can leave it as undefined _.each(standardStyles, function (standardStyle) { var existingStandardStyle = _.find(template.templateObject.styles, { type: standardStyle.type }); if (!existingStandardStyle) { template.templateObject.styles.push(_.cloneDeep(standardStyle)); } else { // this shouldn't be needed if OOB data is setup properly existingStandardStyle.userStyle = false; } }); // sorting should be done in js instead at the html level, otherwise the item will move all // over the place when user editing the type on the fly template.templateObject.styles = _.sortBy(template.templateObject.styles, 'type'); } function setSelectedTemplate(template) { $scope.selectedTemplate = _.cloneDeep(template); mergeWithStandardStyle($scope.selectedTemplate); $scope.selectedTemplate.templateObject.styles = _.sortBy($scope.selectedTemplate.templateObject.styles, 'userStyle'); $scope.selectedStyle = {}; resetDirtyState(); } function dirtyStateCheck() { dirtyState[$scope.selectedStyle.type] = !originalStyle[$scope.selectedStyle.type] || originalStyle[$scope.selectedStyle.type].styles !== $scope.selectedStyle.styles || originalStyle[$scope.selectedStyle.type].element !== $scope.selectedStyle.element; $scope.isDirtyState = false; _.each(dirtyState, function (dirtyStatePerStyle) { $scope.isDirtyState = $scope.isDirtyState || dirtyStatePerStyle; }); } function resetDirtyState() { $scope.isDirtyState = false; dirtyState = {}; originalStyle = {}; } function showLeaveDialog() { var modal = systemAlertService.modal({ type: 'info', title: $filter('i18n')('common.notification.dirty.title'), text: $filter('i18n')('common.notification.dirty.loseChanges'), buttons: [ { text: $filter('i18n')('common.button.yes'), data: true }, { text: $filter('i18n')('common.button.no'), data: false } ] }); return modal.result; } init(); } ]); })();