Custom Elements / Shadow Root in DART lang vs Shadow Root in JavaScript - dart

I've the this Shadow Element/root in this example http://jsfiddle.net/fyf6thte/8/ working perfectly with JavaScript, interested to have similar one with DART, so I wrote the below code (using the same html and css file), but I could not see the button it looks theshadow.innerHTML = '<button id="d">click</button>'is not working
the full code is:
import 'dart:html';
void main() {
var thehost = document.querySelector('#host1');
document.registerElement(fonixDiv.tag, fonixDiv);
thehost.append(new fonixDiv());
}
class fonixDiv extends HtmlElement {
static final tag = 'fonix-div';
var shadow;
bool disabled;
factory fonixDiv() => new Element.tag(tag);
fonixDiv.created() : super.created() {
shadow = this.createShadowRoot();
shadow.host.innerHTML = '<button id="d">click</button>';
shadow.host.onClick.listen((e){
this.host.dataset.disabled='true'; // set Attribute to the custom element
});
shadow.children.d.onClick.listen((e){
this.text = "you clicked me :(";
// or shadow.children[0].textContent="Shadow DOM content changed";
this.disabled=true;
// alert("All: button, text and host should be change");
});
}
#override
void attached() {
super.attached();
this.disabled=disabled;
}
}
I'm not sure about the accuracy of the balance of the code, I can check it only after I see the button.
any help.

The error is correct: in Dart 'this' is not bound contextually as in JS and instead we have lexical scoping;
in your dart code you are actually changing the text content of the custom element and not of the target of the event (the button in the shadow root). So basically you have a custom element, you set the text content on it but you also have a shadow root created inside of that same DOM node and it shadows everything else you put inside that custom element and that is why you do not see it and continue to see the shadow root's content - this is how shadow root works by design.
To fix it you need to update the text content (and the disabled property) on the button (for example e.target.text = ...).
Hope this helps.

Seems like the .host should be removed from this line
shadow.host.innerHTML = '<button id="d">click</button>';
shadow.innerHTML = '<button id="d">click</button>';
The jsfiddle doesn't have it and it seems weird. I think with .host you add it basically to this and therefore as child not as content.

I think the main issue is: Use innerHtml instead of innerHTML.
There are a few additional minor things you need to fix:
Remove 'host', as Gunter says, you want to set the innerHtml of the shadow.
Instead of shadow.children.d.onClick, do shadow.querySelector('#d').onClick.
Also, do dataset['disabled'] instead of dataset.disabled.

Related

Since update from vaadin 22 to 23 appending a element to the shadow root breaks the component

Original Question
I want to add a loading indicator overlay to the grid.
I tried to append the overlay element to the shadow root by using the attachShadow method.
The following code works well in vaadin 22.
final Grid<String> grid = new Grid<>();
final Element element = new Element("div");
element.setText("Hello");
add(grid);
grid.getElement().attachShadow().appendChild(element);
When I execute the same code in vaadin 23 it breaks the component.
Alternative solution
I tried to extend the grid component on the client side with the following typescript code
import { Grid } from "#vaadin/grid";
export class CustomGrid extends Grid {
static get is() {
return 'custom-grid';
}
}
customElements.define(CustomGrid.is, CustomGrid);
To use my custom grid in flow, I have extended the flow Grid class and added my custom typescript code with the #JsModule annotation.
#Tag("custom-grid")
#JsModule("./src/custom-grid/custom-grid.ts")
public class CustomGrid<T> extends Grid<T> {
}
I used the following code to add my custom grid to the layout
final CustomGrid<String> grid = new CustomGrid<>();
grid.addColumn(s -> s).setHeader("Hello");
grid.setItems(List.of("Item 1", "Item 2", "Item 3"));
add(grid);
The problem
The items are not visible. There are just blank rows.
ps: extending other components like buttons or comboboxes works pretty well.
I faced the same issue with my own customization of Vaadin's Grid.
I did exactly the same as you - and it worked with v22 but it does not with v23.
Although it's a dirty hack, it works by doing the follwing:
final Grid<String> grid = new Grid<>();
add(grid);
grid.getElement().executeJs("elem = document.createElement(\"div\"); elem.innerHTML=\"Hallo\"; this.shadowRoot.appendChild(elem);");

