Code Monkey home page Code Monkey logo

pym.js's Introduction

Pym.js

IMPORTANT SECURITY ALERT : Pym users, we’ve released an update that closes a potential security hole. We recommend everyone update to 1.3.2 as soon as possible. More information here.

Build Status Sauce Test Status

Sauce Test Status

What is this?

Using iframes in a responsive page can be frustrating. It’s easy enough to make an iframe’s width span 100% of its container, but sizing its height is tricky — especially if the content of the iframe changes height depending on page width (for example, because of text wrapping or media queries) or events within the iframe.

Pym.js embeds and resizes an iframe responsively (width and height) within its parent container. It also bypasses the usual cross-domain issues.

Use case: The NPR Visuals team uses Pym.js to embed small custom bits of code (charts, maps, etc.) inside our CMS without CSS or JavaScript conflicts. See an example of this in action.

Assumptions

The following things are assumed to be true in this documentation.

  • You are running OS X.
  • You have installed Node.js.
  • You have installed Grunt globally.

For more details on the technology stack used in NPR Visuals' app template, see our development environment blog post.

Modern versions of Windows and Linux should work equally well but are untested by the NPR Visuals Team.

What's in here?

The project contains the following folders and important files:

  • dist -- Unminified and minified versions of pym.js library and the pym-loader.js loader.
  • examples -- Collection of working use cases for pym.js
  • src -- Source files for this project
  • test/pym -- Unit testing specs for pym.js
  • test/pym-loader -- Unit testing specs for pym-loader.js
  • test/html -- Child pages used for pym.js testing
  • test/html-fixtures -- HTML templates for testing loader through the htmljs karma preprocessor
  • .travis.yml -- Travis CI config file
  • Gruntfile.js -- Grunt.js task runner config file
  • karma.conf.js -- Karma runner configuration file
  • karma.conf-sauce.js -- Karma runner configuration file for Sauce Labs
  • nprapps_tools -- NPR Deployment tools to the CDN

Bootstrap the project

Node.js is required. If you don't already have it, get it like this:

brew install node

Then bootstrap the project:

npm install

In order to do your own tests in Sauce Labs (optional) you will need to have a Sauce Labs account (to their credit, they have a free tier for open source projects).

Once you have an account you will need to copy the example credentials file in the sauce folder to the actual credentials that will be used.

$ cd sauce
$ cp sauce_cred_sample.json sauce_cred.json

Edit the sauce_cred.json file to fill in your USERNAME and ACCESSKEY from user settings.

Hide project secrets

In this project the only project secrets that we have are the Sauce Labs credentials to secure a tunnel between Travis and Sauce Labs used in our continuous integration process. Those keys have been encrypted through Travis; you can read more about that process here

Project secrets should never be stored anywhere else in the repository. They will be leaked to the client if you do. Instead, always store passwords, keys, etc. in environment variables and document that they are needed here in the README.

Run the project

In order to run pym.js the best approach is to fire up a local webserver and go to the examples to see it in action.

The included server includes livereload so each time you change something on the examples or src folder the server will refresh the page for you.

$ cd pym.js
$ grunt server

Development tasks

Grunt configuration is included for running common development tasks.

Javascript can be linted with jshint:

grunt jshint

Unminified source can be regenerated with:

grunt concat

Minified source can be regenerated with:

grunt uglify

API documention can be generated with jsdoc:

grunt jsdoc

The release process is documented on the wiki.

Test the project

We have introduced unit testing for Pym.js starting with the 1.0.0 release. The Pym.js testing suite uses a combination of Karma, Jasmine and Sauce Labs to improve our browser coverage (Sauce Labs provides a nice free tier solution for opensource projects)

Test against your local browsers

Requires Chrome and Firefox installed on your machine

In order to run unit tests each time a change is detected, run:

grunt test

In order to run a one-off complete test suite, run:

npm test

Test against Sauce Labs browsers

First you will need to make a copy the credentials sample file sauce_cred_sample.json, call it sauce_cred.json, and update your Sauce Labs USERNAME and ACCESSKEY that you will obtain once you have set up an account with Sauce Labs.

