CKEditor, initialize widget added with insertElement - javascript

I have some widgets created, they on initial startup they load fine, but i add more of this type of widget to the editor through:
ckeditorInstance.insertElement(
CKEDITOR.dom.element.createFromHtml('<html></html>'));
It inserts just fine, but the ckeditor does not recognize the element inserted as a widget, so the widget editable fields are not getting enabled like they should.
Is there any way to make ckeditor do a rescan of its content to initialize any new widgets that it has not already initialized?

Data formats
First of all - there's a separation for data format of a widget (how widget is represented in data) and internal format (how it is represented in editor). You may be familiar with the upcast and downcast functions - they make the transition between those formats (upcasting means transforming data format to internal format).
Upcasting and downcasting work only if data string is processed, but if you insert content using editor#insertElement there's no processing, so there's no upcasting.
Inserting
You've got two solutions:
Use editor#insertHtml instead of editor#insertElement. Your widget will be upcasted before insertion, so it will be inserted in a good format.
Take care of upcasting (if needed) yourself and use editor#insertElement.
Initializing
This was a first step of widget's life - it has to be inserted. Second is to be initialized.
There's a bug currently (it will be fixed in two weeks), that widgets inserted by the insertHtml method are not initialized. So, at this moment, after inserting widget with editor#insertHtml you need to call:
editor.widgets.checkWidgets()
If you use editor#insertElement you need to take care of initializing widget. To do that call:
editor.widgets.initOn( element, 'widgetName' )
In both scenarios initialize widget after inserting it.
Check out the Widgets API for more details.
See also my answer explaining how to know if an element is a widget and how to insert them into editor.

Related

Ext JS 4.2 primer

My company just bought a third party application which is based on the ext js 4.2. framework.
The software is closed source, but it is web based such that I can add a .js file to change the UI to my needs.
I want to add some controls to the rendered page. The software is showing IDs everywhere instead of text.
Example: "Issue created by: ID123". When I hover the field is get "ID123. John Doe". Ok, I am a JS ninja, so I can just add a field to the HTML DOM which will display "John Doe"in the correct spot.
I looked at the HTML code to get the correct control and see the the IDs are generated. The code I would write is prone to break with each new release of the third party software.
Now, since the is an Ext JS application I can probably solve the issue much more elegantly like adding a field not to the DOM directly but to the Ext JS container.
Question:
In Javascript I have a reference to the Ext JS app. How would I access the current view or viewmodel or model to query data and add a field?
Rough idea/Pseudo code:
var id = app.getCurrentModel.getValue("creatorID");
var name = myserver.getPersonData(id).name;
app.currentView.addLabelControl(name);
I googled a lot but all examples I found assumed that you are writing the ext js app and you are already in the controller or the view. But I only got the reference to the app.
Sorry for the newbie question :)
"App Inspector for Sencha"
For a quick glance over component hierarchy, you can use the Sencha browser plugin,
Find a certain ExtJS component programmatically
To quickly search ExtJS components or transform your findings into code, your main tool will be the browser console and the command Ext.ComponentQuery.query(xtype), e.g.
Ext.ComponentQuery.query("grid")
Ext.ComponentQuery.query("panel")
Ext.ComponentQuery.query("form")
You will then find in browser console an array of all components of that type. Select the right one, and check whether it has an id or itemId that is not auto-generated (everything like xtype-1234 is auto-generated). For form fields, the name attribute could be useful. Commands like
Ext.ComponentQuery.query("[itemId=ABC]")
Ext.ComponentQuery.query("[name=DEF]")
Ext.getCmp(id)
are far more readable and not as prone to side effects as Ext.ComponentQuery.query("panel")[12].
Most of the time, it can also be useful to think in tree structure. If you want a certain container which contains the only slider you see, trying
Ext.ComponentQuery.query("slider")
Ext.ComponentQuery.query("slider")[0].up()
could be easier than sifting through dozens or even hundreds of containers. Ways to traverse the component structure include up(xtype), down(xtype), nextSibling(xtype), previousSibling(xtype). If an xtype is provided, the next component of the corresponding xtype is selected; if it isn't provided, the next component is selected regardless of the type (e.g. direct parent, adjacent sibling).
Change anything you want.
You can extend, debug or modify any existing behaviour, including but not limited to ExtJS's own code, using a so-called override over any component, including the views or stores that make up this app. override makes a great search term for further information.
Or you can add new components to existing components, like a button to an existing form, from outside the app. For example, open sencha docs and then insert in console:
Ext.ComponentQuery.query("searchcontainer")[0].up().insert(1,{xtype:'button',text:'Test',handler:function(){Ext.Msg.alert('Test Button clicked');}});
You should then find a button on the top left, right of the Sencha logo. Click it.
Find existing controllers
For this, you have to find the name of the app namespace.
If it is e.g. MyApp, then MyApp.app.controllers.items contains the list of controllers. Controllers contain control logic, and the mapping between the components and the logic. When components are created, controllers attach their events to these new components. Many changes can and should be made in the component layer, because controller overrides are messy.
Find viewmodels
You're already done, ExtJS 4.2 does not support them.
Changing models
If you want to change models, be cautious: There is no supported function to add fields to a model. You can override the model prototype, and push more entries into the fields array. But if you have any model instances (records) already running around by that time, they are not updated and any existing warranty is voided.
That said, you find them in MyApp.model. You can e.g. get all fields of the Sencha Docs' Comment model using Docs.model.Comment.prototype.fields, or even push another field in.

Render dynamic UI with HTML versioning in Angular JS

