CKEditor - Button to switch shown Toolbar - javascript

I'm trying to give a user the ability to swap around the toolbar between presets based on a button press. Ideally that button would be in the CKEditor screen, but I can play around with it.
I've found this SO Article in which I get the concept that you destroy your instance, and re-initialize it with a 'New Config'.
To follow suit I took one of the higher ranked responses, modified it to match my table, and threw it onto a button.
function toolbarSwap(){
var editor = CKEDITOR.instances.editor;
if (editor) { editor.destroy(true); }
CKEDITOR.config.toolbar_Basic = [['Bold','Italic','Underline',
'-','JustifyLeft','JustifyCenter','JustifyRight','-','Undo','Redo']];
CKEDITOR.config.toolbar = 'Basic';
CKEDITOR.config.width=400;
CKEDITOR.config.height=300;
CKEDITOR.replace('editor', CKEDITOR.config);
}
The replace command concerns me since I can't see it working, as to if the data within the editor will go away but either way nothing is happening when I click the button that runs this function.
Is this the best method, or is there a way I can do this within CKEditor directly?
Update
function toolbarSwap(){
var editor = CKEDITOR.instances['editor'];
if (editor) { editor.destroy(true); }
CKEDITOR.config.toolbar_Basic = [['Bold','Italic','Underline',
'-','JustifyLeft','JustifyCenter','JustifyRight','-','Undo','Redo']];
CKEDITOR.config.toolbar = 'Basic';
CKEDITOR.config.width=400;
CKEDITOR.config.height=300;
CKEDITOR.replace('editor', CKEDITOR.config);
}
It seems like modified the instantiation of editor with the ID resolves the issue of it finding it, but the Editor is being emptied every time I click it. Is there a way to reload the config, instead of destroying the instance?
Update 2
function changeToolBar() {
var expanded = true;
if (expanded === true) {
var myToolBar = [{ name: 'verticalCustomToolbar', groups: [ 'basicstyles'], items: [ 'Bold', 'Italic'] }];
var config = {};
config.toolbar = myToolBar;
CKEDITOR.instances.editor.destroy();//destroy the existing editor
CKEDITOR.replace('editor', config);
expanded = false;
} else {
CKEDITOR.instances.editor.destroy();//destroy the existing editor
CKEDITOR.replace('editor', {toolbar: 'Full'});
expanded = true;
console.log("Expand me")
};
}
Here is where I'm at so far. I am not losing the data during the re-init, but I am unable to ever get the 'else' statement to trigger.

My Function was correct, but the var being initialized -in- the function was resetting it's purpose everything. AKA It's -always- true on click
<button type="button" onclick="changeToolBar()">Swap It</button>
function changeToolBar() {
if (expanded === true) {
var myToolBar = [{ name: 'verticalCustomToolbar', groups: [ 'basicstyles'], items: [ 'Bold', 'Italic'] }]; //Generic placeholder
var config = {};
config.toolbar = myToolBar;
CKEDITOR.instances.editor.destroy();//destroy the existing editor
CKEDITOR.replace('editor', config);
console.log(expanded); // Logging to ensure change
expanded = false;
console.log(expanded); // Logging to ensure the change
} else {
CKEDITOR.instances.editor.destroy();//destroy the existing editor
CKEDITOR.replace('editor', {toolbar: 'Full'}); // Toolbar 'full' is a default one
expanded = true;
console.log("Expand me") // Logging if it works
};
}
Can also swap in Full with a predefined config for toolbars.

Related

How to add a new Inspector(apart from the Inspector of elements and links) in jointJS - Rappid

