How is the NodeList implemented? - dom

The DOM NodeList (as returned e.g. by element.getElementsByTagName) is an interesting object, in that it is not a snapshot, but reflects changes to the document made after you have created the NodeList.
I was wondering how one would implement such a collection: Completely lazy evaluation must be horribly slow, but keeping a cached version consistent requires a lot of book-keeping internally.
I tried to google for blog articles on the subject, and also tried to find the relevant source code files for Mozilla, but could not find anything immediately (and when I cannot find something immediately, I come here...).
So how do Firefox, Safari, Internet Explorer (and other non-browser DOM implementations) handle NodeLists?

For .NET's XML library, there are 3 internal subclasses of XmlNodeList with different strategies. The XmlChildNodes collection, for the XmlNode.ChildNodes property, uses simple lazy evaluation based on a reference to its containing element. The XmlElementList uses event listeners for when the DOM changes. The third, XPathNodelList, is for XPath queries (e.g., XmlNode.SelectNodes()) and evaluates the XPath each time its index is accessed, its Count property is read, or it is iterated.

Related

Does the Javascript Firestore client cache document references?

Just in case I'm trying to solve the XY problem here, here's some context (domain is a role-playing game companion app). I have a document (campaign), which has a collection (characters), and I'm working with angular.io / angularfire.
The core problem here is that if I query the collection of characters on a campaign, I get back Observable<Character[]>. I can use that in an *ngFor let character of characters | async just fine, but this ends up being a little messy downstream - I really want to do something like have the attributes block as a standalone component (<character-attributes [character]="character">) and so on.
This ends up meaning down in the actual display components, I have a mixture of items that change via ngOnChanges (stuff that comes from the character) and items that are observable (things injected by global services like the User playing a particular Character).
I have a couple options for making this cleaner (the zeroth being: just ignore it).
One: I could flatten all the possible dependencies into scalars instead of observables (probably by treating things like the attributes as a real only-view component and injecting more data as a direct input - <character-attributes [character]="" [player]="" [gm]=""> etc. Displayable changes kind of take care of themselves.
Two: I could find some magical way to convert an Observable<Character[]> into an Observable<Observable<Character>[]> which is kind of what I want, and then pass the Character observable down into the various character display blocks (there's a few different display options, depending on whether you're a player (so you want much more details of your character, and small info on everything else) or a GM (so you want intermediate details on everything that can expand into details anywhere).
Three: Instead of passing a whole Character into my component, I could pass character.id and have child components construct an observable for it in ngOnInit. (or maybe switchMap in ngOnChanges, it's unclear if the angular runtime will reuse actual components for different items by changing out the arguments, but that's a different stack overflow question). In this case, I'd be doing multiple reads of the same document - once in a query to get all characters, and once in each view component that is given the characterId and needs to fetch an observable of the character in question.
So the question is: if I do firestore.collection('/foo/1/bars').valueChanges() and later do firestore.doc('/foo/1/bars/1').valueChanges() in three different locations in the code, does that call four firestore reads (for billing purposes), one read, or two (one for the query and one for the doc)?
I dug into the firebase javascript sdk, and it looks like it's possible that the eventmanager handles multiple queries for the same item by just maintaining an array of listeners, but I quite frankly am not confident in my code archaeology here yet.
There's probably an option four here somewhere too. I might be over-engineering this, but this particular toy project is primarily so I can wrestle with best-practices in firestore, so I want to figure out what the right approach is.
I looked at the code linked from the SDK and it might be the library is smart enough to optimize multiple observers of the same document to just read the document once. However this is an implementation detail that is dangerous to rely on, as it could change without notice because it's not part of the public API.
On one hand, if you have the danger above in mind and are still willing to investigate, then you may create some test program to discover how things work as of today, either by checking the reads usage from the Console UI or by temporarily modifying the SDK source adding some logging to help you understand what's happening under the hood.
On the other hand, I believe part of the question arises from a application state management perspective. In fact, both listening to the collection or listening to each individual document will notify the same changes to the app, IMO what differs here is how data will flow across the components and how these changes will be managed. In that aspect I would chose whatever approach feels better codewise.
Hope this helps somewhat.

Immutable vs Observable collections in Flutter

When using Flutter with realtime databases, such as Firebase Database, it is beneficial to know not just that a collection has been updated, but where exactly. Such as to show a pretty list animation, or trigger some additional events based on which item has updated. Dart already has an amazing infrastructure for delivering events.
A canonical example is to use a FirebaseAnimatedList, but it's glued to Firebase and doesn't support filtering and ordering (outside of very basic Firebase model). I am looking for a more generic solution, which would allow to inject some logic between database (that notifies of item change/insert/delete), and aforementioned AnimatedList, which expects the same events.
Most recent tendency seems to be in favor of immutable collections, such as built_value, which makes a lot of sense in Dart, as object creation is very cheap. However, immutable collections do not have a way of telling which item has changed, they simply deliver a new collection. This approach also makes it difficult to attach some local information to an item, such as "selected" bit when user multi-selects items, or custom ordering. Because, well, items are immutable, and their reference (aka pointer, aka object ID) keeps changing.
One alternative solution is to implement a kind of observable list, such as what package:observable offers, but it seems that its authors are not convinced of its popularity anymore. So what is the approach you take to create animated, filtered, sorted, selection-supporting lists in Flutter, backed by a realtime database?
However, immutable collections do not have a way of telling which item has changed, they simply deliver a new collection.
Some pseudo code: (old collection) - (new collection) = (what changed) - works the other way around too.
This approach also makes it difficult to attach some local information to an item, such as "selected" bit when user multi-selects items, or custom ordering.
Extend said 'item' and add a property selected (or order, or any other info you want available), then just construct the new list with these properties properly set.
There are a lot of state-management-with-Flutter-related questions around these days, so to avoid repeating myself, I would rather link you to an answer of mine from earlier today.
Edit:
I just want to insert a practical example regarding (old collection) - (new collection) = (what changed):
Basically this is how to see what changed when comparing 2 lists, containing closely related elements.
List currentState = [...];
List nextState = [...];
List addedItems = nextState.where((e) => !currentState.contains(e)).toList(),
List removedItems = currentState.where((e) => !nextState.contains(e)).toList();
doSomethingWith(addedItems);
doSomethingElseWith(removedItems);
Of course you should keep in mind that the Lists should be deeply comparable, i.e. for Dart's specific case you can use built_value or equatable packages.
I have also uploaded a repository, with a pure Dart project example. You're more than welcome to do whatever you want with the code.

Can I refresh all the Word Document metadata using DocumentFormat.OpenXml

I have an application that uses the DocumentFormat.OpenXml API to a Word document from one or more originating documents, inserting and deleting chunks of data as it goes. In other words, the resulting document will be significantly different from the constituent documents.
I have already successfully created things like Custom Document Properties, Document Variables and Core File Properties.
But: is it possible to get the other metadata items (number of pages, words, paragraphs, etc.) refreshed, without actually having to calculate these?
Thank you to #Cindy Meister for the answer.
I was hoping that there might be some method or other in the DocumentFormat.OpenXML SDK that I could call, but it seems that is not possible.

Getting Recursive Tasks in Asana with reasonable performance

I'm using the Asana REST API to iterate over workspaces, projects, and tasks. After I achieved the initial crawl over the data, I was surprised to see that I only retrieved the top-level tasks. Since I am required to provide the workspace and project information, I was hoping not to have to recurse any deeper. It appears that I can recurse on a single task with the \subtasks endpoint and re-query... wash/rinse/repeat... but that amounts to a potentially massive number of REST calls (one for each subtask to see if they, in turn, have subtasks to query - and so on).
I can partially mitigate this by adding to the opt_fields query parameter something like:
&opt_fields=subtasks,subtasks.subtasks
However, this doesn't scale well. It means I have to elongate the query for each layer of depth. I suppose I could say "don't put tasks deeper than x layers deep" - but that seems to fly in the face of Asana's functionality and design. Also, since I need lots of other properties, it requires me to make a secondary query for each node in the hierarchy to gather those. Ugh.
I can use the path method to try to mitigate this a bit:
&opt_fields=(this|subtasks).(id|name|etc...)
but again, I have to do this for every layer of depth. That's impractical.
There's documentation about this great REPEATER + operator. Supposedly it would work like this:
&opt_fields=this.subtasks+.name
That is supposed to apply to ALL subtasks anywhere in the hierarchy. In practice, this is completely broken, and the REST API chokes and returns only the ids of the top-level tasks. :( Apparently their documentation is just wrong here.
The only method that seems remotely functional (if not practical) is to iterate first on the top-level tasks, being sure to include opt_fields=subtasks. Whenever this is a non-empty array, I would need to recurse on that task, query for its subtasks, and continue in that manner, until I reach a null subtasks array. This could be of arbitrary depth. In practice, the first REST call yields me (hopefully) the largest number of tasks, so the individual recursion may be mitigated by real data... but it's a heck of an assumption.
I also noticed that the limit parameter applied ONLY to the top-level tasks. If I choose to expand the subtasks, say. I could get a thousand tasks back instead of 100. The call could timeout if the data is too large. The safest thing to do would be to only request the ids of subtasks until recursion, and as always, ask for all the desired top-level properties at that time.
All of this seems incredibly wasteful - what I really want is a flat list of tasks which include the parent.id and possibly a list of subtasks.id - but I don't want to query for them hierarchically. I also want to page my queries with rational data sizes in mind. I'd like to get 100 tasks at a time until Asana runs out - but that doesn't seem possible, since the limit only applies to top-level items.
Unfortunately the repeater didn't solve my problem, since it just doesn't work. What are other people doing to solve this problem? And, secondarily, can anyone with intimate Asana insight provide any hope of getting a better way to query?
While I'm at it, a suggested way to design this: the task endpoint should not require workspace or project predicate. I should be able to filter by them, but not be required to. I am limited to 100 objects already, why force me to filter unnecessarily? In the same vein - navigating the hierarchy of Asana seems an unnecessary tax for clients who are not Asana (and possibly even the Asana UI itself).
Any ideas or insights out there?
Have you ensured that the + you send is URL-encoded? Whatever library you are using should usually handle this (which language are you using, btw? We have some first-party client libraries available)
Try &opt_fields=this.subtasks%2B.name if you're creating the URL manually, or (better yet) use a library that correctly encodes URL query parameters.

How can I get the index of an item in an IOrderedQueryable?

Background:
I'm designing a list-like control (WinForms) that's backed by a DbSet. A chief requirement is that it doesn't load the entire list into local memory. I'm using a DataGridView in virtual mode as the underlying UI. I'm planning to implement the CellValueNeeded function as orderedQueryable.ElementAt(n).
Problem:
I need to allow the control's consumer to get/set the currently-selected value, by value rather than by index. Getting is easy--it's the same as the CellValueNeeded operation--but setting is harder: it requires me to get the index of a given element. There's not a built-in orderedQueryable.FirstIndexOf(value) operation, and although I could theoretically fake it with some sort of orderedQueryable.SkipWhile shenanigans where the expression has a side-effect, in practice the DbSet's query provider probably doesn't support doing that.
Questions:
Is there an efficient way to get the index of a particular value within an IOrderedQueryable? How?
(If this approach turns out to be untenable, I'd settle for suggestions on how I might restructure the problem to make it solvable.)
Side notes:
Elements can be inserted and removed from the list, in which case the old indices will be invalid--that's acceptable, since they're never exposed to the consumer. It's an error for the consumer to attempt to select an item that isn't actually in the list, and actually the consumer would have gotten the item from the list in the first place (although perhaps the indices have changed since then).