How to show ui.combo popup manually? - javascript

I'm trying to open a popup of Webix combo control programmatically, but there are three issues I can't overcome.
Here's the snippet that represents them:
popup list spreads to the width of the form container (probably the current combo.$view is the wrong target to open a popup)
Only on initial state (I mean the popup wasn't opened yet by user actions)
the initial value is ignored
new value can't be selected from the opened popup
Here's the code of the combo and the button:
{
view:"combo",
inputWidth:350,
id:"mycombo",
value:1,
options:list_data
},
{
view:"button",
value:"show popup",
click:function(){
var combo = $$("mycombo");
var list = combo.getList();
list.show( combo.$view ); // probably wrong
}
}
Unfortunately, I can't figure out what I'm doing wrong (or is it possible at all). Thanks in advance.

Found it! list.show( combo.$view ) was really troublesome notation. In the following code
var combo = $$("mycombo");
var list = combo.getList();
list.show(combo.getInputNode());
show(combo.getInputNode()) resolves two of three problems. Still, I have no idea how to make the visual selection work initially, but for now, it's not a big deal.

Related

Proper Way Of Modifying Toolbar After Init in TinyMCE

I am extending a cloud-hosted LMS with javascript. Therefore, we can add javascript to the page, but cannot modify the vendor javascript for different components.
The LMS uses tinyMCE frequently. The goal is to add a new button on to the toolbar of each tinyMCE editor.
The problem is that since the tinyMCE modules are initialized in the vendor's untouchable code, we cannot modify the init() call. Therefore, we cannot add any text on to the "toolbar" property of the init() object.
So I accomplished this in a moderately hacky way:
tinyMCE.on('AddEditor', function(e){
e.editor.on('init', function(){
tinyMCE.ui.Factory.create({
type: 'button',
icon: 'icon'
}).on('click', function(){
// button pressing logic
})
.renderTo($(e.editor.editorContainer).find('.mce-container-body .mce-toolbar:last .mce-btn-group > div')[0])
});
});
So this works, but needless to say I am not totally comfortable having to look for such a specific location in the DOM like that to insert the button. Although this works, I do not believe it was the creator's intention for it to be used like this.
Is there a proper way to add the button to a toolbar, after initialization, if we cannot modify the initialization code?
I found a more elegant solution, but it still feels a bit like a hack. Here is what I got:
// get an instance of the editor
var editor=tinymce.activeEditor; //or tinymce.editors[0], or loop, whatever
//add a button to the editor buttons
editor.addButton('mysecondbutton', {
text: 'My second button',
icon: false,
onclick: function () {
editor.insertContent(' <b>It\'s my second button!</b> ');
}
});
//the button now becomes
var button=editor.buttons['mysecondbutton'];
//find the buttongroup in the toolbar found in the panel of the theme
var bg=editor.theme.panel.find('toolbar buttongroup')[0];
//without this, the buttons look weird after that
bg._lastRepaintRect=bg._layoutRect;
//append the button to the group
bg.append(button);
I feel like there should be something better than this, but I didn't find it.
Other notes:
the ugly _lastRepaintRect is needed because of the repaint
method, which makes the buttons look ugly regardless if you add new
controls or not
looked in the code, there is no way of adding new controls to the
toolbar without repainting and there is no way to get around it
without the ugly hack
append(b) is equivalent to add(b).renderNew()
you can use the following code to add the button without the hack, but you are shortcircuiting a lot of other stuff:
Code:
bg.add(button);
var buttonElement=bg.items().filter(function(i) { return i.settings.text==button.text; })[0];
var bgElement=bg.getEl('body');
buttonElement.renderTo(bgElement);

Loading delay extjs

I have a panel within which I have two more panels. When you click on panel1 then information in panel2 is loaded. Since the information is quite huge there is some delay when its being loaded. During this interim period I wish to add a loading mask which intimates the user that its getting loaded.
For the same I have done this:
var myMask = new Ext.LoadMask(Ext.getCmp('eventsPanel'), {
msg:"Please wait..."
});
myMask.show();
// eventsPanel is the main panel under which panel1 and panel2 lie.
// This code is in the selectionchange listener of panel1 whose code
// is inside the main eventsPanel code.
However, nothing is being displayed on the screen. Its still the same, i.e., for some amount of time the screen freezes and then after a delay of like 2-3 seconds the information is loaded. Can you please advise as to where am I going wrong?
I would suggest you to first show your masking like the way you are doing:
var myMask = new Ext.LoadMask(Ext.getCmp('eventsPanel'), {
msg:"Please wait..."
});
myMask.show();
Then make a delayed task
var task = new Ext.util.DelayedTask(function(){
//your loading panel2 with heavy data goes here
myMask.hide();
});
//start the task after 500 miliseconds
task.delay(500);
This should solve your problem.
I make a custom mask as follows:
var componentToMasK = Ext.ComponentQuery.query('#myChildComponent')[0];
var customMask = Ext.get(componentToMasK.getEl()).mask('My mask text...');
var task = new Ext.util.DelayedTask(function() {
customMask.fadeOut({
duration : 500,
remove:true
});
});
task.delay(1000);
Normally when a event is triggered in a first component, caused, for example, the loading of a grid in the second component, the mask appears in both components in order to avoid user errors by clicking on the first component as the second component is loading the grid or is loading the mask.
In this case:
var componentToMasK = Ext.ComponentQuery.query('#myParentComponent')[0]; //HBox, BBox layout, tab, etc. with the two child components
Hope this helps!
Edit: 10-06-2015
The 'duration:500' and the 'delay(1000)' is only to illustrate. You can adjust these values to the needs of each component that you apply a mask.
If you remove the mask abruptly the user can not even see
loading the message, that's why I use fadeOut.
Thus, you can apply a mask on virtually any component such as, for example, a fieldset, when you add it fields dynamically.
task -> http://docs.sencha.com/extjs/5.1/5.1.0-apidocs/#!/api/Ext.util.DelayedTask
Ex.get -> http://docs.sencha.com/extjs/5.1/5.1.0-apidocs/#!/api/Ext-method-get
fadeOut - > http://docs.sencha.com/extjs/5.1/5.1.0-apidocs/#!/api/Ext.dom.Element-method-fadeOut
You can also do the following:
var task = new Ext.util.DelayedTask(function() {
Ext.getBody().unmask();
});
task.delay(1000);
You can read more about this technique in the book: Mastering Ext JS - Second Edition (Loiane Groner)
Edit: 10-06-2015
One more detail:
If we apply one mask on a Hbox layout, containing as one of the childs a grid, we have two mask: HBOX mask and grid mask.
In these cases, I turn off dynamically the grid mask:
var grid = Ext.ComponentQuery.query('#griditemId')[0];
if(grid){
grid.getView().setLoading(false);
}
Hope this helps.

SharePoint 2013 List - Tooltip over Items

We have large SharePoint lists with lots of columns. Our users are forgetting which cells they are viewing because after scrolling the headers disappear (no way to freeze headers like in Excel).
We want to try adding tooltips to the cell items so when they hover over it will display a tooltip with the column name.
Has anyone ever tried doing this before?
I have the following code which works initially on the load but stops working after the user sorts, filters or switches the list into Edit mode:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script type="text/javascript">
jQuery(
function()
{
$('td').hover
(
function()
{
var idx = jQuery(this).parent().children().index(jQuery(this));
jQuery(this).attr('title',jQuery(this).parent().parent().parent().find('th').eq(idx).text());
jQuery('div.ms-core-brandingText').html(jQuery(this).parent().parent().parent().find('th').eq(idx).text());
}
)
}
);
</script>
Your code stops working because SharePoint reloads the list content. This is a common issue when adding client side scripts to SharePoint pages.
First, you should actually be able to render a view with frozen headers. Right, it doesn't come out of the box, but there are third party datatable tools available.
Another option is to include your code via the Client Side Rendering option. This is a broad topic, so probably the first step would be to google it.
Okay, getting closer, using CSR instead of just jQuery. This works but needs each field specified manually. Looking for a way to apply this to every field in the view.
<script type="text/javascript">
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
Templates: {
Fields: {
'Comments': {
'View': function (ctx) {
return String.format('<span title="{0}">{1}</span>', this.FieldTitle, ctx.CurrentItem.Comments);
}
},
'Name': {
'View': function (ctx) {
return String.format('<span title="{0}">{1}</span>', this.FieldTitle, ctx.CurrentItem.Name);
}
}
}
}
});
It occurs since when filtering/sorting is getting applied the List View is reloaded.
How to hover List Item in SharePoint 2013
The following function could be used for hovering List Item cells in SharePoint 2013:
function hoverListItems()
{
$('tr.ms-itmhover td').hover(
function() {
var $td = $(this);
var $th = $td.closest('table').find('th').eq($td.index());
$td.attr('title',$th.text());
}
);
}
Since in SharePoint 2013 Client-Side-Rendering (CSR) is the default rendering mode, the example below demonstrates how to register hoverListItem function using OnPostRender event
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
OnPostRender: function() {
hoverListItems();
}
});
Note: using the specified technique List Item hover will also work after
sorting/filtering is applied.
References
Introduction to Client-Side Rendering in SharePoint 2013
Tool-Tip Work-around:
The solution I have been using is a simple, non-html solution. I simply create a link to an item; insert it's own address (so that it doesn't go anywhere); then under the new LINK tab type the tip you want in the Description box.
save the page then try mousing over your new link, voilĂ 
Hope that helps some!

