CKEditor Change Config Setting on Focus / Click - javascript

I need to be able to change the filebrowserUploadUrl of CKEditor when I change some details on the page, as the querystring I pass through is used by the custom upload process I've put in place.
I'm using the JQuery plugin. Here's my code:
$('#Content').ckeditor({
extraPlugins: 'autogrow',
autoGrow_maxHeight: 400,
removePlugins: 'resize'
});
$("#Content").ckeditorGet().on("instanceReady", function () {
this.on("focus", function () {
// Define browser Url from selected fields
this.config.filebrowserUploadUrl = filebrowserUploadUrl: '/my-path-to-upload-script/?ID1=' + $("ID1").val() + '&ID2=' + $("#ID2").val();
});
});
This works fine the first time, but if I come out of the dialogue and change the value of #ID1 and #ID2, it keeps the previous values. When I debug, the filebrowserUploadUrl is set correctly, but it doesn't affect the submission values. It seems the config values are cached.
Is there any way to change a config value on the fly?

Currently I don't see any possibility to change this URL on the fly without hacking.
Take a look at http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/filebrowser/plugin.js#L306
This element.filebrowser.url property is set once and as you can see few lines above it will be reused again. You can try to somehow find this element and reset this property, but not having deeper understanding of the code of this plugin I don't know how.
Second option would be to change this line #L284 to:
url = undefined;
However, I haven't check if this is the correct solution :) Good luck!
BTW. Feel free to fill an issue on http://dev.ckeditor.com.

I solved this by reloading the editor whenever a change occurred; I actually went through the source code for the browser plugin etc, but couldn't get any changes to work (and of course, I really didn't want to change anything for future upgrades).
function setFileBrowserUrl() {
// Remove editor instance
$("#Content").ckeditorGet().destroy();
// Recreate editor instance (needed to reset the file browser url)
createEditor();
}
function createEditor() {
$('#Content').ckeditor({
filebrowserUploadUrl: '/my-path-to-upload-script/?ID1=' + $("ID1").val() + '&ID2=' + $("#ID2").val(),
extraPlugins: 'autogrow',
autoGrow_maxHeight: 400,
removePlugins: 'resize'
});
}
Then I call setFileBrowserUrl every time the relevant elements on the page change. Not ideal, but it works for my purposes :)

Related

DOM elements manipulation with javascript persists after reload or going to next page in pagination

I am trying to toggle a view between grid and list view mode on my frontend HTML page. I am able to do this fine with dom and HTML classes manipulation by toggling "display: none" between two containers. However, when I go to the next product page(through pagination) or when I reload the page, the default view is the one that appears and not the one that was last toggled. Is there a way to persist the view in case a page reload or product pagination changes? thank you.
here is the dom code that achieves this :
viewList.addEventListener('click', function() {
this.classList.add('view__active');
viewGrid.classList.remove('view__active');
gridItem.classList.add('hidden');
listItem.classList.remove('hidden');
});
viewGrid.addEventListener('click', function() {
this.classList.add('view__active');
viewList.classList.remove('view__active');
gridItem.classList.remove('hidden');
listItem.classList.add('hidden');
});
So far I found that I have to use localStorage to achieve this. but is there a better way to do this?
Essentially what is happening is when you request something from the server, the server responds with an HTML document, and whichever scripts associated with that document is run, So whatever JS executed in the first request is not in context when the second request(paginate or reload) is made.
So you need a way to persist information across these page loads, For that, you have 3 options.
Use sessionStorage.
Use localStorage
Use Cookies.
Of the 3 above the easiest would be to use either option 1 or 2.
Replying to your comment,
Also, If I am using localStorage, What am I using to store the view state?
I'm not quite clear as to what you mean by "What you are using to store the state" If your question is about where your data is stored, you need not worry about it as this is handled by the browser. If your question is about "How" to store it you can go through the MDN docs attached in option 1 or 2. This is simply storing a key-value pair as shown in the docs
localStorage.setItem('preferedView', 'grid'); You can add this to your on click handlers as follows,
viewList.addEventListener('click', function() {
this.classList.add('view__active');
viewGrid.classList.remove('view__active');
gridItem.classList.add('hidden');
listItem.classList.remove('hidden');
localStorage.setItem('preferedView', 'grid');
});
viewGrid.addEventListener('click', function() {
this.classList.add('view__active');
viewList.classList.remove('view__active');
gridItem.classList.remove('hidden');
listItem.classList.add('hidden');
localStorage.setItem('preferedView', 'list');
});
Then when loading a new page at the top of your script you can get the users preferedView(if existing) via const preferedView = localStorage.getItem('preferedView');
Here is a complete example from MDN
In order for anyone to find an answer for a similar task, thanks to #Umendra insight, I was able to solve this by using this :
function viewToggeler(viewBtn1, viewBtn2, view1, view2, viewStord) {
viewBtn2.classList.add('view__active');
viewBtn1.classList.remove('view__active');
view1.classList.add('hidden');
view2.classList.remove('hidden');
sessionStorage.setItem('preferedView', viewStord);
}
viewList.addEventListener('click', () => {
viewToggeler(viewGrid, viewList, gridItem, listItem, 'list');
});
viewGrid.addEventListener('click', () => {
viewToggeler(viewList, viewGrid, listItem, gridItem, 'grid');
});
if (sessionStorage.getItem('preferedView') === 'grid') {
viewToggeler(viewList, viewGrid, listItem, gridItem, 'grid');
} else if (sessionStorage.getItem('preferedView') === 'list') {
viewToggeler(viewGrid, viewList, gridItem, listItem, 'list');
}
I ended up using sessionStorage over localStorage because it empties itself on window/tab closing which might be the most desirable result. localStorage persists even after exiting the browser and opening it back.
Also, at any point someone wants to empty the sessionStorage on exit, I used :
window.addEventListener('onbeforeunload', () => {
sessionStorage.removeItem('preferedView');
});