I want to add a 3rd Inspector which will open only for an element(not a link) of specific type, for example only for basic.Rect in Rappid.
So far, there are 2 Inspectors.For elements and for links.
Is there any way it can be done?
The following code is a part of the KitchenSkink version of Rappid.
Here is function createInspector:
createInspector: function(cellView) {
var cell = cellView.model || cellView;
// No need to re-render inspector if the cellView didn't change.
if (!this.inspector || this.inspector.options.cell !== cell) {
// Is there an inspector that has not been removed yet.
// Note that an inspector can be also removed when the underlying cell is removed.
if (this.inspector && this.inspector.el.parentNode) {
this.inspectorClosedGroups[this.inspector.options.cell.id] = _.map(app.inspector.$('.group.closed'), function(g) {
return $(g).attr('data-name');
});
// Clean up the old inspector if there was one.
this.inspector.updateCell();
this.inspector.remove();
}
var inspectorDefs = InspectorDefs[cell.get('type')];
this.inspector = new joint.ui.Inspector({
inputs: inspectorDefs ? inspectorDefs.inputs : CommonInspectorInputs,
groups: inspectorDefs ? inspectorDefs.groups : CommonInspectorGroups,
cell: cell
});
this.initializeInspectorTooltips();
this.inspector.render();
$('.inspector-container').html(this.inspector.el);
if (this.inspectorClosedGroups[cell.id]) {
_.each(this.inspectorClosedGroups[cell.id], this.inspector.closeGroup, this.inspector);
} else {
this.inspector.$('.group:not(:first-child)').addClass('closed');
}
}
}
If you use joint.ui.Inspector.create('#path', inspectorProperties) any previous instance of the Inspector in a specific DOM element is removed and new one is created and rendered into the DOM automatically (it avoids creating a new instance of joint.ui.Inspector(), rendering it, adding the rendered result manually and removing the previous instance).
It also keeps track on open/closed groups and restore them based on the last used state.
Besides this, you may always have several different inspectorProperties objects previously defined when you are about to create() the inspector. So following the code you pasted, you could perform the tests you need first and then create the appropriate inspector:
if(cell instanceof joint.basic.Rect){
var customInputs = _.clone(CommonInspectorInputs);
// extend more inputs into `customInputs` from a variable previously defined
// OR modify the default rectangle's inspector directly, example:
customInputs.attrs.text = {
type: 'textarea',
label: 'Multiline text',
text: 'Type\nhere!',
group: joint.util.getByPath(CommonInspectorInputs.attrs, 'text/group', '/');
};
joint.ui.Inspector.create('.extra-inspector-container', {
cell: cell
inputs: customInputs,
groups: CommonInspectorGroups,
});
} // if only ONE inspector needs to be loaded add an ELSE block here
// and use '.inspector-container' in the `create()` above
// If `InspectorDefs` is a global variable with all the cells inspectors properties
// create and load the default inspector
joint.ui.Inspector.create('.inspector-container', _.extend({cell: cell},
InspectorDefs[cell.get('type')])
);

In Quilljs Editor, How to insert an undeletable block-level element?

Here I customize a block element by Quill.import('blots/block/embed') which I insert into the editor content. I would like to know that if there is any way to make it undeletable, therefore the user could not delete it or edit it? Thanks a lot.
I had a similar issue and the solution I came up with was to intercept the keyboard binding for backspace. In the example here I have a custom 'video' blot. So, if backspace is entered and the cursor is on or directly after a video, it does nothing. Here is the documentation for the Keyboard Module for reference: https://quilljs.com/docs/modules/keyboard/
let _this = this;
this.quill = new Quill(this.contentElement, {
modules: {
keyboard: {
bindings: {
video: {
key: 'backspace',
handler: function(range, keycontext) {
let format = _this.quill.getFormat(range.index - 1);
if (!format.video && !keycontext.format.video) {
// propogate to Quill's default
return true;
} // else do nothing to prevent deleting video
}
}
}
}
},
theme: 'snow'
});
Also, another thing to keep in mind, the editor has contenteditable="true", which your custom blot will inherit. So you'll probably want to set contenteditable="false" on the node in your custom blot.

selection not working on WinJS ListView in click mode

Below is my WinJS.UI.ListView definition. However, onselectionchanged is never called when right clicking or doing Ctrl+Click. I have setup my ListView identically to the samples(which work). Am I missing something? Or could something be interfering, just with the click selection?
this.m_listView = new WinJS.UI.ListView(this.domNode,
{
layout : {type: WinJS.UI.GridLayout},
itemTemplate : this.itemTemplate.bind(this),
selectionMode: 'multi',
tapBehavior: 'invokeOnly',
swipeBehavior: 'select'
});
this.m_listView.oniteminvoked = this.itemInvoked.bind(this);
this.m_listView.onselectionchanged = this.selectionChanged.bind(this);
EDIT: I Assign my datasource in a separate function with these lines
var itemList = new WinJS.Binding.List(this.m_nodes);
this.m_listView.itemDataSource = itemList.dataSource;
This ListView is wrapped in a javascript class. So my template function is a prototype of my EntriesList class. This is that function(I pulled out the real content for simplicity, I still have this issue with the content though):
EntriesList.prototype.itemTemplate = function(itemPromise)
{
return itemPromise.then
(
function (item)
{
var entry = document.createElement("div");
entry.className = "tile";
entry.style.height = "120px";
entry.style.width = "340px";
return entry;
}
);
The issue was something in our internal API was blocking pointer events. We were able to resolve the problem. The code/configuration in the question works.

Use Ckeditor like a simple input text

I need to use CKEDITOR ( http://ckeditor.com/ ) like a simple
<input type="text" />
I modified the file config.js adding the following settings:
config.toolbar = 'SimpleVersion';
config.toolbar_SimpleVersion =
[
['Cut','Copy','Paste','PasteText'],
];
Then, in the main page:
editor = CKEDITOR.replace("mydiv", { toolbar : 'SimpleVersion' });
editor.config.height = 50;
editor.config.removePlugins = 'resize';
editor.config.resize_enabled = false;
It works, but I need, if it's possible, to remove the bottom part where "body" is written, and also inhibit the new line whenever the Return button is pressed.
I think that for the last one, it may be possible to use a JQuery trigger.
Removing plugin works good. But on new line below code worked for me:
editor.on('key', function(e) {
var key = e.data.keyCode;
if(key==13){
e.cancel();
}
}
);
I found the solution:
1) when I create the editor there is a configuration option to toggle the bottom part of the editor
editor = CKEDITOR.replace("mydiv", { toolbar : 'SimpleVersion', removePlugins : 'elementspath' });
2) to inhibite the return button I've created the following trigger on key:
editor.on('key', function(e) {
var key = e.data.keyCode;
if(key==13){
return false;
}
}
);