How to remove the background of a dialog?

I created a custom dialog with my own panes and controls in it. But the dialog has a white border default which I want to remove. Here is an example with a single image:
I tried using ScenicView but couldn't find a way to catch the dialog layer and modify it:
public class MainView extends View {
Image img = new Image("https://i.stack.imgur.com/7bI1Y.jpg", 300, 500, true, true);
public MainView(String name) {
super(name);
Button b = new Button("Pop");
b.setOnAction(e -> {
Dialog<Void> dialog = new Dialog<>();
dialog.setOnShown(e2 -> {
Parent parent = getParent();
Pane p = (Pane) parent.lookup(".dialog");
p.setPadding(new Insets(0));
});
dialog.setGraphic(new ImageView(img));
dialog.showAndWait();
});
setCenter(b);
}
}
Best i got was removing the flowpane child to remove some of the lower part
dialog.setOnShown(e2 -> {
Parent parent = getParent();
Pane p = (Pane) parent.lookup(".dialog");
p.getChildren().removeIf(c -> (c instanceof FlowPane));
System.out.println(p.getChildren());
});
Removing the VBox moves the dialog which i don't want to do and changing its padding also dose nothing.
As you can see with ScenicView, the Dialog has the dialog style class.
One easy way to modify the dialog style is via css. Just add a css file to your view, and set:
.dialog {
-fx-background-color: transparent;
}
That will set the background transparent, instead of the default white color.
If you want to remove the borders instead, then you can play with padding. As you can also see with ScenicView, the dialog has a VBox with style class container for the content in the center, and the flow pane for the buttons at the bottom, with style class dialog-button-bar.
Before anything, just use the setContent method to add the image instead of the setGraphic one:
dialog.setContent(new ImageView(img));
And this will be required to remove all the borders, and let the image take the whole dialog:
.dialog,
.dialog > .container,
.dialog > .dialog-button-bar {
-fx-padding: 0;
}

How to get the selected text or the inner html in Dart