Prevent typeahead.js dropdown from closing on select

How can I prevent a typeahead dropdown from closing when an item is selected? I've tried using preventDefault like this:
$('#q').bind('typeahead:selected',function(obj, datum, name) {
...
obj.preventDefault();
});
But no success.
Edit:
I've managed to "fix" this by building Typeahead with lines 217-218 commented from typeahead_views.js:
byClick && utils.isMsie() ?
utils.defer(this.dropdownView.close) : this.dropdownView.close();
But there has to be another way without modifying source files?
Had the same problem and the (very easy) solution doesn't seem to be documented anywhere
$(document).on('typeahead:beforeclose', function(event, data) {
event.preventDefault()
})
(this just prevents the dropdown from closing at all which can be very helpful during development, use 'typeahead:beforeselect' if you want to prevent closing just on selet).
Trigger the focus of the input on the closed callback.
$('#typeahead-input').on('typeahead:closed', function(e, d) {
$('#typeahead-input').focus();
});
I'm working on typeahead inside tokenfield so the first part is me accessing the Typeahead.dropdown object, which in itself took some hunting.
Tried toying with isOpen or overwriting close functions, in the end closest I got was this. Breaking down the marshalling of events. You'd have to reimplement any saving of values etc, basically the first 3 lines of Typeahead.select.
I myself was blocked at being able to put a form (focus stays in input field) in the dropdown and still a bit more hunting if were to put something interactive in there. Think I'll go for a roll-your-own solution on this one but might help someone who just wants to block the closing, put the original function in a var to put it back in place when you're finished.
$('input[id="test"]').data('bs.tokenfield')
.$input.data('ttTypeahead').dropdown.trigger = function(e) {};
Also this has potential:
$('input[id="test"]').data('bs.tokenfield')
.$input.data('ttTypeahead').eventBus.trigger = function(e) {};
A simpler way:
input.data('tt-typeahead')._selectOld = input.data('tt-typeahead')._select
input.data('tt-typeahead')._select = function(datum) {
if (false)
this._selectOld(datum)
}