$ cd sauce
$ cp sauce_cred_sample.json sauce_cred.json

In order to run unit tests each time a change is detected, run:

$ grunt sauce

In order to run a one-off complete test suite, run:

$ npm run sauce

For local testing the list of browsers to use can be modified on sauce/saucelabs-local-browsers.js. We use Travis CI for our continuous integration. When Travis is invoked it will use sauce/saucelabs-browsers.js as the list of browsers to test on.

A note around testing Pym.js on Sauce Labs, since the architecture of the tests with Travis and Sauce Labs creating tunnels between VMs is a bit unreliable in terms of timing in some random cases the response to a test case will not arrive in time and the test will fail due to a Timeout. We have tried to configure longer Timeouts for that error not to happen but still we find them during some test runs.

We have decided to create a small test suite using Travis own VM capabilities to test Pym.js on Firefox and declared the build successful if those tests pass. After that in the after_success section of the Travis CI configuration we launch the Sauce Labs tests but that will not affect the result of the build process.

So If you see some of the Browsers in the Sauce Labs Matrix as failures that is, presumably, the reason for it. We are in contact with Sauce Labs to figure out if there's a way around this issue.

Build the project

We use grunt tasks to build the project into the dist folder. Linting JS, preprocessing, uglyfing, etc.

$ grunt

We generate two copies of the pym and pym-loader libraries due to some really tight length requirements when embedding scripts in the homepage of some of our users CMSs.

  • p.v1.m.js is a copy/alias of pym-v1.min.js
  • pl.v1.m.js is a copy/alias of pym-loader-v1.min.js

Update the project

NPR only If a new version of pym is needed the workflow would be:

  • Make the needed changes on code and test it thoroughly in NPR.org and member stations test sites.
  • Change the version according following the semantic versioning pattern inside package.json and bower.json.

We use grunt tasks to build the project into the dist folder. Linting JS, preprocessing, uglyfing, etc.

$ grunt

That execution will create a minified and unminified version of our custom folder on the dist folder.

It will also generate an API documentation if you want to check that out run:

$ grunt server

and navigate to http://localhost:9000/api/pym.js/X.X.X/ on your browser.

Where X.X.X is the actual version defined in package.json

Deploy the project

After having build the new version of the library see above.

NPR only If a new version of the projects is needed the workflow would be:

cd nprapps_tools
mkvirtualenv pym.js
pip install -r requirements.txt
fab deploy

This will deploy whatever is inside the dist folder to S3 and make it available through a CDN at https://pym.nprapps.org/

Note: Pym.js is used widely outside of NPR so test thoroughly and use semantic versioning in order not to impact existing applications

Versioning

Starting with Pym.js v1.0.0, the project follows the semantic versioning pattern MAJOR.MINOR.PATCH.

  • MAJOR version changes for backwards-incompatible API changes.
  • MINOR version for new backwards-compatible functionality.
  • PATCH version for backwards-compatible bug fixes.

To minimize the impact on our current and future customers, on the uncompressed and on the minified production side of pym we are only going to keep the major version exposed. That we can apply PATCHES and MINOR version changes without any change being made on our customer's code but we maintain the possibility of new major releases that are somewhat disruptive with previous versions of the library.

  • pym.v1.0.0 and pym.v1.1.1 will both end up being minified into the same pym.v1.min.js.

  • You can safely assume that pym.v1.js and pym.v1.min.js will have the latest version of pym in that MAJOR version.

  • The same can be said for the pym-loader. pym-loader.v1.js and pym-loader.v1.min.js will have the latest version of pym-loader in that MAJOR version.

NPR will host and serve pym.js and pym-loader.js through a canonical CDN at pym.nprapps.com. We recommend that you link directly there to benefit instantaneously from the patches and minor releases.

What is the loader script for? Why do we need it?

Pym.js v1.0.0 development has been driven by a change needed to extend the ability to use Pym.js in certain CMSs used by NPR member stations and other use cases found by our collaborators that broke the loading process of loading Pym.js in common cases and thus made the embeds unusable.

We have decided to separate the particular needs of the Pym.js loading process in these special situations into a separate script that will act wrap and load Pym.js for these cases instead of polluting the Pym.js library itself with special needs of certain CMSs.