ExtJS Change Event Listener failing to fire

I was asked to post this as a question on StackOverflow by http://twitter.com/jonathanjulian which was then retweeted by several other people. I already have an ugly solution, but am posting the original problem as requested.
So here's the back story. We have a massive database application that uses ExtJS exclusively for the client side view. We are using a GridPanel (Ext.grid.GridPanel) for the row view loaded from a remote store.
In each of our interfaces, we also have a FormPanel (Ext.form.FormPanel) displaying a form that allows a user to create or edit records from the GridPanel. The GridPanel columns are bound to the FormPanel form elements so that when a record is selected in the GridPanel, all of the values are populated in the form.
On each form, we have an input field for the table row ID (Primary Key) that is defined as such:
var editFormFields = [
{
fieldLabel: 'ID',
id: 'id_field',
name: 'id',
width: 100,
readOnly: true, // the user cannot change the ID, ever.
monitorValid: true
} /* other fields removed */
];
So, that is all fine and good. This works on all of our applications. When building a new interface, a requirement was made that we needed to use a third-party file storage API that provides an interface in the form of a small webpage that is loaded in an IFrame.
I placed the IFrame code inside of the html parameter of the FormPanel:
var editForm = new Ext.form.FormPanel({
html: '<div style="width:400px;"><iframe id="upload_iframe" src="no_upload.html" width="98%" height="300"></iframe></div>',
/* bunch of other parameters stripped for brevity */
});
So, whenever a user selects a record, I need to change the src attribute of the IFrame to the API URL of the service we are using. Something along the lines of http://uploadsite.com/upload?appname=whatever&id={$id_of_record_selected}
I initially went in to the id field (pasted above) and added a change listener.
var editFormFields = [
{
fieldLabel: 'ID',
id: 'id_field',
name: 'id',
width: 100,
readOnly: true, // the user cannot change the ID, ever.
monitorValid: true,
listeners: {
change: function(f,new_val) {
alert(new_val);
}
}
} /* other fields removed */
];
Nice and simple, except that it only worked when the user was focused on that form element. The rest of the time it failed to fire at all.
Frustrated that I was past a deadline and just needed it to work, I quickly implemented a decaying poller that checks the value. It's a horrible, ugly hack. But it works as expected.
I will paste my ugly dirty hack in an answer to this question.
"The GridPanel columns are bound to
the FormPanel form elements so that
when a record is selected in the
GridPanel, all of the values are
populated in the form."
As I understand it from the quote above, the rowclick event is what actually triggers the change to your form in the first place. To avoid polling, this could be the place to listen, and eventually raise to your custom change event.
Here is the ugly hack that I did to accomplish this problem:
var current_id_value = '';
var check_changes = function(offset) {
offset = offset || 100;
var id_value = document.getElementById('id_field').value || '';
if ( id_value && ( id_value != current_id_value ) ) {
current_id_value = id_value;
change_iframe(id_value);
} else {
offset = offset + 50;
if ( offset > 2500 ) {
offset = 2500;
}
setTimeout(function() { check_changes(offset); }, offset);
}
};
var change_iframe = function(id_value) {
if ( id_value ) {
document.getElementById('upload_iframe').src = 'http://api/upload.php?id=' + id_value;
} else {
document.getElementById('upload_iframe').src = 'no_upload.html';
}
setTimeout(function() { check_changes(100); }, 1500);
};
It's not pretty, but it works. All of the bosses are happy.
If you took a moment to read the source, you would see that the Ext.form.Field class only fires that change event in the onBlur function

Categories

Resources