10

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 won't 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 as well.

So, although I've never thought I'd think so: I think using an iframe may be the better option here, isn't it?

PS: My main problem is that I can't 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 didn't 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.

bad_coder
  • 5,829
  • 13
  • 26
  • 41
Alex
  • 9,339
  • 2
  • 28
  • 46
  • You could have a "reset.css" file which cleans up all of the previously loaded css - but then you'd need to know exactly what each page was going to apply in the way of css, which it sounds like you have no control over. It's also possible to unload css if loaded via `link`s, but again, depends on how you load the css, have a look here: http://stackoverflow.com/questions/1598899/unload-css-from-webpage – freedomn-m Feb 02 '16 at 11:44
  • the css is no problem. if you remove style or link elements, the css gets undone. if you append the new ones, the styles get updated. but scripts behave differently – Alex Feb 02 '16 at 14:15
  • Why do you need to have different css/js files? Can't you concatenate/minify them and serve once? In this way when change page you just need to handle correctly the different states (bind events, unbind them...). – Luigi De Rosa Feb 07 '16 at 00:18
  • are you using pjax (or similiar, e.g. https://github.com/defunkt/jquery-pjax) for those requests? – luchaos Feb 09 '16 at 00:23
  • 1
    @luchaos nope, common jquery ajax – Alex Feb 09 '16 at 08:52
  • I personally like ajax over iframe because ajax can deal with simple xml responses that will affect the properties of objects and not need to worry about the visual aspects. – CoveGeek Feb 11 '16 at 17:40
  • @CoveGeek but that doesnt help me in this particular case :) – Alex Feb 12 '16 at 09:10
  • `iframe` is definitely buggy as hell. I know it's easier said than done, but you could totally avoid it if you have scripts that don't conflict each other -- targeted to only the dynamic container. – ton Aug 31 '16 at 08:30

5 Answers5

3

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.

Flip Vernooij
  • 804
  • 5
  • 10
  • We are currently testing the iframe method and its gorgeous. The only real downside is iOS, it has huge problems with iframes and also bugs :( – Alex Feb 12 '16 at 09:05
3

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

jlulloav
  • 152
  • 3
  • If your goal is to keep a single content region, then this will work. – CoveGeek Feb 11 '16 at 17:39
  • We are currently testing the iframe method and its gorgeous. The only real downside is iOS, it has huge problems with iframes and also bugs. I dont think SEO will be a problem since the iframe will only be generated when you click a link (via JS). – Alex Feb 12 '16 at 09:04
0

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.

Community
  • 1
  • 1
Serge Seredenko
  • 3,421
  • 7
  • 19
  • 36
  • Allude this is fun too do, solutions like this are very complex and will undoubtedly cause issues in the future. While their are instances that this is worth the risc... in this case there is a solution that is much easier. – Flip Vernooij Feb 11 '16 at 15:28
  • @FlipVernooij Which is exactly why I advise against such approach in the answer. – Serge Seredenko Feb 11 '16 at 20:21
-1

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.

serdarsenay
  • 2,363
  • 19
  • 21
  • Thanks for your input, but I dont quite get what you're trying to say. Even if I would use backbone or angular, I'd still face the problem of page-depended scripts and styles. What exactly are your questions? :) temporary upvote <3 – Alex Feb 12 '16 at 09:02
  • Hey thanks, well what I asked was your backend, ie where the js and css run, on a simple apache/nginx/jetty whatever webserver or accompanied with a backend language like php, java or nodejs, according to this I was going to suggest organising your content serving part in a better way so that you do not run into issues where you're only stuck with using iframes. – serdarsenay Feb 12 '16 at 12:48
  • As I wrote we use Drupal, so PHP. Still, the language does not prevent my problem, that different pages may have different scripts – Alex Feb 12 '16 at 14:25
  • thanks for your time but you havent understood at all what the problem is :) never mind – Alex Feb 16 '16 at 08:22
  • You're welcome, thanks for the down vote I deserve it because at least I tried to help. – serdarsenay Feb 16 '16 at 10:33
-1

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.

  • "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)." – Alex Feb 12 '16 at 08:59
  • But that would be preferable then to load whole page with css and js elements in iframe itself. – Sahil Kanani Feb 12 '16 at 09:07
  • I think you havent understood any bit of the problem. Loading the content via AJAX is no big deal, but what about JS and CSS? Please read my question again carefully. – Alex Feb 12 '16 at 09:10
  • To elaborate, I assume your users upload sound files somehow and you need to persist these in a database, how do you talk to your database? You need a server side bit to do this, frontend js can't speak to a db? If your content are all static, still you can make use of a server side to make it easier for you to add content – serdarsenay Feb 12 '16 at 12:50
  • OK sure I get your question but I wanted to help in a deeper way as iframes will not solve your issue completely, you need to always have a solid architecture for future proofingyour app, would you like to talk on skype or something? I'd love to help if you want. – serdarsenay Feb 12 '16 at 12:52