Code Monkey home page Code Monkey logo

intentionjs's Introduction

intention.js

DOM Manipulation via html attribute specification

Why intention.js

It's like a super amped up version of media queries on a per element basis!

The technology for dealing with responsive design is all over the place. Media queries, hacky javascript, and convoluted HTML. intention.js allows you to make all of the changes to HTML in the HTML itself. It's a way to describe the necessary differences of an HTML document between one device and another.

What should the classes of an element be on mobile vs tablet? Where should your advertising code get placed when you're on a desktop? Does the page require an alternate slideshow widget on touch enabled devices? These are all changes that intention.js can make to the page based on a user's device. context.js creates a set of common page contexts for width thresholds, touch devices, highres displays and a fallback.

And you can easily add your own contexts on top of these or create all your own custom contexts.

What's included:

* intention.js
* context.js

intention.js is the library that manages the responsive axis, manipulates elements based on their specifications and emits events when contexts change.

context.js is an implementation of intention.js that sets up common use patterns in responsive design.

Specifically it has the responsive contexts: * base (a catch-all) * mobile (triggered by width) * tablet (triggered by width) * standard (triggered by width) * portrait (orientation axis) * landscape (orientation axis) * touch * highres

Installation

Dependencies of intention

* jquery
* underscore.js

include scripts on your page or just Intention via require.

	<!-- use with context defaults -->
	<script
		data-main="assets/js/context"
		src="assets/js/require/require.js"></script>

OR:

	<!-- use only intention to build your own context -->
	<script src="underscore.js"></script>
	<script src="jquery.js"></script>
	<script src="intention.js"></script>
	<script src="context.js"></script>
	<script>
		// your amazing contextual threshold specification here!
	</script>

Usage

By default context.js provides a number of threshold groups via intention.js: browser widths, orientation, touch, highres, and a base group

the default thresholds in each group are respectively: mobile (510 and below), tablet (510 to 840) and standard (840 to Infinity) portrait or landscape touch (are touch gestures available) highres (devicePixelRatio > 1) base (default, always on)

There are three manipulation types: class names, attributes, placement on the page

Interface

flag the element as "intentional"

	<div intent>

Or for valid html:

	<div data-intent>

An intentional attribute:

For the purposes of the documentation the prefix "in-" will be used instead of "data-in-" to keep the code snippets concise

Context aware elements

	<img intent in-orientation: src="cat.jpg" />

In the "portrait" orientation the above implementation will produce:

	<img class="portrait" src="cat.jpg" />

And in "landscape" orientation:

	<img class="landscape" src="cat.jpg" />

context.js includes four context groups or "axes"

* width
* orientation
* touch
* highres

They are associated with the following classes

* width
	* mobile
	* tablet
	* standard
* orientation
	* portrait
	* landscape
* touch
	* touch
* highres
	* highres

Attribute structure: prefix-context-function="value"

i.e.

	<div class="not interesting" intent in-mobile-class="more interesting">

Types of manipulation

Attribute Manipulation

mark an element as intention, set the base(default) attribute, specify which image to load in a given context

	<img
		intent
		in-base-src="small_img.png"
		in-highres-src="big_img.png" />

the specification above will produce the following in each context default:

<img src="small_img.png" />

highres:

<img src="big_img.png" />

Class Manipulation

An element can have more than one class. intent's aim is to be as unobtrusive as possible, at the same time allowing for a lot of flexibility with the way classes are combined.

	<section
		class="column"
		intent
		in-mobile-class="narrow"
		in-tablet-class="medium"
		in-standard-class="wide"
		in-luxury-class="x-wide"
		in-touch-class="swipe-nav"
	>...</section>

Placement Manipulation

take this html structure

	<header><nav></nav></header>
	<section>...</section>
	<footer>...</footer>

suppose we want to demote the status of the nav when the user is on smaller devices

the following specification on the nav might do what we need

	<nav intent
		in-mobile-prepend="footer"
		in-tablet-append="section"
		in-standard-append="header">

when the device is 320px units or below the nav will appear at the top of the footer. when the device is between 320 and 768 it will go to the end of the section tag, and so forth.

Move functions
* prepend
* append
* before
* after

Why a base context?

In most scenarios you don't want to have to specify the way something will change in every context. Often times an element will be one of two things among many different contexts. take an img tag with two possible sources, it's either going to be highres or not. by specifying the in-highres-src attribute, you know that the source will be appropriately applied in that scenario. With a in-base-src attribute, you can rely on the source being set accordingly for all other contexts.

Making your own custom contexts or Intentional plugins

In addition to what is provided as a set of useful page contexts in the context.js script. You can define your own contexts, for anything!

You can extend the functionality of context.js or scrap the whole thing entirely.

Here is an example for scroll depth responsive axis:

	var scrolldepth_axis = intent.responsive({
		ID: 'scrolldepth',
		// contexts
		contexts: [{name:'shallow', value:20}, {name:'deep', value:1/0}],
		// matching:
		matcher: function(measure, context){
			return measure < context.value;
		},
		// measure
		measure:function(){
			return window.pageYOffset;
		}});

