Set default focus on first item in grid list - javascript

Once a grid is rendered how can I set focus to the first item. I am running into a problem where when the grid is updated (collection changes) then focus is lost for the entire application .
I am using the moonstone library.
{
kind: "ameba.DataGridList", name: "gridList", fit: true, spacing: 20, minWidth: 300, minHeight: 270, spotlight : 'container',
scrollerOptions:
{
kind: "moon.Scroller", vertical:"scroll", horizontal: "hidden", spotlightPagingControls: true
},
components: [
{kind : "custom.GridItemControl", spotlight: true}
]
}

hightlight() is a private method for Spotlight which only adds the spotlight class but does not do the rest of the Spotlight plumbing. spot() is the method you should be using which calls highlight() internally.
#ruben-ray-vreeken is correct that DataList defers rendering. The easiest way to spot the first control is to set initialFocusIndex provided by moon.DataListSpotlightSupport.
http://jsfiddle.net/dcw7rr7r/1/
enyo.kind({
name: 'ex.App',
classes: 'moon',
bindings: [
{from: ".collection", to: ".$.gridList.collection"}
],
components: [
{name: 'gridList', kind:"moon.DataGridList", classes: 'enyo-fit', initialFocusIndex: 0, components: [
{kind:"moon.CheckboxItem", bindings: [
{from:".model.text", to:".content"},
{from:".model.selected", to: ".checked", oneWay: false}
]}
]}
],
create: enyo.inherit(function (sup) {
return function () {
sup.apply(this, arguments);
// here, at least, the app starts in pointer mode so spotting the first control
// isn't apparent (though it would resume from that control upon 5-way action).
// Turning off pointer mode does the trick.
enyo.Spotlight.setPointerMode(false);
this.set("collection", new enyo.Collection(this.generateRecords()));
};
}),
generateRecords: function () {
var records = [],
idx = this.modelIndex || 0;
for (; records.length < 20; ++idx) {
var title = (idx % 8 === 0) ? " with long title" : "";
var subTitle = (idx % 8 === 0) ? "Lorem ipsum dolor sit amet" : "Subtitle";
records.push({
selected: false,
text: "Item " + idx + title,
subText: subTitle,
url: "http://placehold.it/300x300/" + Math.floor(Math.random()*0x1000000).toString(16) + "/ffffff&text=Image " + idx
});
}
// update our internal index so it will always generate unique values
this.modelIndex = idx;
return records;
},
});
new ex.App().renderInto(document.body);

Just guessing here as I don't use Moonstone, but the plain enyo.Datalist doesn't actually render its list content when the render method is called. Instead the actual rendering task is deferred and executed at a later point by the gridList's delegate.
You might want to dive into the code of the gridList's delegate and check out how it works. You could probably create a custom delegate (by extending the original) and highlight the first child in the reset and/or refresh methods:
enyo.Spotlight.highlight(this.$.gridList.childForIndex(0));

Ruben's answer adds on to my answer that I posted in the Enyo forums, which I'm including here for the sake of completeness:
Try using
enyo.Spotlight.highlight(this.$.gridList.childForIndex(0));
I added a rendered() function to the Moonstone DataGridList sample in the Sampler and I found that this works:
rendered: function() {
this.inherited(arguments);
this.startJob("waitforit", function() {
enyo.Spotlight.highlight(this.$.gridList.childForIndex(0));
}, 400);
},
It didn't work without the delay.

Related

Save slickgrid cell autocomplete value

I have a slickgrid cell with an autocompletion and a custom formatter. The cell value is a key field of dynamically loading autocompletion list. The list is shown as labels (e.g. Contract: ABCDEF-123, thick:10, width:210, City: Chicago) and when I select one it appears in the according input field. The point is that the formatter does not know that label, it only knows the key (order_id).
function contractFormatter(row, cell, value, columnDef, dataContext) {
var res = '';
var val = get_contract_list()[value] ? get_contract_list()[value]['label'] : '';
res = '<span class="' + getSpanClass() + '" style="float: left;"></span>\n\
'+ (val =='' ? '<span style="color:slategrey;"> Enter 3 symbols </span>' + val : val) + '';
return res;
}
The function get_contract_list returns the whole list of contracts and it is very big, so it was decided to make that list dynamic. So the function is empty now and it would be nice just to take the selected label into val.
Is there any way to achieve it?
You have to remember that Formatters are synchronous and it must return right away in a string format, if it requires a lot of processing power while staying synchronous then you'll end up slowing down your grid. You should probably cache your list once in a separate variable and use it afterward instead of reloading the list every time. If you load something that takes time and is asynchronous (a delayed output) then you'll want to look up the asyncPostRenderer (you can see this Example)
So going back to displaying the associated key to a label, I've done something similar in my lib in this Example and a live demo here, in my use case the value is a key index and I use the complexityLevelList to find its associated object which I can then read its label to display in the formatter.
export class MyExample {
complexityLevelList = [
{ value: 0, label: 'Very Simple' },
{ value: 1, label: 'Simple' },
{ value: 2, label: 'Straightforward' },
{ value: 3, label: 'Complex' },
{ value: 4, label: 'Very Complex' },
];
prepareGrid() {
this.columnDefinitions = [
{
id: 'complexity', name: 'Complexity', field: 'complexity', minWidth: 100,
formatter: (_row, _cell, value) => this.complexityLevelList[value].label,
filter: {
model: Filters.multipleSelect,
collection: this.complexityLevelList
},
editor: {
model: Editors.singleSelect,
collection: this.complexityLevelList,
massUpdate: true
},
},
];
}
}
Note that the Filters & Editors are specific to my lib Slickgrid-Universal, but you should get the idea on how to refactor your code to make it work.