Update image rotator .xml config file without refresh

I have a 3D model being rendered on my site through an image rotator .xml config file. This feature works but I am attempting to render a completely different .xml in place of the previous file through a JS on change event.
I have done a fair bit of reading in order to solve this issue, although I have not found an answer. I have already tried to make the JQuery script into a function as seen below:
function updateModel(xml_file_path) {
console.log('updating room model...');
console.log('xml_file_path: ' + xml_file_path);
// clear past model
$("#wr360PlayerId").empty();
jQuery('#wr360PlayerId').rotator({
licenseFileURL: 'license.lic',
configFileURL: '/static/360_assets/' + xml_file_path,
graphicsPath: '/static/img/basic',
zIndexLayersOn: false,
responsiveBaseWidth: 600,
responsiveMinHeight: 0,
googleEventTracking: false,
});
console.log('rendering: ' + xml_file_path);
}
// clears the old model then updates the configFileURL to the new model
This was successful in clearing the previous model although when I inspect the new model the images used by the image rotator are not being loaded and nothing is displayed.
wr360 documentation
I've also read through the documentation for wr360 above and found a few different ways of loading the image rotator on my site. I've gone through each and attempted to make it update using similar methods as JQuery but each had their own oddities that were difficult to overcome.
There's not much to code to this as for most of it is created dynamically on page load, but I'll try to provide all code necessary below:
js
function updateModel(xml_file_path) {
console.log('updating room model...');
console.log('xml_file_path: ' + xml_file_path);
// clear past model
$("#wr360PlayerId").empty();
jQuery('#wr360PlayerId').rotator({
licenseFileURL: 'license.lic',
configFileURL: '/static/360_assets/' + xml_file_path,
graphicsPath: '/static/img/basic',
zIndexLayersOn: false,
responsiveBaseWidth: 600,
responsiveMinHeight: 0,
googleEventTracking: false,
});
console.log('rendering: ' + xml_file_path);
}
$(document).ready(function(){
$('#rooms').on('change', function() {
updateModel(room.xml_path);
console.log('model updated');
});
});
// truncated for simplicity
html
<div id="wr360PlayerId" class="wr360_player" style="background-color:#FFFFFF;">
</div>
The xml file path is getting passed correctly (checked by the console.log('xml_file_path: ' + xml_file_path);) it just doesn't render the second rotator.
$('#rooms') is a select field, and room.xml_path is the selected rooms .xml file path. With this being said, ideally, the on change event would show the selected model and if the selection changes again it should render the new model (instead of nothing like it currently does).
Either I am missing something or it is impossible to update a model without refreshing the page, either way, any help is appreciated!
You can actually use,
apiObj.reload(xml_path);
to simply reload the image rotator with a new xml file path.

jQuery - bxSlider plugin reloadSlider issues

I'm using jQuery with the bxSlider plugin, here is the link to it just incase: http://bxslider.com/
I'm trying to reload the slider and my custom pager after I've removed certain slides from it.
Here is what I have tried:
$(function() {
var slider = $('#slider').bxSlider({
pagerCustom: '#bx-pager'
});
$('.list').on('click', '.delete', function() {
image = $(this).closest('li').find('[type="hidden"]');
// image.attr('id') contains a string: image-0, image-1, image-2, etc.
$('#slider, #bx-pager').find('.' + image.attr('id')).remove();
slider.reloadSlider({
pagerCustom: '#bx-pager'
}); // I have also tried: slider.reloadSlider();
});
});
It works partially. What happens is the slider gets reloaded just fine but it removes the pager completely when it runs the reload.
Thank you very much for any help.
As long as I see, this is a bug in bxSlider, in fact, when you call the reloadSlider method, internally are called the methods destroySlider and init.
In the destroySlider method the pagerEl element is destroyed, this is right if you are not using a custom one, because it is recreated programmatically in the init method, but if you are using a custom one it can't be recreated programmatically.
I ended up modifying the destroySlider method to check if a custom pager is used, in this case it must not be deleted.
Here is the before (line 1294):
if(slider.pagerEl) slider.pagerEl.remove();
And after:
if (slider.settings.pagerCustom === '') {
if(slider.pagerEl) slider.pagerEl.remove();
}
I'll post the bug on GitHub as soon as I have the time.