How to get the text or the inner html of the current selection by using dart:html? I use on-mouseup event of the div as the start point to do it:
<div on-mouseup="{{on_mouseup}}">
void on_mouseup(MouseEvent e, var detail, DivElement src) {
final selection = window.getSelection();
// do somthing
// ..
// final selectedText = ..;
window.alert("Selected text is $selectedText!");
}
Example:
The value of the variable selectedText should be 'window.getSel'
src.innerHtml` or `src.text
print(window.getSelection().getRangeAt(0).cloneContents().innerHtml);
print(window.getSelection().getRangeAt(0).cloneContents().text);
There is also a shadowRoot.getSelection() in PolymerElement.
print(shadowRoot.getSelection().getRangeAt(0).cloneContents().innerHtml);
print(shadowRoot.getSelection().getRangeAt(0).cloneContents().text);
I tried it with content outside the custom element, in the shadow DOM of the element and as child of the custom Element.
There are some issues what can be selected when the selection crosses the shadow boundary (immediately selects the entire content of the shadow DOM. Beside from that document.getSelection() and shadowRoot.getSelection() always return the same result.
It seems getSelection doesn't work when the end (mouse-up) is within the shadow DOM. When the selection starts in the shadow DOM and ends in the (child) content it works but not the other way around.
I think this is a bug.

Styling and Listening for items in template Custom Element at Dart

I'm trying to build equivalent example of this
the code I used is:
class proto extends HtmlElement {
static final tag = 'x-foo-from-template';
factory proto()=>new Element.tag(tag);
proto.created() : super.created(){
// 1. Attach a shadow root on the element.
var shadow = this.createShadowRoot();
// 2. Fill it with markup goodness.
var t = new TemplateElement();
t..id="sdtemplate"
..innerHtml = """
<style>
p { color: orange; }
</style>
<p>I'm in Shadow DOM. My markup was stamped from a <template>.</p>
<button>click</button>
""";
var span = t.content.querySelector('span');
span.text= "hello "+span.text;
var btn = t.content.querySelector('button');
btn..onClick.listen((e) => print('hello'));
shadow.nodes.add(t.content.clone(true));
}
}
The code displayed the statement and button, but the following did not work:
1. Styling, nothing had been styled, I checked with the developer tools, and found this output "Removing disallowed element ",
2.OnClick.listen for the button
any thoughts?
I found that Listening to items in Templates is not possible till the template be cloned and called, and Listeners can be added to the script that is calling the template, this is applicable for both Dart and JS.
to add event listeners to the template items, we have to go one step up, and use Custom Elements instead.

Preventing flexcroll on event

What I have currently is a very simple div that has a flexcroll scroll bar. This simple div contains some draggable itmes inside of it. My goal is to be able to drag one of the items and and move it about without the flexcroll scroll bar moving.
As it stands right now if I were to drag one of the items below the viewable area the simple div will scroll down. I would like to prevent this.
I'm using jQuery UI for the draggable items. I've already tried using the option "scroll:false" but this does not work for flexcroll.
I'm sorry I don't have any example code, I'm currently away from my work computer.
flexcroll: http://www.hesido.com/web.php?page=customscrollbar
I don't know if you have already resolved this problem. This morning, I have the same problem and I found your post. After that, I have googled a lot to find a solution without any lucky. So finally, I decided to do someting myself, I hope my idea will help you.
After read the Programming Guid, I found that in this version (2.0) of flexcroll, we could register a function for onfleXcroll whose description could be found by searching the keyword "Pseudo-event: onfleXcroll". This is to say that the method will be executed after a scroll is done. So here, what I restore the "top" style with the value before you drag an element.
Here are the code
var $assetswrapper; // This variable indicates the contentwrapper of you div.
var $assetsscrollbar; // This variable indicates the vscroller of you div.
window.onfleXcrollRun = function () { // This method will be executed as soon as the div has been rendered with the help of flexcroll
// You could find these two divs by using firebug, because the top value of these two divs will be changed when we scroll the div which use the class .flexcroll.
$assetswrapper = $('#contentwrapper');
$assetsscrollbar = $('#vscrollerbar');
}
var wrapperTopPosition = 0; // This is used to stock the top value of the wrapperContent before dragging.
var scrollbarTopPosition = 0; // This is used to stock the top value of the scrollbar before dragging.
var dragged; // This is a boolean variable which is used for indicating whether the draggable element has been dragged.
var dropped = false; // This is a boolean variable which used to say whether the draggable element has been dropped.
$('.draggable').draggable({ // you could change .draggable with any element.
start: function (event, ui) {
// Your code here.
wrapperTopPosition = $assetswrapper.position().top;
scrollbarTopPosition = $assetsscrollbar.position().top
dragged = true;
},
stop: function (event, ui) {
// Your code here.
dragged = false;
dropped = true;
}
});
$('your drag div')[0].onfleXcroll = function () { // This method will be called each time when a scroll has been done.
if (dragged) {
$assetswrapper.css('top', wrapperTopPosition);
$assetsscrollbar.css('top', scrollbarTopPosition);
} else {
// Code here is used for keeping the top position as before even though you have dragged an element out of this div for a long time.
// You could test the scrollbar without this piece of code, if you drag an element out of the div for a long time, the scrollbar will keep its position,
// but after you dropped this element and try to scroll the div, then the scrollbar will reach the end of the div. To solve this problem,
// I have introduced the method setScrollPos with the old top position plus 72. 72 here is to set the scroll increment for this scroll, I know
// this value is not fit for any size of windows, but I don't know how to get the scroll-increment automatically.
if (dropped) {
dropped = false;
$('your drag div')[0].fleXcroll.setScrollPos(false, Math.abs(wrapperTopPosition) + 72);
$('your drag div')[0].fleXcroll.setScrollPos(false, Math.abs(wrapperTopPosition) + 72);
}
}
};
I hope this could give you a help if you haven't found any solution yet.

Resources