// Example:
// <a ng-click="$broadcast('my-insert-target', 'some new text')>Insert</a>
// <textarea crm-ui-insert-rx='my-insert-target'></textarea>
- // TODO Consider ways to separate the plain-text/rich-text implementations
.directive('crmUiInsertRx', function() {
return {
link: function(scope, element, attrs) {
scope.$on(attrs.crmUiInsertRx, function(e, tokenName) {
CRM.wysiwyg.insert(element, tokenName);
$(element).select2('close').select2('val', '');
- CRM.wysiwyg.focus();
+ CRM.wysiwyg.focus(element);
});
}
};
return;
}
-
if (attr.ngBlur) {
- $(elm).on('blur', function(){
- $timeout(function(){
+ $(elm).on('blur', function() {
+ $timeout(function() {
scope.$eval(attr.ngBlur);
});
});
}
- $(elm).on('paste', function () {
- scope.$apply(function () {
- ngModel.$setViewValue(CRM.wysiwyg.getVal(elm));
- });
- });
-
- $(elm).on('keypress', function () {
- $timeout(function () {
+ $(elm).on('paste change keypress', function() {
+ scope.$apply(function() {
ngModel.$setViewValue(CRM.wysiwyg.getVal(elm));
});
});
- ngModel.$render = function (value) {
+ ngModel.$render = function(value) {
CRM.wysiwyg.setVal(elm, ngModel.$viewValue);
};
}
$(this).data('crm-initial-value', $(this).is(':checkbox, :radio') ? $(this).prop('checked') : $(this).val());
});
$('textarea.crm-wysiwyg', e.target)
- .not('.wysiwyg-enabled')
- .addClass('wysiwyg-enabled')
+ .not('.crm-wysiwyg-enabled')
+ .addClass('crm-wysiwyg-enabled')
.each(function() {
if ($(this).hasClass("collapsed")) {
- CRM.wysiwyg.createPlain(this);
+ CRM.wysiwyg.createCollapsed(this);
} else {
CRM.wysiwyg.create(this);
}
}
}
},
- beforeSerialize: function(form, options) {
- if (window.CKEDITOR && window.CKEDITOR.instances) {
- $.each(CKEDITOR.instances, function() {
- if (this.updateElement) this.updateElement();
- });
- }
- if (window.tinyMCE && tinyMCE.editors) {
- $.each(tinyMCE.editors, function() {
- this.save();
- });
- }
- },
beforeSubmit: function(submission) {
$.each(formErrors, function() {
if (this && this.close) this.close();
.on('dialogcreate', function(e) {
$('.ui-dialog-content.crm-ajax-container:hidden[data-unsaved-changes=true]').crmSnippet('destroy').dialog('destroy').remove();
})
+ // Ensure wysiwyg content is updated prior to ajax submit
+ .on('form-pre-serialize', function(e) {
+ $('.crm-wysiwyg-enabled', e.target).each(function() {
+ CRM.wysiwyg.updateElement(this);
+ });
+ })
// Auto-resize dialogs when loading content
.on('crmLoad dialogopen', 'div.ui-dialog.ui-resizable.crm-container', function(e) {
var
// https://civicrm.org/licensing
(function($, _) {
function getInstance(item) {
- var name = $(item).attr("name");
- var id = $(item).attr("id");
+ var name = $(item).attr("name"),
+ id = $(item).attr("id");
if (name && CKEDITOR.instances[name]) {
return CKEDITOR.instances[name];
}
}
}
CRM.wysiwyg.supportsFileUploads = true;
- CRM.wysiwyg.create = function(item) {
- var browseUrl = CRM.config.userFrameworkResourceURL + "packages/kcfinder/browse.php";
- var uploadUrl = CRM.config.userFrameworkResourceURL + "packages/kcfinder/upload.php";
- var editor = CKEDITOR.replace($(item)[0]);
+ CRM.wysiwyg.create = function(item) {
+ var editor,
+ browseUrl = CRM.config.userFrameworkResourceURL + "packages/kcfinder/browse.php?cms=civicrm",
+ uploadUrl = CRM.config.userFrameworkResourceURL + "packages/kcfinder/upload.php?cms=civicrm";
+ if ($(item).length) {
+ editor = CKEDITOR.replace($(item)[0]);
+ }
if (editor) {
- editor.config.filebrowserBrowseUrl = browseUrl+'?cms=civicrm&type=files';
- editor.config.filebrowserImageBrowseUrl = browseUrl+'?cms=civicrm&type=images';
- editor.config.filebrowserFlashBrowseUrl = browseUrl+'?cms=civicrm&type=flash';
- editor.config.filebrowserUploadUrl = uploadUrl+'?cms=civicrm&type=files';
- editor.config.filebrowserImageUploadUrl = uploadUrl+'?cms=civicrm&type=images';
- editor.config.filebrowserFlashUploadUrl = uploadUrl+'?cms=civicrm&type=flash';
+ editor.config.filebrowserBrowseUrl = browseUrl + '&type=files';
+ editor.config.filebrowserImageBrowseUrl = browseUrl + '&type=images';
+ editor.config.filebrowserFlashBrowseUrl = browseUrl + '&type=flash';
+ editor.config.filebrowserUploadUrl = uploadUrl + '&type=files';
+ editor.config.filebrowserImageUploadUrl = uploadUrl + '&type=images';
+ editor.config.filebrowserFlashUploadUrl = uploadUrl + '&type=flash';
editor.on('blur', function() {
editor.updateElement();
$(item).trigger("blur");
+ $(item).trigger("change");
});
editor.on('insertText', function() {
$(item).trigger("keypress");
if (editor) {
editor.insertText(text);
} else {
- CRM.wysiwyg.insertIntoTextarea(item, text);
+ CRM.wysiwyg._insertIntoTextarea(item, text);
}
};
CRM.wysiwyg.focus = function(item) {
var editor = getInstance(item);
if (editor) {
editor.focus();
+ } else {
+ $(item).focus();
}
};
// https://civicrm.org/licensing
(function($, _) {
- function openWysiwyg(item) {
- $(item).show();
- $(item).next('.replace-plain').hide();
- CRM.wysiwyg.create(item);
- $(item).on('blur', function() {
- CRM.wysiwyg.destroy(item);
- $(item).hide().next('.replace-plain').show().html($(item).val());
- });
- }
- CRM.wysiwyg = {};
- CRM.wysiwyg.supportsFileUploads = false;
- CRM.wysiwyg.create = _.noop;
- CRM.wysiwyg.destroy = _.noop;
- CRM.wysiwyg.updateElement = _.noop;
- CRM.wysiwyg.getVal = function(item) {
- return $(item).val();
+ // This defines an interface which by default only handles plain textareas
+ // A wysiwyg implementation can extend this by overriding as many of these functions as needed
+ CRM.wysiwyg = {
+ supportsFileUploads: false,
+ create: _.noop,
+ destroy: _.noop,
+ updateElement: _.noop,
+ getVal: function(item) {
+ return $(item).val();
+ },
+ setVal: function(item, val) {
+ return $(item).val(val);
+ },
+ insert: function(item, text) {
+ CRM.wysiwyg._insertIntoTextarea(item, text);
+ },
+ focus: function(item) {
+ $(item).focus();
+ },
+ // Fallback function to use when a wysiwyg has not been initialized
+ _insertIntoTextarea: function(item, text) {
+ var origVal = $(item).val();
+ var origPos = item[0].selectionStart;
+ var newVal = origVal + text;
+ $(item).val(newVal);
+ var newPos = (origPos + text.length);
+ item[0].selectionStart = newPos;
+ item[0].selectionEnd = newPos;
+ $(item).triggerHandler('change');
+ CRM.wysiwyg.focus(item);
+ },
+ createCollapsed: function(item) {
+ $(item)
+ .hide()
+ .after('<div class="replace-plain" tabindex="0"></div>')
+ .on('blur', function () {
+ CRM.wysiwyg.destroy(item);
+ $(item).hide().next('.replace-plain').show().html($(item).val());
+ });
+ $(item).next('.replace-plain').attr('title', ts('Click to edit')).on('click keypress', function () {
+ $(item).show().next('.replace-plain').hide();
+ CRM.wysiwyg.create(item);
+ });
+ }
};
- CRM.wysiwyg.setVal = function(item, val) {
- return $(item).val(val);
- };
- CRM.wysiwyg.insert = function(item, text) {
- CRM.wysiwyg.insertIntoTextarea(item, text);
- };
- CRM.wysiwyg.insertIntoTextarea = function(item, text) {
- var origVal = $(item).val();
- var origPos = item[0].selectionStart;
- var newVal = origVal + text;
- $(item).val(newVal);
- var newPos = (origPos + text.length);
- item[0].selectionStart = newPos;
- item[0].selectionEnd = newPos;
- $(item).triggerHandler('change');
- CRM.wysiwyg.focus(item);
- };
- CRM.wysiwyg.focus = function(item) {
- $(item).focus();
- };
- CRM.wysiwyg.createPlain = function(item) {
- $(item)
- .hide()
- .after('<div class="replace-plain" tabindex="0" title="Click to edit"></div>');
- $(item).next('.replace-plain').click(function(){
- openWysiwyg(item);
- });
- $(item).next('.replace-plain').keypress(function(){
- openWysiwyg(item);
- });
- };
-
})(CRM.$, CRM._);
beforeSubmit: function(arr, $form, options) {
$form.block();
},
- beforeSerialize: function(form, options) {
- // Copied from crm.ajax.js
- if (window.CKEDITOR && window.CKEDITOR.instances) {
- $.each(CKEDITOR.instances, function() {
- if (this.updateElement) this.updateElement();
- });
- }
- if (window.tinyMCE && tinyMCE.editors) {
- $.each(tinyMCE.editors, function() {
- this.save();
- });
- }
- },
success: requestHandler,
error: errorHandler
};