intent.responsive returns an object with a bunch of useful properties. probably the most important is "respond" when you want to evaluate which context is relevant call scrolldepth_axis.respond();

for the above example you would want to call the respond function on window scroll

like so:

	$(window).on('scroll', scrolldepth_axis.respond);

The optional "ID" property allows for context aware element feature for the axis outlined above.

this will compare the measurement against each context and determine which context is relevant every time the window is scrolled.

Other properties of intent.responsive include:

* ID
* current (the current context)
* contexts (the list of contexts you passed)

this will add all elements matching the "$('[data-intent],[intent],[data-in],[in]')" selector. Optionally pass a scope argument to this function to specify where in the dom to start searching. The default is the document.

calling the elements function will change the elements' attributes to the specification provided in the html as it finds them. This way your responsive axis can all be defined before any changes are made to the DOM.

The components intent.responsive

axis (contexts)

The thresholds are an array of context objects. the only requirement of these objects is that they have a name property.

name is a required property of a context object

	[{name:'shallow'}, {name:'deep'}]

You can specify any other properties (such as scroll depth values)

	[{name:'shallow', depth:20},
		{name:'deep', depth: Infinity}]
"matcher" function

The matching function is called for each item in the thresholds array until a match is made i.e. it returns true. it is totally optional. However if it is not specified a default will be used which matches based on the context name. have a look in the Default Compare Functions section for the specifics.

The context that produces a match is then understood as the current context for the threshold group. In other words there will only every be ONE matched context for a threshold group.

If a matching function is not specified this default is used:

    function(measure, context){
      return measure === context.name;
    };
"measure" function

default measure function is a pass-through

	function(arg){
      return arg;
    };

why? intent.responsive() // outputs a function. so calling the result of that function with an argument passed to it will get used as the measure arg in the matcher function

like so:

	// make a responsive group *thresholds* is the array of contexts and *matcher* is a custom comparison function
	var responsive = intent.responsive(thresholds, matcher);
	// assuming we want to compare the scroll depth against each context you could do something like this:
	responsive(window.pageYOffset);

in this example window.pageYOffset would get passed as the first argument to the matcher function for every context until the matcher returns true.

Putting it all together

Threshold objects must be passed to intent.responsive as an array

The only other requirement is that the threshold object has a "name" property, i.e. {name:'slow_page'}. The name is used for two main things: emmiting an event of that name on the intent object and allowing you to create specifications in the html for that threshold.

* names may *not* have dashes
* names can have "_"
* the regex to match them is simply: [_a-zA-Z0-9]+

to create an event handler for a threshold:

intent.on('slow_page', function(){
	alert('try another wifi network');
});

to specify changes to the html when in that threshold

	<img intent in-slow_page-src="toobad.gif" />

Default Matcher and Measure Functions

Matcher

    function(measure, ctx){
      return measure === ctx.name;
    };

Measure

  	// measure default is just a pass through
    function(arg){
      return arg;
    };

Stuff to note:

Master list of document manipulation types:

Multi-value attr (union of all current contexts)

* class

Move Functions

* append
* prepend
* before
* after

Single-value attrs, (everything else)

* any arbitrary atribute that doesn't include a dash.

Author

* Joe Kendall

Contributors

* Erin Sparling
* Adrian Lafond
* Mike Stamm

Major Contributions to examples and documentation

* Camila Mercado
* Paul Pangrazzi

License

	// MIT license for everything

	// Copyright (c) 2012 The Wall Street Journal,
	// http://wsj.com/

	// Permission is hereby granted, free of charge, to any person obtaining
	// a copy of this software and associated documentation files (the
	// "Software"), to deal in the Software without restriction, including
	// without limitation the rights to use, copy, modify, merge, publish,
	// distribute, sublicense, and/or sell copies of the Software, and to
	// permit persons to whom the Software is furnished to do so, subject to
	// the following conditions:

	// The above copyright notice and this permission notice shall be
	// included in all copies or substantial portions of the Software.

	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
	// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
	// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
	// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
	// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

intentionjs's People

Contributors

1800joe avatar adamrights avatar daviddacosta avatar everyplace avatar heatloss avatar tylerpaige avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

intentionjs's Issues

Intent doesn't validate

Adding intention invalidates html. Is there any way to add intention and make it validate?

"Attribute intent not allowed on element link at this point."

Intention is not called when window is maximized(maximize button clicked)

I'm trying to use intentionjs.
It works very nicely, but when the window is maximized from mobile view the structure stays as mobile structure.

Can you help me please?

Here is the code:

var responsive = intent.responsive({
    ID: "responsive",
    contexts: [
        {name:"desktop",min:mobile, max: desktop},
        {name:"mobile",min:0, max:mobile}
    ],
    matcher: function(test, context) {
        return (test > context.min && test < context.max);
    },
    measure:function(arg) {
        return window.innerWidth;
    }
});

