Creating a rich text WYSIWYG editor in inRiver's web client

Hi!

We all know that in a PIM you want your data to be as pure as possible so that you can use it in a lot of different channels with ease. But sometimes the users wants to write very long texts and have specific needs to structure them dynamically. In inRiver's web client there is no out of the box way to get a WYSIWYG editor, and in the (desktop) Rich Client there is an old WYSIWYG editor but it is deprecated. So I created a solution where I use the new in-context editing concept to create a WYSIWYG editor inside inRiver using TinyMCE.

The end result looks like this: A language selector at the top followed by the TinyMCE text area and a simple save button at the bottom. I haven't put any effort into the design of this page, no css is used.

As you can see the text in the image has a lot of different formats; headlines, bold, underline, strikethrough, italic and so on. TinyMCE has the power to add a lot of formats to your texts and it all gets saved as html. So, let's take a look at the how this works.

I'm using a razor template where the body consists of the parts noted above like this:
<body>
    <select id="selector"></select>
    <textarea id="richTextData"></textarea>
    <button id="save-b" type="button" onclick="save()">Save</button>
</body>

The script tag is where the magic happens but I also use three external libraries: jQuery, Underscore and as noted above TinyMCE.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js" async></script>
<script src="https://cloud.tinymce.com/stable/tinymce.min.js"></script>

Ok, so let's get into the code! I'm using a CVL to know which languages are active. You can read my previous post on how to get a CVL that is always updated with all the active languages in the system. The Key is the language code used in inRiver and the Value is simply what we want the user to see. I start with using the TemplateHelper to get the languages. When the document is ready I then fill the language selector with the different options and set the changeLanguage() function to be fired if the user selects another language. I also initiate TinyMCE to use the TextArea as a TinyMCE editor.
var languages = @TemplateHelper.RenderCvlValuesJson("Languages")
var currentLanguage, currentData, savedData;

$(document).ready(function () {
  $.each(languages, function (key, value) {
    $('#languageSelector').append($('<option></option>').val(key).html(value));
  });

  $('#languageSelector').change(changeLanguage);

  tinymce.init({
    selector: 'textarea#richTextData'
  });
});

Next we have an important part, hooking into inRivers onInRiverTemplateReady() function. This gives us all the data on the entity and will also allow us to save any changes. In the helper function getField() I find the field ProductRichText that I have used to store the data in. Since it is a LocaleString object it consists of a "dictionary" of language-codes and then you get the data by accessing property 1 for each language. I then map the data from inRivers format into my own object. I have two of those in order to know what the user is currently working on and what has been saved in inRiver.

It's also important to note that currently you can't use the "View Template In Browser" button in Control Center because that won't fire the onInRiverTemplateReady method. So, in order to try it out you need to go to the Enrich app and then use the template there.
window.onInRiverTemplateReady = function (enrichEntityModel) { // Called from inRiver
  window.enrichEntityModel = enrichEntityModel;

  var field = getField();
  var langData = {};
  for (var lang in languages) {
    langData[lang] = field[lang]["1"];
  }

  savedData = langData;
  currentData = Object.assign({}, langData);

  for (var lang in languages) { //Be sure to initiate with the same language order
    currentLanguage = lang;
    tinyMCE.activeEditor.setContent(field[lang]["1"]);
    break;
  }
}

function getField() {
  return _.findWhere(window.enrichEntityModel.get("Fields"), { FieldType: "ProductRichText" }).Value;
}

The changeLanguage() function is pretty straight forward. Use currentLanguage to save the text that the user was working on into currentData and then load the text for the new language.
function changeLanguage() {
  var newLanguage = this.value;
  currentData[currentLanguage] = tinyMCE.activeEditor.getContent();
  tinyMCE.activeEditor.setContent(currentData[newLanguage]);
  currentLanguage = newLanguage;
}

The really interesting part comes next - how to save the information back into inRiver! Here I use currentData to update the field on enrichEntityModel with the new data. Then the actual save is done by accessing the save method on enrichEntityModel which stores the data back into the database. The savedData object is then updated with the same information.
function save() {
  currentData[currentLanguage] = tinyMCE.activeEditor.getContent();
  var field = getField();

  for (var lang in languages) {
    field[lang]["1"] = currentData[lang];
  }

  window.enrichEntityModel.save();
  savedData = Object.assign({}, currentData);
}

So why do we keep the savedData-object updated? The final thing we want to add is a reminder to the user to save before leaving the tab if any changes have been made. To get the same user experience as when working within the Details tab, you can hook into inRivers hasUnsavedChanges() function. This function will be called when the user tries to switch tabs. Here we simply compare savedData against currentData for all languages.
window.hasUnsavedChanges = function () { // Called from inRiver
  currentData[currentLanguage] = tinyMCE.activeEditor.getContent();
  for (var lang in languages) {
    if (savedData[lang] != currentData[lang]) {
      return true;
    }
  }

  return false;
}

So this is how you can build your very own WYSIWYG editor. On a final note, having text without formatting is greatly beneficial when publishing it in different channels. This WYSIWYG editor should therefore be used in cases where you have specific needs.

If you have any ideas or thoughts, let me know.
/Peter

Comments

  1. Big thanks for sharing this great post about Rich text editor javascript that will help all bloggers.

    ReplyDelete
  2. Hi. Thanks for this post! Our Inriver partner seems to have used this code to provide us a wysiwyg editor. Anyhow this editor takes ages to load. Do you have any ideas how can i make it faster? I mean it is realy frustrating to wait 10-15 seconds every time you want to edit the product descriptions.

    ReplyDelete
    Replies
    1. Hi! Nice to hear that this has been used as inspiration but that waiting time sounds very frustrating. When I wrote this post all we had to work with to get data was using inRivers razors functions, they aren't that quick so to get better performance I would switch to use the newly released REST-api. That should be a lot quicker. If you want to know more you welcome to contact me on linkedin (link at the top). /Peter

      Delete
    2. Thanks for your reply Peter! I was thinking that it's the javascript that's loading everytime you open the RTE tab, but razor fuction sounds more likely cause to the problem. Anyhow, as we're still adopting the new PIM system I guess I'll ask our Inriver partner to take a look of the REST-api solution first. We have agreed to get this RTE feature (which now doesn't work well enough) so I thinks it's their responsibility to fix it. I'll surely contact you if they don't fix this for some reason. /Jarmo

      Delete
    3. This comment has been removed by the author.

      Delete
  3. Great blog.you put Good stuff.All the topics were explained briefly.so quickly understand for me.I am waiting for your next fantastic blog.Thanks for sharing.Any coures related details learn...
    Blockchain Technology

    ReplyDelete
  4. With your dedication and hard effort, you accomplished an outstanding job. Thank you for taking the time to share it with me. I really appreciate it.
    WYSIWYG Builder Web

    ReplyDelete

Post a Comment

Popular Posts