Generating TinyMCE drop-down menu dynamically

I am trying to create toolbar button in TinyMCE with options that are derived from the array. I've followed the examples on Tiny's website and the button is getting generated as expected. Here is the code:
var mergeFields = {one: "first", two: "second", three: "third"};
tinymce.init({
selector: 'textarea',
menubar: false,
toolbar: 'mergefields',
setup: function (editor) {
editor.ui.registry.addMenuButton('mergefields', {
text: 'Merge Fields',
fetch: function (callback) {
var items = [];
for (var fieldName in mergeFields) {
var menuItem = {
type: 'menuitem',
text: mergeFields[fieldName],
onAction: function() {
// The problem: this function always inserts the last element of the array
// instead of the expected fieldName associated with this menuItem
editor.insertContent(fieldName);
},
};
items.push(menuItem);
}
callback(items);
},
});
}
});
<script src="https://cloud.tinymce.com/5/tinymce.min.js?apiKey=XXXXX"></script>
<textarea>Editor</textarea>
The problem happens when one of the options is selected and the anonymous function assigned to onAction property is executed -- it always inserts "three" into the document (presumably because after running through the whole array, fieldName is set to "three"). How can I make the onAction handler insert the right value into the document?
This needs to work in TinyMCE 5.
I've found a similar question here: Adding custom dropdown menu to tinyMCE and insert dynamic contents, but it was referring to TinyMCE 4 and unfortunately the provided answer does not work for TinyMCE 5.
Thanks for your help!
I had the same problem.
I solved it using value+onSetup
https://jsfiddle.net/stvakis/tjh7k20v/8/
var mergeFields = {
one: "first",
two: "second",
three: "third"
};
tinymce.init({
selector: 'textarea',
menubar: false,
toolbar: 'mergefields',
setup: function(editor) {
editor.ui.registry.addMenuButton('mergefields', {
text: 'Merge Fields',
fetch: function(callback) {
var items = [];
for (var fieldName in mergeFields) {
var menuItem = {
type: 'menuitem',
text: mergeFields[fieldName],
value:fieldName,
onSetup: function(buttonApi) {
var $this = this;
this.onAction = function() {
editor.insertContent($this.data.value);
};
},
};
items.push(menuItem);
}
callback(items);
},
});
}
});

Kendo scheduler custom view doesn't get the right class when selected

I am currently working on a kendo scheduler.
I was asked by my client to implement a 3-days view, which I successfully did, but there is one problem : that custom view does not get the "k-state-selected" class when it is selected, which means it can't be fully stylized.
I failed to find why that could be the case : none of the examples for creating a custom time view I found mentionned anything about defining the class the view takes when selected, and furthermore, it does get the "k-state-hover" class when hovered. Strange.
Here's the (I think) relevant JS :
var ThreeDayView = kendo.ui.MultiDayView.extend({
nextDate: function () {
return kendo.date.nextDay(this.startDate());
},
options: {
selectedDateFormat: "{0:D} - {1:D}"
},
name: "ThreeDayView",
calculateDateRange: function () {
//create a range of dates to be shown within the view
var start = this.options.date,
idx, length,
dates = [];
for (idx = 0, length = 3; idx < length; idx++) {
dates.push(start);
start = kendo.date.nextDay(start);
}
this._render(dates);
}
});
$("#scheduler").kendoScheduler({
date: new Date(), // The current date of the scheduler
showWorkHours: true,
height: 600,
views: [
"week",
{ type: ThreeDayView, title: "3 Jours", selected: false },
"day"
],
editable:
{
resize: true,
move: true,
template: $("#templateEdition").html()
},
dataSource: finalSource,
add: onAdd,
edit: onUpdate,
remove: onDelete,
save: onSaving
})
});
Does anyone have any idea why that might be ?
Thanks !
The type or the view should be a string - the name of the custom view - "ThreeDayView" (instead of ThreeDayView) in this case.

