I want to have a "Restore defaults" button in my extension's preferences window:
<prefpane id="nextplease.phrases" label="&options.phrases.title;"
image="chrome://nextplease/skin/Document.png">
<preferences>
<preference id="nextphrases" name="nextplease.nextphrase.expr0"
type="unichar"/>
...
</preferences>
<hbox flex="1">
...
<listbox id="nextphrases_list" seltype="multiple" flex="1"
onkeypress="nextplease.removeSelectedOnDelete(event, this);"
onselect="nextplease.enableDisableRemoveButton(this);"
preference="nextphrases" preference-editable="true"
onsynctopreference="return nextplease.syncListbox(this);"
onsyncfrompreference="nextplease.loadListboxPreference(this);"/>
...
<button label="&options.restoreDefault;"
oncommand="nextplease.restoreDefaultListbox(this);" />
</hbox>
</vbox>
</hbox>
</prefpane>
This is the JavaScript code for the functions:
nextplease.restoreDefaultListbox = function (node) {
var listbox = node.parentNode.parentNode.firstChild.selectedPanel;
var preferenceId = listbox.getAttribute("preference");
var preference = document.getElementById(preferenceId);
preference.reset();
alert("preference.value="+preference.value+"; preference.valueFromPreferences="+preference.valueFromPreferences);
preference.setElementValue(listbox);
};
nextplease.loadListboxPreference = function (listbox) {
var i, phrase, values;
var preferenceId = listbox.getAttribute("preference");
var preference = document.getElementById(preferenceId);
var prefValue = ??? // neither preference.value nor preference.valueFromPreferences work, see below
// alert("Loading: "+prefValue);
// remove all items already in listbox
for (i = listbox.itemCount; i >= 0; i--) {
listbox.removeItemAt(i);
}
values = prefValue.split("|");
for (i = 0; i < values.length; i++) {
phrase = values[i].replace(/&pipe;/g, "|");
if (phrase !== "") {
listbox.appendItem(phrase, phrase);
// Scroll to the newly added item to workaround
// what I think is a Firefox bug. I was getting
// Javascript exceptions when trying to read the
// values at the bottom that are "hidden".
listbox.ensureIndexIsVisible(listbox.getRowCount() - 1);
}
}
listbox.ensureIndexIsVisible(0);
};
Now, when I click on the button, the alert I get (after preference.reset()) looks like this:
preference.value=undefined; preference.valueFromPreferences=old user-set preference value
So it seems like in onsyncfrompreference the correct preference value can't be accessed except in a really ugly way:
if (preference.value === undefined) {
prefValue = preference.preferences.defaultBranch.getIntValue(preference.name); // or other type instead of Int
} else {
prefValue = preference.value;
}
Is there a better alternative? Specifically, one which would work for any preference type?
If pref.value === undefined, you should use pref.defaultValue to get the value to display. I updated the reference page and the onsyncfrompreference documentation to say that.
Related
I have a List of Map items property.
#property
List<Map<String, dynamic>> items = [
{'name': 'Acrid', 'checked': false},
{'name': 'Fishy', 'checked': false}
];
that are displayed when an if condition evaluates to true.
<template
restamp
is = "dom-if"
if = "[[normalChangedRestampedToggler]]">
<div
class = "layout horizontal wrap body auto"
id = "container">
<paper-material
pad-bottom
class = "dropdown-content layout vertical"
elevation = "5">
<paper-input
value = "{{filterValue}}"
label = "Search"
class = "margin">
<iron-icon
suffix
icon = "search"></iron-icon>
</paper-input>
<paper-menu multi
on-click = "onClickHandler">
<template
id = "repeat"
is = "dom-repeat"
items = "{{items}}"
filter = "{{filter(filterValue)}}">
<paper-item
role = "menuitemcheckbox"
toggles = "true"
active = "{{item.checked}}">
<paper-checkbox
checked = "[[item.checked]]"
checked-changed = "checkedChanged"></paper-checkbox>
[[label(item)]]
</paper-item>
</template>
</paper-menu>
</paper-material>
</div>
</template>
The conditional if is set by a paper-toggle button:
#reflectable
void toggleNormalChangedEvent( event, [_] ) {
normalChangedRestampedToggler = !normalChangedRestampedToggler;
set('normalChangedRestampedToggler', normalChangedRestampedToggler);
switch ( normalChangedRestampedToggler ) {
case false:
for(var item in data)
{
item['checked'] = false;
}
set('items', data);
data = new List<Map<String, dynamic>>( );
break;
}
}
While the UI toggles as expected, the
set('items', data);
does not seem to reset the items - the old checked state of the checkboxes still remain. It appears that the items property does not update.
Can this update be forced by some means?
PS Could the problem be due to the fact that the checkboxes are in a nested-template? If so, is there a way to overcome this problem?
Thanks
This is redundant
normalChangedRestampedToggler = !normalChangedRestampedToggler;
because this includes the above (added !)
set('normalChangedRestampedToggler',! normalChangedRestampedToggler);
for(var item in data) {
item['checked'] = false;
}
should be
for(int i = 0; i < items.length; i++) {
set('items.$i.checked', false);
}
data = new List<Map<String, dynamic>>( );
doesn't do anything because you probably assign the same list again and Polymer recognizes that there is no change.
Also template is="dom-repeat uses
items = "{{items}}"
why do you set data?
I want to open a new window, configured with height and width, all while using < h:commandLink >
<h:commandLink id="zyzid" value="click me" action="#{test.testDo}" target="_blank" />
this renders into:
<a onclick="mojarra.jsfcljs(document.getElementById('myForm'),{'myForm:xyzid':'myForm:xyzid'},'_blank');return false" href="#" id="myForm:xyzid">click me</a>
I looked at jsfcljs() function. It submits the form with target="_blank", but i don't see window.open() anywhere. So, how would I be able to alter this code to change new window's height and width?
for reference:
mojarra.jsfcljs = function jsfcljs(f, pvp, t) {
mojarra.apf(f, pvp);
var ft = f.target;
if (t) {
f.target = t;
}
f.submit();
f.target = ft;
mojarra.dpf(f);
};
I found a few relevant links, and this and I arrived at this solution, which seems to work for me. h:commandLink opens a new page, and I get to manipulate it's width and height. This involves slightly modifying/overwriting the mojarra.jsfcljs function. It opens a window with standard window.open() (triggered by onclick) and associates the form it is submitting with that window.
$(window).load(function(){
mojarra.jsfcljs = function jsfcljs(f, pvp, t) {
mojarra.apf(f, pvp);
var ft = f.target;
if (t) {
if (t.indexOf('options') != -1){
f.target = '_blank' + new Date().getTime();
var options = t.substring(t.indexOf('optionts') + 9);
window.open('', f.target, options);
}
else{
f.target = t;
}
}
f.submit();
f.target = ft;
mojarra.dpf(f);
};
});
markup:
< h:commandLink id="viewLink" action="#{testBean.doTest}" value="h:commandLink" target="options:height=200, width=300" />
Normally this would not be a problem, but this time I don't control the dom. Anyway
<dt>foo</dt>
<dd>bar</dd>
<dd>bar
<div id="myElem">baz</div>
</dd>
<dd>bar</dd>
<dd>bar</dd>
<dd class="moo">bar</dd> <-- I want to get this one
<dd>bar</dd>
<dd>bar</dd>
<dd class="moo">bar</dd>
<dd>bar</dd>
<dd>bar</dd>
Here is what I have tried
$('#myElem').closest('dd').next('.moo').something();
$('#myElem').closest('dd').nextUntil('.moo').something();
However non of these get the next sibling with the class.
Anyone know how to traverse this?
Try
$('#myElem').closest('dd').nextAll('.moo:first').something();
or
$('#myElem').closest('dd').nextUntil('.moo').next().something();
I don't know zepto but from a quick check of the docs it doesn't look like you can do it with a simple chain. Try
var $dd = $('#myElem').closest('dd');
var $moo = $dd.next();
while (!$moo.is('.moo')){
$moo = $moo.next();
if ($moo.length == 0) break;
}
DEMO
You can accomplish by creating a simple new method:
/**
* Get the next element of a particular class, relative to a different element.
*/
var nextOfClass = function(relativeTo, className) {
var el = relativeTo, nextEl;
// Leading period will confuse Zepto.
if (className[0] === '.') className = className.slice(1);
while (el.next()) {
// If target element is found, stop
if (el.hasClass(className)) return el;
nextEl = el.next();
if (nextEl.length === 0) {
// No more siblings. Go up in DOM and restart loop to check parent
el = el.parent();
continue;
}
el = nextEl;
// End of doc. Give up.
if (el.parent().length === 0) return false;
}
};
Then you can simply use the following method:
var moo = nextOfClass($("#myElem"), '.moo');
I would like to allow the user of my XULRunner based app to be able to do copy/paste via a context menu.
Keyboard shortcuts Ctrl-C and Ctrl-V are already working fine
Here it is without flash. The getInputSelection function is from here: Is there an Internet Explorer approved substitute for selectionStart and selectionEnd?.
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window id="mywin" title="my app"
width="800" height="600" persist="screenX screenY width height sizemode"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<popupset>
<menupopup id="clipmenu">
<menuitem label="Copy" oncommand="copy()"/>
<menuitem label="Paste" oncommand="paste();"/>
</menupopup>
</popupset>
<browser
type="content-primary"
src="http://127.0.0.1/"
flex="1"
disablehistory="true"
id="browserId"
context="clipmenu"
/>
<script>
<![CDATA[
function copy()
{
var tabBrowser = document.getElementById("browserId");
var selectedTagName = tabBrowser.contentWindow.document.activeElement.tagName;
var windowObj;
if(selectedTagName == "IFRAME")
{
windowObj = tabBrowser.contentWindow.frames[tabBrowser.contentWindow.document.activeElement.name];
}
else
{
windowObj = document.getElementById("browserId").contentWindow;
}
var selectedText = windowObj.getSelection();
if(!selectedText || selectedText == "")
{
var focused = windowObj.document.activeElement;
if(focused && focused.value)
{
selectedText = getSelectionFromInput(focused);
}
}
//alert(selectedText + "---");
const clipHelper = Components.classes["#mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper);
clipHelper.copyString(selectedText);
}
function getSelectionFromInput(focused)
{
var focusedValue = focused.value;
var sel = getInputSelection(focused);
var selectedText = "";
if(focusedValue.length == (sel.end))
{
selectedText = focusedValue.substring(sel.start);
}
else
{
selectedText = focusedValue.substring(sel.start, (sel.end));
}
return selectedText;
}
function paste()
{
var clip = Components.classes["#mozilla.org/widget/clipboard;1"].getService(Components.interfaces.nsIClipboard);
var trans = Components.classes["#mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
trans.addDataFlavor("text/unicode");
clip.getData(trans, clip.kGlobalClipboard);
var str = new Object();
var len = new Object();
trans.getTransferData("text/unicode",str,len);
str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
str = str.data.substring(0, len.value / 2);
var focused = document.commandDispatcher.focusedElement;
var focusedValue = focused.value;
var sel = getInputSelection(focused);
focused.value = focusedValue.substring(0,sel.start) + str + focusedValue.substring(sel.end);
}
function getInputSelection(el) {
var start = 0, end = 0, normalizedValue, range,
textInputRange, len, endRange;
if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();
if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");
// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());
// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}
return {
start: start,
end: end
};
}
]]>
</script>
</window>
Updated to support iframes.
Create menu using the code below.
<popupset>
<menupopup id="clipmenu">
<menuitem label="Copy" oncommand="copy();"/>
<menuseparator/>
<menuitem label="paste" oncommand="paste();"/>
</menupopup>
</popupset>
<browser type="content" src="chrome://myapp/content/theme1/index.html" flex="1" context="clipmenu"/>
Connect it to whatever you want, here am making it the context menu of the browser element by giving the id of menu in the context attribute of the browser element.
Then for each menu you can give the command to execute in oncommand event. We have given the function copy and paste.
Then write the code to copy text from whatever element you want or if you want to copy the selected data only.
See the below link for copying command.
http://www.deluxeblogtips.com/2010/06/javascript-copy-to-clipboard.html
One more example for "Copy" context menu in XULRunner under SWT Browser (code was implemented for Eclipse v3.5.1, XULRunner v1.8.1.3):
Browser browser = new Browser(parent, style | SWT.MOZILLA);
Menu menu = new Menu(browser);
MenuItem item = new MenuItem(menu, SWT.NONE);
item.setText("Copy");
item.addSelectionListener(new SelectionListener() {
#Override
public void widgetSelected(SelectionEvent e) {
nsIWebBrowser webBrowser = (nsIWebBrowser) browser.getWebBrowser();
nsIInterfaceRequestor req = (nsIInterfaceRequestor) webBrowser.queryInterface(nsIInterfaceRequestor.NS_IINTERFACEREQUESTOR_IID);
nsIDocShell docShell = (nsIDocShell) req.getInterface(nsIDocShell.NS_IDOCSHELL_IID);
nsIClipboardCommands cmds = (nsIClipboardCommands) docShell.queryInterface(nsIClipboardCommands.NS_ICLIPBOARDCOMMANDS_IID);
cmds.copySelection();
}
#Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
browser.setMenu(menu);
I'm trying to use class names to change the color of a link after it has been selected, so that It will remain the new color, but only until another link is selected, and then it will change back.
I'm using this code that was posted by Martin Kool in this question:
<html>
<head>
<script>
document.onclick = function(evt) {
var el = window.event? event.srcElement : evt.target;
if (el && el.className == "unselected") {
el.className = "selected";
var siblings = el.parentNode.childNodes;
for (var i = 0, l = siblings.length; i < l; i++) {
var sib = siblings[i];
if (sib != el && sib.className == "selected")
sib.className = "unselected";
}
}
}
</script>
<style>
.selected { background: #f00; }
</style>
</head>
<body>
One
Two
Three
</body>
It works fine until I try to out the links in a table. Why is this? Be easy, I'm a beginner.
There is no error, the links are changing to the "selected" class, but when another link is selected, the old links are keeping the "selected" class instead of changing to "unselected". Basically, as far as I can tell, it's functioning like a vlink attribute, which is not what I'm going for.
And yes, the links are all in different cells, how would you suggest I change the code so that it works correctly?
OK, actually, I spoke too soon.
document.onclick = function(evt)
{
var el = window.event? event.srcElement : evt.target;
if (el && el.className == 'unselected')
{
var links = document.getElementsByTagName('a');
for (var i = links.length - 1; i >= 0; i--)
{
if (links[i].className == 'selected')
links[i].className = 'unselected';
}
el.className = 'selected';
}
return false;
}
This code you gave me works great, visually, it does exactly what I want it to do. However, It makes my links stop working... They change color, but dont link to anything, and then when I remove the script, they work fine. What am I doing wrong/what do I have to change to make this work?
Also, I want to do the same thing somewhere else in my website, where the links are all in one <div> tag, separated by <p> tags. How can I make this work?
You're looping through the siblings. If the links are in separate <td>'s then they're no longer siblings.
You can loop through all the links like this:
document.onclick = function(evt)
{
var el = window.event? event.srcElement : evt.target;
if (el && el.className == 'unselected')
{
var links = document.getElementsByTagName('a');
for (var i = links.length - 1; i >= 0; i--)
{
if (links[i].className == 'selected')
links[i].className = 'unselected';
}
el.className = 'selected';
}
return false;
}
I've also added a return false; at the end of the function to stop you going to '#'
Is there an error or is there just nothing happening? A good first step if you are a javascript beginner is to use a tool like Firebug so you see detailed error messages, and you can add in console.log statements to see what's going on while you run your code.
By ‘in tables’ do you mean putting each link in its own cell? Because that would make this line:
var siblings = el.parentNode.childNodes;
fail to select other links outside of the cell. You'd have to find another way to signal which element is the link container.