Moving a toolbar button in XUL - firefox-addon

I'm trying to get an element to move from right to left in XUL. I am doing this with a toolbar and want one toolbarbutton w/ a label to remain anchored to the right, while one of them moves from right to left, starting to the left of the anchor.
I'm trying to achieve this effect by modifying marginLeft, but my element stays still. I'm not really sure why it does not move.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE overlay >
<overlay id="my-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/x-javascript">
// Install load handler
var marginLeft = 0;
window.addEventListener("load", function(e) {
function moveIt() {
document.getElementById("moveit").style.marginLeft = marginLeft + "px";
marginLeft -= 30;
}
setInterval(moveIt, 1000);
}, false);
</script>
<vbox id="browser-bottombox">
<toolbar id="theToolbar">
<!-- holds the scrolling items and the refresh time -->
<hbox id="scrollingItemContainer" flex="1" align="end">
<!-- container for our scrolling items -->
<spacer flex="1"/>
<hbox id="movingItems" align="end">
<toolbarbutton id="moveit" label="moving"/>
</hbox>
<hbox>
<toolbarbutton id="rightAnchor" label="right"/>
</hbox>
</hbox>
</toolbar>
</vbox>
</overlay>
Any help you can provide will be helpful. I've tried this on FF4, but I think the problem exists on FF3 as well.
I should note that if I add a spacer with flex=1 after scrollingItemContainer then I see the item move, but it is not anchored to the right.

Related

.NET MAUI Shell TabBar does not behave as expected

In our .Net MAUI iOS app, we use Shell TabBar:
<TabBar>
<Tab Title="Home" Icon="{StaticResource IconHome}">
<ShellContent ContentTemplate="{DataTemplate local:MainPage}" />
</Tab>
<Tab Title="Coverage
Calculator" Icon="{StaticResource IconCalculator}" >
<ShellContent ContentTemplate="{DataTemplate calculator:CoverageCalculatorPage}" />
</Tab>
<Tab Title="Distributor
Locator" Icon="{StaticResource IconLocator}">
<ShellContent ContentTemplate="{DataTemplate locator:DistributorsLocatorPage}" />
</Tab>
<Tab Title="Scan
QR Code" Icon="{StaticResource IconQrScanner}">
<ShellContent ContentTemplate="{DataTemplate qrScanner:QrScannerPage}" />
</Tab>
<Tab Title="More" Icon="{StaticResource IconMore}">
<ShellContent ContentTemplate="{DataTemplate more:MoreFeaturesPage}" />
</Tab>
</TabBar>
As you can see, some tab titles have two lines. To show both lines, and to center the titles' texts, I use custom renderer:
internal class MyShellRenderer : ShellRenderer
{
protected override IShellTabBarAppearanceTracker CreateTabBarAppearanceTracker()
{
return new MyCreateTabBarAppearanceTracker();
}
public class MyCreateTabBarAppearanceTracker : ShellTabBarAppearanceTracker, IShellTabBarAppearanceTracker
{
void IShellTabBarAppearanceTracker.SetAppearance(UITabBarController controller, ShellAppearance appearance)
{
base.SetAppearance(controller, appearance);
var items = controller.TabBar.Items;
if (items == null)
{
return;
}
for (int i = 0; i < items.Length; i++)
{
if (items[i] == null) continue;
else
{
UITabBarItem item_temp = items[i];
UIView view = item_temp.ValueForKey(new Foundation.NSString("view")) as UIView;
UILabel label = view.Subviews[1] as UILabel;
label.Lines = 2;
label.LineBreakMode = UILineBreakMode.WordWrap;
label.TextAlignment = UITextAlignment.Center;
}
}
}
}
}
With this custom renderer, the goal is achieved only partially. Here is how the TabBar looks at the beginning:
The titles are centered, but only the first line shows up.
If the app is placed in the background, when it re-appears, all tabs have now two lines, but the text is not centered:
If I touch a tab, the texts get centered:
But the text of the second tab is truncated.
And the 2nd line of the fourth tab that has two words, loses the second word (wrapped to the 3rd line).
And when the phone is turned to landscape view, the labels are distorted even more:
Only one line shows up, but wrapped to occupy both lines.
How can this behavior be fixed? I.e. 1) how to make the text to show both centered lines initially, and 2) how to increase the tabs' width to avoid truncating, and 3) how to fix the landscape view?