move item control bar videojs

I'm using the video.js 4.12 library and I want replace control bar items. For example, move one of my custom buttons to the 2nd slot of the control bar.
How do I change the order of items on the taskbar? I had no luck on Google.
Videojs place good class on elements. By this way you can identify control bar's elements.
To handle the item's order I used Jquery :
var createPrevButton = function() {
var props = {
className: 'vjs-control player-prev-button', //We use this class in Jquery
innerHTML: '<div class="vjs-control-content"></div>',
role: 'button',
'aria-live': 'polite',
tabIndex: 0
};
return videojs.Component.prototype.createEl(null, props);
};
var myPlayer = me.player = videojs(me.idVideo, {
plugins : { chapters : {} },
children: {
controlBar: {
children: [
{
name: 'playToggle'
},
{
name: 'currentTimeDisplay'
},
{
name: 'timeDivider'
},
{
name: 'durationDisplay'
}
/*
...........
*/
]
}
}
});
$(".player-prev-button").insertAfter(".vjs-play-control");
$(".player-next-button").insertAfter(".player-prev-button");
After the instanciation of my player just handle item by Jquery.
I think it's better than use CSS.
But the best way should be by videojs's option or somethink like that

Why is the button in my ExtJS grid appearing as "[object Object]"?

In an ExtJS grid I have a column in which when the content of a cell is a certain value, a button should be displayed.
I define the column which will contain the button like this, which calls a rendering function:
{
header: 'Payment Type',
width: 120,
sortable: true,
renderer: renderPaymentType,
dataIndex: 'paymentType'
}]
in the rendering function, I return either text or the button itself:
function renderPaymentType(val) {
if(val!='creditInform') {
return val;
} else {
return new Ext.Button({
text: val,
width: 50,
handler: function() {
alert('pressed');
}
});
}
}
This basically works, except that the button is displayed as the text [object Object]:
What do I have to do so that the button is displayed as a button instead of as text?
Addendum
adding .getEl():
function renderPaymentType(val) {
if(val!='creditInform') {
return val;
} else {
return new Ext.Button({
text: val,
width: 50,
handler: function() {
alert('pressed');
}
}).getEl();
}
}
produces a blank:
adding .getEl().parentNode.innerHTML:
function renderPaymentType(val) {
if(val!='creditInform') {
return val;
} else {
return new Ext.Button({
text: val,
width: 50,
handler: function() {
alert('pressed');
}
}).getEl().parentNode.innerHTML;
}
}
causes some kind of rendering problem with the rest of the code altough in Firebug I strangely don't get any errors:
Try
return new Ext.Button({
text: val,
width: 50,
handler: function() {
alert('pressed');
}
}).getEl();
Your returning a JavaScript object to your renderer rather then a dom node. If doesn't work then your renderer expects a HTML string so you can try
Ext.Button({ ... }).getEl().parentNode.innerHTML
Either should solve your problem.
This worked for me:
renderer: function (v, m, r) {
var id = Ext.id();
Ext.defer(function () {
Ext.widget('button', {
renderTo: id,
text: 'Edit: ' + r.get('name'),
width: 75,
handler: function () { Ext.Msg.alert('Info', r.get('name')) }
});
}, 50);
console.log(Ext.String.format('<div id="{0}"></div>', id));
return Ext.String.format('<div id="{0}"></div>', id);
}
Ref: http://ext4all.com/post/how-add-dynamic-button-in-grid-panel-column-using-renderer
When ever you see syntax of that nature, chances are you're looking at the output of the toString method on an object.
Which means you're displaying the object, and not a result.
console.log({
toString:function(){
return 'toString method.'
};
});
console.log(new Object())
Object.prototype.toString = function(){
return 'All object to string methods are now overriden.';
}
console.log(new Object());
the API documentation says this
renderer : Mixed For an alternative to
specifying a renderer see xtype
Optional. A renderer is an
'interceptor' method which can be used
transform data (value, appearance,
etc.) before it is rendered). This may
be specified in either of three ways:
A renderer function used to return
HTML markup for a cell given the
cell's data value.
A string which
references a property name of the
Ext.util.Format class which provides a
renderer function.
An object
specifying both the renderer function,
and its execution scope (this
reference) e.g.:
{
fn: this.gridRenderer,
scope: this
}
You're using the renderer function option, which means your function needs to return a html markup string, rather than a new Button object. To show a button, you might need to use the column's editor property

Categories

Resources