| 00:05 | <TabAtkins> | heycam: See, for example, CSS Syntax, which declares the meaning of each token. |
| 00:06 | <heycam> | TabAtkins, CSS Syntax also defines parsing algorithms in terms of token consumption, which is something that I'd like to avoid if possible |
| 00:06 | <heycam> | TabAtkins, I think for CSS it's fine, since you can't neatly describe it with "parse with this grammar or fail" |
| 00:07 | <TabAtkins> | You're doing that anyway, if you say things like "the digit-sequence construction represents the result of evaluating the matched characters as a base-10 number", or whatever. |
| 00:08 | <TabAtkins> | heycam: Also, only the *parser* has error-recovery of that sort. Virtually all individual constructs in CSS are described in "parse correctly or fail" terms. |
| 00:08 | <heycam> | TabAtkins, ok |
| 00:08 | <heycam> | TabAtkins, well I'll see what happens when I eventually rewrite that section :) |
| 00:08 | <TabAtkins> | The three-level parsing we have is just a convenience, allowing us to do the various definition work in one place for each thing. |
| 00:08 | <TabAtkins> | Tokenizing -> Generic Parsing -> Feature Grammars |
| 00:44 | <Hixie> | othermaciej: i gotta say, "this.elements.a.value" seems vastly preferable to "this.querySelector("#a").value" |
| 00:44 | <Hixie> | othermaciej: maybe i've just got odd engineering aesthetic taste :-) |
| 00:45 | <othermaciej> | Hixie: if it's based on aesthetics and not terseness, I could go either way |
| 00:46 | <othermaciej> | (a) magic namespaces can be convenient but on the other hand they can be conceptually confusing |
| 00:46 | <othermaciej> | (b) using a very context-specific way to access an element is in some ways less elegant than using a fully general way |
| 00:47 | <TabAtkins> | (c) What happens with <div id="toString">??? |
| 00:47 | <othermaciej> | if it were not for the issues with form.elements that Jonas raised, I would be all for extending it (after all, what's the downside) |
| 00:47 | <TabAtkins> | <div id="__proto__"> |
| 00:47 | <othermaciej> | but the fact that it misses some kinds of form elements and is a live collection - ick |
| 00:48 | <othermaciej> | Jonas's getParticipants() could provide a symbolic magic namespace if desired, though at some cost of terseness relative to elements |
| 00:48 | <TabAtkins> | Also, we're gaining just a plain .query() (iirc the name it's ending up with?), so "this.query('#a')" versus "this.elements.a" becomes more evenly matched in terseness. |
| 00:48 | <othermaciej> | this.query('#a') is some sweet syntax IMO |
| 00:50 | <sicking> | in general, proxy like APIs do not seem that great to me. Especially when they have built-in properties like .length, .item, .namedItem and .__proto__ |
| 00:51 | <othermaciej> | I tend to prefer things that are more overtly a dictionary instead of relying on the poor-man's-dictionariness of JS objects |
| 00:51 | <sicking> | I think form.control("name") is just as good as form.elements.name |
| 00:51 | <sicking> | oh, right, form.elements does the crazy thing of "return a node or a nodelist" thing |
| 00:52 | <TabAtkins> | Yes, objects as pretend dictionaries is terrible. |
| 00:52 | <sicking> | that adds another level of crazyness |
| 00:52 | <sicking> | especially considering the liveness. It means that a property can morph from being a Node to a NodeList |
| 00:53 | <sicking> | a live NodeList to make things worse |
| 00:55 | <sicking> | I'll also note that ES6's map class is based on .get() and .set() functions, rather than .foo. |
| 00:56 | <sicking> | I generally prefer to defer to the API design patterns from TC39 than the ones from the DOM |
| 00:57 | <TabAtkins> | And I've been pushing hard in the same direction, encouraging use of Map/Set methods rather than homebrew collections. |
| 00:58 | <sicking> | I'll add Array to that list |
| 01:04 | <othermaciej> | Map, Set and Array are good primitives and good ways of managing collections |
| 01:09 | <sicking> | TabAtkins: that said, the way you are inheriting Map in the fontloader looks iffy to me. I sent feedback to jdaggett (since he reached out for review). Not sure if he forwarded it to you? |
| 01:09 | <TabAtkins> | I didn't get that feedback, I don't think. |
| 01:09 | <TabAtkins> | What's iffy about it? |
| 01:10 | <TabAtkins> | (heycam also said he might have problems with how I asked for [MapClass] to work, but he hasn't worked out how to fix yet.) |
| 01:10 | <sicking> | TabAtkins: for example, what happens if a font is removed from the Set (I forget if you inherit Map or Set?) |
| 01:10 | <TabAtkins> | It's a Map. |
| 01:10 | <sicking> | TabAtkins: key'ed on? |
| 01:10 | <TabAtkins> | Blarg, sorry. It's a set. |
| 01:11 | <TabAtkins> | Anyway, this <http://dev.w3.org/csswg/css-font-loading/#font-face-set-css> defines what happens if you mutate the set yourself. |
| 01:11 | <heycam> | TabAtkins, if we make plain Array objects the values of choice for IDL attributes that reflect list-ish things, we might be able to do the same with Map for associated array stuff. but while the browser can Object.watch the Array to watch for changes to it from script, you can't do that with Maps |
| 01:11 | <sicking> | TabAtkins: what's the purpose of keying it on FontFace objects? When would you ever want to do a lookup based on a FontFace object? |
| 01:12 | <heycam> | since the data is stored in internal properties, and there aren't real property changes that would trigger the Object.watch observer |
| 01:12 | <TabAtkins> | heycam: I know. :/ That lack of ability to hook maps/sets is super frustrating. |
| 01:12 | <TabAtkins> | sicking: I don't understand your question, since it's not keyed on anything. |
| 01:12 | <sicking> | TabAtkins: sets are keyed on their values, no? |
| 01:12 | <TabAtkins> | sicking: They're not really "keyed" on anything? |
| 01:12 | <sicking> | TabAtkins: i disagree |
| 01:12 | <TabAtkins> | I mean, technically, sets can be implemented as maps with a dummy value. |
| 01:13 | <sicking> | TabAtkins: sets are maps with no value |
| 01:13 | <sicking> | but they still have keys |
| 01:13 | <TabAtkins> | But they're just an Array with a less visible ordering, and no duplicates. |
| 01:13 | <sicking> | hence they are keyed |
| 01:13 | <TabAtkins> | I don't see how they have keys. |
| 01:13 | <TabAtkins> | There's no .get() method. |
| 01:13 | <TabAtkins> | Just .add() |
| 01:13 | <TabAtkins> | And .has() |
| 01:14 | <sicking> | TabAtkins: there's a .has() method |
| 01:14 | <TabAtkins> | And? |
| 01:14 | <sicking> | the has method does a lookup based on the value you pass in. I.e. it uses the value as a key |
| 01:14 | <TabAtkins> | Sure. |
| 01:14 | <sicking> | expectation is that .has() runs in constant time, no? |
| 01:15 | <sicking> | ish |
| 01:15 | <TabAtkins> | Yes. |
| 01:15 | <sicking> | that means that there's a hash table |
| 01:15 | <TabAtkins> | Yes. |
| 01:15 | <sicking> | hash tables have keys |
| 01:15 | <TabAtkins> | We can keep doing this all day, or you can tell me what your point is. ^_^ |
| 01:15 | <othermaciej> | talking about keys in the context of a non-associative data structure is not the clearest terminology |
| 01:16 | <sicking> | TabAtkins: why would you ever want to do .has(FontFace)? Or .add(FontFace)? |
| 01:16 | <sicking> | TabAtkins: or .delete(FontFace) |
| 01:16 | <TabAtkins> | You probably don't want to do .has(). |
| 01:16 | <TabAtkins> | .add() is useful if you construct your own. |
| 01:17 | <TabAtkins> | .delete() isn't useful most of the time, but if you can add, there might be use-cases for deleting. |
| 01:17 | <TabAtkins> | And it comes for free with the "act like a Set", so we keep it. |
| 01:17 | <sicking> | TabAtkins: what's the use case for de-duping FontFace objects? |
| 01:17 | <sicking> | TabAtkins: i.e. what's the use case for making the .add function not add if the FontFace instance already exists? |
| 01:17 | othermaciej | guesses is that sicking's point is that an array would be better |
| 01:17 | <TabAtkins> | the fact that dupes are meaningless? |
| 01:18 | <othermaciej> | is the sequence relevant? |
| 01:18 | <sicking> | othermaciej: right. The current API doesn't seem to take advantage of the hash at all |
| 01:18 | <TabAtkins> | Using an array means that I expose an index as well. This index isn't stable (it changes if you add/remove @font-face rules from the document's stylesheets). |
| 01:18 | <sicking> | i think having a myFontLoader.loadedFonts Array would be much more intuitive |
| 01:19 | <TabAtkins> | The only thing I really want to expose is .add() and [iterator]() |
| 01:19 | <TabAtkins> | Set is the best match for that. |
| 01:19 | <sicking> | TabAtkins: as soon as you have an iterator you have indexes |
| 01:20 | <sicking> | so you'll have to deal with that problem no matter what |
| 01:20 | <othermaciej> | index being unstable is not really a good reason to specifically not use an Array |
| 01:20 | sicking | isn't sure if Sets have stable indexes |
| 01:20 | <othermaciej> | as long as there's still an order |
| 01:20 | <TabAtkins> | Only ad-hoc ones you invent yourself. You can't use those indexes later to directly access something (and be fooled by the value at that index being swapped out). |
| 01:20 | <TabAtkins> | The worst you could do is associate it with an index in a side data structure, and assume that'll be stable across invocations. |
| 01:20 | <othermaciej> | document.queryAll() gives you an array, because element order in the document is still an order, even though indices can change if you add or remove elements |
| 01:21 | <othermaciej> | well, an array-ish thing |
| 01:21 | <TabAtkins> | But if you have modern JS, you can just use a Map (or a WeakMap) instead and key it to the FontFace directly. |
| 01:21 | <othermaciej> | rather than a set-ish one |
| 01:21 | <othermaciej> | Array doesn't really promise a stable order, but it does vaguely imply that order is in some what meaningful |
| 01:22 | <sicking> | TabAtkins: is synchronously adding fonts even a good idea. It forces parsing on the main thread, no? |
| 01:22 | <TabAtkins> | Everything has an order in JS, because we're not comfortable with enforcing randomized iteration orders, and anything less creates a compat hazard. |
| 01:22 | <TabAtkins> | sicking: Nope, read the spec. ^_^ |
| 01:22 | <TabAtkins> | It doesn't force any more synchrony than adding a new @font-face to the document via script does. |
| 01:22 | <sicking> | TabAtkins: sorry, if you want me to read the full spec in full detail you won't get my review |
| 01:23 | <TabAtkins> | I wasn't aware we were doing an ad hoc review right now. ^_^ |
| 01:23 | <TabAtkins> | Normally, questions that can be answered by the spec can be adequately answered by "read the spec". ^_^ |
| 01:23 | <TabAtkins> | Actually parsing the font face data is done asynchronously. We expose a promise for when the font is fully loaded and ready. |
| 01:24 | <sicking> | ah |
| 01:24 | <sicking> | any reason you're not accepting URLs or Blobs in the ctor then |
| 01:24 | <sicking> | ? |
| 01:24 | <TabAtkins> | I am. |
| 01:24 | TabAtkins | holds off saying "read the spec" again... |
| 01:25 | <TabAtkins> | http://dev.w3.org/csswg/css-font-loading/#font-face-constructor step 3 |
| 01:26 | <TabAtkins> | Right now I only accept TypedArrays as direct data, but I could accept a Blob as well I suppose. |
| 01:26 | <sicking> | ah, URLs are indeed accepted, but not Blobs afaict |
| 01:26 | <sicking> | not a big deal as long as URLs are there |
| 01:26 | <sicking> | though less leak prone |
| 01:26 | <TabAtkins> | Well... Do blobs have serializable URLs? |
| 01:27 | <sicking> | yes, if you use URL.createObjectURL |
| 01:27 | <TabAtkins> | Okay. |
| 01:27 | <sicking> | but it's leak prone |
| 01:27 | <TabAtkins> | It's not a problem to take a Blob directly. |
| 01:28 | <TabAtkins> | Hm, is there anything weird I need to know about Blobs? Or does http://dev.w3.org/csswg/css-font-loading/#font-face-constructor step 4 handle Blobs sufficiently? |
| 01:28 | <TabAtkins> | (Being somewhat generic about "the data in it".) |
| 01:29 | <sicking> | i think that's pretty much good enough |
| 01:29 | <TabAtkins> | kk |
| 01:29 | <TabAtkins> | I'll just add Blob to the BinaryData typedef, then. |
| 01:29 | <TabAtkins> | (We don't implement the BinaryData side of the constructor quite yet.) |
| 01:29 | <annevk-cloud> | At some point blobs will have a way to read their data, not in the blob spec yet |
| 01:30 | <sicking> | TabAtkins: i'm still not sure I see the value in the current use of a Set though |
| 01:30 | <annevk-cloud> | You need that to better deal with failure or the blob being closed and such |
| 01:30 | <sicking> | TabAtkins: Adding a property with an Array seems better |
| 01:30 | <TabAtkins> | Shrug. Array has more stuff in it than I needed - all I need is something that'll hold some objects. |
| 01:31 | <TabAtkins> | (I'm seeing Set as being simpler than an Array.) |
| 01:31 | <sicking> | TabAtkins: you could make the Array be frozen to avoid worrying about mutations |
| 01:31 | <TabAtkins> | Nah, we want to allow mutations. |
| 01:31 | <sicking> | TabAtkins: and add a .add(FontFace) function on the loader |
| 01:31 | <sicking> | TabAtkins: including removals? |
| 01:31 | <TabAtkins> | Why not? |
| 01:31 | <sicking> | more code in implementations |
| 01:31 | <TabAtkins> | (Note that you can't remove CSS-connected ones, only manually-added ones.) |
| 01:32 | <TabAtkins> | Why not just say that .delete() and .clear() don't do anything? |
| 01:33 | <TabAtkins> | I gotta head home - we can pick this up tomorrow. |
| 01:33 | <sicking> | TabAtkins: how would we implement .delete() not doing anything? |
| 01:33 | <sicking> | since we'll likely reuse the actual JS Set implementation |
| 01:33 | <TabAtkins> | Exactly that way. |
| 01:34 | <TabAtkins> | You can override the methods. |
| 01:34 | <sicking> | i'm not entirely sure how we would implement subclassing Set, so i'm not sure |
| 01:35 | <sicking> | but having a .delete() function that didn't delete seems pretty poor |
| 01:38 | <TabAtkins> | I mean, it would probably throw instead. |
| 01:38 | <TabAtkins> | (Subclassing Set/Map is pretty piss-poor right now, I think.) |
| 01:39 | <sicking> | agreed. Array too |
| 01:39 | <TabAtkins> | (I think the only way to reliably do it is to put Set/Map on your proto chain, for detection purposes, but then implement reimplement all the methods yourself and forward to a contained Set/Map holding the real data.) |
| 01:39 | <sicking> | i'm kind'a worried that subclassing in JS is entirely broken |
| 01:39 | <sicking> | apparently one of the design patterns is to allow base classes to instantiate subclasses |
| 01:39 | <TabAtkins> | Subclassing works fine in user-land. :/ |
| 01:40 | <sicking> | yeah, i think in user-land they use different rules |
| 01:40 | <sicking> | than what tc39 is trying to implement |
| 01:40 | <sicking> | at least that's my perception |
| 01:46 | <TabAtkins> | heycam: All I really want WebIDL to do is let me define a handful of core methods for my thing, have it act like a Map/Set, and then I never have to worry about it again. |
| 01:47 | <TabAtkins> | In particular, "not worry about it" means that if new Map/Set methods get added, it can be handled directly in WebIDL, not in every single spec that uses a Map/Set-like interface. |
| 01:47 | <sicking> | TabAtkins: I don't think we should make WebIDL go beyond what ES6 provides |
| 01:47 | <TabAtkins> | Also, for friendliness, basic typechecking should work (instanceof), and userland methods added to Map/Set.prototype should work. |
| 01:48 | <TabAtkins> | sicking: It's possible that this should be better handled in ES6. I proposed this a year or so ago, didn't get anywhere with it. |
| 01:48 | <heycam> | TabAtkins, those latter points paint us into this awkward corner of subclassing Map where it's not really designed to be subclassed |
| 01:48 | <sicking> | TabAtkins: i hear you :( |
| 01:48 | <TabAtkins> | (Specifically, I suggested defining a MapCore or whatever class that had just get/set/has/delete, and similar for Set.) |
| 01:49 | <TabAtkins> | And Map is defined to store its data in an internal MapCore, and other methods are defined on top of that. |
| 01:49 | <TabAtkins> | Maybe MapCore#clear too, just to let that one be efficient. Oh, and [iterator], obviously. |
| 01:50 | <TabAtkins> | So 5 or 6 core methods, and everything else forever defined on top of just those. |
| 01:51 | <TabAtkins> | Then WebIDL could specify that when you subclass you can swap out the core for something else that implements the same methods. |
| 01:51 | <TabAtkins> | And we can expose that to userland via a [core] symbol or something. |
| 01:51 | <heycam> | that sounds more much reasonable than the current [MapClass] setup |
| 01:52 | <heycam> | plug a map behaviour into a Map object |
| 01:52 | <TabAtkins> | Tell that to AWB. |
| 01:55 | <heycam> | the alternative is to do something like we want to do with Arrays, where at defined times the browser can update/replace an IDL attribute's Array object, and uses Object.watch on it |
| 01:55 | <heycam> | you'd need to forgo exceptions being thrown with bad values inserted into the Map though |
| 01:55 | <heycam> | and you'd need a Map.watch mechanism |
| 01:56 | <TabAtkins> | A watch mechanism that lets me filter out the bad things before they get used is sufficient. |
| 01:56 | <heycam> | TabAtkins, yeah you can always in prose skip over items of bad types |
| 01:57 | <TabAtkins> | Since you'd only be able to insert bad things by doing silly monkeypatching, like "Map.prototype.set.call(mapSubclass, badVal)" |
| 01:57 | <heycam> | TabAtkins, doesn't need to be integrated with the watching mechanism |
| 01:57 | <sicking> | yeah, synchronously calling into a validate-value hook would help hugely with DOM APIs |
| 01:57 | <sicking> | for all container types |
| 01:57 | <heycam> | sicking, I think that argues for the map core kind of pattern |
| 01:57 | <heycam> | I wonder if you could retrofit something like that onto Arrays as well |
| 03:18 | SamB | wonders if he is the only one who gets oddly-aligned checkboxes on http://naesten.mooo.com:8080/checkbox-off-kilter.html ... |
| 03:18 | <TabAtkins> | SamB: Off kilter for me too, in Chrome stable channel. |
| 03:20 | SamB | wonders if it's been like this forever and he only just noticed |
| 03:27 | <Goplat> | it should be off in any browser due to the table's cellspacing and cellpadding |
| 04:34 | <SamB> | Goplat: does only the one in the table look bad to you? |
| 04:35 | <Goplat> | They both look fine on their own, they're just not aligned with each other |
| 04:36 | <SamB> | oh, that's really two examples that happen to be in one file |
| 04:36 | <SamB> | my problem is that the text seems to be a few pixels below where it ought to be |
| 09:23 | <Ms2ger> | foolip is on a roll |
| 09:39 | <Ms2ger> | Does anything define the initial networkState? |