How to vertically align the content in Vuetify version 1.5

I am trying to make cards on the screen and I want to add a title and icon for that card that title and icon I want to align vertically center of the card. I am trying everything but still is not working
This is my main component
<v-container fluid>
<v-layout row wrap align-center justify-center fill-height>
<v-flex xs12 sm6 md4 lg4>
<v-hover v-slot="{ hover }">
<v-card
:elevation="hover ? 12 : 2"
:class="{ 'on-hover': hover }"
class="primary ma-4 white--text"
height="300"
>
<FirstTile></FirstTile>
</v-card>
</v-hover>
</v-flex>
</v-layout>
<v-container>
This is my FirstTile tag code
<v-flex xs12>
<v-layout align-center justify-center fill-height>
<v-card-title primary-title id="heading">
Profit/Loss
</v-card-title>
</v-layout>
<v-layout align-center justify-center fill-height>
<v-card-action>
<v-icon
x-large
color="white"
> swap_vert
</v-icon>
</v-card-action>
</v-layout>
</v-flex>
Your FirstTile html could be something like this. align-center will fill the space vertically.
<v-container bg fill-height grid-list-md text-xs-center>
<v-layout row wrap align-center>
<v-flex>
<v-card-text >Profit/loss </v-card-text>
<v-icon
x-large
color="white"
> swap_vert
</v-icon>
</v-flex>
</v-layout>
</v-container>

Matching the vertical scroll position of a Grid to a RichEditBox or TextBox

