Closed (duplicate)
Project:
Drupal core
Version:
8.0.x-dev
Component:
javascript
Priority:
Normal
Category:
Bug report
Assigned:
Unassigned
Reporter:
Created:
26 Jan 2012 at 09:06 UTC
Updated:
29 Jul 2014 at 20:20 UTC
Jump to comment: Most recent file
Comments
Comment #1
gary4gar commentedPatch for tableheader.js. I tested it and sticky table headers do work before & after applying these changes.
Let me know, if its acceptable
Comment #2
nod_new Functionis exactly the same aseval(). So no, it won't do.Try going up from where
Drupal.settings.tableHeaderOffsetis defined, right now it's a string it should be a function that can be called directly without having to useeval.Comment #3
gary4gar commentedThat makes sense. If we define Drupal.settings.tableHeaderOffset as an function, then such hackery won't be needed. Now, I need to find where is Drupal.settings.tableHeaderOffset defined.
Thanks for reply
Another patch - version 2. Please ignore this.new Function & eval are NOT the sameComment #4
gary4gar commentedVersion 3 Patch, one line change. Tested in FF 9.0 no syntax errors & sticky table header do work after the change
Comment #5
droplet commentedif Drupal.settings.tableHeaderOffset = 'test'
eval => test()
Drupal.settings.tableHeaderOffset() = tableHeaderOffset() method inside Drupal.settings object
It doesn't same ?
Comment #6
damien tournoud commentedThe intent of the code is to call the function which name is stored in a variable, not to call a function stored in a variable.
Comment #7
nod_Turns out, it's complicated who would have guessed :þ. There is a need for API change on
ajax.jsandtableheader.js.Tableheader
Let's travel to 2007 when this
eval()was introduced.The issue is related to elements that are displayed fixed on top of the screen. If nothing is done, tableheader will set the header to go on top of the screen, under toolbar and shortcut. That's why the
tableHeaderOffsetsetting was introduced, to have the offset from the top given by a js function that can tell the fixed element's height in order to display the header correctly.Now there is 2 issues with this code (beside using
eval()):overlay_child.jshad to monkey-patch it's way around :There should be a js-only solution to this problem. A script should only have to register it's function to tableheader that will go through the array of registered function summing it's results to end up with the right offset.
Ajax
This actually was introduced in ahah.js (yeah it's old too, both were a few days apart).
I'm a bit lost, I couldn't find code using this, to me that's dead code that should be removed, unless someone tell me which module uses it. The problem and solutions are the same as above, lucky.
Comment #8
gary4gar commentedin that case how about:
window[ Drupal.settings.tableHeaderOffset ]()assuming it's a global function?In order to make that easier and provide some flexibility, here is a convenience function:
calling it as
executeFunctionByName("Namespace.functionName", window, arguments);Source: http://stackoverflow.com/a/359910/367985
Comment #9
nod_No that won't work, the API needs to be changed it's flawed.
Comment #10
nod_Here is a patch, a side effect is that It should be
muchsmoother to scroll down a module list with a lot of packages now,evalwas used at the worst possible place.the API change is that
Drupal.settings.tableHeaderOffsetis now an array added by thetheme_tablefunction, where modules add their offset function, I got rid of overlay monkey-patch. Too bad jQuery doesn't have a .reduce() function that would have helped :þ.I'm still looking for code that uses
this.progress.update_callbackinajax.js. In the meantime please review this.(edit) removed a bit of exaggeration :)
Comment #11
damien tournoud commented#10 looks like a decent change, although I really doubt it would lead to any significant performance improvement :)
Comment #12
aspilicious commentedAre you hardcoding the offset in code? Isn't that bad practice?
(maybe I just don't know what it does :p )
-27 days to next Drupal core point release.
Comment #13
nod_that's not an offset that's the base the number will be parsed with/in. it's because
parseInt('08')gives an… interesting result. just fool-proofing this bit of code.Comment #14
sunThat should be a separate issue. The Batch API / batch.js was originally supposed to use ajax.js, but we never got around to implement that.
You likely won't find usage of update_callback in core, but CTools in contrib might. In any case, let's move this to a separate issue.
Doesn't tableheader already have a dedicated settings object in Drupal.settings?
?
unless I'm terribly mistaken, the assigned expression makes imax a Boolean value, so I'm not sure how i < imax can work (aside from counting from 0 to true == 1)...?
Comment #15
nod_1) the var was defined by
core/modules/toolbar/toolbar.modulewhich has nothing to do with tableheader, I took it out and forced the empty array in the theme function to avoid painful checking on the JS side.2) yeah wasn't inspired for comments.
3) It's more complicated, it's basically an inline if, expanded it's the same as :
It's to be extra sure
Drupal.settings.tableHeaderOffsetis defined and that the script won't choke on it.About ajax.js since it's the same problem with the same solution I didn't think i needed a separate issue.
Comment #16
sunWe don't have a coding standard for this yet, but in all of my core code and contrib modules, I preferred a conditional JS initialization. That is, because Drupal.settings produces code in the HTML page, and thus, even if the setting is empty - whereas the JS is not only cached but also aggregated/optimized. It's a very small thing when only looking at one setting, but when projecting it to many settings that might be empty, it starts to make a difference.
In a sense, it also avoids a dependency in the JS on the setting to be there, which in turn avoids JS errors.
I'd avoid the separate imax variable for readability and clarity then:
Comment #17
nod_That makes sense, I like when js gets out from PHP.
met you halfway for the imax thing.
Comments might still need some work, i'm just not very good at it.
Comment #18
nod_Comment #19
nod_I broke stuff when the table gets reloaded by ajax.
Comment #20
nod_Working patch. Did some profiling while scrolling on the module page (with just the list of core modules). What I'm looking at is the time spent in the function
eventhandlerRecalculateStickyHeaderwhich is called on page scroll, even if it's not scrolling over a table.I'm scrolling gently on the module page like you'd do to look at modules titles (takes around 10 seconds). Below is the average time spent on this function, used Firebug profiler, google chrome profiler gives similar results.
Patched
Eval version
It's twice as fast now. Just need to check I haven't broken other things, ajax and overlay is working obviously :)
Oh and it looks like two binds are useless:
drupalDisplaceAnchor.drupal-tableheader,drupalDisplaceFocus.drupal-tableheader. I didn't get how there were called.Comment #21
nod_Just tested on a website with around 70 tables on the module page (don't ask) half of that with sticky headers. It makes a very significant difference, so real world usage +1.
Comment #22
droplet commentedunused var ?
(needs reroll)
26 days to next Drupal core point release.
Comment #23
nod_You're right, here it is fixed.
Comment #24
cosmicdreams commented@nod_ are you sure you're not changing the functionality of Drupal.overlayChild.tableHeaderOffset ? That seems like a fundamentally different calculation.
Comment #25
nod_topoffset was always 0, because
Drupal.overlayChild.prevTableHeaderOffset(which isDrupal.settings.tableHeaderOffset) is always undefined. what is defined here istop.Drupal.settings.tableHeaderOffset. there is an iframe involve and two differentDrupalobjects.So no, i'm not changing the calculation. Moreover, Drupal.settings.tableHeaderOffset is an object now, you can add as many functions you want and they'll be summed up.
(edit) Oh and
$(document.body).css('marginTop')is actually calculated earlier in the iframe creation and guess what it's calculated from… yes, the toolbar size.It's just a big mess, this patch solve the eval issue, not the crazy way everything is calculated, that'll be a followup patch.
Comment #26
cosmicdreams commented@nod_ Gotcha. Thanks for the head's up. This patch does succeed in removing the evals from all Drupal-authored javascript. Is there a table javascript followup already created?
Comment #27
nod_I'd like to keep talking in this issue: #1440628: [Meta] javascript toolbar/tableheader with url fragment mess there are links to other issues related there.
Comment #28
nod_reroll
Comment #30
nod_yeah yeah, failling patch is for D7.
Comment #31
klonos...yeah, wish we had #66484: Allow issues to be filed against multiple versions/branches. and #1171958: Allow files to be assigned to branch(es)/version(s) and thus tested against it
Comment #32
jcisio commentedTested D8 patch. I really like this direction: embed the offset in each module JS (so it is added up to Drupal.settings) instead of using inline Drupal.settings code.
Not sure if we need a change record for this.
Comment #33
sunDo I need to understand why .extend() is used here? It doesn't seem to merge anything in? So why .extend() and not:
In any case, the code is missing a space before and after
tableHeaderOffset: {}.I'd love to see a follow-up issue to investigate whether we can generalize this approach, in order to make it work for other "sticky" things on the page (e.g., toolbar, admin_menu, etc), not only tableHeader.
1) Why .extend() again?
2) Missing spaces also here.
I'm not sure why Overlay takes into account the marginTop of the page. That looks bogus to me - this implementation shouldn't care for that. If anything, then it would be computeStickyOffsetTop().
settings.tableHeaderOffset.toolbar = Drupal.toolbar.height;
?
Still not sure why or how .extend() is useful here.
If the idea is to allow overrides by other modules, then the settings would have to merged in last?
However, I guess that custom overrides can be easily handled via JS file weights/ordering when added to the page.
Comment #34
nod_All right I think I haven't explained enough. I'm changing the nature of the tableHeaderOffset setting.
Before it was a string that we called with eval() later on.
Drupal.settings.tableHeaderOffset = 'Drupal.toolbar.height';This is not flexible. If another module, say overlay wants to add an offset it has to do monkey patching.
What it is now is an object of function:
And in the tableheader script, we just sum all the functions of this object. I choose an object instead of an array to be able to modify all that and avoid duplicates. extend is just an easy way to merge things and create what is needed if it doesn't exists. Since you can have several values, the || trick wouldn't work here.
Overlay is looking for the wrong value at the wrong place. Turns out this margin comes from toolbar to begin with, it should look for
parent.Drupal.tableHeaderOffsetinstead of that. I'll change the patch :) didn't want to move things around too much for this patch.So i'm actually making that extensible and contrib friendly. Which it is not right now.
The follow-up to make this generalized is to use a
data-offset-topattribute on the right HTML elements and expose an event that scripts can be bound to and react in case the value changes. the values would be fetched from a"[data-offset-top]"CSS selector so that you won't have to care about which element it is.There are other solution but this one would be the simplest from a code and extensibility perspective. I think there is an issue already i'll look it up.
Comment #35
nod_reroll
Comment #36
nod_See: #1574738: Rewrite tableheader.js
Comment #36.0
nod_add reference to meta issue