How do I disable hotkeys in Dojo StackContainer - javascript

I am using Dojo 1.2 to implement some functionality on my customer's webpage. One of the widgets I use is the dijit.layout.TabContainer, which inherits StackContainer. The StackContainer subscribes on keyboard events and creates a few hotkeys, like arrow left to move one tab to the left and so on.
Now to the question: I would like to disable this hotkey feature in my TabContainer. Is there a configuration option I can set (can't find any in the API) to achieve this, or will have to hack the Dojo code or perhaps create my own versions of StackContainer and TabContainer in order to rid myself of the hotkeys? I would of course prefer not to mess with the Dojo code.
Best regards / Fredrik

Simply override _onKeyPress with an empty body:
<div dojoType='dijit.layout.TabContainer'>
<script type='dojo/method' event='_onKeyPress'></script>
...
<div>
Works like a charm.

I'm just coding off the cuff here, and I didn't test it out at all. I'm making this wikified, so post the correct source if there are any problems, please.
Use the following javascript within a file called com/stackoverflow/KeyPresslessTabContainer.js:
dojo.provide("com.stackoverflow. KeyPresslessTabContainer");
dojo.require("dijit.layout. TabContainer");
dojo.declare("com.stackoverflow.KeyPresslessTabContainer", dijit.layout. TabContainer, {
_controllerWidget: "com.stackoverflow.KeyPresslessTabController"
});
dojo.declare("com.stackoverflow.KeyPresslessTabController", dijit.layout.TabController, {
/*
* this is the important part. The original code was:
* templateString: "<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'></div>"
* In the template below, we remove the onkeypress listener,
* and thus key presses should be ignored.
*/
templateString: "<div wairole='tablist'></div>"
});

Related

Prototype not defined when accessing children on creation of custom-tag

__What I am trying todo____
Right now I am working with custom HTML5 tags. I am trying to create a tab-control element that is easy to set up. Todo this I create a parent element called 'tab-set' which works much like the 'ul' tag.
To insert tabs, you simply insert 'tab-element' tags (like 'li' tags). The tags can implement own behavior through custom prototypes which extend standardized element-prototypes such as the basic HTMLElement and are then registered with 'document.registerElement()'. At that point there are also opportunities to set callbacks that let you know whenever your element has been created or attached to something, which is what I use to do the necessary calculations on the placement of the individual tabs on the tab-control.
Let me say up-front that I've had trouble with this at first, then got it working, but upon rewriting the whole thing had troubles again for who knows why.
So, in the creation routine of the tab-set I iterate through all the child-tab-elements, calling their custom function 'setDimension', or atleast I am trying to. For some reason Chrome won't initialize the tab-element prototype (setDimension etc) before it has called both 'createdCallback' and 'attachedCallback' on my tab-set. This means that I can't call the child elements custom functions to set it's placement on creation of the tab-set.
Here you have some code samples of what I just described.
simple.html
...
<tab-set>
<tab-element>
<img>guybrush</img>
</tab-element>
<tab-element>
<img>le chuck</img>
</tab-element>
</tab-set>
...
tabs.js
...
tabSet = Object.create(HTMLDivElement.prototype);
tabSet.attachedCallback = function(){
for(/** calculations here **/)
listOfChildren[index].setDimensions(/** placement info **/);
//
// Chrome console: 'setDimensions' is not a function!
//
}
tabElement = Object.create(HTMLDivElement.prototype);
tabElement.setDimensions = function(/** placement info **/){
$(this).css(...);
}
document.registerElement('tab-set',tabSet);
document.registerElement('tab-element',tabElement);
...
The weird thing is that I have a working version of this, and yes, I have tried to emulate it's particular conditions such as for example loading the html-portion through jquery's .load() routine. But no matter what I do, I can not get this to work in my current script. What knowledge am I missing?
Thanks in advance for any help.
__ Solved __
All I had todo was add a link-tag inside the tab-set and have the tab-elements load it's containing style-class. I guess making the tab-elements have a css-class is somehow provoking Chrome to load their prototypes 'prematurely'.

jQuery Mobile "enhance" dynamically re-generated html

jQuery Mobile 1.2.0
I generate the HTML using JavaScript ($(selector).html(content)), add it to the DOM and then display it ($.mobile.changePage()).
Then I invoke an AJAX call, get some data, and re-generate the html (but the parent element, the same $(selector), stays the same, I just change its html(...)).
At this poing the HTML is not "enhanced" by jQM, no styling applied on it.
Now according to the docs I should simply call the page() function on the parent element, i.e $(selector).page().
Other places in the docs suggest triggering the create event, i.e $(selector).trigger("create").
The problem is that non of the above two methods works - the styling of jQM is not applied.
Looking at the code of jQM, I've tried triggering the pagecreate event on that element and it does work, but, this is not documented anywhere, so I'm uncertain of it, especially concerning future releases of jQM.
At some poing in the docs I've read that I can call page() on a page only once..
Anyway, is there any concise/standard way to tell jQM to "enhance" the whole element and its child-elements? Or should I simply stay with triggering the pagecreate event?
Thank you!
To recreate a whole page use this:
$(selector).trigger("pagecreate");
This was my answer to a simmilar question: https://stackoverflow.com/a/14011070/1848600. There's an example of page recreation. Take a look, this should probably solve your problem.
What is the scope of
$(selector).trigger("create");
You should be able to add any elements on the 'pagecreate' event which comes right before 'pageshow' jqm styling is applied to elements. For example I dynamically add a header/footer like this
$(document).on('pagecreate', "[data-role=page]", function() {
var header = "<div data-role='header'>some header stuff</div>";
var footer= "<div data-role='footer'>some footer stuff</div>";
$(this).prepend(header);
$(this).append(footer);
$("[data-role=header]").fixedtoolbar({tapToggle: false});
$("[data-role=footer]").fixedtoolbar({tapToggle: false});
});
Make sure you're using jquery 1.7 or above I think that's when the on method was introduced;
It sounds like you may be generating the DOM and then changing the page, try it the other way around go to the page first then dynamically edit the dom.
EDIT
set the reload page option to true
$.mobile.changePage($(page), {reloadPage: true});
Edit 2
$(selector).children().each(function(){
$(this).trigger('create');
})

jQuery call function when language in selectbox is changed

I have the following problem.
To translate a website, I'm using the jQuery Localize plugin.
This works fine. However, I want a CSS styled selectbox with flags and languages, and when a different option is selected the call to $("[data-localize]").localize("example", { language: $(this).attr('value') should be made to translate the page.
This code I'm currenly using, and it works fine for a plain, not-styled selectbox.
<script type="text/javascript">
$(function() {
$('#polyglot-language-options').change(function() {
if ($(this).attr('value') == "en") {
$("[data-localize]").localize("example", {
language: $(this).attr('value')
});
}
else if ($(this).attr('value') == "nl") {
location.reload();
}
});
});
</script>
But I want to style it, so I tried to integrate the "polyglot" language switcher. However, the current code doesn't work.
How can I integrate the $("[data.localize]").localize(); function in this code:
$('#polyglotLanguageSwitcher').polyglotLanguageSwitcher({
effect: 'fade'
});
This plugin (source code) does not follow the guidelines for jQuery plugin design. The bugs I found quickly:
It does not allow chaining, because it does not return this
It works only on one element at a time (does not use each())
It has a queer element hierarchy. It seems to require an element with an id, containing a form containing a select (as in the demo). In my opinion, such a plugin should be called on the language select element only.
It seems to navigate automatically, wanting to be configured with the page structure. Each of the li items in that fancy box contains a link to the respective page.
Therefore, it does neither trigger the form it live in or fire the change event you want to listen to.
As it stands, you can't use this particular plugin as you want to. If you want to fix all the bugs, I wish you a happy time :-) Nonetheless it might be possible to manipulate the plugin code, to let you register callbacks on select events (where you can invoke the localisation plugin). Otherwise, you will need to choose an other select plugin (or build one yourself from scratch, adapting the existing code)

Is it possible to create element on the fly with jQuery Mobile?

I have an app built using jQuery (and using various jQuery-UI tools).
For some reason, i have to port it to smartphones/tablet computer, and decided to use jQuery Mobile for that (in order to minimize the number of changes).
In my vanilla app, I created some elements of the page on the fly, depending of user interactions.
For example a slider could be created like that (p is an object with a bunch of params):
function createSlider(p){
return $("<div/>",{
"id":p.id,
"class":p.divClass,
}).slider({
"orientation": p.align,
"min":p.constraint.min,
"max":p.constraint.max,
"step":p.step,
"value":p.curVal,
"animate":"normal"
/*and some event handling here, but it doesn't matter*/
});
}
And it will produce a nice looking slider. Now it looks like:
function createSlider(p){
return $("<range/>",{
"id":p.id,
"class":p.divClass,
"min":p.constraint.min,
"max":p.constraint.max,
"step":p.step,
"value":p.curVal,
});
}
But as it's created on the fly, all the stuff done by jQuery Mobile on the page load isn't done on it.
Is there a way to force that initialization without writing the slider in the html?
Thanks.
EDIT: I found in the doc that it could be achieved using container.trigger("create");
However this does not work yet.
EDIT2: Ok create was the solution.
According to the documentation (see edit in the question), using trigger("create") on the containing element works.
And to make that work, you also need to remember that range is an input type and not a tag...
Working solution:
function createSlider(){
return $("<input/>",{
"type":"range",
"id":"sl",
"min":0,
"max":15,
"step":1,
"value":1,
});
}
function appendSlider(){
$("#yourdiv").append(createSlider()).trigger("create");
}
As a sidenote, the documentation for jQuery mobile lacks a search option.
Try calling .page() on the container the content is being added to. Alternatively, adding .page() to the content you're returning may also work.

Needing an ExtJS bug workaround

I have a web application that uses Ext-JS 2.2. In a certain component, we have an empty toolbar that we are trying to add a button to using
myPanel.getTopToolbar().insertButton(0, [...array of buttons...]);
However, in IE6/7 this fails because of lines 20241-20242 in ext-all-debug.js:
var td = document.createElement("td");
this.tr.insertBefore(td, this.tr.childNodes[index]);
Since "this.tr.childNodes([0])" does not yet exist in IE, this fails with "Invalid argument".
THE REAL QUESTION:
Can I, using CSS similar to the below add a child to every toolbar <tr> so that this.tr.childNodes[0] is found:
div.x-toolbar tr:after { content: " "; }
I totally realize this is a hack, but for legal reasons I cannot change any Javascript, not even to add an empty button ({}) to each toolbar. Major kudos to anyone that can figure this out.
What I've had to do in the past was include an empty toolbar in my element config:
tbar:[]
Then (and only after the element has completely rendered) use the .add() method for injecting buttons.
Order of events will get you every time. It takes a while to get a handle on it.
If all you are doing is adding to a empty panel
myPanel.getTopToolbar().add(buttons etc);
Or
myPanel.getTopToolbar().addButton(..);
Either should work. It looks like purpose of insertButton is for putting a button within a non-empty toolbar.
Did you look into adding the button after the panel has been rendered? Maybe something like:
myPanel.on('render', function() {
this.getTopToolbar().insertButton(0, [...array of buttons...]);
}, true);
I didn't think there was a CSS-only solution.
For the record, I ended up injecting javascript into the page that overrides the Ext.Toolbar prototype for the insertButton() function to check for the existance of "this.tr.childNodes([0])" and default to addButton() if it didn't exist.

Categories

Resources