I've got a Windows Store app with a RichEditBox (editor) and a Grid (MarginNotes).
I need the vertical scroll position of the two elements to be matched at all times. The purpose of this is to allow the user to add notes in the margin of the document.
I've already figured out Note positioning based on the cursor position - when a note is added, a text selection is made of everything up to the cursor. that selection is then added to a second, invisible RichEditBox, inside a StackPanel. I then get the ActualHeight of this control which gives me the position of the note in the grid.
My issue is that when I scroll the RichEditBox up and down, the Grid does not scroll accordingly.
First Technique
I tried putting them both inside a ScrollViewer, and disabling scrolling on the RichEditBox
<ScrollViewer x:Name="EditorScroller"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="{Binding *" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Grid x:Name="MarginNotes" Grid.Column="0" HorizontalAlignment="Right"
Height="{Binding ActualHeight, ElementName=editor}">
</Grid>
<StackPanel Grid.Column="1">
<RichEditBox x:Name="margin_helper" Opacity="0" Height="Auto"></RichEditBox>
</StackPanel>
<RichEditBox x:Name="editor" Grid.Column="1" Height="Auto"
ScrollViewer.VerticalScrollBarVisibility="Hidden" />
</Grid>
</ScrollViewer>
When I scroll to the bottom of the RichEditBox control, and hit enter a few times, the cursor drops out of sight. The ScrollViewer doesn't scroll automatically with the cursor.
I tried adding C# code which would check the position of the cursor, compare it to the VerticalOffset and height of the editor, and then adjust the scroll accordingly. This worked, but was incredibly slow. Initially I had it on the KeyUp event which brought the app to a standstill when I typed a sentence. Afterwards I put it on a 5 second timer, but this still slowed down the app performance and also meant that there could be a 5 second delay between the cursor dropping out of sight and the RichEditBox scrolling.
Second Technique
I also tried putting just MarginNotes in its own ScrollViewer, and programmatically setting the VerticalOffset based off my RichEditBoxs ViewChanged event.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="{Binding *" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<ScrollViewer x:Name="MarginScroller" Grid.Column="0"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid x:Name="MarginNotes" HorizontalAlignment="Right"
Height="{Binding ActualHeight, ElementName=editor}">
</Grid>
</ScrollViewer>
<StackPanel Grid.Column="1">
<RichEditBox x:Name="margin_helper" Opacity="0" Height="Auto"></RichEditBox>
</StackPanel>
<RichEditBox x:Name="editor" Grid.Column="1" Height="Auto"
Loaded="editor_loaded" SizeChanged="editor_SizeChanged" />
</Grid>
relevant event handlers
void editor_Loaded(object sender, RoutedEventArgs e)
{
// setting this in the OnNavigatedTo causes a crash, has to be set here.
// this uses WinRTXAMLToolkit as suggested by Nate Diamond to find the
// ScrollViewer and add the event handler
editor.GetFirstDescendantOfType<ScrollViewer>().ViewChanged += editor_ViewChanged;
}
private void editor_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
// when the RichEditBox scrolls, scroll the MarginScroller the same amount
double editor_vertical_offset = ((ScrollViewer)sender).VerticalOffset;
MarginScroller.ChangeView(0, editor_vertical_offset, 1);
}
private void editor_SizeChanged(object sender, SizeChangedEventArgs e)
{
// when the RichEditBox size changes, change the size of MarginNotes to match
string text = "";
editor.Document.GetText(TextGetOptions.None, out text);
margin_helper.Document.SetText(TextSetOptions.None, text);
MarginNotes.Height = margin_helper.ActualHeight;
}
This worked, but was quite laggy as scrolling is not applied until the ViewChanged event fires, after scrolling has stopped. I tried using the ViewChanging event, but it does not fire at all for some reason. Additionally, the Grid was sometimes mis-positioned after a fast scroll.
So, what makes this difficult is that the size of the text or the placement of the text in different types of TextBoxes means that syncing the scrollbar doesn't guarantee you are syncing the text. Having said that, here's how you do it.
void MainPage_Loaded(object sender, RoutedEventArgs args)
{
MyRichEditBox.Document.SetText(Windows.UI.Text.TextSetOptions.None, MyTextBox.Text);
var textboxScroll = Children(MyTextBox).First(x => x is ScrollViewer) as ScrollViewer;
textboxScroll.ViewChanged += (s, e) => Sync(MyTextBox, MyRichEditBox);
}
public void Sync(TextBox textbox, RichEditBox richbox)
{
var textboxScroll = Children(textbox).First(x => x is ScrollViewer) as ScrollViewer;
var richboxScroll = Children(richbox).First(x => x is ScrollViewer) as ScrollViewer;
richboxScroll.ChangeView(null, textboxScroll.VerticalOffset, null);
}
public static IEnumerable<FrameworkElement> Children(FrameworkElement element)
{
Func<DependencyObject, List<FrameworkElement>> recurseChildren = null;
recurseChildren = (parent) =>
{
var list = new List<FrameworkElement>();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
if (child is FrameworkElement)
list.Add(child as FrameworkElement);
list.AddRange(recurseChildren(child));
}
return list;
};
var children = recurseChildren(element);
return children;
}
Deciding when to invoke the sync is tricky. Maybe on PointerReleased, PointerExit, LostFocus, KeyUp - there are a lot of ways to scroll is the real issue there. You might need to handle all of those. But, it is what it is. At least you can.
Best of luck.

onsyncfrompreference not being called

