Updated: Comment #6
Problem/Motivation
Currently the Juicebox javascript (both the library and the gallery-specific js logic) are added with drupal_add_js() and library_load(). This means that whenever a field/view that contains a gallery is built, the js will be included on the page no matter what. This is an issue because sometimes build logic will get triggered even when the embed code does not ultimately get displayed on the page. When this happens javascript is triggered that looks for an embed div that it can't find, and Juicebox errors result.
A specific example is when an entity that contains a gallery comes back as a "hit" in the core Drupal search. In this case the the entity is both built and rendered, even though only a very small snippet will be included on the search results. This leads to the very intrusive "Cannot find div with id on Search page" library error that takes over the whole page.
Proposed resolution
There are a couple layers that need to be addressed. First, this module should start using the '#attached' part of a render array to include all it's js and css assets. This will ensure that its js is only loaded when a gallery is actually rendered. Hopefully this will address most issues.
Secondly, there are potentially special cases where a gallery is rendered by not displayed in full (such as in search results). This will probably require some custom logic that detects incompatible cases/view-modes where a gallery should never be displayed with its assets.
User interface changes
None.
API changes
Sorting all this out may lead to at least one new method on the JuiceboxGalleryInterface, most likely called getEmbed(). This will be used instead of the previous renderEmbed() and will return a render array instead of direct embed markup. The change can be handled internally as part of the fix for this issue, but anyone building galleries programmatically may need to adjust as well (I'm not aware of anyone doing this, but it's worth noting).
Original report by pdesai
Juicebox Error: Cannot find div with id on Search page
I am not sure why juicebox is being added since I don't have the image field in the teaser. Anyway to disable it?
| Comment | File | Size | Author |
|---|---|---|---|
| #18 | Screen Shot 2014-11-10 at 5.02.02 PM.png | 70.66 KB | MO-2 |
| #9 | juicebox_fix_js_error_on_search_results-2217791-9.patch | 5.11 KB | rjacobs |
Comments
Comment #1
rjacobs commentedHi pdesai,
Are you saying that you get the Juicebox javascript "Cannot find div with id" error (the one that insists on taking up the whole page) whenever you run a search that finds a match/hit on a node that happens to contain a Juicebox gallery field? Is the behavior that you encounter even if search does not actually render that Juicebox field in the results list?
I just want to better understand what's involved in replicating this.
Comment #2
pdesai commentedYes that is exactly correct. It takes up the whole page, but I don't have a field in the easier.
Comment #3
rjacobs commentedI see. I was able to replicate this and I think I have an idea about what's going on. It seems that once Drupal finds "hits" for a search phrase (against the search index) it does a full load of the matched nodes, which also builds all the fields on those matched nodes. I assume it does this so that it can extract a teaser of the matched text in context with the rest of node's content for display in the results list.
Anyway, this module currently includes its javascript and css via calls to libraries_load() and drupal_add_js(), which fire when the field is loaded and built. This means that the Juicebox javascript for a field can get included even if the field is never actually rendered. In these cases the embed code does not appear on the page, but javascript is still triggered that expects to find it, hence the error.
The better way to do things will be to add the needed javascript and css via the '#attached' part of a render array, so that it's only added if the field is actually fully rendered and displayed. This is already how things work in the Drupal 8 branch of this module, and I've been meaning to backport the idea to the Drupal 7 version in the interest of "best practices". I hadn't gotten around to that yet as there was no known issue with the old method... until now that is.
This should be a fairly straightforward issue to address, but it will require some refactoring.
Comment #4
pdesai commentedGlad you were able to reproduce it. Appreciate the thorough explanation. Looking forward to a patch.
Comment #5
rjacobs commentedWell, like so many things, this is actually more complicated than I thought.
There will be great value in switching to '#attached' instead of drupal_add_js() for the gallery javascript additions, but unfortunately it won't solve this specific problem. From what I can see, when a search "hit" is found not only is the found node built, but it's also fully rendered. I guess that the core search method needs to render all of the node text before it can calculate which specific text to display. Because of this it does not matter how the js is included. With either '#attached' or drupal_add_js(), the gallery javascript will still get added. That makes me sad.
Anyway, there is an easy way around this, and it has nothing to do with Juicebox. The key is the fact that Drupal allows you to specify a different view mode for search results, and the gallery field can simply be excluded from that view mode. To do this:
After doing this, that search problem should go away, as the Juicebox formatter will no longer be used when any search results are displayed.
This should be a workable fix for most situations, but I'll still give this some thought to see if there is something else the module can do to avoid this.
I also still plan in making that switch to using '#attached' in the code. As I noted, there is still much value in doing that.
Comment #6
rjacobs commentedAdd summary as this issue has a few layers, and it'll be easiest to just address them all at once.
Comment #8
rjacobs commentedThe commit above is broad-sweeping and addresses:
This should not only prevent lots of weird cases where that "Cannot find div with id" error could popup, but also lays the foundation to address other specific cases (such as the issue with search results).
Comment #9
rjacobs commentedAs noted, with the commit above in place the specific search results part can now be addressed. The attached patch simply detects the "search_result" view mode and omits the javascript in that case.
@pdesai, can you test this out against the most recent dev? Note that it will only apply against today's dev or later. For testing you'll want to make sure that you did not follow my suggestion in comment #5. That suggestion is still totally valid and will eliminate this problem (so feel free to use it later), but the point of this patch is to make sure people don't have to do that to avoid the search-related error.
Comment #11
rjacobs commentedThis has decent test coverage in 7.x-2.x, so I committed the final part.
Now there are a couple pieces related to this that will need attention in 8.x-2.x. That D8 branch already processes all js/css via '#attached' keys in a render array, but there may be some value in porting the search results display mode filter logic, etc. I guess I'll just address that in this issue as well...
Comment #13
rjacobs commentedOk, the relevant pieces have now been ported to 8.x-2.x.
Comment #15
pdesai commentedGreat stuff rjacobs!
Comment #16
MO-2 commentedHi Guys,
I have a very similar issue that has popped up, but the dev version with the patch doesn't address it. I'm using display suite search and want to use the "search snippet" field to display some of the search text. However, that field must be calling the juicebox JS because I get the following error and the entire search results page is greyed out:
Juicebox Error: Cannot find div with id: "field--node--303--field-article-image--search-index"
Any ideas on a patch for the search snippets?
Thanks ahead of time,
MO
Comment #17
rjacobs commentedHi MO. I suspect that you have indeed found a case that's technically related to the initial issue, but I'm only superficially familiar with Display Suite, so I can't say anything too definitive just yet.
One of the changes that was implemented above is some ad hoc detection of the view mode that Drupal typically uses for rendering entities within the presentation of individual search results. This detection then allows the module to ensure no Juicebox javascript is added when that mode is used (thus preventing the "cannot find div" error in search results lists). This detection is really just a convenience though as it's still also possible to manually set the field instance specifics for the "search result" view mode to not use Juicebox altogether - see comment #5. I might guess that this same thing is also possible for whatever custom view mode Display Suite uses for it's search results. Would you be able to test the numbered steps from comment #5 to see if it applies for display suites as well? You would just have to see if there is a Display Suite equivalent for the "search result" view mode that those steps reference (perhaps it's called something like "Display Suite Search Result").
Either way, I would not be opposed to enhancing the search result detection of the module itself to be aware of Display Suite Search (so manual steps are not needed), but that would requite a bit more analysis.
Comment #18
MO-2 commentedHi RJacobs,
Thanks for the quick response. I have done exactly this. The specific field that is breaking the search results page is the "search snippet" as shown in the attached screenshot. This display field is made available via the display suite search module. When I remove this filed, then the search results page renders correctly. As you can see, I'm only showing the image using the classic formatter (leveraging another module to show only one result). The search snippet field must be referencing the juicebox gallery, but I'm not sure how to troubleshoot this and avoid it from crashing the search results page.
I would like to use the search snippet field because it provides a nice UX on the search results page.
Thanks ahead of time for any ideas,
MO
Comment #19
rjacobs commentedHumm, that's interesting. I thought the built-in "Search Result" view mode is what Drupal uses to calculate the search snippet, and not what's actually shown in the search result (i.e., it represents what's rendered before the snippet is calculated). What you've shown seems to indicate that display suite might somehow override this core behavior while also offering it's own separate "snippet" field.
So the big question is how Display Suite sources the data for that "search snippet" field. Can that be configured? Is it possible to tell Display Suite to use a specific view mode when calculating that snippet, or does it always use the full/default view mode to source that data?
Obviously I'm not to clued up on Display Suite :) ... at some point soon I'll have to dig into it on a dev instance.
If this gets too detailed, we will probably want to open a new issue. Things are technically aligned with the comments above, but we may be venturing into "feature request" land if an explicit Display Suite compatibility commit is needed.
Comment #20
rjacobs commentedOk, I think I see what's happening. It looks like Display Suite uses a different view mode for its search snippet, which is not getting detected by Juicebox.
Addressing this will probably require a patch, so opening another issue makes sense. I've opened the follow-up feature request: #2376401: Prevent javascript from being added within a Display Suite search snippet view mode
MO, if you can check-in on that other issue that would be great.
Comment #21
rjacobs commentedAs a separate follow-up issue is open for the Display Suite case, I'll restore the closed status on this one.