intent.on("desktop", function (e) {
    console.log(e); // does not work on maximize
});

intent.on("mobile", function (e) {
    console.log(e); // this works on minimize
});

The problem with Wordpress

The problem is that when generating the content to which containers are steps for each duplicate div after which the condition is set.

Add plug to Twitter

Might as well consider how to leave room for all external links (DJ Foundry, twitter, etc)

Confusion in checking replicate elements

https://github.com/dowjones/intentionjs/blob/master/intention.js#L103

I found it quite confusing in the add method. elms is a jquery object so I expect elm is HTMLElement. But this.elms is an array-like object of which the element is wrapped intent object like {elm: elm, spec: spec}.

So it seems remove existing elements in add method will not work. Just change it to respElm.elm as in https://github.com/dowjones/intentionjs/blob/master/intention.js#L129.

_2013-11-17_15-11-37

Best wishes ;)

Separate document content from presentation

Hey guys, what do you think of the idea of extracting intention's attributes into an intent-sheet?

Just as we first had styles in the document, and then extracted them into stylesheets to separate the document content from its presentation, I think it may make sense to also extract the intent attributes to get the same benefits here.

Here's a before / after examples:

Before:

<body>
   <header>
      <img intent
         in-standard-src="med.png"
         in-mobile-src="small.png" />
   </header>
   <nav intent
      in-abovethefold-after="header"
      in-belowthefold-prepend="body"
      in-belowthefold-class="sticky">
   </nav>
   <section intent
      in-daytime-class="light"
      in-nighttime-class="dark">
         Hello, World!
   </section>

   <script>
      intent.on('nighttime', function() {
         $('section').text("Goodnight, World!");
      });
   </script>
</body>

After:

index.html

<head>
  <link rel="intentsheet" type="text/intent" href="/assets/intent/simple.intent" />
</head>
<body>
  <header>
    <img />
  </header>

  <nav>
  </nav>

  <section class="main">
    Hello, World!
  </section>

  <script>
    intent.on('nighttime', function() {
      $('section').text("Goodnight, World!");
    });
  </script>
</body>

simple.intent

header > img {
  standard-src: "med.png"
  mobile-src: "med.png"
}

nav {
  abovethefold-after: header
  belowthefold-prepend: body
  belowthefold-class: sticky
}

.main {
  daytime-class: light
  nighttime-class: dark
}

What do you think?

Question about Intentionjs

I am researching about DOM manipulations for my team (front and back end developer), I am not developer but I read alot, research and understand technology.

My question is next:

Can we for example load some website into iframe in our APP, and then manipulate DOM by, editing, deleting, drag and dropping elements ? I saw many kind of examples in Website Builder apps, or on Optimizely.com https://www.youtube.com/watch?v=0S0IrbwpfzE .

Any help or points welcome. Also, developer with DOM experience are welcome for paid work.

Peace,

skype:ksifoking

debug option

If some of the css queries don't work, it would be nice to get feedback! Currently you are trying it in the dark.

iPhone not displaying in_phone view on load.

We at urbanspoon have integrated intention.js into our responsive site it has solved so many issues for us. Thank you.

We have one bug when the iPhone loads a page it displays the in_base / in_standard layout of the page. If I rotate the iPhone the in_phone layout is displayed. On an android device the page renders correctly.

This is on load.

photo-1

After the iPhone has been rotated.

photo-2

To recreate the issues:

  1. Navigate to on an iPhone to http://us1.stg.usw2.spny.us/r/1/1744583/restaurant/Downtown/Radiator-Whiskey-Seattle?responsive=b
  2. Scroll to the bottom of the mobile view and click on "Full site" in the footer
    image
  3. Reload the page.

"licesnse" misspelling on site

MIT licesnse for everything

โžก๏ธ "license"


Congrats on open sourcing this btw! Pretty huge achievement to successfully open source a project (WSJ's first?) in that environment. ๐Ÿ‘

Large Screen header content

Assign new placement to platform images for wide screen computers.
Even / more deliberate placement needs to be applied to screens.

Finding elements that match current context

Hi,

Maybe im missing the obvious here, im trying to figure out a way to find all the elements that match current context via event like below

intent.on( "image:standard", function() {
    var elements = ... get all elements that match this context;
    elements.callSomeMethod();
});

Thanks in advance,

Varinder

_attrsToSpec fails in IE8 in IE9 dev mode

Hi,

In the IE8 development mode of IE9 the if condition on line 378 fails because specMatch[0] actually equals an empty string. It might also fail on a real IE8 browser, but I have not tested it.

A possible fix would be to add an || condition to check for an empty string as well.

Stephen

Remove underscore dependency

Hello,

I think intentionjs is awesome, but the dependency on underscore seems a bit excessive.

Most if not all of the underscore functions that are used (_.extend, _.isObject, _.isArray, etc) are already implemented in jQuery.

Those that aren't should be brought over.

Just a thought...

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.