I have a challenging requirement. The requirement is as follows.
We are designing a UI today with 10 UI elements.
Users are creating few records.
After a month, a new release comes and it has 12 UI elements on screen.
When the user creates new records, he should see 12 UI elements, when he opens an old record he should see 10 elements.
In order to achieve this, I thought, we could store the version with which the record was created and render the HTML belonging to that version. But, this will unnecessarily keep increasing the project size, as if the code gets 100 revisions, that much of HTML duplicates will be present.
I thought of using "switch-case" or "if-else" statements in front end, but it will slow the UI as too much heavy lifting is done by JS.
Please suggest a way to do this requirement with JS or jQuery or Angular. Any one framework is also fine, until it will work.
Thanks a lot for your responses in advance,
Look at a framework called angular-schema-forms. You write no HTML with this framework. Instead you pass it a JSON object that has the fields you want to display and their corresponding display as attributes. It comes preloaded with its own templates for all common controls and also allows you to write your own.

Calling ko.applyBindings on dynamic elements not working

I have a chat room style application and each entry is processed on the client once it is received and then some html is generated to display it. As certain messages will have tooltips and other bits of data embedded within them which use knockout bindings to display.
Now after looking over all the posts around this the answers to this problem seem to be:
Make sure all your elements exist up front but are empty
Call ko.applyBindings on the new elements when they are added
The first one is not feasible as you only create the elements as the chat comes in from the server, so the second option seems the only way to do it, however this would require calling for each chat message that comes in. A lot of people say that ko.applyBindings can incur significant overheads, however I think they mean if you were to call it upon all elements rather than just targeting specific ones.
Just so that everyone is on the same page, here is the basic snippet of the view around the area that matters:
<!-- ko foreach: {data: ChatRoom.Entries, afterRender: ChatEntryRendered } -->
<div class="entry-content" data-bind="html: ProcessedContent"></div>
<!-- /ko -->
Ignoring the bits around that, it will basically loop around each entry, add a div which will contain html which will contain bindings which need knockout goodness applied. So for example the ProcessedContent could look something like:
<span>Some content with a <span data-bind="tooltip: 'Some Content Here'">DYNAMIC</span> bit of <span class="special-text">Content</span></span>
So this above html would not currently be processed by the foreach as it is dynamically applied to the page, and before everyone starts freaking out about injecting html into the views, the server does not send down any markup, it just sends down a string with a load of tokens which the client converts into html. Also without muddying the waters too much, in this scenario the ChatRoom.Entries object is culled every now and again so it will fluctuate from 0-200 (usually 100-200) entries at any given time and the rest of the chat entries are cached in local storage, just so there are never more than about 150 bound Entries to the view at any given time.
Here is a jsfiddle showing the issue in a practical example.
http://jsfiddle.net/Mps4Q/8/
The main reason that the html binding doesn't bind the inserted html is because it can be unsafe. But if you know it's safe, you can use a custom binding that does bind the contents. Here's an example from another SO question: https://stackoverflow.com/a/17756777/1287183
Fiddle: http://jsfiddle.net/Mps4Q/9/

How to reload format-box in CKEDitor 4 dynamically?

I want to populate the format-box in CKEditor toolbar dynamically (depending on what the user selects in another select box).
Is it possible to change the options of the format-combo box dynamically , without reloading the whole CKEditor ?
The shortest answer is: no. However...
The plugin responsible for this box is the format plugin. It gathers all the data during the init function called when editor is being initialized. If you want to have this thing dynamically populated, you need to change some logic of this plugin on your own.
You might be interested in onRender callback for rich combos which is used by the plugin to dynamically change the value of the combo. Another handful thing might be add() method of rich combo used by format plugin. I'm pretty sure you got to extend the richcombo plugin to remove items.
Good luck anyway!

How to add custom field to dhtmlxScheduler?

I want to add multiple custom fields to the lightbox in dhtmlScheduler. I realize that this is a dup of a prior question but that answer is incomplete/incorrect.
My application correctly stores and recalls data from a MySQL database using dhtmlxDataProcessor on the client and dhtmlxConnector via PHP on the server side. I have carefully read, re-read, and parsed documentation on Custom "details" form. I've worked with the code in the 05_custom_editor.html sample.
The problem is that those examples do not work - they silently fail to store the second field, "Details", in the Description section. This is not surprising since nowhere is the field mapped to a database column.
What changes are needed so the "Details" field of the example form stored in the database and recalled with the event?
What changes are needed to support read-only data in the Details field that is populate based on the "Text" field? What I'm thinking of is a name that has an address associated with it.
How to invoke a custom windows with a form from the lightbox to populate the address?
I would prefer to be able to do this by extending the default lightbox, but that is not a requirement.
Any guidance is appreciated.
There are 3 required fields when using dhtmlScheduler. They are the first 3 in your PHP connector:
$scheduler->render_table("my_table","id","start_date,end_date,name,details,....
Your connector may use any column names as long as the order is preserved. But because it's required and used all over the place the dhtmlScheduler must refer to the name of the event. It is called "text".
The lightbox section maps description on to "text". I think that there is no
scheduler.locale.labels.section_description
for the same reason.
1) Update the PHP connector to pull in the required fields.
2) You can use sched.formSection('myfield') to get components from inside the lightbox, then you can add javascript to blur on focus.
3) Normal javascript
You can use one of the custom events alter any form items before you display the lightbox.
My dhtmlScheduler seems very vocal when it fails! What does the console say? Have you stepped through to see where it's failing?

Categories