We're building a Drupal site with an audio player which should keep playing while you browse the page (something like soundcloud).
Currently we're loading clicked <a>
's sites with ajax and inject the html into the page and use history.js to manipulate the location.
There is a major downside though:
Since a newly loaded page may have different css and js on it, we have to compare the current script, style and link elements to the ajax response text (ugly regex) and only add the new, yet non-existing elements. By doing so, loading another page wont delete/remove/undo once executed scripts. This may become a performance issue (while regex against markup is anyways).
Using an iframe may solve this and other problems:
When you first click a link on the site, the page content is replaced by an iframe which just loads the page. The audio player is in the original dom, i. e. outside the iframe. Clicking links inside the iframe can be caught and used within the history api aswell.
So, although I've never thought I'd think so: I think using an iframe may be the better option here, isnt it?
PS: my main problem is that I cant control that different pages on the website have different scripts, the styles really are no problem. If there was just one huge static js and css website-wide, I didnt have a problem.
Update
The iframe solution works fine, except in iOS. Iframes are buggy as hell. Still, I think we're going with the iframe solution.
I would say... keep it simple, stupid.
Go for the iframe solution, I know it kills a part of your soul, but it is the easiest solution to your problem and represents the lowest change of running into problems in the future.
KISS.
I don't see a reason you shouldn't use iframe. I think using iframe to embed pages inside your website is fine. That is what an iframe is for.
The iframes used to be bad for SEO, however, today web crawlers can usually travel between your website and iframes content.
Using iframe will be easier and simpler for you instead of using "ugly regex". Why don't keep it simple, right? KISS principle
You could try doing some weird stuff.
Firstly, you could compare window
object to fresh one and remove all extra properties (here's an example). Same thing could be done do document
, HTMLElement
, Array.prototype
objects and others, which are possibly extended via scripts. That way you'd eliminate much of the defined stuff, and garbage collector would drop that at some point.
Secondly, you'd want to remove all event listeners. That is possible by redefining addEventListener
etc (refer to this question for example).
Thirdly, you shouldn't forget about intervals and timeouts, which can be dealt with using the same approach as previous one (wrapping setTimeout
etc) (found it here).
Of course there would be a lot of stuff left, depending on which scripts are run in the page. So you could refresh a page when user clicks a link while a song isn't playing (transition between tracks maybe). See? A lot of work to do, and this may give nothing. So after all those theories I'd use iframe. Because, you know, example: if some of your site's scripts wrap any js function (like we do in secondly and thirdly), then ajaxing would pile up wrapping calls on that function, which is really bad.
As you said,
Using an iframe may solve this and other problems:
When you first click a link on the site, the page content is replaced by an iframe which just loads the page. The audio player is in the original dom, i. e. outside the iframe. Clicking links inside the iframe can be caught and used within the history api aswell.
You can do similar thing with ajax. Put all the content that needs to be replaced in one container and just replace the content of that container based on ajax response. Don't touch the content outside of that container. I think that will also solve your performance issue as well.
I'd like to ask you a few questions and edit this response as you respond, if you don't mind.
The reason for this is I believe you have made some inconvenient architectural decisions when you started this project. From your description I'm asuming you're loading static html pages when a tags are clicked, if not, what is your backend technology?
You should ideally separate the logic into front and back end, and separate your front end into models, views and controllers, not necessarily by using frame works, or by doing so (or MVVM, as angular does it) Some quick recommendations on how you're loading the data, do not inject html directly, use your backend tech to send json or xml to front end, and parse that to display your html, on a template that resides on frontend, rather than sending your dom down, which will be unnecessarily slow and expensive to do so. When you have a back end, try to build your persistance layer in a black box environment, and call the manipulator methods via a simple API, that way it'll be way more clean and perform faster and more reliable. Also that way, when you build mobile native apps, you simply re-use your API layer.
Regular expression comparisons on css and js sounds like a total bad hack, I agree, it would be more suitable to use iframes, but again, I need a bit more info to discuss your overall setup and hopefully help you on a broader perspective.
UPDATE:
I understand why the pages may have different css but I assume your music player js should be the same source with different media IDs attached to them. Assuming this setup, in your drupal database, which I assume is MySql, make a custom table for your "music player" pages, apart from the standard id index entry as well as created_at, modified_at etc, have one field for your playable sources.
On your Drupal front end template, where you create the actual player, write this source ID from your database. this way you have one page for your musical pages. For CSS keep everything in one file, perhaps use something like SASS or LESS to compile your css file, to keep everything in more order.
In a gist, have your drupal side, php write your html page with embedded JS, and have the ID pass from the DB to front end via a PHP variable, as PHP rendering happens server side, by the time DOM is loaded along with your JS, the page ID's will be present. Hope this helps, let me know if you have more questions.