};
});
+ crmCaseType.directive('crmEditableTabTitle', function($timeout) {
+ return {
+ restrict: 'AE',
+ link: function(scope, element, attrs) {
+ element.addClass('crm-editable crm-editable-enabled');
+ var titleLabel = $(element).find('span');
+ var penIcon = $('<i class="crm-i fa-pencil crm-editable-placeholder"></i>').prependTo(element);
+ var saveButton = $('<button type="button"><i class="crm-i fa-check"></i></button>').appendTo(element);
+ var cancelButton = $('<button type="cancel"><i class="crm-i fa-times"></i></button>').appendTo(element);
+ $('button', element).wrapAll('<div class="crm-editable-form" style="display:none" />');
+ var buttons = $('.crm-editable-form', element);
+ titleLabel.on('click', startEditMode);
+ penIcon.on('click', startEditMode);
+
+ function detectEscapeKeyPress (event) {
+ var isEscape = false;
+
+ if ("key" in event) {
+ isEscape = (event.key == "Escape" || event.key == "Esc");
+ } else {
+ isEscape = (event.keyCode == 27);
+ }
+
+ return isEscape;
+ }
+
+ function detectEnterKeyPress (event) {
+ var isEnter = false;
+
+ if ("key" in event) {
+ isEnter = (event.key == "Enter");
+ } else {
+ isEnter = (event.keyCode == 13);
+ }
+
+ return isEnter;
+ }
+
+ function startEditMode () {
+ if (titleLabel.is(":focus")) {
+ return;
+ }
+
+ penIcon.hide();
+ buttons.show();
+
+ saveButton.click(function () {
+ updateTextValue();
+ stopEditMode();
+ });
+
+ cancelButton.click(function () {
+ revertTextValue();
+ stopEditMode();
+ });
+
+ $(element).addClass('crm-editable-editing');
+
+ titleLabel
+ .attr("contenteditable", "true")
+ .focus()
+ .focusout(function (event) {
+ $timeout(function () {
+ revertTextValue();
+ stopEditMode();
+ }, 500);
+ })
+ .keydown(function(event) {
+ event.stopImmediatePropagation();
+
+ if(detectEscapeKeyPress(event)) {
+ revertTextValue();
+ stopEditMode();
+ } else if(detectEnterKeyPress(event)) {
+ event.preventDefault();
+ updateTextValue();
+ stopEditMode();
+ }
+ });
+ }
+
+ function stopEditMode () {
+ titleLabel.removeAttr("contenteditable").off("focusout");
+ titleLabel.off("keydown");
+ saveButton.off("click");
+ cancelButton.off("click");
+ $(element).removeClass('crm-editable-editing');
+
+ penIcon.show();
+ buttons.hide();
+ }
+
+ function revertTextValue () {
+ titleLabel.text(scope.activitySet.label);
+ }
+
+ function updateTextValue () {
+ var updatedTitle = titleLabel.text();
+
+ scope.$evalAsync(function () {
+ scope.activitySet.label = updatedTitle;
+ });
+ }
+ }
+ };
+ });
+
crmCaseType.controller('CaseTypeCtrl', function($scope, crmApi, apiCalls) {
// CRM_Case_XMLProcessor::REL_TYPE_CNAME
var REL_TYPE_CNAME = CRM.crmCaseType.REL_TYPE_CNAME,
var $httpBackend;
var $q;
var $rootScope;
+ var $timeout;
var apiCalls;
var ctrl;
var compile;
});
});
- beforeEach(inject(function(_$controller_, _$compile_, _$httpBackend_, _$q_, _$rootScope_) {
+ beforeEach(inject(function(_$controller_, _$compile_, _$httpBackend_, _$q_, _$rootScope_, _$timeout_) {
$controller = _$controller_;
$compile = _$compile_;
$httpBackend = _$httpBackend_;
$q = _$q_;
$rootScope = _$rootScope_;
+ $timeout = _$timeout_;
}));
describe('CaseTypeCtrl', function() {
});
});
+ describe('crmEditableTabTitle', function () {
+ var element, titleLabel, penIcon, saveButton, cancelButton;
+
+ beforeEach(function() {
+ scope = $rootScope.$new();
+ element = '<div crm-editable-tab-title title="Click to edit">' +
+ '<span ng-keydown="$event.stopImmediatePropagation()">{{ activitySet.label }}</span>' +
+ '</div>';
+
+ scope.activitySet = { label: 'Title'};
+ element = $compile(element)(scope);
+
+ titleLabel = $(element).find('span');
+ penIcon = $(element).find('i.fa-pencil');
+ saveButton = $(element).find('button[type=button]');
+ cancelButton = $(element).find('button[type=cancel]');
+
+ scope.$digest();
+ });
+
+ describe('when initialized', function () {
+ it('hides the save and cancel button', function () {
+ expect(saveButton.parent().css('display') === 'none').toBe(true);
+ expect(cancelButton.parent().css('display') === 'none').toBe(true);
+ });
+ });
+
+ describe('when clicked on title label', function () {
+ beforeEach(function () {
+ titleLabel.click();
+ });
+
+ it('hides the pen icon', function () {
+ expect(penIcon.css('display') === 'none').toBe(true);
+ });
+
+ it('shows the save button', function () {
+ expect(saveButton.parent().css('display') !== 'none').toBe(true);
+ });
+
+ it('makes the title editable', function () {
+ expect(titleLabel.attr('contenteditable')).toBe('true');
+ });
+ });
+
+ describe('when clicked outside of the editable area', function () {
+ beforeEach(function () {
+ titleLabel.click();
+ titleLabel.text('Updated Title');
+ titleLabel.blur();
+ $timeout.flush();
+ scope.$digest();
+ });
+
+ it('shows the pen icon', function () {
+ expect(penIcon.css('display') !== 'none').toBe(true);
+ });
+
+ it('hides the save and cancel button', function () {
+ expect(saveButton.parent().css('display') === 'none').toBe(true);
+ expect(cancelButton.parent().css('display') === 'none').toBe(true);
+ });
+
+ it('makes the title non editable', function () {
+ expect(titleLabel.attr('contenteditable')).not.toBe('true');
+ });
+
+ it('does not update the title in angular context', function () {
+ expect(scope.activitySet.label).toBe('Title');
+ });
+ });
+
+ describe('when ESCAPE key is pressed while typing', function () {
+ beforeEach(function () {
+ var eventObj = $.Event('keydown');
+ eventObj.key = 'Escape';
+
+ titleLabel.click();
+ titleLabel.text('Updated Title');
+ titleLabel.trigger(eventObj);
+ scope.$digest();
+ });
+
+ it('shows the pen icon', function () {
+ expect(penIcon.css('display') !== 'none').toBe(true);
+ });
+
+ it('hides the save and cancel button', function () {
+ expect(saveButton.parent().css('display') === 'none').toBe(true);
+ expect(cancelButton.parent().css('display') === 'none').toBe(true);
+ });
+
+ it('makes the title non editable', function () {
+ expect(titleLabel.attr('contenteditable')).not.toBe('true');
+ });
+
+ it('does not update the title', function () {
+ expect(scope.activitySet.label).toBe('Title');
+ });
+ });
+
+ describe('when ENTER key is pressed while typing', function () {
+ beforeEach(function () {
+ var eventObj = $.Event('keydown');
+ eventObj.key = 'Enter';
+
+ titleLabel.click();
+ titleLabel.text('Updated Title');
+ titleLabel.trigger(eventObj);
+ scope.$digest();
+ });
+
+ it('shows the pen icon', function () {
+ expect(penIcon.css('display') !== 'none').toBe(true);
+ });
+
+ it('hides the save and cancel button', function () {
+ expect(saveButton.parent().css('display') === 'none').toBe(true);
+ expect(cancelButton.parent().css('display') === 'none').toBe(true);
+ });
+
+ it('makes the title non editable', function () {
+ expect(titleLabel.attr('contenteditable')).not.toBe('true');
+ });
+
+ it('updates the title in angular context', function () {
+ expect(scope.activitySet.label).toBe('Updated Title');
+ });
+ });
+
+ describe('when SAVE button is clicked', function () {
+ beforeEach(function () {
+ titleLabel.click();
+ titleLabel.text('Updated Title');
+ saveButton.click();
+ scope.$digest();
+ });
+
+ it('shows the pen icon', function () {
+ expect(penIcon.css('display') !== 'none').toBe(true);
+ });
+
+ it('hides the save and cancel button', function () {
+ expect(saveButton.parent().css('display') === 'none').toBe(true);
+ expect(cancelButton.parent().css('display') === 'none').toBe(true);
+ });
+
+ it('makes the title non editable', function () {
+ expect(titleLabel.attr('contenteditable')).not.toBe('true');
+ });
+
+ it('updates the title in angular context', function () {
+ expect(scope.activitySet.label).toBe('Updated Title');
+ });
+ });
+
+ describe('when CANCEL button is clicked', function () {
+ beforeEach(function () {
+ titleLabel.click();
+ titleLabel.text('Updated Title');
+ cancelButton.click();
+ scope.$digest();
+ });
+
+ it('shows the pen icon', function () {
+ expect(penIcon.css('display') !== 'none').toBe(true);
+ });
+
+ it('hides the save and cancel button', function () {
+ expect(saveButton.parent().css('display') === 'none').toBe(true);
+ expect(cancelButton.parent().css('display') === 'none').toBe(true);
+ });
+
+ it('makes the title non editable', function () {
+ expect(titleLabel.attr('contenteditable')).not.toBe('true');
+ });
+
+ it('does not update the title in angular context', function () {
+ expect(scope.activitySet.label).toBe('Title');
+ });
+ });
+ });
+
describe('CaseTypeListCtrl', function() {
var caseTypes, crmApiSpy;