Sometimes it is useful to have the HTML editor in CRM interface. It is possible to implement the editor directly to CRM 2013. As editor we will use ckeditor which allows to use it without installation on the server.
Identify the field where you would like to use the rich text editor.
Create html-webresource which will define ckeditor. Go to Settings-Customizations-Customize the System-Web Resources.
In html editor of web resource, select the Source tab and insert the following code:
<html>
<head>
<title></title>
<script src="//cdn.ckeditor.com/4.4.7/standard/ckeditor.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript">
function getTextFieldName()
{
var vals = new Array();
if (location.search != "")
{
vals = location.search.substr(1).split("&");
for (var i in vals)
{
vals[i] = vals[i].replace(/\+/g, " ").split("=");
}
//look for the parameter named 'data'
for (var i in vals)
{
if (vals[i][0].toLowerCase() == "data")
{
var datavalue = vals[i][2];
var vals2 = new Array();
var textFieldName = "";
vals2 = decodeURIComponent(datavalue).split("&");
for (var i in vals2)
{
var queryParam = vals2[i].replace(/\+/g, " ").split("=");
if (queryParam[0] != null && queryParam[0].toLowerCase() == "datafieldname")
{
textFieldName = queryParam[1];
}
}
if (textFieldName == "")
{
alert('No "dataFieldName" parameter has been passed to Rich Text Box Editor.');
return null;
}
else
{
return textFieldName;
}
}
else
{
alert('No data parameter has been passed to Rich Text Box Editor.');
}
}
}
else
{
alert('No data parameter has been passed to Rich Text Box Editor.');
}
return null;
}
CKEDITOR.timestamp = null;
// Maximize the editor window, i.e. it will be stretched to target field
CKEDITOR.on('instanceReady',
function( evt )
{
var editor = evt.editor;
editor.execCommand('maximize');
});
var Xrm;
$(document).ready(function ()
{
// Get the target field name from query string
var fieldName = getTextFieldName();
var Xrm = parent.Xrm;
var data = Xrm.Page.getAttribute(fieldName).getValue();
document.getElementById('editor1').value = data;
/*
// Uncomment only if you would like to update original field on lost focus instead of property change in editor
//Update textbox on lost focus
CKEDITOR.instances.editor1.on('blur', function ()
{
var value = CKEDITOR.instances.editor1.getData();
Xrm.Page.getAttribute(fieldName).setValue(value);
});
*/
// Update textbox on change in editor
CKEDITOR.instances.editor1.on('change', function ()
{
var value = CKEDITOR.instances.editor1.getData();
Xrm.Page.getAttribute(fieldName).setValue(value);
});
// Following settings define that the editor allows whole HTML content without removing tags like head, style etc.
CKEDITOR.config.allowedContent = true;
CKEDITOR.config.fullPage = true;
});
</script>
<meta>
</head>
<body style="word-wrap: break-word;">
<textarea class="ckeditor" cols="80" id="editor1" name="editor1" rows="10"></textarea>
</body>
</html>
Note:
As you can see, there are a few important sections
a) The following code loads the ckeditor and jquery from web so that they don't have to be installed on server.
<script src="//cdn.ckeditor.com/4.4.7/standard/ckeditor.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
b) Function getTextFieldName() which gets the name of target field where should be rich text editor placed. This information is obtained from query string. This will allow to use this web resource on multiple forms.
c) Initialization of ckeditor itself - setting the target field and properties of ckeditor. Also binding the editor with predefined textarea on the page.
Open the form designer on the form where you would like to use WYSIWYG editor. Create a text field with sufficient length (e.g. 100 000 chars) which will hold the html source code.
Insert the iframe on the form. As a webresource use the resource created in previous steps. Also define Custom Parameter(data) where you should define the name of the text field defined in step 4. In our situation we created new_bodyhtml text field so the parameter holds this value. This value is returned by the getTextFieldName() of the web resource.
Do not forget to save and publish all changes in CRM customization otherwise added webresources and updated form are not available.
That's all, here is example how it looks like:
Yes, you can use CKEditor, but when I implemented the CKEditor on a form, it turns out it is quite limited in the functionality in provides. Also, the HTML it generates leaves much to be desired. So, I tried a similar idea to Pavel's but using a backing field to store the actual HTML using TinyMCE. You can find the code here:
Javascript
HTML
Documentation
I have package my solution as a managed and unmanaged CRM solution that can be imported and utilised on any form. Moreover, it works on both CRM 2013 and CRM 2015
Related
I am working on a SharePoint page, utilizing the jslink for the list web part. I have the following code written out:
(function () {
var overrideCurrentContext = {};
overrideCurrentContext.Templates = {};
overrideCurrentContext.Templates.Header = "<div class='ListAccordion'>";
overrideCurrentContext.Templates.Footer = "</div>";
overrideCurrentContext.OnPostRender = OnPostRender;
overrideCurrentContext.Templates.Item = ItemTemplate;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCurrentContext);
})();
function ItemTemplate(ctx) {
var Title = ctx.CurrentItem["Title"];
var Body = ctx.CurrentItem["Body"];
return "<h2>" + Title + "</h2><p>" + Body + "</p><br/>";
}
function OnPostRender() {
$('.ListAccordion h2').click(function () {
$(this).next().slideToggle();
}).next().hide();
$('.ListAccordion h2').css({
"background-color": "#0B0B61",
"cursor": "pointer",
"color": "white" ,
"border-radius" : "15px",
"padding-left" : "10px"
});
}
The problem I am having, is that my accordion view will not display until I utilize the manual refresh option, or I wait for the Asynchronous Automatic Refresh both under the AJAX option of the web part properties.
The accordion shows up perfect, until I save, or reload the page, but it works if I utilize the ajax options. Is there anything I can do to make sure the accordion shows right away when the page is first opened?
also I have the file saved in my siteassets and this is the link I am using ~site/SiteAssets/Accordions12.js
Add the following to the header of your script editor but replace the middle parts with what your file/location is
<script src="/_catalogs/masterpage/test1/jquery-1.11.2.min.js" type="text/javascript"></script>
I was working with wkhmtltopdf and found that I have a problem with it.
I am using the html page to also preview the content in a browser prior to converting to PDF.
But to make it more readable in my preview, I have added some css on the page: (In javascript/jQuery on document ready)
$(document).ready(function () {
if(window.location.href.indexOf("preview") > -1 && window.location.href.indexOf(".pdf") == -1) {
appendCSStoHtml();
}
});
function appendCSStoHtml() {
$("body").css({"background-color":" #F0F8FF"});
$("#previewHtml").css({
"margin-left":"15%",
"margin-right":"15%",
"margin-top":"15px",
"max-width":"1024px"});
$("#previewHtml > h2").css({"margin-left":" 15px"});
}
So this is all good and dandy, but when I generate my PDF based on this HTML page, then the css is also renderend inside my PDF and the outlining and background are also present inside the PDF.
I don't want this to happen, I only want my css style elements to be renderen on the HTML page and not inside the PDF.
How can I achieve this?
I tried with the following:
$(document).ready(function () {
if(window.location.href.indexOf("preview") > -1 && window.location.href.indexOf(".pdf") == -1) {
appendCSStoHtml();
}
});
But that did not matter.
Any ideas?
it's me again.
Not sure if there is something that resembles what I am looking for.
Thus I made my own.
I added a page parameter and check this in the code to see if it's true or false:
<script type="text/javascript">
$(document).ready(function () {
var url_string = window.location.href;
var url = new URL(url_string);
var renderCss = url.searchParams.get("renderCss");
if(renderCss == 'true') {
appendCSStoHtml();
}
});
function appendCSStoHtml() {
$("body").css({"background-color":" #F0F8FF"});
$("#previewHtml").css({
"margin-left":"15%",
"margin-right":"15%",
"margin-top":"15px",
"max-width":"1024px"});
$("#previewHtml > h2").css({"margin-left":" 15px"});
}
</script>
<script type="text/javascript">
function GetContents() {
var oEditor = CKEDITOR.instances.editor1;
document.getElementById('field').value = oEditor.getData();
}
</script>
Here i passed value from CKEditor to text field. In the similar way I want do vice verse from textbox to CKEditor.
field.value = oEditor.getValue();
oEditor.setValue(field.value);
But why do you need to do it? CKEditor perfectly works in form as it is when you apply it to the textarea.
Also as your function named GetContents it should return a value but not set it to the textbox. Follow the coding guidelines.
If you want to update <textarea> value with editor's data, use CKEDITOR.editor.updateElement.
If you want to synchronize editor's data with <textarea>, use CKEDITOR.editor.setData. There's no method in the API similar to updateElement that works the opposite way. Still, the official jQuery Adapter allows setting editor's data by calling $( textarea ).val( newValue ).
function GetContents() {
var oEditor = CKEDITOR.instances.editor1;
alert(document.getElementById('').value);
oEditor.setData(document.getElementById('').value);
}
I created the instance and did its working fine.
I am looking for a way to make the CKEDITOR wysiwyg content interactive. This means for example adding some onclick events to the specific elements. I can do something like this:
CKEDITOR.instances['editor1'].document.getById('someid').setAttribute('onclick','alert("blabla")');
After processing this action it works nice. But consequently if I change the mode to source-mode and then return to wysiwyg-mode, the javascript won't run. The onclick action is still visible in the source-mode, but is not rendered inside the textarea element.
However, it is interesting, that this works fine everytime:
CKEDITOR.instances['editor1'].document.getById('id1').setAttribute('style','cursor: pointer;');
And it is also not rendered inside the textarea element! How is it possible? What is the best way to work with onclick and onmouse events of CKEDITOR content elements?
I tried manually write this by the source-mode:
<html>
<head>
<title></title>
</head>
<body>
<p>
This is some <strong id="id1" onclick="alert('blabla');" style="cursor: pointer;">sample text</strong>. You are using CKEditor.</p>
</body>
</html>
And the Javascript (onclick action) does not work. Any ideas?
Thanks a lot!
My final solution:
editor.on('contentDom', function() {
var elements = editor.document.getElementsByTag('span');
for (var i = 0, c = elements.count(); i < c; i++) {
var e = new CKEDITOR.dom.element(elements.$.item(i));
if (hasSemanticAttribute(e)) {
// leve tlacitko mysi - obsluha
e.on('click', function() {
if (this.getAttribute('class') === marked) {
if (editor.document.$.getElementsByClassName(marked_unique).length > 0) {
this.removeAttribute('class');
} else {
this.setAttribute('class', marked_unique);
}
} else if (this.getAttribute('class') === marked_unique) {
this.removeAttribute('class');
} else {
this.setAttribute('class', marked);
}
});
}
}
});
Filtering (only CKEditor >=4.1)
This attribute is removed because CKEditor does not allow it. This filtering system is called Advanced Content Filter and you can read about it here:
http://ckeditor.com/blog/Upgrading-to-CKEditor-4.1
http://ckeditor.com/blog/CKEditor-4.1-Released
Advanced Content Filter guide
In short - you need to configure editor to allow onclick attributes on some elements. For example:
CKEDITOR.replace( 'editor1', {
extraAllowedContent: 'strong[onclick]'
} );
Read more here: config.extraAllowedContent.
on* attributes inside CKEditor
CKEditor encodes on* attributes when loading content so they are not breaking editing features. For example, onmouseout becomes data-cke-pa-onmouseout inside editor and then, when getting data from editor, this attributes is decoded.
There's no configuration option for this, because it wouldn't make sense.
Note: As you're setting attribute for element inside editor's editable element, you should set it to the protected format:
element.setAttribute( 'data-cke-pa-onclick', 'alert("blabla")' );
Clickable elements in CKEditor
If you want to observe click events in editor, then this is the correct solution:
editor.on( 'contentDom', function() {
var element = editor.document.getById( 'foo' );
editor.editable().attachListener( element, 'click', function( evt ) {
// ...
// Get the event target (needed for events delegation).
evt.data.getTarget();
} );
} );
Check the documentation for editor#contentDom event which is very important in such cases.
i am using HTML.TEXTAREA in my MVC2.0 application but i cant restrict the textarea to allow user to input only 255 characters.
I have also provided <% html.textarea("Name",new {#maxlength = "255"}) %> but still i couldnt achieve the target.
Please provide me any solutions.
Thanks
Verify your HTML version
In Html 4.0,
maxlength is not a valid property for TextArea.
maxLength attribute is added in HTML 5.0.(But unfortunately HTML 5.0 is quite new and not much browser support it)
For more information,
http://www.w3schools.com/html5/att_textarea_maxlength.asp
You can write java script and restrict text area size.
<script type="text/javascript">
$(function () {
$("#id").keypress(function () {
var maxlen = 100;
if ($(this).val().length > maxlen) {
return false;
}
})
});
</script>
A very easy way is to use SubString. Its not something that you need to bang your head for and you can write it yourself.
For Example:
var textAreaObject = document.getElementById("TextAreaId");
if (textAreaObject != null) {
var maxlength = 60; //Give the desired value for your Maxlength
if (textAreaObject .value.length > maxlength) {
//Substring from the entered text. Easy-peezy
textAreaObject .value = textAreaObject .value.substring(0, maxlength);
}
}
Works everywhere and anywhere. And use this for on paste and on keypress events. Happy coding.