Given this screenshot of a Firefox DOM rendering, I'm interested in reading that highlighted element down a ways there and writing to the "hidden" attribute 3 lines above it. I don't know the Javascript hierarchy nomenclature to traverse through that index "0" subwindow that shows in the first line under window indexed "3" which is the root context of my code's hierarchy. That innerText element I'm after does not appear anywhere else in the DOM, at least that I can find...and I've looked and looked for it elsewhere.
Just looking at this DOM, I would say I could address that info as follows: Window[3].Window[0].contentDocument.children[0].innerText (no body, interestingly enough).
How this DOM came about is a little strange in that Window[0] is generated by the following code snippet located inside an onload event. It makes a soft EMBED element, so that Window[0] and everything inside is transient. FWIW, the EMBED element is simply a way for the script to offload the task of asynchronously pulling in the next .mp4 file name from the server while the previous .mp4 is playing so it will be ready instantly onended; no blocking necessary to get it.
if (elmnt.contentDocument.body.children[1] == 'undefined' || elmnt.contentDocument.body.children[1] == null)
{
var mbed = document.createElement("EMBED");
var attsrc = document.createAttribute("src")
mbed.setAttributeNode(attsrc);
var atttyp = document.createAttribute("type")
mbed.setAttributeNode(atttyp);
var attwid = document.createAttribute("width")
mbed.setAttributeNode(attwid);
var atthei = document.createAttribute("height")
mbed.setAttributeNode(atthei);
elmnt.contentDocument.body.appendChild(mbed);
}
elmnt.contentDocument.body.children[1].src=elmnt.contentDocument.body.children[0].currentSrc + '\?nextbymodifiedtime'
elmnt.contentDocument.body.children[1].type='text/plain'
I know better than to think Window[3].Window[0]...... is valid. Can anyone throw me a clue how to address the DOM steps into the contentDocument of that Window[0]? Several more of those soft Windows from soft EMBED elements will eventually exist as I develop the code, so keep that in mind. Thank you!
elmnt.contentWindow[0].document.children[0].innerText does the trick
Related
I'm trying to create a Selenium script in Powershell that automatically buys something that I tell it to. I've gotten it past finding the item, and clicking the Buy Now button, but then this window pops up and I've tried what seems like 3000 different ways of failing to click the Place your order button. Web code to the right. Appears to be the "turbo-checkout-pyo-button", but finding it by ID, XPath, CSSselector, etc have all failed for me. It's not a wait issue. I've even thrown in an explicit (and overly long) 5 second delay to be sure this field is present and "should" be clickable. Any ideas?
I've tried all of these. They're all followed by $placeYourOrderBtn.click() (and have all failed):
$placeYourOrderBtn = $ChromeDriver.FindElementByXpath("//*[#id='turbo-checkout-pyo-button']")
$placeYourOrderBtn = $ChromeDriver.FindElementByXPath("//*[#id='turbo-checkout-place-order-button']")
$placeYourOrderBtn = $ChromeDriver.FindElementByXPath("//span[text() = Place your order]")
$placeYourOrderBtn = $ChromeDriver.FindElementById("turbo-checkout-place-order-button-announce")
$placeYourOrderBtn = $ChromeDriver.FindElementById("turbo-checkout-pyo-button")
$placeYourOrderBtn = $ChromeDriver.FindElementByCssSelector("#turbo-checkout-pyo-button")
I did this for a windows that sends email. You have to click the button to open the new window, then use "SwitchTo()" to change to the new window.
[void]$Webdriver.SwitchTo().Window($WebDriver.WindowHandles[1])
You may have to read the window handles attribute and query each one to determine which one you need to open.
Update March 2021:
FireFox bug fixed, now behaves the same as Chromium and Safari.
That means waiting for the JS EventLoop to be empty (with setTimeout or requestAnimationFrame) in the connectedCallback is now a cross-browser method
connectedCallback(){
setTimeout(()=>{
// can access lightDOM here
}); // ,0 not required
}
What the heck is the Event Loop? - Philip Roberts
https://www.youtube.com/watch?v=8aGhZQkoFbQ
Update Oct. 28 2020:
Now reported by Mozilla engineer Anne van Kesteren as a bug in FireFox:
FireFox invokes the connectedCallback too late:
https://bugzilla.mozilla.org/show_bug.cgi?id=1673811
First post May. 2020:
Bitten again by this Chrome Element upgrade issue, after spending a week in FireFox.
Forgot to wrap code in a setTimeout before delivering to Chromium browsers.
FireFox prints: ABCD
Chromium prints: ADCD
Question: Why the difference?
<script>
customElements.define('my-element', class extends HTMLElement {
connectedCallback() {
console.log(this.innerHTML);// "A" in FireFox, "" in other Browsers
if (this.innerHTML == "A")
this.innerHTML = this.innerHTML + "B";
else
setTimeout(() => this.innerHTML = this.innerHTML + "D");
}
})
</script>
<my-element>A</my-element><my-element>C</my-element>
Related answers over the past years:
How to have a 'connectedCallback' for when all child custom elements have been connected
How to wait for Custom Element reference to be "upgraded"?
Update #1
Apple/Safari: prints: ADCD (same as Chromium)
note: Chromium Blink engine is a fork of Apples (WebKit)WebCore code!!
Update #2
With Supersharps reference we found the related threads:
(2016) connectedCallback timing when the document parser creates custom elements
https://github.com/w3c/webcomponents/issues/551
(2019) Need a callback for when children changed or parser finished parsing children
https://github.com/w3c/webcomponents/issues/809
order of callbacks in FireFox versus Chromium:
source: https://jsfiddle.net/WebComponents/9p5qyk1z/
I think the Chrome/Safari behaviour is less intuitive for the beginners, but with some more complex scenarios (for example with child custom elements) then it is much more consistant.
See the different examples below. They act strangely in Firefox...
Another use case that I don't have the courage to code: when a document is parsed, maybe you don't have the end of the document yet. Therefore, when a custom element is created, you cannot be sure you get all its children until you get the closing tag (that could never arrive).
According to Ryosuke Niwa for WebKit:
The problem then is that the element won't get connectedCallback until
all children are parsed. For example, if the entire document was a
single custom element, that custom element would never receive
connectedCallback until the entire document is fetched & parsed even
though the element is really in the document. That would be bad.
So it's better no to wait and connect the custom element as soon as it is created, that means with no child.
<script>
customElements.define( 'c-e', class extends HTMLElement {} )
customElements.define('my-element', class extends HTMLElement {
connectedCallback() {
console.log(this.innerHTML, this.childNodes.length)
let span = document.createElement( 'span' )
if (this.innerHTML.indexOf( 'A' ) >= 0 )
span.textContent = 'B'
else
span.textContent = 'D'
setTimeout( () => this.appendChild( span ) )
}
})
</script>
<my-element>A</my-element><my-element>C</my-element>
<br>
<my-element><c-e></c-e>A</my-element><my-element>A<c-e></c-e></my-element>
<br>
<my-element><c-e2></c-e2>A</my-element><my-element>A<c-e2></c-e2></my-element>
As far as I understand, there was a consensus on it that led to adjust the spec that (Chrome/Safari) way:
Fixes w3c/webcomponents#551 by ensuring that
insertions into the DOM trigger connectedCallback immediately, instead
of putting the callback reaction on the the backup element queue and
letting it get triggered at the next microtask checkpoint. This means
connectedCallback will generally be invoked when the element has zero
children, as expected, instead of a random number depending on when the
next custom element is seen.
We can conclude that Firefox also follow the spec... yes, but we should not rely on the content in connectedCallback for the reasons discussed above.
EDIT: As it turns out, the grid does not support unbound mode in MultiRecordView layout.
I will try to ask this question a different way since my last one was downvoted without comment, so I don't know what the downvoter was objecting to.
I've worked quite a lot with the DevExpress VerticalGrid in unbound mode in SingleRecordView. We use it in all of our desktop applications that involve lots of data-entry. All data-entry forms are consistent in look-and-feel and so user training is minimal. I think it is a great control.
However, I don't understand how to use it in unbound mode in MultiRecordView layout. I cannot even figure out how to populate the unbound grid with the data for several records. In SingleRecord layout, I use the RowsIterator to move data from my data object in memory into the corresponding row/cell in the VerticalGrid's single record.
But in MultiRecordView layout, I can't figure out how to add the second record and the third record, etc etc, and position the current record pointer so that the RowsIterator is working with the rows of the correct record.
A small code snippet, showing how to move the current record pointer when adding the second and subsequent records in MultiRecordView, would be very helpful.
I've tried AddNewRecord() and setting the FocusedRecord but without success:
for (int i = 0; i < MyTable.Rows.Count; i++)
{
vGridControl1.AddNewRecord();
vGridControl1.FocusedRecord = i;
vGridControl1.RowsIterator.DoOperation(new DataPuller(MyTable.Rows[i]));
}
and here's a relevant snippet from my DataPuller object:
public override void Execute(DevExpress.XtraVerticalGrid.Rows.BaseRow brow)
{
//<snip>
if (brow is DevExpress.XtraVerticalGrid.Rows.EditorRow)
{
string fieldname = brow.Properties.FieldName;
if (table.Columns.Contains(fieldname))
{
brow.Properties.Value = (table[fieldname] == DBNull.Value) ? null : table[fieldname];
}
}
//<snip>
}
The vertical grid doesn't support unbound mode when in MultiRecordView layout.
Up until now, this block of code has been using to build documents with text for several months with no snags. I am now trying to dynamically add images. I've spent about two days staring at code and researching and am at an end. I suspect the issue is that relationships are not being created (more details below.) Maybe not?
//set stuff up...
WordprocessingDocument doc = WordprocessingDocument.Open(fsPat, true, new OpenSettings(){
AutoSave = true,
MarkupCompatibilityProcessSettings = new MarkupCompatibilityProcessSettings(MarkupCompatibilityProcessMode.ProcessAllParts,
DocumentFormat.OpenXml.FileFormatVersions.Office2007),
MaxCharactersInPart = long.MaxValue
});
MainDocumentPart mainPart = doc.MainDocumentPart;
.
.Other stuff goes here
.
//now the fun...
Run r2 = new Run();
// Add an ImagePart.
ImagePart ip = mainPart.AddImagePart(ImagePartType.Png);
string imageRelationshipID = mainPart.CreateRelationshipToPart(ip); //
using (Stream imgStream = ip.GetStream())
{
System.Drawing.Bitmap b = new System.Drawing.Bitmap("myfile.png");
b.Save(imgStream, System.Drawing.Imaging.ImageFormat.Png);
}
Drawing drawing = BuildImage(imageRelationshipID, "name"+imageRelationshipID.ToString(), 17, 17);
r2.Append(drawing);
p.Append(r2);
The image part is essentially copied from http://blog.stuartwhiteford.com/?p=33) and is running in a loop presently. I also copied his BuildImage() function and use it as-is.
When I open the resulting docx, I see red Xs where the images are saying "This image cannot currently be displayed."
When I open the zip, the images will appear in root/media, but not root/word/media as I'd expect. I also cannot find the images referenced in any of the relationship files. Ideally they'd be in root/word/_rels/document.xml.rels. You'll notice I changed how imageRelationshipID is set hoping to fix this. It didn't.
Please help. Thank you.
So... It seems like OpenXML just hates me. I copied AddImagePart code from like 3-4 places among trying other things--none of which lasted long--and just could not get relationships to form. The implication I see is that they happen automatically with the AddImagePart function.
I ended up doing a complete workaround where I add all the pictures I might want to put and remove the Drawing nodes' parents of the ones I didn't want (Run nodes, generally.) Since these are very small pictures, it's feasible and in ways more elegant than trying to add them as necessary since I don't have to keep track of where images are stored on disk.
On Windows Phone 7 there is a new version of the BufferWithTimeOrCount extension method for IObservable that returns a "stream of streams" instead of the previous "stream of lists". I'm having difficulty trying to use either the new or old methods, so maybe I just don't understand how it works, but my goal is to create a stream that only fires when an existing stream matches a specified time based pattern during the previous 2 touch events. So far I have created streams for TouchUp and TouchDown (see related question) and In pseudo code I want something like:
//BufferLast2 should contain the last 1 or 2 touch events that occurred in the last 500ms. If no touches occurred this should return an empty set
var BufferLast2 = TouchDown.Merge(TouchUp).BufferWithTimeOrCount(TimeSpan.FromSeconds(0.5), 2);
//Use BufferLast2 to detect tap (TouchDown then TouchUp occuring in less than 0.5s)
var TouchTap = from touch2 in BufferLast2
where touch2.Count == 2 && touch2.First().Action == TouchAction.Down && touch2.Last().Action == TouchAction.Up
select touch2.First(); //returns initial TouchDown event
//Use BufferLast2 to detect Hold (TouchDown with no TouchUp occuring in 0.5s)
var TouchHold = from touch2 in BufferLast2
where touch2.Count == 1 && touch2.First().Action == TouchAction.Down
select touch2.First(); //returns initial TouchDown event
When using the "Stable" Microsoft.Phone.Reactive version of Rx that is built into the ROM calling IObservable<Class>.BufferWithTimeOrCount(...) returns a IObservable<IList<Class>>, which is pretty easy to work with using the standard list operators (as outlined above), but for some reason BufferLast2 was always returning two down events instead of the Down->Up sequence that I expected.
I figured it might be a bug in the code, so I tried adding a reference to the latest version of Rx and used the Observable Extensions from C:\Program Files (x86)\Microsoft Cloud Programmability\Reactive Extensions\v1.0.2838.0\WP7\System.Reactive.dll in which BufferWithTimeOrCount(...) returns a IObservable<IObservable<Class>>. This makes simple filters like Where x.Count == 2 or Where x.First().P == ... much harder to write. I haven't actually figured out how to do a simple filter like x.Count() == 2 on this return value without creating a completely separate subscription or Subject object, which seams way too complex. It's probably a simple error like my last question (all I needed was a Where clause :-P) but it is really driving me bonkers. Any help?
Changing the api makes the buffering look more Rx-y and fits with their Window operator implementation (wouldn't be surprised if using reflector you'd be able to see the Buffer operators using Window). I would think there's probably a variety of reasons that they've changed it. I'm not going to second guess them as they're a lot smarter than me!
So here's my stab at a solution. There may be a cleaner way to get what you're after but i'd probably implement my own extention method to buffer into a list. Maybe something like:
public static class BufferToList
{
public static IObservable<IEnumerable<TSource>> BufferToList<TSource>(this IObservable<TSource> source)
{
return Observable.CreateWithDisposable<IEnumerable<TSource>>(observer =>
{
var list = new List<TSource>();
return source.Subscribe(list.Add,
observer.OnError,
() =>
{
observer.OnNext(list);
observer.OnCompleted();
});
});
}
}
Then something like:
TouchDown.Merge(TouchUp)
.BufferWithTimeOrCount(TimeSpan.FromSeconds(0.5), 2)
.Select(bufferedValues => bufferedValues.BufferToList())
.Subscribe(OnBufferOpen)
private void OnBufferOpen(IObservable<IEnumerable<IEvent<IEventArgs>>> bufferedListAsync)
{
bufferedListAsync.Where(list => list.Count() == 2);
}
I suggest if you want a full explanation of why they've changed the api, go and ask the question over on the rx forums on msdn
The latest release of Rx, v1.0.2856.0, provides both buffers and windows. For the buffers, we restored the original signatures, based on IList. The corresponding window operators will return nested observable sequences.
The way the Buffer* operators are implemented is by composing the corresponding Window* operator with the new ToList extension method that takes an IObservable into an IObservable>. All the Buffer* operator does is invoke this new ToList operator in a SelectMany selector.