We want to keep Pym.js loading and invocation as manageable as possible. Due to the extensive use of Pym.js in many different environments, we encourage implementers to create special loaders if their integrations require it.

License and credits

Released under the MIT open source license. See LICENSE for details.

Pym.js was built by the NPR Visuals team, based on work by the NPR Tech Team and Ioseb Dzmanashvili. Thanks to Erik Hinton for suggesting the name.

Contributors

See CONTRIBUTORS

pym.js's People

Contributors

onyxfish avatar alykat avatar coreyhaines avatar jeremyjbowers avatar inadarei avatar awinder avatar eads avatar mbseid avatar jhnlsn avatar tylerfisher avatar jugglinmike avatar laurian avatar jschill avatar jaredbiehler avatar acmcelwee avatar al-the-x avatar eamodio avatar igowerf avatar zippy1981 avatar reefdog avatar mathisonian avatar veltman avatar paulschreiber avatar eyeseast avatar

Stargazers

Pierre Noël avatar Patrick Canella avatar Justin Myers avatar Cedric Twillie avatar Andrii Matenka avatar Jacqueline McCrief avatar Ilya Pomaskin avatar Bryan Leung avatar Evo Stamatov avatar Mark Baillie avatar asrar avatar Jerome Velociter avatar Tri Nguyen avatar 李学明 avatar Steven Benisek avatar Arthur avatar Christopher Meyers avatar  avatar  avatar Luca Talevi avatar  avatar Patrick Nelson avatar Danny Massey avatar  avatar Rohit Jain avatar fikrihakim avatar Karel Petrak avatar Zachary Taylor avatar Diana Chu avatar YiJie avatar  avatar Jeff Jack avatar Karabo The Answer avatar Tian Davis avatar Noritaka Kitamura avatar fones avatar Vitalii Kiiko avatar Calogero Guagenti avatar Logan King (DarkComet) avatar ShihJyun Yeo avatar Jasper Travers avatar Giorgos Sarigiannidis avatar Nina Lin avatar Yasin ATEŞ avatar Reacher avatar Stephen Harman avatar  avatar vulcangz avatar Manuel Gutjahr avatar Sérgio Santos avatar Z.-L. Deng avatar bison avatar Alex Popescu avatar Amit Kapoor avatar Jesse Tarnowski avatar Chad avatar yanglong avatar Mészáros Róbert avatar Ruchit Patel avatar Mohammad Tomaraei avatar Luiyit Hernandez avatar Mr. Rosario avatar Abhishek Tiwari avatar Intars Students avatar Micah Wood avatar Andrew Mason avatar Jeff avatar Alexey Golev avatar RenHans avatar baw123 avatar David Neuhaus avatar Everaldo Gomes avatar Daniel avatar Nikolay Kolev avatar BELHARRADI JAMAL avatar Glauber Funez avatar Jedsada Tiwongvorakul avatar Jeff Bargmann avatar Luciano avatar Ding avatar Jan Wächter avatar Thomas Pouillevet avatar David Authier avatar Hans Lemuet avatar 陈先生 avatar Daniel Kao avatar Hedula avatar Peter Harman avatar Juan avatar Damien Golding avatar Sam Carlton avatar Clifford avatar  avatar Alexey Volkov avatar JJ. Ramirez avatar Zen Monk Alain M. Lafon avatar  avatar chockingxiao avatar Augusto Franzoia avatar WelkinVan avatar

Watchers