I'm writing a Firefox add-on and for the <scale> XUL element, onsyncfrompreference doesn't seem to be called (Firefox 14). Here's my preference:
<preferences>
<preference id="pref-sensitivity" name="bbaddon.sensitivity" type="string"/>
...
</preferences>
and here is the scale:
<scale min="1" max="100" increment="1" preference="pref-sensitivity"
id="bb-sensitivity"
onsynctopreference="Application.console.log('onsynctopreference called')"
onsyncfrompreference="Application.console.log('onsyncfrompreference called')" />
The logs are just for debugging at the moment, onsynctopreference is called no problem as it shows up on the console, but there's no entry from onsyncfrompreference. I have a default value defined in defaults.js.
If you look at the implementation of this feature in preferences.xml, onsyncfrompreference will only be called for "editable" elements. As to what is considered "editable", you can see that below. Some elements are always considered editable, others have to specify preference-editable="true" attribute explicitly. In your case it's the latter meaning that your fix would look like this:
<scale min="1" max="100" increment="1" preference="pref-sensitivity"
preference-editable="true" id="bb-sensitivity"
onsynctopreference="Application.console.log('onsynctopreference called')"
onsyncfrompreference="Application.console.log('onsyncfrompreference called')" />
I've worked around this using Javascript:
<script type="text/javascript">
var loaded = false;
//load preferences
var prefs = Components.classes["#mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService)
.getBranch("extensions.bb");
prefs.QueryInterface(Components.interfaces.nsIPrefBranch2);
function loadpref() //call this in the prefwindow onload
{
document.getElementById('bb-sensitivity').value = prefs.getCharPref('sensitivity');
loaded = true;
}
function setpref(sensitivity)
{
if(loaded) //onchange for scale fires before onload for the window
{
prefs.setCharPref('sensitivity',sensitivity);
}
}
</script>
and the scale element:
<scale min="1" max="100" increment="1"
preference="pref-sensitivity"
id="bb-sensitivity"
onchange="setpref(this.value);"
/>
I'll leave this question open for now to see if anyone else can help. I'd still like to do this the 'correct' way.

Tooltips (Titles) in XUL browser content are not working?

I'm developing an extension for FireFox. I use a XUL deck element that contains a XUL browser element. Unfortunately, whenever the page displayed in the browser has an HTML title attribute, the value of this title attribute will not show up as a tooltip.
How can I get tooltips to display correctly?
There is no mechanism to automatically display title attributes in tooltips - the browser window has special code for that and you need to replicate this code in your extension. This means that you need to define a <tooltip> element, e.g.:
<popupset>
<tooltip id="browserTooltip" onpopupshowing="return fillTooltip(this);"/>
</popupset>
You should use this tooltip in your <browser> element, like this:
<browser tooltip="browserTooltip"/>
And you should create a fillTooltip() function that will be called whenever your tooltip shows up. It will need to look at the HTML element that the mouse pointer hovers over, check its title attribute and put the value of the attribute into the tooltip. The function performing this job in Firefox is FillInHTMLTooltip() though you might want to go with a simpler variant like this (untested code):
function fillTooltip(tooltip)
{
// Walk up the DOM hierarchy until we find something with a title attribute
var node = document.tooltipNode;
while (node && !node.hasAttribute("title"))
node = node.parentNode;
// Don't show tooltip if we didn't find anything
if (!node)
return false;
// Fill in tooltip text and show it
tooltip.setAttribute("label", node.getAttribute("title"));
return true;
}
I found the solution for those who are interested, it's by adding a tooltip property to the XUL browser element with the following value:
tooltip="aHTMLTooltip"
Or adding it programmatically using javascript like this:
browser.setAttribute('tooltip','aHTMLTooltip');
for more details check: https://bugzilla.mozilla.org/show_bug.cgi?id=451792#c1
Working example:
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window id="mainWindow" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" title="NanoFL" width="800" height="600" persist="screenX screenY width height sizemode">
<script>
<![CDATA[
function fillTooltip(tooltip)
{
var nodes = document.getElementById("browser").contentWindow.document.querySelectorAll(":hover");
for (var i=nodes.length-1; i>=0; i--)
{
if (nodes[i].hasAttribute("title"))
{
tooltip.setAttribute("label", nodes[i].getAttribute("title"));
return true;
}
}
return false;
}
]]>
</script>
<browser id="browser" src="chrome://nanofl/content/index.html" flex="1" disablehistory="true" tooltip="browserTooltip" />
<tooltip id="browserTooltip" onpopupshowing="return fillTooltip(this)"/>
</window>

Resources