I stumbled about a strange circumstance.
We use dojo AMD Vers. 1.9. in which dojo.connect is replaced by dojo.on
So far all is okay. Now i want to connect an Eventlistener ( Checkbox is Selected) to the IndirectSelection-plugin of my EnhancedGrid. I search for a solution with dojo.on but just find dojo.connect?!
Is that correct? I mean dojo.connect is deprecated generaly in dojo 1.9?
This is the code i find in the dojo-side:
dojo.connect(grid.selection, 'onSelected'|'onDeselected', function(rowIndex){...})
Reference: http://dojotoolkit.org/reference-guide/1.9/dojox/grid/EnhancedGrid/plugins/IndirectSelection.html#usages
and here's my Code:
if(!registry.byId("GraphGrid")){
grid = new EnhancedGrid({
id: 'GraphGrid',
store: GraphicStore,
query: { ident: "*" },
structure: layout,
rowSelector: '20px',
keepSelection: false,
plugins: {
indirectSelection: {
headerSelector:false,
width:"40px",
styles:"text-align: center;"
}}
},"GridGraphicInMap");
/*Call startup() to render the grid*/
grid.startup();
grid.on("rowClick", function(evt){
var idx = evt.rowIndex,
item = this.getItem(idx);
// get a value out of the item
var value = this.store.getValue(item, "geom");
highlightGeometry(value,true);
});
dojo.connect(grid.selection, 'onSelected', getSelectedItems);
}
else {
setTimeout(function(){
grid.setStore(GraphicStore);
}, 1000);
}...
I tried to change it to dojo.on or grid.selection.on('Selected',getSelectedItems); but it doesn't work. Is in this special Case dojo.connect still the right way to connect?
The code above works fine, theres nothing wrong with it.
Regards, Miriam
You can use dojo.connect it wont affect event triggering.
And try using your connect in the following manner:
dojo.connect(grid, 'onSelected', getSelectedItems);
or
dojo.connect(grid, 'onselectionchanged', getSelectedItems);
Please let me know if any of these doesn't work.
Related
I want to use the options from here:
http://materializecss.com/dropdown.html#options (The docs don't say so much).
My app is a rails app that use the materialize gem with the asset
pipeline.
My code now looks like this:
ul#dropdown1.dropdown-content.z-depth-0
li
a Profile settings
li
a payments
a.dropdown-button.btn-large.btn-flat.waves-effect.menu_trigger href="#!" data-activates="dropdown1"
i.material-icons menu
javascript:
var elem = document.querySelector('.menu_trigger');
var instance = M.Dropdown.init(elem, {
coverTrigger: false,
constrainWidth: false,
});
In practice, using the data attribute isn't always the best way. Options can (or rather should be, correct me if I'm wrong) passed the following way:
// native javascript way
document.addEventListener('DOMContentLoaded', function() {
var dropdown1 = document.querySelector('.simple-dropdown');
var dropdownOptions = {
'closeOnClick': true,
'hover':true
}
var instanceDropdown1 = M.Dropdown.init(dropdown1, dropdownOptions);
});
// Initializing the jQuery way
$(".simple-dropdown").dropdown(
{
'closeOnClick': true,
'hover': true,
});
Solved!
Finally like it says here http://archives.materializecss.com/0.100.2/dropdown.html#options
Solved where it says:
To use these inline you have to add them as data attributes. If you
want more dynamic control, you can define them using the jQuery plugin
below.
So then, with something like this:
a.dropdown-button.btn-large.btn-flat.waves-effect href="#!" data-activates="dropdown1" data-beloworigin="true"
i.material-icons menu
Done what i wanted
Couldn't find directly in Materialize docs, but by trial and error I found this javscript code is working fine. It looks like an expected options variable should be an Object with property "dropdownOptions" with assigned another Object with properties listed in docs.
document.addEventListener('DOMContentLoaded', function () {
var options = {
dropdownOptions: {
alignment: 'right',
hover: true
}
}
var elems = document.querySelectorAll('.dropdown-trigger');
var instances = M.Dropdown.init(elems, options);
});
I'm working with a lot of Kendo UI windows. Is there some way to specify default values somehow globally? Or maybe a more realistic version, can I create some parent with predefined values and then just overwrite the values I need to change?
For example, I want the same error behavior and a modal parameter for all of the windows, so I would like to do something like:
$("#parentWindow").kendoWindow({
modal: true,
error: function () {
this.close();
new Notification().error();
}
});
And then use the parent window as a base for new windows:
$("#newWindow").kendoWindow({
title: "This window should have the options (modal and error) of the parentWindow",
}).??getTheRestOfTheValuesFromParent()??;
Or rewrite some parameter:
$("#newWindow2").kendoWindow({
modal: false,
title: "A window with overwritten modal parameter",
}).??getTheRestOfTheValuesFromParent()??;
Is it somehow possible to achieve this, is there any possibility of something like C# inheritance?
Maybe it's a stupid question, but I'm not so familiar with JS.
I highly encourage you to create your own wrapper code over all - or at least those more complex - kendo widgets. My team has been doing it for years in a project we use kendo for everything and we are having very positivelly results. The main purpose is what you need: a global behaviour. If after thousand windows coded over your project, you need to change them all, just change the wrapper. It's just a simple jQuery function:
$.fn.MyWindow = function(options) {
var $target = $(this);
var widget = {
_defaultOptions: {
actions: ["Minimize", "Maximize", "Close"],
visible: false,
width: 400,
height: 400,
modal: true
},
_options: options || {},
_target: $target,
_widget: null,
_init: function() {
this._manageOptions();
this._createWidget();
return this;
},
_manageOptions: function() {
// Here you can perform some validations like displaying an error when a parameter is missing or whatever
this._options = $.extend(this._options, this._defaultOptions);
},
_createWidget: function() {
this._widget = this._target.kendoWindow(this._options).data("kendoWindow");
// Create here some behaviours that the widget doesn't haves, like closing the window when user click the black overlay
if (this._options.closeOnOverlayClick) {
$('body').off('click', '.k-overlay').on('click', '.k-overlay', function() {
this._widget.close();
}.bind(this));
}
},
Show: function(center) {
if (center) {
this._widget.center();
}
this._widget.open();
}
};
return widget._init();
};
var wnd = $("#wnd").MyWindow({
title: "My first window",
closeOnOverlayClick: true // Your own parameter
});
// Now you work with your own functions:
wnd.Show(true);
Demo.
There are so many customizations, like your own events - some of those kendo's widgets doesn't haves - etc..
I will just add that there is an article(here) about creating custom Kendo widgets where you can find more information about the specifics of different scenarios that may be implemented.
Ι had a case like yours with kendo windows, kendo grids and kendo dropdownlists. For that I created HtmlHelpers for all my elements and called them when I needed to. Since you are using kendo asp.net-mvc I would recommend to look at this way.
public static WindowBuilder GlobalKendoWindow(this HtmlHelper helper)
{
return helper.Kendo().Window()
.Draggable()
.Animation(true)
.Visible(false)
.AutoFocus(true)
.Modal(true)
.Scrollable(true)
.HtmlAttributes(new { #class = "atn-modal-container" })
.Actions(actions => actions.Minimize().Close())
.Deferred();
}
and render it in my Html like this
#(Html.GlobalKendoWindow()
.Name("addCandidateDialog")
.Title(Html.GetResource(cps, "AddCandidateDialogTitle"))
.LoadContentFrom("AddCandidate", "Candidate")
.Events(events => events.Open("athena.addCandidacy.onAddCandidateOpen").Close("athena.addCandidacy.onAddCandidateClose"))
)
I have a TinyMCE 4.x instance where the text should be in read only mode. But I still have some buttons that I want to have enabled. For example, one button could provide a character count for the part of the text I've selected.
But when I turn on read only mode for TinyMCE all buttons are disabled. Can I enable just my buttons while still retaining read only mode?
It's probably too late for you but other people may pass by here.
I came up by writing this function
function enableTinyMceEditorPlugin(editorId, pluginName, commandName) {
var htmlEditorDiv = document.getElementById(editorId).previousSibling;
var editor = tinymce.get(editorId);
var buttonDiv = htmlEditorDiv.querySelectorAll('.mce-i-' + pluginName.toLowerCase())[0].parentElement.parentElement;
buttonDiv.className = buttonDiv.className.replace(' mce-disabled', '');
buttonDiv.removeAttribute('aria-disabled');
buttonDiv.firstChild.onclick = function () {
editor.execCommand(commandName);
};
}
It does the trick in 2 steps:
make the button clickable (remove mce-disabled CSS class and remove the aria-disabled property)
assign the good command to the click event
And in my editor init event I call the function.
editor.on('init', function () {
if (readOnly) {
editor.setMode('readonly');
enableTinyMceEditorPlugin(htmlEditorId, 'preview', 'mcePreview');
enableTinyMceEditorPlugin(htmlEditorId, 'code', 'mceCodeEditor');
}
});
Current version of TinyMCE for which I wrote this code is 4.4.3. It may break in a future version, specifically about the selectors to get and modify the good HTML elements.
Command identifiers can be found at this page otherwise you can also find them under tinymce\plugins\PluginName\plugin(.min).js
Here is a simple way to enable your custom toolbar button and attach a click event handler inside a read only TinyMCE editor using JQUERY:
//Initialize read only Tinymce editor so that Lock button is also disabled
function initReadOnlyTinyMCE() {
tinymce.init({
selector: '#main'
, toolbar: 'myLockButton'
, body_class: 'main-div'
, content_css: 'stylesheets/index.css'
, readonly: true
, setup: function (readOnlyMain) {
readOnlyMain.addButton('myLockButton', { //Lock button is disabled because readonly is set to true
image: 'images/lock.png'
, tooltip: 'Lock Editor'
});
}
});
}
function displayReadOnlyTinyMCEwithLockButtonEnabled() {
var edContent = $('main').html();
$("#main").empty();
initReadOnlyTinyMCE(true);
tinyMCE.activeEditor.setContent(edContent);
//enable the lock button and attach a click event handler
$('[aria-label="Lock Editor"]').removeClass("mce-disabled");
$('[aria-label="Lock Editor"]').removeAttr("aria-disabled");
$('[aria-label="Lock Editor"]').attr("onclick", "LockEditor()");
}
function LockEditor() {
alert("Tiny mce editor is locked by the current user!!");
//Write your logic to lock the editor...
}
I couldn't find an easy way to do this. The simplest way is to remove the contenteditable attribute from the iframe body instead and substitute a read only toolbar set. It also means that people will still be able to copy content from the editor.
$("iframe").contents().find("body").removeAttr("contenteditable");
How about this :
editor.addButton('yourButton', {
title: 'One can Enable/disable TinyMCE',
text: "Disable",
onclick: function (ee) {
editor.setMode('readonly');
if($(ee.target).text() == "Disable"){
var theEle = $(ee.target).toggle();
var edit = editor;
var newBut = "<input type='button' style='opacity:1;color:white; background-color:orange;' value='Enable'/>";
$(newBut).prependTo($(theEle).closest("div")).click(function(e){
edit.setMode('design');
$(e.target).remove();
$(theEle).toggle();
});
}
}
});
You can try to run the code below:
$("#tinymce").contentEditable="false";
if you have more than one editors, you can use their id like below
$("#tinymce[data-id='idOfTheEditor']").contentEditable="false";
I'd like to have multiple instances of CKEditor based on the same config settings, but with different heights. I tried setting up config with the default height, setting up the 1st instance, then overriding the height & setting up the 2nd instance:
var config = {
.....
height:'400'
};
$('#editor1').ckeditor(config);
config.height = '100';
$('#editor2').ckeditor(config);
...but I get two CKEditor instances that both have 100px height.
I also tried this:
CKEDITOR.replace('editor2',{
height: '100'
});
.. I got error messages that the instance already existed. I searched around a bit & found someone in a similar situation got advice that you have to destroy() the instance before replace(), but that seems too complicated for just setting a different initial height.
In the end I set up two different configs & copied over the toolbar_Full property:
var config1 = {
height:'400',
startupOutlineBlocks:true,
scayt_autoStartup:true,
toolbar_Full:[
{ name: 'clipboard', items : [ 'Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo' ] },
{ name: 'editing', items : [ 'Find','Replace','-' ] },
{ name: 'basicstyles', items : [ 'Bold','Italic','Underline','Strike','Subscript','Superscript','-','RemoveFormat' ] },
{ name: 'paragraph', items : [ 'NumberedList','BulletedList','-','Outdent','Indent','-','Blockquote','-','JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock','-','BidiLtr','BidiRtl' ] },
'/',
{ name: 'links', items : [ 'Link','Unlink','Anchor' ] },
{ name: 'insert', items : [ 'Image','HorizontalRule' ] },
{ name: 'styles', items : [ 'Styles','Format','Font','FontSize' ] },
{ name: 'colors', items : [ 'TextColor','BGColor' ] },
{ name: 'tools', items : [ 'Maximize', 'ShowBlocks' ] },
{ name: 'document', items : [ 'Source' ] }
]
}
var config2 = {
height:'100',
startupOutlineBlocks:true,
scayt_autoStartup:true
};
config2.toolbar_Full = config1.toolbar_Full;
$('#editor1').ckeditor(config1);
$('#editor2').ckeditor(config2);
Is there a better way? Anything I'm missing? There's this question but they didn't post quite enough to be useful, & this very similar question hasn't been answered. Thanks!
Update:
This seems to be a timing/config handling quirk of CKEditor -- the config is read & applied later (I'm guessing after the editor's DOM framework has been set up) rather than when the editor is first instantiated.
So, any changes to the config settings made immediately after the 1st editor is instantiated with .ckeditor() are actually applied by the editor at some point in the following several milliseconds. I'd argue this isn't normal behavior, or logical.
For instance, you can get the expected behavior in my first example (overriding the config.height property after the first editor has been instantiated) to work by delaying the 2nd CKEditor instance with setTimeout(). Firefox needed ~100ms, IE needed 1ms. Wacky & wrong.
CKEditor should read the config settings when each editor is first instantiated. For now, everyone has to work around that quirk.
The easiest way to initialize two editors with custom heights is:
$('#editor1').ckeditor({ height: 100 });
$('#editor2').ckeditor({ height: 200 });
or without jQuery:
CKEDITOR.replace('editor1', { height: 100 });
CKEDITOR.replace('editor2', { height: 200 });
AFAIK it isn't possible to change editor's height on the fly.
If these methods weren't working for you, then you were doing sth else wrong.
Update:
Answering to your comment - your question in fact wasn't about CKEditor, but rather about sharing one object with only two different properties. So you can try like this:
var configShared = {
startupOutlineBlocks:true,
scayt_autoStartup:true,
// etc.
},
config1 = CKEDITOR.tools.prototypedCopy(configShared),
config2 = CKEDITOR.tools.prototypedCopy(configShared);
config1.height = 100;
config2.height = 200;
CKEDITOR.replace('editor1', config1);
CKEDITOR.replace('editor2', config2);
CKEDITOR.tools.prototypedCopy is a tool that creates new object with prototype set to the passed one. So they share all properties except of these you override later.
Update 2:
This is the update for the "Update" section in the question :).
There's no quirk in CKEditor's timing or bug or whatsoever - it's pure JavaScript and how BOM/DOM and browsers work plus some practical approach.
First thing - 90% of BOM/DOM is synchronous, but there are a couple of things that aren't. Because of this entire editor has to have asynchronous nature. That's why it provides so many events.
Second thing - in JS object are passed by reference and as we want CKEditor to initialize very quickly we should avoid unnecessary tasks. One of these is copying config object (without good reason). So to save some msecs (and because of async plugins loading too) CKEditor extends passed config object only by setting its prototype to object containing default options.
Summarizing - I know that this may look like a bug, but it's how JS/BOM/DOM libs work. I'm pretty sure that many other libs' async methods are affected by the same issue.
Add this you will get the different toolbar for both CKeditor in single page
<script>
CKEDITOR.on('instanceCreated', function (event) {
var editor = event.editor,
element = editor.element;
if (element.is('h1', 'h2', 'h3') || element.getAttribute('id') == 'editorTitle') {
editor.on('configLoaded', function () {
// Remove unnecessary plugins to make the editor simpler.
editor.config.removePlugins = 'find,flash,' +
'forms,iframe,image,newpage,removeformat,' +
'smiley,specialchar,stylescombo,templates';
// Rearrange the layout of the toolbar.
editor.config.toolbarGroups = [
{ name: 'editing', groups: ['basicstyles'] },
{ name: 'undo' },
//{ name: 'clipboard', groups: ['selection', 'clipboard'] },
{ name: 'styles' },
{ name: 'colors' },
{ name: 'tools' }
// { name: 'about' }
];
});
}
});
</script>
Solution above from Reinmar is working for me, however I decided to give 1 more solution that i used before this one.
It's really simple, all you need to know is that ckeditor create content div element for every instance with almost the same id, only difference is incremental value. So if you have 2,3,4.. instances only difference will be ordinal number. Code is here:
CKEDITOR.on('instanceReady', function(){
$('#cke_1_contents').css('height','200px');
});
This event will be activated for every instance you have, so if you want to set height for all instances you could create global variable and use it like x in #cke_"+x+"contents, every time event is activated increase x for 1, check which instance in row is with simple if and then set height.
var x=1;
CKEDITOR.on('instanceReady', function(){
if(x==1) h='200px';
else if(x==2)h='400px';
else if(x==3)h='700px';
$('#cke_'+x+'_contents').css('height',h);
x++;
});
This is not best solution but it is working, problem is you actually see content div resizing.
Update 25 Jun 2019.
Please Use this code to add multiple CKEditor instances with custom height for each one. Easiest way ever.
<textarea name="editor1" style="height:30px;" class="ckeditor"></textarea>
<script type="text/javascript">
CKEDITOR.replace( 'editor1' );
CKEDITOR.add
</script>
<textarea name="editor2" style="height:40px;" class="ckeditor"></textarea>
<script type="text/javascript">
CKEDITOR.replace( 'editor2' );
CKEDITOR.add
</script>
<textarea name="editor3" style="height:50px;" class="ckeditor"></textarea>
<script type="text/javascript">
CKEDITOR.replace( 'editor3' );
CKEDITOR.add
</script>
<textarea name="editor4" style="height:60px;" class="ckeditor"></textarea>
<script type="text/javascript">
CKEDITOR.replace( 'editor4' );
CKEDITOR.add
</script>
<textarea name="editor5" style="height:70px;" class="ckeditor"></textarea>
<script type="text/javascript">
CKEDITOR.replace( 'editor5' );
CKEDITOR.add
</script>
Ref: Here
If you add the ckeditor.js to page more than once too, it may cause that problem.
The script code must be defined once in every page.
<script type="text/javascript" src="Fck342/ckeditor.js"></script>
just use CKEDITOR.replaceAll();
Here's my goal :
- open a tree
- download the root nodes
- expand automatically one specific node using AJAX (and loop n times here) until i find a leaf then select the leaf
Here's the function that works when I declare the Tree :
listeners: {
load: function(n) {
console.log('load(n)');
n.eachChild(
function(n) {
if ((n.id=='lys/2007') ||
(n.id=='lys/2007/08') ||
(n.id=='lys/2007/08/29')) {
n.expand(false,false);
}
});
}
}
But if I don't know how to make it more "generic" (almost exactly like the ExtJs documentation). But they don't jump automatically to a specific node (i.e. I want no user interaction).
Any idea / advice how to do this?
Don't hesitate to edit my post to make it proper English :)
If you already have a handle to your node, use node.getPath() to get the full "path" of it, and then use selectPath to "select" it programatically.
tree.selectPath(node.getPath());
Since you seem to know the exact path, you can probably just call selectPath on the tree.
tree.selectPath('lys/2007/08/29'); //adjust to match node.getPath() format
Thanks for the answer.
Here's the code that works : I moved it outside, into the TreeLoader object, this way :
var lysTreeLoader = new Ext.tree.TreeLoader({
dataUrl: 'json/lys.php',
listeners: {
load: function(loader,n,response) {
console.log('Données chargées');
n.eachChild(
function(n) {
if ((n.id=='lys/2007') ||
(n.id=='lys/2007/08') ||
(n.id=='lys/2007/08/29')) {
n.expand(false,false);
}
if (n.id=='lys/2007/08/29/21_14_04') {
n.select();
console.log(n.id);
console.log(n.getPath());
}
});
}
}
});
Then in the tree declaration, declare the lysTreeLoader :
...blabla...
id: 'treepanel-labys',
xtype: 'treepanel',
width: 400,
autoScroll: true,
split: true,
// use a TreeLoader :
loader: lysTreeLoader,
...blabla...
And I just had to use the function select(); (which didn't work as expected in my question)
Thanks again !