Mikko Ohtamaa avatar Maciej Kuś avatar Tom Maslen avatar  avatar Geoffrey Hing avatar John Pearl avatar Matt Stiles avatar Bodey Baker avatar Danny Chapman avatar Mr. Rosario avatar Le TOULLEC Martial avatar Kryspin Ziemski avatar Urs Joss avatar  avatar Francesco Bartoli avatar david avatar  avatar  avatar Alex Bresler avatar  avatar James Cloos avatar Thomas Wilburn avatar Ian Rose avatar Katie Park avatar Gustavo Rodriguez Baldera avatar Dan Keemahill avatar Hilary Fung avatar Michael Anthony avatar Juan Elosua avatar jessenia araya avatar Greg avatar Quoctrung Bui avatar Ryan Marx avatar Claire O'Neill avatar Alice Goldfarb avatar  avatar liang.xu avatar  avatar Puneet B avatar Miles Watkins avatar  avatar Becky Lettenberger avatar Clinton King avatar  avatar Meredith Rizzo avatar Emily Bogle avatar Emily Martinez avatar  avatar Helga Salinas avatar Eunice Esomonu avatar Nathan Goldbaum avatar 1008k avatar Owen Phillips avatar  avatar Brittany Renee Mayes avatar  avatar  avatar  avatar Matthew Zhang avatar  avatar Paula Martinez avatar Jim Hill avatar panda avatar  avatar  avatar  avatar VQ avatar Roy avatar  avatar

pym.js's Issues

body with height: 100% doesn't work with sendHeight()

Child documents which have height: 100% set on their body (which many .css reset libraries do), accessing the document height with:

 document.getElementsByTagName('body')[0].offsetHeight.toString();

will return the initial height of the iframe regardless of additional calls to sendHeight().

A more robust height calculation might be:

var body = document.body,
  html = document.documentElement;

var height = Math.max( body.scrollHeight, body.offsetHeight,
          html.clientHeight, html.scrollHeight, html.offsetHeight );

as referenced here: http://stackoverflow.com/questions/1145850/how-to-get-height-of-entire-document-with-javascript.

I'm not sure that this would cause an issue to existing height calculations, but I'd be happy to go ahead and create a pull request if you guys think that this approach is good.

IE11 compatibility

Since upgrading to the latest version of Pym, we've been getting reports that it's not resizing on load from IE11 users. We haven't been able to reproduce it just yet, but I'm wondering if anyone else has seen this issue.

Capture status from the child page inside iframe

Hello,

I am trying to capture error status from a child page that I am loading from pym. When the child page detects invalid user, it will return status 401 on the header and I want to be able to get that status and redirect the user to the parent site's login page.

How can I get this status code from the child page?

Thanks,
Suriyanto

Jump/anchor links within the iframe don't work on iOS

Use case: A table with information specific to each state — something like this early voting project from 2012:

image

And, when the table is iframed in, it makes total sense that it wouldn't work. But maybe it's not terribly painful to figure out? Initial thought: Get the y-position of the iframe on the parent page and the y-position of the anchor on the child page, and then jump to (iframe-y + anchor-y) on the parent page.

sendMessage documentation is inaccurate

Specifically, this line:

pymParent.sendMessageToChild('navigate', e.target.href);

Looks like we need to update to reflect the pymParent.sendMessage() in the current release and maybe also provide an example using pymChild.sendMessage().

Shouldn't use HTML tags to select iframe containers

Because that means they all have to be on the page when I run it. And if I run it again now I've initialized them twice. I don't think I would care about this if it was just for us, but a library should be more flexible.

Suggested pattern:

window.responsiveParent('#embed1', {});
window.responsiveParent('#embed2', {});

Scrollbar quirk in OS X: Inaccurate width calculated on initial load

Found an interesting quirk re: scrollbars in OS X and calculating browser width.

If the content on the page is super-short before the iframe loads (and therefore the page has no scrollbar initially), and you have one of these OS X scrollbar settings set:

image
image

Pym will calculate the width of the browser and without taking into account the width of the scrollbar. So, on initial load, a graphic might be drawn about 15px too wide (but will fix itself onresize).

To replicate, on a Mac, go to System Preferences > General and try one of the two settings above. Then test this URL:

http://apps.npr.org/dailygraphics/graphics/salt-yeast-alcohol-alastair/

When it's misbehaving, the "4" at the end of the x-axis gets cut off / does not appear.