TinyMCE UndoManager. Get event to fire

I have made a webform that uses a TinyMCE editor. When the user clicks on a link to leave the page, I want a message to be displayed if he still has unsaved changes. For this, I was thinking of using the TinyMCE undoManager, http://www.tinymce.com/wiki.php/API3:class.tinymce.UndoManager
Essentially, I want the events onAdd, onUndo, OnRedo to fire. I will then keep track of the number of changes (if any) since the last save. But how do I get them to fire? Where do I set them up?
Also, it would be nice to have access to the hasUndo method in the rest of my javascript code. Again, not sure where to initiate this?
Not sure if it matters, but I'm using Django.
Edit: I have tried
tinyMCE.init({
...,
setup : function(ed) {
ed.UndoManager.onAdd(function(ed) {
ed.windowManager.alert('added.');
});
}
});
This gives me an error: Unable to get value of the property 'onAdd': object is null or undefined
I created a tinym fiddle for this: http://fiddle.tinymce.com/H0caab .
The solution is to use the oninit setting and to addresss the onAdd.add:
tinyMCE.init({
...
setup : function(ed) {
ed.onInit.add(function(ed) {
ed.undoManager.onAdd.add(function(ed) {
alert('added.');
});
});
}
});

ExtJS: starting HtmlEditor defaulting to source

I'm using ExtJS 3.2.1 and I need a component almost identical to the bundled HtmlEditor, with one exception: it must start editing the HTML source code directly. The reason I don't use a normal TextArea is that the user should be able to preview the result of his actions before submitting.
I've tried calling toggleSourceEdit(), as per ExtJS documentation, with no success. Debugging, I see that the editor object has the sourceEditMode property set to true, and the Source Edit button seems as if it was "pressed", but clicking on it does not render the typed HTML, and clicking it again goes to the Source Mode.
I've tried calling toggleSourceEdit() after the container show() method, on the container afterLayout listener and on the editor afterRender listener. I've tried also calling it on another button that I added to the container. The result is the same on every try.
The only other option I see is updating ExtJS to 3.3.0, but I haven't seem anything related on the changelogs. Either way, it's going to be my next step. EDIT: The app had another problems when updating, we'll make a bigger effort to update later. As of right now, we are using the HtmlEditor in its original setting.
Thanks!
ran into the same problem (using 3.3.0 by the way)
stumbled upon a fix by dumb luck. i have no idea why this works, but second time is the charm. call it twice in a row to achieve the desired effect..
HTMLEditor.toggleSourceEdit(true);
HTMLEditor.toggleSourceEdit(true);
hope that helps!
Rather calling toggleSourceEdit(), try to setup the configuration while you create HtmlEditor Object
Using toggleSourceEdit() caused some problems for me. One was that this seemed to put the editor somewhere in limbo between source edit and WYSIWYG mode unless I used a timeout of 250ms or so. It also puts the focus in that editor, and I don't want to start the form's focus in the editor, especially since it's below the fold and the browser scrolls to the focused html editor when it opens.
The only thing that worked for me was to extend Ext.form.HtmlEditor and then overwrite toggleSourceEdit, removing the focus command. Then adding a listener for toggling to the source editor when the component is initialized. This is for Ext 4.1 and up. For older versions, replace me.updateLayout() with me.doComponentLayout().
var Namespace = {
SourceEditor: Ext.define('Namespace.SourceEditor', {
extend: 'Ext.form.HtmlEditor',
alias: 'widget.sourceeditor',
initComponent: function() {
this.callParent(arguments);
},
toggleSourceEdit: function (sourceEditMode) {
var me = this,
iframe = me.iframeEl,
textarea = me.textareaEl,
hiddenCls = Ext.baseCSSPrefix + 'hidden',
btn = me.getToolbar().getComponent('sourceedit');
if (!Ext.isBoolean(sourceEditMode)) {
sourceEditMode = !me.sourceEditMode;
}
me.sourceEditMode = sourceEditMode;
if (btn.pressed !== sourceEditMode) {
btn.toggle(sourceEditMode);
}
if (sourceEditMode) {
me.disableItems(true);
me.syncValue();
iframe.addCls(hiddenCls);
textarea.removeCls(hiddenCls);
textarea.dom.removeAttribute('tabindex');
//textarea.focus();
me.inputEl = textarea;
} else {
if (me.initialized) {
me.disableItems(me.readOnly);
}
me.pushValue();
iframe.removeCls(hiddenCls);
textarea.addCls(hiddenCls);
textarea.dom.setAttribute('tabindex', -1);
me.deferFocus();
me.inputEl = iframe;
}
me.fireEvent('editmodechange', me, sourceEditMode);
me.updateLayout();
}
})
}
Then to use it:
Ext.create('Namespace.SourceEditor', {
/*regular options*/
listeners: {
initialize: function(thisEditor) {
thisEditor.toggleSourceEdit();
}
}
});
htmlEditor.toggleSourceEdit(true);
one time should be enough if you do this listening to the afterrender event of the editor.

Categories

Resources