Set Kendo UI Window values globally - javascript

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"))
)

Related

Materialize dropdown options

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);
});

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.

calling a template helper function from inside a template event callback

I am very new to meteor and it is possible that I am going about this entirely incorrectly.
I have a simple template that represents a menu bar. When the user clicks an Icon, the menu is supposed to appear. When they click it again, it is supposed to disappear.
Here is the markup:
<template name="menu">
<div class="menu">
<div class="toggler">
<i class="fa fa-bars fa-3x"></i>
</div>
<div class="menu-body">
<!-- ... -->
</div>
</div>
</template>
Here is the JS that I have:
Template.menu.helpers({
self: Template.instance(),
menu_body: self.find('.menu-body'),
toggler: self.find('.toggler'),
currently_open: false,
open: function() {
menu_body.style.display = 'flex';
},
close: function() {
menu_body.style.display = 'none';
},
toggle: function() {
if(currently_open) close();
else open();
}
});
Template.menu.events({
'click .toggler': function(event, template) {
console.log(template);
template.toggle();
}
});
I thought the template instance would have access to the helper functions, but according to the log statement, this is what the template instance consists of:
B…e.TemplateInstance {view: B…e.View, data: null, firstNode: div.menu, lastNode: div.menu, _allSubsReadyDep: T…r.Dependency…}
_allSubsReady: false
_allSubsReadyDep: Tracker.Dependency
_subscriptionHandles: Object
data: null
firstNode: div.menu
lastNode: div.menu
view: Blaze.View
__proto__: Blaze.TemplateInstance
Can someone point me in the right direction here. Please feel free to be scrutinous if I am going about it wrong.
Helpers are for functional calls - not event driven works.
Meteor has an events handle that you can use to track events like clicks. Also you can use your css classes to define the styles nicely without programatically overwriting them.
Template.name.events({
'click .menuToggler': function(event, template) {
event.preventDefault();
var menu = template.find('.menu-body'); //(make this in ID!)
if($(menu).hasClass('menuOpen')) {
$(menu).removeClass('menuOpen');
//menu.style.display = 'none';
} else {
$(menu).addClass('menuOpen');
//menu.style.display = 'flex'; Use css to define these on the menuOpen class
}
});
Some things to note: This event handle assumes that your menu-body class is available under the template called "name" in my example. So you will want this event handler at the most top level template you have. It also assumes.
If you want to share state between the various components of your template (helpers, event callbacks etc) it should be done by setting properties directly on the template instances.
This can be done through the onCreated() callback
As per the documentation:
Callbacks added with this method [are] called before your template's logic
is evaluated for the first time. Inside a callback, this is the new
template instance object. Properties you set on this object will be
visible from the callbacks added with onRendered and onDestroyed
methods and from event handlers.
These callbacks fire once and are the first group of callbacks to
fire. Handling the created event is a useful way to set up values on
template instance that are read from template helpers using
Template.instance().
So, to provide a more relevant and concise example than the one in my original question.
Template.menu.onCreated(function() {
this.items = [
{title: 'Home', icon: 'home'},
{title: 'Profile', icon: 'user'},
{title: 'Work', icon: 'line-chart'},
{title: 'Contact', icon: 'phone'}
];
});
Template.menu.helpers({
items: function() {
var self = Template.instance();
return self.items;
}
});
Template.menu.events({
'click .toggler': function(event, template) {
console.log(template.items); //[Object,Object,Object,Object]
//do something with items
}
});
That's actually funny but I created a mini package that helps you do just that: https://atmospherejs.com/voidale/helpers-everywhere
But in your case it's not the right way of doing it. I can you see you want to add an display either flex or none it's better add CSS element like active that hold display: flex and add active or remove it on click like this: $('').addClass('active') or $().removeClass('active')
one liner can also work here: $('.menu-body').toggleClass('active')

jQuery custom plugin - setting private options for multiple instances

Hi folks!
I'm currently developing a client project where I saw myself doing the same javascript code over and over again. So I though it would be useful to wrap the logic inside a custom jQuery plugin. I've achieved it for a single instance of the plugin, but for multiple instances, I think I'm having a problem with the properties of each instance overwriting each other.
Well, let's get to the code! Here is the currently code that I have for the plugin:
// RESPONSIVE MENU ===========================//
// wrapper for a responsive menu plugin, //
// made by Favolla Comunicação //
//============================================//
/* INSTRUCTIONS
Apply the plugin on the main wrapper of the responsive menu. For example:
$(#menu).responsiveMenu($(#trigger));
The plugin just toggles the classes, leaving the effects and layout for the css
CONFIG
- trigger: the selector of the button that will activate the menu (required)
- activeClass: class name to be injectet when the toggle is activated (default: active)
- submenuTrigger: the selector of the buttons that will activate the submenus, if the menu will have another levels (default: $('sub-toggle'))
- submenu: the selector of the submenus (default: $('.submenu'))
- submenuActiveClass: class name to be injected on the submenus when they are activated (default: open)
- breakpoint: max window whidth where the plugin will work (default: 720)
- timeOut: time in milissegundos to limite the onResize repeat. (default: 100)
- moveCanvas: option to activate the "off canvas" pattern or not (just puts a class on the main elements of the page). (default: false)
- canvas: class name of the elements that build the "canvas" (default: null)
*/
;(function ( $, window, document, undefined ) {
$.fn.responsiveMenu = function(settings){
var config = {
'trigger': '',
'activeClass': 'active',
'submenuTrigger': $('.sub-toggle'),
'submenu': false,
'submenuActiveClass': 'open',
'breakpoint': 720,
'timeOut': 100,
'moveCanvas': false,
'canvas': '',
};
if (settings){$.extend(config, settings);}
// plugin variables
var mTrigger,
menu = $(this),
active = config.activeClass,
button = config.trigger,
bpoint = config.breakpoint,
submTrigger = config.submenuTrigger,
submenu = config.submenu,
submenuActive = config.submenuActiveClass;
canvasOn = config.moveCanvas;
canvas = config.canvas;
time = config.timeOut;
return this.each(function () {
if($(window).width() > bpoint){
mTrigger = false;
} else {
mTrigger = true;
}
onChange = function(){
clearTimeout(resizeTimer);
var resizeTimer = setTimeout(function(){
if($(window).width() > bpoint){
mTrigger = false;
menu.removeClass(active);
button.removeClass(active);
if(canvasOn){
canvas.removeClass(active);
}
} else {
mTrigger = true;
}
}, time);
}
$(window).bind('resize',onChange);
$(document).ready(onChange);
button.click(function(){
if(mTrigger) {
menu.toggleClass(active);
button.toggleClass(active);
if(canvasOn){
canvas.toggleClass(active);
}
}
});
if(submenu){
var submenuClass = '.' + submenu.prop('class');
// toggle for the submenus
submTrigger.click(function(){
if(mTrigger) {
if($(this).hasClass(active)){
submTrigger.removeClass(active);
submenu.removeClass(submenuActive);
} else {
submTrigger.removeClass(active);
$(this).addClass(active);
submenu.removeClass(submenuActive);
$(this).next(submenuClass).addClass(submenuActive);
}
}
});
}
});
}
})( jQuery, window, document );
And then, when I want to apply the plugin, I make like this:
$('#menu-wrapper').responsiveMenu({
trigger: $('#nav-toggle'),
submenu: $('.submenu'),
submenuTrigger: $('.submenu-toggle'),
moveCanvas: true,
canvas: $('.canvas'),
breakpoint: 862
});
$('#search').responsiveMenu({
trigger: $('#search-toggle'),
breakpoint: 862
});
The main issue here is when I set to instances of the responsiveMenu();, it seems like some options are overwriting. For example, the first instance set moveCanvas to true, and it works, but when I leave it blank for the second instance (which leaves the moveCanvas option set to false for this element, this options for the first instance don't work anymore.
I know that maybe I'm not following the jQuery plugin best pratices, and I even read something about the jQuery Boilerplate, which looks great, but I'm not an advanced javascript developer, so there a lot of things that I could do better, but I just don't now how to do.
Anyway, any help with this issue (and opinions about the plugin) will be very welcome!
var mTrigger,
menu = $(this),
active = config.activeClass,
button = config.trigger,
bpoint = config.breakpoint,
submTrigger = config.submenuTrigger,
submenu = config.submenu,
Until here you were doing correct.
submenuActive = config.submenuActiveClass;
canvasOn = config.moveCanvas;
canvas = config.canvas;
time = config.timeOut;
Then, you introduced a semicolon - which leads to the further assignments (canvasOn, canvas and time) not being part of the var statement any more. They're no variable declarations, you assign to global variables here - and that way you overwrite the settings of the first plugin instance.
Change every but the last semicolon to commata.
You need to encapsulate your settings in a class or closure and store them for each element the plugin is called on.
return this.each(function () {
...
$(this).data('some-key', settings);
...
});
If you'd like to learn about jQuery plugin authoring, they have an article on it here http://learn.jquery.com/plugins/basic-plugin-creation/

ExtJs: Tree: how download then select using AJAX calls?

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 !

Categories

Resources