ACE change key binding conditionally - javascript

If the user presses the down key while a custom popup is displayed, I would like this down event to be cancelled from the editor and handled manually.
However, if the popup is disactivated, the 'down' key should perform as usual.
For that, I wrote this:
editor.commands.addCommand({
name: 'nav_down.',
bindKey: {win: 'Down', mac: 'Down'},
exec: function(editor) {
if(myPopupIsOpen()) {
// Do whatever I want with the popup.
return false;
} else {
// just leave the key.
return true;
}
readOnly: true
});
Unfortunately, I can return false or true, the result is the same, it always capture the down event, which is annoying. How can I prevent that?
I already tried the following:
Add a key binding to the DOM. But after that, the interaction always happen (i.e. I cannot capture it).
Return false or true as suggested for common events but this does not work here.
EDIT
The solution from #a user works very well.
Instead of the above command, I wrote:
var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
keyboardHandler = new HashHandler();
keyboardHandler.addCommand({
name: 'nav_down.',
bindKey: {win: 'Down', mac: 'Down'},
exec: function(editor) {
if(myPopupIsOpen()) {
// Do whatever I want with the popup.
return true; // CHANGE HERE ! true is when it capture it.
} else {
// just leave the key.
return false; // CHANGE HERE ! false is when I don't capture it.
}
readOnly: true
});
editor.keyBinding.addKeyboardHandler(keyboardHandler);

In the current version ace only keeps one command for each key so your addCommand call removes default binding for down.
You can add new keyboard handler similar to what autocompletion does https://github.com/ajaxorg/ace/blob/v1.1.3/lib/ace/autocomplete.js#L221
var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
keyboardHandler = new HashHandler();
keyboardHandler.addCommand(/*add your command with return false*/)
editor.keyBinding.addKeyboardHandler(keyboardHandler);

Related

CKEDITOR: Disable plugin button when text is not highlighted

I have a CKEDITOR plugin that I'm having trouble disabling when there is no selected copy in the editor. Right now, the user can click the button without any highlighted text in the editor. I would like to modify it so that the plugin button is only active when there is copy highlighted in the editor. I've followed the suggestion here, but it isn't working.
Main Plugin Code:
CKEDITOR.plugins.add('cta', {
icons: 'cta',
init: function (editor) {
// Funciton depending on editor selection (taken from the scope) will set the state of our command.
function RefreshState() {
console.log('RefreshState');
var editable = editor.editable(),
// Command that we want to control.
command = editor.getCommand('source'),
range,
commandState;
if (!editable) {
// It might be a case that editable is not yet ready.
console.log("editable not ready yet");
return;
}
// We assume only one range.
range = editable.getDocument().getSelection().getRanges()[0];
console.log(`range: `);
console.log(range);
// The state we're about to set for the command.
commandState = (range && !range.collapsed) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;
console.log('commandState');
console.log(commandState);
command.setState(commandState);
}
// We'll use throttled function calls, because this event can be fired very, very frequently.
var throttledFunction = CKEDITOR.tools.eventsBuffer(250, RefreshState);
// Now this is the event that detects all the selection changes.
editor.on('selectionCheck', throttledFunction.input);
// You'll most likely also want to execute this function as soon as editor is ready.
editor.on('instanceReady', function (evt) {
// Also do state refresh on instanceReady.
RefreshState();
});
editor.addCommand('ctabtn', new CKEDITOR.dialogCommand('ctaDialog'));
editor.ui.addButton('cta', {
label: 'Insert Call to Action button',
command: 'ctabtn',
toolbar: 'insert'
});
CKEDITOR.dialog.add('ctaDialog', this.path + 'dialogs/cta.js');
}
});
My dialog code is here:
CKEDITOR.dialog.add('ctaDialog', function (editor) {
return {
// Basic properties of the dialog window: title, minimum size.
title: 'Call to Action',
minWidth: 400,
minHeight: 200,
// Dialog window content definition.
contents: [{
// Definition of the Basic Settings dialog tab (page).
id: 'tab-basic',
label: 'Basic Settings',
// The tab content.
elements: [{
// Text input field for the Call to Action text.
type: 'text',
id: 'cta',
label: 'Call to Action',
// Validation checking whether the field is not empty.
validate: CKEDITOR.dialog.validate.notEmpty("Call to Action field cannot be empty.")
},
{
// Text input field for the link text.
type: 'text',
id: 'url',
label: 'URL',
// Validation checking whether the field is not empty.
validate: CKEDITOR.dialog.validate.notEmpty("URL field cannot be empty.")
}
]
}],
// method invoked when the dialog button is clicked
onShow: function () {
var element = editor.getSelection();
var link = CKEDITOR.plugins.link;
var _this = this.getParentEditor();
var CTAhref = link.getSelectedLink(_this);
this.setValueOf('tab-basic', 'cta', element.getSelectedText().toString());
if (CTAhref != '' && CTAhref !== null) {
this.setValueOf('tab-basic', 'url', CTAhref.$.href);
}
},
// This method is invoked once a user clicks the OK button, confirming the dialog.
onOk: function () {
var dialog = this;
var CTA = editor.document.createElement('a');
CTA.setAttribute('href', dialog.getValueOf('tab-basic', 'url'));
CTA.setAttribute('class', 'btn btn-special--lg');
CTA.setText(dialog.getValueOf('tab-basic', 'cta'));
editor.insertElement(CTA);
}
};
});
Any ideas on why the plugin icon button on the toolbar doesn't become inactive when there is no copy highlighted in the editor? I can see in the console that CKEDITOR.dom.range.collapsed is toggling between TRUE/FALSE depending upon whether text is highlighted or not. It's just not disabling the button.
As stated, the suggested way of handling this was not working for me. What was working was using range.collapsed in returning a true value if a selection was made in the editor. With that, I turned to using Jquery to handle the rest.
// Hacky. But it gets the job done.
// a.cke_button.cke_button__cta.cke_button_off is the selector for my toolbar button.
// The onclick function listed was pulled from looking at the CKeditor functions
// to initiate my plugins modal.
// The setting of the "onclick" prop to null is needed to override the modal onclick
// binding when there is no selection.
range = editable.getDocument().getSelection().getRanges()[0];
if (range.collapsed === false) {
$('a.cke_button.cke_button__cta.cke_button_off').attr("onclick", 'CKEDITOR.tools.callFunction(83,this);return false;');
$('a.cke_button__cta').toggleClass('cta_button_disabled');
} else {
$('a.cke_button.cke_button__cta.cke_button_off').prop("onclick", null);
}

Toggle button with panel in Firefox extension with Mozilla SDK

I am developing a firefox extension with the Mozilla SDK. The situation is:
I want a toggle/action button to show/hide the extension's panel.
My code:
// the panel
let panel = require("sdk/panel").Panel({
// ...
onHide: handleHide
});
// the button
let button = ToggleButton({
// ...
// will be executed, when user clicks the button
onChange: handleChange
});
// event handlers
function handleChange(state) {
// state.checked is always true
if (???) {
panel.show();
}
}
function handleHide() {
// un-check the button
button.state('window', {checked: false});
}
The problem is, that inside of handleChange, where the toggling logic should be, i can't tell if the panel is supposed to show or hide. In the docs theres an example which uses state.checked, but since this code is run while i am clicking on the button, the state.checked is always true. In the end, the toggling does not work this way, because the panel never gets hidden when clicking the "toggle"-button.
help much appreaciated, i already tried so many things.. mothings works.
thanks in advance!
simply use console.log to see what's inside the state:
{
"disabled": false,
"checked": false,
"label": "the default label",
"icon": "./icon.png",
"id": "show-panel"
}
so we can go on like this:
if(state.checked)
{
myExt.show();
return false;
} else {
myExt.hide();
return false;
}
in older versions you need to return false.

JavaScript multipage form onbeforeunload issue

I am putting together a quiz system using the multipage form jQuery script and I would like to be able to warn the user if tries to close the page. I managed to do this just fine using the code below:
$(document).ready(function($) {
window.onbeforeunload = function(){
return 'Sure you want to close the page?';
};
});
My problem is that when I try to submit the form and post the results I get the warning asking me if I want to navigate away from this page. This is the code:
$('#quizForm').formwizard({
validationEnabled: true,
focusFirstInput : true,
formOptions: {
beforeSubmit: window.onbeforeunload = null,
resetForm: true
}
});
What am I doing wrong?
LE: I created this fiddle maybe someone can help me out, I am running out of ideas.
http://jsfiddle.net/awLYY/5/
first, you don't need to wait for the DOM to be ready in order to attach an onbeforeunload handler.
second, since the onbeforeunload is a function, you can choose wither to return a string or return nothing in case you're submitting some data to the server
var isFormBeingSubmitted = false;
window.onbeforeunload = function() {
if( isFormBeingSubmitted ) {
return;
}
return 'Sure you want to close the page?';
};
// now before you submit your form, just enable the isFormBeingSubmitted
$('#quizForm').formwizard({
validationEnabled: true,
focusFirstInput : true,
formOptions: {
beforeSubmit: function() {
isFormBeingSubmitted = true;
return true;
},
resetForm: true
}
});
To answer my own question, all I had to do was to add to the formwizard options:
formPluginEnabled: true
Now everything is working fine. Thanks

Backbone.js model.get not retrieving value

This is a really strange problem I'm having with an app in Backbone.js. I have different search results which are displayed in an accordion, only one result can be selected at a time.
The model for each result has an attribute, "selected" which represents whether the result is selected or not.
For some reason I'm not able to deselect the match. This is the code that's run on clicks on the result.
I've been looking through it, selected always returns false, and somehow, never gets set to true in this function.
click_header: function (e) {
e.stopPropagation();
var s = this.model.get("selected");
if (s == true) {
this.model.set({ selected: false, expanded:false});
} else {
this.model.set("selected", true, { silent: true });
this.model.set("expanded", true, { silent: true });
}
}
EDIT:
I fixed the problem. A function elsewhere in the program triggered by changes to select was setting select to false on all models.
I fixed the problem. A function elsewhere in the program triggered by changes to select was setting select to false on all models.
Updated Here is a more streamlined approach:
click_header: function (e) {
e.stopPropagation();
var s = this.model.get("selected");
this.model.set({ selected: !s, expanded: !s}, { silent: !s });
}

Integrate virtual keyboard into extjs 4.2 form

I'm adding the virtual keyboard from http://www.greywyvern.com/code/javascript/keyboard to a text field of an extjs 4.2 form.
It basically works, see here: http://jsfiddle.net/g5VN8/1/
1) My first question is: is this really the best way to connect them? Looks ugly to me with a timer instead of events to keep the extjs value up to date.
Plus I can't overcome the following two issues:
2) the keyboard icon is wrapped to a new line. It should instead be at the end of the field, on the right side, just as in the examples here: http://www.greywyvern.com/code/javascript/keyboard
3) The field focus doesn't work. I have it in a show listener. Even when wrapped in a window.setTimeout() it doesn't work, so it's not a timing issue. No error is thrown.
Here is a copy-paste (stackoverflow's rules). I'll keep both places up to date.
Ext.onReady(function() {
Ext.QuickTips.init();
var formPanel = Ext.create('Ext.form.Panel', {
renderTo: Ext.getBody(),
bodyStyle: 'padding: 5px 5px 0 5px;',
defaults: {
anchor: '100%',
},
items: [{
xtype:'textfield',
name: 'string',
fieldLabel: 'String',
maxLength:30, enforceMaxLength:true,
allowBlank: false,
listeners: {
show: function(field) {
//focus the field when the window shows
field.focus(true, 1000); //TODO: doesn't work, no error
},
afterrender:function(cmp){
cmp.inputEl.set({ //see http://jsfiddle.net/4TSDu/19/
autocomplete:'on'
});
//attach the keyboard
//because it modifies the dom directly we need to hack it to
//inform extjs (really, ext has no such listener option?)
var interval = window.setInterval(function() {
try {
var newValue = cmp.inputEl.dom.value;
var oldValue = cmp.getValue();
if (newValue != oldValue) {
//only do it then, cause it also moves the cursor
//to the end and that sucks.
cmp.setValue( newValue );
}
} catch (e) {
//form was removed
window.clearInterval(interval);
}
}, 100);
// see http://www.greywyvern.com/code/javascript/keyboard
VKI_attach(cmp.inputEl.dom);
}
}
}],
buttons: [{
text: 'Alert string',
handler: function() {
var stringField = this.up('form').getForm().findField('string');
alert(stringField.getValue());
}
}]
});
});
You can attach a listener to the keyboard and when the user clicks on a VKI key you trigger the textfield change event.
Ext.getBody().on({
mousedown: function (ev) {
if (ev.target.tagName === 'TD') {
// We trigger change event only on textfield with the focus
if (document.activeElement) {
if (document.activeElement.id === cmp.inputEl.dom.id) cmp.fireEvent('change');
}
}
},
delegate: '#keyboardInputMaster'
});
This is because ExtJS 4 writes the input field with "style=width:100%".
An easy way is to add a negative margin to the textfield
fieldStyle: 'margin-right:-40px'
Weird ExtJS behaviour. You must focus the input element, not te thextfield component
Ext.defer(function () {
cmp.inputEl.dom.focus();
}, 100);
You can see the whole solution here: http://jsfiddle.net/EGbLn/3/
Avoid timers. Use regular dom event listeners instead.
afterrender: function (cmp) {
...
// simply attach this to the change event from dom element
cmp.inputEl.dom.addEventListener('change', function(){
cmp.setValue(this.value);
});
...
}
(answered already by Samy Rancho)
fieldStyle: 'margin-right:-40px',
Again, avoid timers and anything similar. Simply add this:
afterrender: function (cmp) {
...
//focus on field
cmp.inputEl.dom.focus();
...
}
Find updated fiddle here: http://jsfiddle.net/g5VN8/11/

Categories

Resources