Noted in OS X 10.9.3 in Chrome and Firefox. (Didn't check Safari.)

(Thanks to @dannydb for helping to identify what was causing the problem.)

Use JSON to pass messages instead of plaintext?

In attempting to utilize Pym with another library, I encountered a situation in which the other library was listening to message events, expecting JSON, and blindly passing the message through JSON.parse(). This 3rd-party would be better served by filtering messages from domains that it cared about instead of everybody and their siblings, and I've filed a bug with that author appropriately.

However, it made me aware of the message format that Pym was using for communication: responsive(parent|child) [id] [height]. Have you considered using JSON instead? This would have the advantage of utilizing JSON.parse() instead of regex parsing and make the communication a little more readable. Just a thought, and I'm happy to send a PR.

hash in child_url breaks the params

If I need to load the frame as frame.html#foo, the iframe src will be frame.html#foo?initialWidth=970&childId=frame, it should be frame.html?initialWidth=970&childId=frame#foo

Browser testing

Make sure everything still works the way we expect in all the browsers we support.

Handle iframes created by external javascript

Hi,

The way I understand Pym from looking at its documentation, it currently needs a child HTML URL as a parameter of pym.Parent. What about iframes created by inserting a piece of 3rd-party javascript, is this going to be within the scope of your library? It sounds like a lot of extra work to create chunks of HTML in the CMS to host just the javascript embeds to be inserted in actual entries.

For context about my use case, I'm looking for something akin to FitVids or Fluidvids to make Tableau embeds responsive.

Link clicking inside <iframe>, explicitly setting child id

I have an <iframe> where normal click-the-link navigation and post-the-form page loading is possible. The child JavaScript re-initializes the Pym messaging on window.load after the page has been reloaded. I am not sure if this is a very common use case or should it have worked out of the box.

The site: http://libertymusicstore.net/

I had to make some changes to Pym to make this work, so that the page inside the iframe can message the parent after clicking the link. Link becomes <iframe src> and because this src doesn't contain Pym-specific query parameters given on the initial Pym embed when parent creates the iframe, the id token needed for postMessage() communication is lost.

When the child in initialized it explicitly gives the id in JavaScript:

/**
* Handle <iframe> embed and signalling with the parent frame.
*/
function initEmbed() {
    pymChild = new pym.Child({id: "store-embed-iframe-wrapper"});

    $(window).load(function() {      
        pymChild.sendHeightToParent();
    });
}

And then Pym can pick this id up from from the settings, instead of link URL

    // Identify what ID the parent knows this child as.
    // Also accept id from the child contruction parameters,
    // so that you can keep sending message to the parent with specific
    // after iframe page loads
    this.id = this.getParameterByName('childId') || this.settings.id; 

If you are interested in pull request, I can create one, now the code lives only here:

https://github.com/miohtama/LibertyMusicStore/blob/master/tatianastore/static/pym.js#L230

Multiple responsive iframes not getting height value till resize

I'm using pym.js to display multiple iframes on a single page, each iframe is contained on a different tab of a javascript tab table (http://publicsource.org/pittsburgh-crime-statistics-2010-2013).

I'm running into issues on Firefox and Internet Explorer where the iframes on tabs 2 and 3 are not receiving a height until the iframe page is manually resized. Not working at all on Internet Explorer.

I'm pretty sure the issues is with how/where I'm calling the pym.js, but I was hoping you could give me a bit of help on this. Using Drupal 7.

Best,
A

"autoinit" feature

My use-case for pym.js is similar to the motivating example in the project website (embedding an iframe in a CMS document), but I have an additional restriction: the CMS actively scrubs in-line JavaScript. I would like to instruct pym.js to automatically instantiate a parent connection on iframes that opt-in to the functionality. For instance:

<!-- opt in to the "auto initialization" functionality with an HTML5 `data-` attribute -->
<script src="pym.js" data-pym-autoinit="autoinit-target-class"></script>

<div class="autoinit-target-class" data-pym-src="http://example.com/some/child.html"></div>
<!-- optionally specify an `domain` regex: -->
<div class="autoinit-target-class" data-pym-src="http://example.com/some/child.html" data-pym-xdomain="\.npr\.org"></div>

I would be happy to draw up a draft implementation (I'm actively pursuing this in a fork), but I'm interested in gauging interest from the maintainers before submitting a pull request. What do you think?

renderCallback arguments

The README might want to specify that renderCallback is passed the new width of the parent. Sort of obvious, but had to go through source to verify.

This is a life changer.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.