TinyMCE opened in jqueryUI modal dialog

When using tinyMCE in a jqueryUI modal dialog, I can't use the hyperlink or 'insert image' features.
Basically, after lots of searching, I've found this:
http://www.tinymce.com/develop/bugtracker_view.php?id=5917
The weird thing is that to me it seams less of a tinyMCE issue and more of a jqueryUI issue since the problem is not present when jqueryUI's modal property is set to false.
With a richer form I saw that what happens is that whenever the tinyMCE loses focus, the first element in the form gets focus even if it's not the one focused / clicked.
Does some JavaScript guru have any idea how I might be able to keep the dialog modal and make tinyMCE work?
This fixed it for me when overriding _allowInteraction would not:
$(document).on('focusin', function(e) {
if ($(event.target).closest(".mce-window").length) {
e.stopImmediatePropagation();
}
});
I can't really take credit for it. I got it from this thread on the TinyMCE forums.
(They have moved their bugtracker to github. tinymce/issues/703 is the corresponding github issue.)
It seems there are no propper solution for this issue yet. This is kind of a hack but it really worked for me.
Every time you open the Dialog remove the text area and re add it like following,
var myDialog = $('#myDialog');
var myTextarea = myDialog.find('textarea');
var clonedTextArea = myTextarea.clone(); // create a copy before deleting from the DOM
var myTextAreaParent = myTextarea.parent(); // get the parent to add the created copy later
myTextarea.remove(); // remove the textarea
myDialog.find('.mce-container').remove(); // remove existing mce control if exists
myTextAreaParent.append(clonedTextArea); // re-add the copy
myDialog.dialog({
open: function(e1,e2){
setTimeout(function () {
// Add your tinymce creation code here
},50);
}
});
myDialog.dialog('open');
This seems to fix it for me, or at least work around it (put it somewhere in your $(document).ready()):
$.widget('ui.dialog', $.ui.dialog, {
_allowInteraction: function(event) {
return ($('.mce-panel:visible').length > 0);
}
});

Categories