Full Code of blasten/turn.js for AI

master 08c1f6599a14 cached
7 files
53.6 KB
16.4k tokens
1 requests
Download .txt
Repository: blasten/turn.js
Branch: master
Commit: 08c1f6599a14
Files: 7
Total size: 53.6 KB

Directory structure:
gitextract_61qrn7na/

├── changelog.txt
├── demos/
│   ├── bible/
│   │   └── index.html
│   ├── magazine/
│   │   └── index.html
│   └── magazine_single/
│       └── index.html
├── license.txt
├── readme.md
└── turn.js

================================================
FILE CONTENTS
================================================

================================================
FILE: changelog.txt
================================================
TURN.JS
------------------------------------------------------
Github: https://github.com/blasten/turn.js
Reference: https://github.com/blasten/turn.js/wiki/Reference
Website: www.turnjs.com 
------------------------------------------------------
Release 3 - 2012/03/01
------------------------------------------------------

- Added 'range'
- Added 'addPage'
- Added 'removePage'
- Added 'hasPage'
- Added 'pages'
- Added 'display'
- Added 'when' to the initial configuration
- Added 'pages' to the initial configuration
- Added 'inclination' to the initial configuration
- Added 'first' event
- Added 'last' event
- Added gradients for non-webkit browsers

------------------------------------------------------
Release 2 - 2012/02/15
------------------------------------------------------

- Added 'size'.
- Bug in Chrome 17-18 Beta about losing background-image was fixed.

------------------------------------------------------
Release 1 - 2012/02/05
------------------------------------------------------
- First alpha release 

================================================
FILE: demos/bible/index.html
================================================
<!doctype html>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="../../turn.min.js"></script>

<style type="text/css">
body{
	background:#ccc;
}
#book{
	width:800px;
	height:500px;
}

#book .turn-page{
	background-color:white;
}

#book .cover{
	background:#333;
}

#book .cover h1{
	color:white;
	text-align:center;
	font-size:50px;
	line-height:500px;
	margin:0px;
}

#book .loader{
	background-image:url(loader.gif);
	width:24px;
	height:24px;
	display:block;
	position:absolute;
	top:238px;
	left:188px;
}

#book .data{
	text-align:center;
	font-size:40px;
	color:#999;
	line-height:500px;
}

#controls{
	width:800px;
	text-align:center;
	margin:20px 0px;
	font:30px arial;
}

#controls input, #controls label{
	font:30px arial;
}

#book .odd{
	background-image:-webkit-linear-gradient(left, #FFF 95%, #ddd 100%);
	background-image:-moz-linear-gradient(left, #FFF 95%, #ddd 100%);
	background-image:-o-linear-gradient(left, #FFF 95%, #ddd 100%);
	background-image:-ms-linear-gradient(left, #FFF 95%, #ddd 100%);
}

#book .even{
	background-image:-webkit-linear-gradient(right, #FFF 95%, #ddd 100%);
	background-image:-moz-linear-gradient(right, #FFF 95%, #ddd 100%);
	background-image:-o-linear-gradient(right, #FFF 95%, #ddd 100%);
	background-image:-ms-linear-gradient(right, #FFF 95%, #ddd 100%);
}
</style>
</head>
<body>

<div id="book">
	<div class="cover"><h1>The Bible</h1></div>
</div>

<div id="controls">
	<label for="page-number">Page:</label> <input type="text" size="3" id="page-number"> of <span id="number-pages"></span>
</div>

<script type="text/javascript">

	// Sample using dynamic pages with turn.js

	var numberOfPages = 1000; 


	// Adds the pages that the book will need
	function addPage(page, book) {
		// 	First check if the page is already in the book
		if (!book.turn('hasPage', page)) {
			// Create an element for this page
			var element = $('<div />', {'class': 'page '+((page%2==0) ? 'odd' : 'even'), 'id': 'page-'+page}).html('<i class="loader"></i>');
			// If not then add the page
			book.turn('addPage', element, page);
			// Let's assum that the data is comming from the server and the request takes 1s.
			setTimeout(function(){
					element.html('<div class="data">Data for page '+page+'</div>');
			}, 1000);
		}
	}

	$(window).ready(function(){
		$('#book').turn({acceleration: true,
							pages: numberOfPages,
							elevation: 50,
							gradients: !$.isTouch,
							when: {
								turning: function(e, page, view) {

									// Gets the range of pages that the book needs right now
									var range = $(this).turn('range', page);

									// Check if each page is within the book
									for (page = range[0]; page<=range[1]; page++) 
										addPage(page, $(this));

								},

								turned: function(e, page) {
									$('#page-number').val(page);
								}
							}
						});

		$('#number-pages').html(numberOfPages);

		$('#page-number').keydown(function(e){

			if (e.keyCode==13)
				$('#book').turn('page', $('#page-number').val());
				
		});
	});

	$(window).bind('keydown', function(e){

		if (e.target && e.target.tagName.toLowerCase()!='input')
			if (e.keyCode==37)
				$('#book').turn('previous');
			else if (e.keyCode==39)
				$('#book').turn('next');

	});

</script>


</body>
</html>


================================================
FILE: demos/magazine/index.html
================================================
<!doctype html>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="../../turn.min.js"></script>

<style type="text/css">
body{
	background:#ccc;
}
#magazine{
	width:1152px;
	height:752px;
}
#magazine .turn-page{
	background-color:#ccc;
	background-size:100% 100%;
}
</style>
</head>
<body>

<div id="magazine">
	<div style="background-image:url(pages/01.jpg);"></div>
	<div style="background-image:url(pages/02.jpg);"></div>
	<div style="background-image:url(pages/03.jpg);"></div>
	<div style="background-image:url(pages/04.jpg);"></div>
	<div style="background-image:url(pages/05.jpg);"></div>
	<div style="background-image:url(pages/06.jpg);"></div>
</div>


<script type="text/javascript">

	$(window).ready(function() {
		$('#magazine').turn({
							display: 'double',
							acceleration: true,
							gradients: !$.isTouch,
							elevation:50,
							when: {
								turned: function(e, page) {
									/*console.log('Current view: ', $(this).turn('view'));*/
								}
							}
						});
	});
	
	
	$(window).bind('keydown', function(e){
		
		if (e.keyCode==37)
			$('#magazine').turn('previous');
		else if (e.keyCode==39)
			$('#magazine').turn('next');
			
	});

</script>

</body>
</html>


================================================
FILE: demos/magazine_single/index.html
================================================
<!doctype html>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="../../turn.min.js"></script>

<style type="text/css">
body{
	background:#ccc;
}
#magazine{
	width:576px;
	height:752px;
}
#magazine .turn-page{
	background-color:#ccc;
	background-size:100% 100%;
}
</style>
</head>
<body>

<div id="magazine">
	<div style="background-image:url(pages/01.jpg);"></div>
	<div style="background-image:url(pages/02.jpg);"></div>
	<div style="background-image:url(pages/03.jpg);"></div>
	<div style="background-image:url(pages/04.jpg);"></div>
	<div style="background-image:url(pages/05.jpg);"></div>
	<div style="background-image:url(pages/06.jpg);"></div>
</div>


<script type="text/javascript">

	$(window).ready(function() {
		$('#magazine').turn({
							display: 'single',
							acceleration: true,
							gradients: !$.isTouch,
							elevation:50,
							when: {
								turned: function(e, page) {
									/*console.log('Current view: ', $(this).turn('view'));*/
								}
							}
						});
	});
	
	
	$(window).bind('keydown', function(e){
		
		if (e.keyCode==37)
			$('#magazine').turn('previous');
		else if (e.keyCode==39)
			$('#magazine').turn('next');
			
	});

</script>

</body>
</html>


================================================
FILE: license.txt
================================================
turn.js 3rd release
www.turnjs.com

Copyright (c) 2012, Emmanuel Garcia
All rights reserved.

Redistribution and use in source and binary forms,
with or without modification, are permitted provided
that the following conditions are met:

- Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.

- Any redistribution, use, or modification is done solely for personal 
  benefit and not for any commercial purpose or for monetary gain.

THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ''AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

================================================
FILE: readme.md
================================================

![Bilby Stampede](http://turnjs.com/pics/small-turnjs-letters.png)

**Get the turn.js 4th release on [turnjs.com](http://www.turnjs.com/)**


### What's new in turn.js 4th release?

- Added option `autoCenter`

- Added option `zoom`

- Added property `animating`

- Added property `zoom`

- Added method `center`

- Added method `destroy`

- Added method `is`

- Added method `zoom`

- Added event `missing`

- Added event `zooming`

- Added class `.even`

- Added class `.fixed`

- Added class `.hard`

- Added class `.odd`

- Added class `.own-size`

- Added class `.sheet`

- Added the ignore attribute

- New turn.html4.js

- New scissors.js

- Changed the class `.turn-page` to `.page`

- Improved the animation frame generator with requestAnimationFrame

- Improved the animation speed for hard pages with CSS3 transitions

- Redesigned the event sequence to listen to only three events

- Fixed issue #79

- Fixed issue #91

- Fixed issue about the event order turning + turned

- Fixed issue about appending pages in wrong locations

Available only on [turnjs.com](http://www.turnjs.com/)

* * *

turn.js 3rd release
=========

### Make a flip book with HTML5

Turn.js is a plugin for jQuery that adds a beautiful transition similar to real pages in a book or magazine. It works in all modern browsers including touch devices.

### What's new?

- New `addPage` for creating pages dynamically.

- New `display` for single and double pages.

- Gradients for non-webkit browsers.

#### Usage

**CSS code:**
```css
#magazine{
	width: 800px;
	height: 400px;
}
#magazine .turn-page{
	background-color:#ccc;
}
```

**HTML code:**
```html
<div id="magazine">
	<div><span class="text">Page 1</span></div>
	<div><span class="text">Page 2</span></div>
	<div><span class="text">Page 3</span></div>
</div>
```

**JavaScript code:**
```javascript
$('#magazine').turn({gradients: true, acceleration: true});
```

#### Requirements

jQuery 1.7 or later

#### Browser support
* Chrome 12, Safari 5, Firefox 10, IE 9

#### License
Released under a non-commercial BSD license

[Full documentation](https://github.com/blasten/turn.js/wiki/Reference)

* * *

[turnjs.com](http://www.turnjs.com/)


================================================
FILE: turn.js
================================================
/**
 * turn.js 3rd release
 * www.turnjs.com
 *
 * Copyright (C) 2012, Emmanuel Garcia.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * 2. Any redistribution, use, or modification is done solely for personal 
 * benefit and not for any commercial purpose or for monetary gain.
 * 
 **/

(function($) {

'use strict';

var has3d,

	vendor ='',

	PI = Math.PI,

	A90 = PI/2,

	isTouch = 'ontouchstart' in window,

	events = (isTouch) ? {start: 'touchstart', move: 'touchmove', end: 'touchend'}
			: {start: 'mousedown', move: 'mousemove', end: 'mouseup'},

	// Contansts used for each corner
	// tl * tr
	// *     *
	// bl * br

	corners = {
		backward: ['bl', 'tl'],
		forward: ['br', 'tr'],
		all: ['tl', 'bl', 'tr', 'br']
	},

	displays = ['single', 'double'],

	// Default options

	turnOptions = {

		// First page

		page: 1,
		
		// Enables gradients

		gradients: true,

		// Duration of transition in milliseconds

		duration: 600,

		// Enables hardware acceleration

		acceleration: true,

		// Display

		display: 'double',

		// Events

		when: null
	},

	flipOptions = {

		// Back page
		
		folding: null,

		// Corners
		// backward: Activates both tl and bl corners
		// forward: Activates both tr and br corners
		// all: Activates all the corners

		corners: 'forward',
		
		// Size of the active zone of each corner

		cornerSize: 100,

		// Enables gradients

		gradients: true,

		// Duration of transition in milliseconds

		duration: 600,

		// Enables hardware acceleration

		acceleration: true
	},

	// Number of pages in the DOM, minimum value: 6

	pagesInDOM = 6,
	
	pagePosition = {0: {top: 0, left: 0, right: 'auto', bottom: 'auto'},
					1: {top: 0, right: 0, left: 'auto', bottom: 'auto'}},

	// Gets basic attributes for a layer

	divAtt = function(top, left, zIndex, overf) {
		return {'css': {
					position: 'absolute',
					top: top,
					left: left,
					'overflow': overf || 'hidden',
					'z-index': zIndex || 'auto'
					}
			};
	},

	// Gets a 2D point from a bezier curve of four points

	bezier = function(p1, p2, p3, p4, t) {
		var mum1 = 1 - t,
			mum13 = mum1 * mum1 * mum1,
			mu3 = t * t * t;

		return point2D(Math.round(mum13*p1.x + 3*t*mum1*mum1*p2.x + 3*t*t*mum1*p3.x + mu3*p4.x),
						Math.round(mum13*p1.y + 3*t*mum1*mum1*p2.y + 3*t*t*mum1*p3.y + mu3*p4.y));
	},
	
	// Converts an angle from degrees to radians

	rad = function(degrees) {
		return degrees/180*PI;
	},

	// Converts an angle from radians to degrees

	deg = function(radians) {
		return radians/PI*180;
	},

	// Gets a 2D point

	point2D = function(x, y) {
		return {x: x, y: y};
	},

	// Returns the traslate value

	translate = function(x, y, use3d) {
		return (has3d && use3d) ? ' translate3d(' + x + 'px,' + y + 'px, 0px) ' : ' translate(' + x + 'px, ' + y + 'px) ';
	},

	// Returns the rotation value

	rotate = function(degrees) {
		return ' rotate(' + degrees + 'deg) ';
	},

	// Checks if a property belongs to an object

	has = function(property, object) {
		return Object.prototype.hasOwnProperty.call(object, property);
	},

	// Gets the CSS3 vendor prefix

	getPrefix = function() {
		var vendorPrefixes = ['Moz','Webkit','Khtml','O','ms'],
			len = vendorPrefixes.length,
			vendor = '';

		while (len--)
			if ((vendorPrefixes[len] + 'Transform') in document.body.style)
				vendor='-'+vendorPrefixes[len].toLowerCase()+'-';

		return vendor;
	},

	// Adds gradients

	gradient = function(obj, p0, p1, colors, numColors) {
	
		var j, cols = [];

		if (vendor=='-webkit-') {
		
			for (j = 0; j<numColors; j++)
					cols.push('color-stop('+colors[j][0]+', '+colors[j][1]+')');
			
			obj.css({'background-image': '-webkit-gradient(linear, '+p0.x+'% '+p0.y+'%,  '+p1.x+'% '+p1.y+'%, '+ cols.join(',') +' )'});

		} else {

			// This procedure makes the gradients for non-webkit browsers
			// It will be reduced to one unique way for gradients in next versions
			
			p0 = {x:p0.x/100 * obj.width(), y:p0.y/100 * obj.height()};
			p1 = {x:p1.x/100 * obj.width(), y:p1.y/100 * obj.height()};

			var dx = p1.x-p0.x,
				dy = p1.y-p0.y,
				angle = Math.atan2(dy, dx),
				angle2 = angle - Math.PI/2,
				diagonal = Math.abs(obj.width()*Math.sin(angle2)) + Math.abs(obj.height()*Math.cos(angle2)),
				gradientDiagonal = Math.sqrt(dy*dy + dx*dx),
				corner = point2D((p1.x<p0.x) ? obj.width() : 0, (p1.y<p0.y) ? obj.height() : 0),
				slope = Math.tan(angle),
				inverse = -1/slope,
				x = (inverse*corner.x - corner.y - slope*p0.x + p0.y) / (inverse-slope),
				c = {x: x, y: inverse*x - inverse*corner.x + corner.y},
				segA = (Math.sqrt( Math.pow(c.x-p0.x,2) + Math.pow(c.y-p0.y,2)));

				for (j = 0; j<numColors; j++)
					cols.push(' '+colors[j][1]+' '+(( segA + gradientDiagonal*colors[j][0] )*100/diagonal)+'%');
		
				obj.css({'background-image': vendor+'linear-gradient(' + (-angle) + 'rad,' + cols.join(',') + ')'});
		}
	},

turnMethods = {

	// Singleton constructor
	// $('#selector').turn([options]);

	init: function(opts) {

		// Define constants
		if (has3d===undefined) {
			has3d = 'WebKitCSSMatrix' in window || 'MozPerspective' in document.body.style;
			vendor = getPrefix();
		}

		var i, data = this.data(), ch = this.children();
	
		opts = $.extend({width: this.width(), height: this.height()}, turnOptions, opts);
		data.opts = opts;
		data.pageObjs = {};
		data.pages = {};
		data.pageWrap = {};
		data.pagePlace = {};
		data.pageMv = [];
		data.totalPages = opts.pages || 0;

		if (opts.when)
			for (i in opts.when)
				if (has(i, opts.when))
					this.bind(i, opts.when[i]);


		this.css({position: 'relative', width: opts.width, height: opts.height});

		this.turn('display', opts.display);

		if (has3d && !isTouch && opts.acceleration)
			this.transform(translate(0, 0, true));
	
		for (i = 0; i<ch.length; i++)
			this.turn('addPage', ch[i], i+1);
	
		this.turn('page', opts.page);

        // allow setting active corners as an option
        corners = $.extend({}, corners, opts.corners);

		// Event listeners

		$(this).bind(events.start, function(e) {
			for (var page in data.pages)
				if (has(page, data.pages) && flipMethods._eventStart.call(data.pages[page], e)===false)
					return false;
		});
			
		$(document).bind(events.move, function(e) {
			for (var page in data.pages)
				if (has(page, data.pages))
					flipMethods._eventMove.call(data.pages[page], e);
		}).
		bind(events.end, function(e) {
			for (var page in data.pages)
				if (has(page, data.pages))
					flipMethods._eventEnd.call(data.pages[page], e);

		});

		data.done = true;

		return this;
	},

	// Adds a page from external data

	addPage: function(element, page) {

		var incPages = false,
			data = this.data(),
			lastPage = data.totalPages+1;

		if (page) {
			if (page==lastPage) {
				page = lastPage;
				incPages = true;
			} else if (page>lastPage)
				throw new Error ('It is impossible to add the page "'+page+'", the maximum value is: "'+lastPage+'"');

		} else {
			page = lastPage;
			incPages = true;
		}

		if (page>=1 && page<=lastPage) {

			// Stop animations
			if (data.done) this.turn('stop');

			// Move pages if it's necessary
			if (page in data.pageObjs)
				turnMethods._movePages.call(this, page, 1);

			// Update number of pages
			if (incPages)
				data.totalPages = lastPage;

			// Add element
			data.pageObjs[page] = $(element).addClass('turn-page p' + page);

			// Add page
			turnMethods._addPage.call(this, page);

			// Update view
			if (data.done)
				this.turn('update');

			turnMethods._removeFromDOM.call(this);
		}

		return this;
	},

	// Adds a page from internal data

	_addPage: function(page) {
		
		var data = this.data(),
			element = data.pageObjs[page];

		if (element)
			if (turnMethods._necessPage.call(this, page)) {
				
				if (!data.pageWrap[page]) {

					var pageWidth = (data.display=='double') ? this.width()/2 : this.width(),
						pageHeight = this.height();

					element.css({width:pageWidth, height:pageHeight});

					// Place
					data.pagePlace[page] = page;

					// Wrapper
					data.pageWrap[page] = $('<div/>', {'class': 'turn-page-wrapper',
													page: page,
													css: {position: 'absolute',
													overflow: 'hidden',
													width: pageWidth,
													height: pageHeight}}).
													css(pagePosition[(data.display=='double') ? page%2 : 0]);

					// Append to this
					this.append(data.pageWrap[page]);

					// Move data.pageObjs[page] (element) to wrapper
					data.pageWrap[page].prepend(data.pageObjs[page]);
				}

				// If the page is in the current view, create the flip effect
				if (!page || turnMethods._setPageLoc.call(this, page)==1)
					turnMethods._makeFlip.call(this, page);
				
			} else {

				// Place
				data.pagePlace[page] = 0;

				// Remove element from the DOM
				if (data.pageObjs[page])
					data.pageObjs[page].remove();

			}

	},

	// Checks if a page is in memory
	
	hasPage: function(page) {

		return page in this.data().pageObjs;
	
	},

	// Prepares the flip effect for a page

	_makeFlip: function(page) {

		var data = this.data();

		if (!data.pages[page] && data.pagePlace[page]==page) {

			var single = data.display=='single',
				even = page%2;
			
			data.pages[page] = data.pageObjs[page].
								css({width: (single) ? this.width() : this.width()/2, height: this.height()}).
								flip({page: page,
									next: (single && page === data.totalPages) ? page -1 : ((even || single) ? page+1 : page-1),
									turn: this,
									duration: data.opts.duration,
									acceleration : data.opts.acceleration,
									corners: (single) ? 'all' : ((even) ? 'forward' : 'backward'),
									backGradient: data.opts.gradients,
									frontGradient: data.opts.gradients
									}).
									flip('disable', data.disabled).
									bind('pressed', turnMethods._pressed).
									bind('released', turnMethods._released).
									bind('start', turnMethods._start).
									bind('end', turnMethods._end).
									bind('flip', turnMethods._flip);
		}
		return data.pages[page];
	},

	// Makes pages within a range

	_makeRange: function() {

		var page,
			data = this.data(),
			range = this.turn('range');

			for (page = range[0]; page<=range[1]; page++)
				turnMethods._addPage.call(this, page);

	},

	// Returns a range of `pagesInDOM` pages that should be in the DOM
	// Example:
	// - page of the current view, return true
	// * page is in the range, return true
	// 0 page is not in the range, return false
	//
	// 1 2-3 4-5 6-7 8-9 10-11 12-13
	//    **  **  --   **  **

	range: function(page) {

		var remainingPages, left, right,
			data = this.data();
			page = page || data.tpage || data.page;
			var view = turnMethods._view.call(this, page);

			if (page<1 || page>data.totalPages)
				throw new Error ('"'+page+'" is not a page for range');
		
			view[1] = view[1] || view[0];
			
			if (view[0]>=1 && view[1]<=data.totalPages) {

				remainingPages = Math.floor((pagesInDOM-2)/2);

				if (data.totalPages-view[1] > view[0]) {
					left = Math.min(view[0]-1, remainingPages);
					right = 2*remainingPages-left;
				} else {
					right = Math.min(data.totalPages-view[1], remainingPages);
					left = 2*remainingPages-right;
				}

			} else {
				left = pagesInDOM-1;
				right = pagesInDOM-1;
			}

			return [Math.max(1, view[0]-left), Math.min(data.totalPages, view[1]+right)];

	},

	// Detects if a page is within the range of `pagesInDOM` from the current view

	_necessPage: function(page) {
		
		if (page===0)
			return true;

		var range = this.turn('range');

		return page>=range[0] && page<=range[1];
		
	},

	// Releases memory by removing pages from the DOM

	_removeFromDOM: function() {

		var page, data = this.data();

		for (page in data.pageWrap)
			if (has(page, data.pageWrap) && !turnMethods._necessPage.call(this, page))
				turnMethods._removePageFromDOM.call(this, page);
		

	},

	// Removes a page from DOM and its internal references

	_removePageFromDOM: function(page) {

		var data = this.data();

		if (data.pages[page]) {
			var dd = data.pages[page].data();
			if (dd.f && dd.f.fwrapper)
				dd.f.fwrapper.remove();
			data.pages[page].remove();
			delete data.pages[page];
		}

		if (data.pageObjs[page])
			data.pageObjs[page].remove();

		if (data.pageWrap[page]) {
			data.pageWrap[page].remove();
			delete data.pageWrap[page];
		}

		delete data.pagePlace[page];

	},

	// Removes a page

	removePage: function(page) {

		var data = this.data();

		if (data.pageObjs[page]) {
			// Stop animations
			this.turn('stop');

			// Remove `page`
			turnMethods._removePageFromDOM.call(this, page);
			delete data.pageObjs[page];

			// Move the pages behind `page`
			turnMethods._movePages.call(this, page, -1);

			// Resize the size of this magazine
			data.totalPages = data.totalPages-1;
			turnMethods._makeRange.call(this);

			// Check the current view
			if (data.page>data.totalPages)
				this.turn('page', data.totalPages);
		}

		return this;
	
	},

	// Moves pages

	_movePages: function(from, change) {

		var page,
			data = this.data(),
			single = data.display=='single',
			move = function(page) {

				var next = page + change,
					odd = next%2;

				if (data.pageObjs[page])
					data.pageObjs[next] = data.pageObjs[page].removeClass('page' + page).addClass('page' + next);

				if (data.pagePlace[page] && data.pageWrap[page]) {
					data.pagePlace[next] = next;
					data.pageWrap[next] = data.pageWrap[page].css(pagePosition[(single) ? 0 : odd]).attr('page', next);
					
					if (data.pages[page])
						data.pages[next] = data.pages[page].flip('options', {
							page: next,
							next: (single || odd) ? next+1 : next-1,
							corners: (single) ? 'all' : ((odd) ? 'forward' : 'backward')
						});

					if (change) {
						delete data.pages[page];
						delete data.pagePlace[page];
						delete data.pageObjs[page];
						delete data.pageWrap[page];
						delete data.pageObjs[page];
					}
			}
		};

		if (change>0)
			for (page=data.totalPages; page>=from; page--) move(page);
		else
			for (page=from; page<=data.totalPages; page++) move(page);

	},

	// Sets or Gets the display mode

	display: function(display) {

		var data = this.data(),
			currentDisplay = data.display;

		if (display) {

			if ($.inArray(display, displays)==-1)
				throw new Error ('"'+display + '" is not a value for display');
			
			if (display=='single') {
				if (!data.pageObjs[0]) {
					this.turn('stop').
						css({'overflow': 'hidden'});
					data.pageObjs[0] = $('<div />', {'class': 'turn-page p-temporal'}).
									css({width: this.width(), height: this.height()}).
										appendTo(this);
				}
			} else {
				if (data.pageObjs[0]) {
					this.turn('stop').
						css({'overflow': ''});
					data.pageObjs[0].remove();
					delete data.pageObjs[0];
				}
			}

			data.display = display;

			if (currentDisplay) {
				var size = this.turn('size');
				turnMethods._movePages.call(this, 1, 0);
				this.turn('size', size.width, size.height).
						turn('update');
			}

			return this;

		} else
			return currentDisplay;
	
	},

	// Detects if the pages are being animated

	animating: function() {

		return this.data().pageMv.length>0;

	},

	// Disables and enables the effect

	disable: function(bool) {

		var page,
			data = this.data(),
			view = this.turn('view');

			data.disabled = bool===undefined || bool===true;

		for (page in data.pages)
			if (has(page, data.pages))
				data.pages[page].flip('disable', bool ? $.inArray(page, view) : false );

		return this;

	},

	// Gets and sets the size

	size: function(width, height) {

		if (width && height) {

			var data = this.data(), pageWidth = (data.display=='double') ? width/2 : width, page;

			this.css({width: width, height: height});

			if (data.pageObjs[0])
				data.pageObjs[0].css({width: pageWidth, height: height});
			
			for (page in data.pageWrap) {
				if (!has(page, data.pageWrap)) continue;
				data.pageObjs[page].css({width: pageWidth, height: height});
				data.pageWrap[page].css({width: pageWidth, height: height});
				if (data.pages[page])
					data.pages[page].css({width: pageWidth, height: height});
			}

			this.turn('resize');

			return this;

		} else {
			
			return {width: this.width(), height: this.height()};

		}
	},

	// Resizes each page

	resize: function() {

		var page, data = this.data();

		if (data.pages[0]) {
			data.pageWrap[0].css({left: -this.width()});
			data.pages[0].flip('resize', true);
		}

		for (page = 1; page <= data.totalPages; page++)
			if (data.pages[page])
				data.pages[page].flip('resize', true);


	},

	// Removes an animation from the cache

	_removeMv: function(page) {

		var i, data = this.data();
			
		for (i=0; i<data.pageMv.length; i++)
			if (data.pageMv[i]==page) {
				data.pageMv.splice(i, 1);
				return true;
			}

		return false;

	},

	// Adds an animation to the cache
	
	_addMv: function(page) {

		var data = this.data();

		turnMethods._removeMv.call(this, page);
		data.pageMv.push(page);

	},

	// Gets indexes for a view

	_view: function(page) {
	
		var data = this.data();
		page = page || data.page;

		if (data.display=='double')
			return (page%2) ? [page-1, page] : [page, page+1];
		else
			return [page];

	},

	// Gets a view

	view: function(page) {

		var data = this.data(), view = turnMethods._view.call(this, page);

		return (data.display=='double') ? [(view[0]>0) ? view[0] : 0, (view[1]<=data.totalPages) ? view[1] : 0]
				: [(view[0]>0 && view[0]<=data.totalPages) ? view[0] : 0];

	},

	// Stops animations

	stop: function(ok) {

		var i, opts, data = this.data(), pages = data.pageMv;

		data.pageMv = [];

		if (data.tpage) {
			data.page = data.tpage;
			delete data['tpage'];
		}

		for (i in pages) {
			if (!has(i, pages)) continue;
			opts = data.pages[pages[i]].data().f.opts;
			flipMethods._moveFoldingPage.call(data.pages[pages[i]], null);
			data.pages[pages[i]].flip('hideFoldedPage');
			data.pagePlace[opts.next] = opts.next;
			
			if (opts.force) {
				opts.next = (opts.page%2===0) ? opts.page-1 : opts.page+1;
				delete opts['force'];
			}

		}

		this.turn('update');

		return this;
	},

	// Gets and sets the number of pages

	pages: function(pages) {

		var data = this.data();

		if (pages) {
			if (pages<data.totalPages) {

				for (var page = pages+1; page<=data.totalPages; page++)
					this.turn('removePage', page);

				if (this.turn('page')>pages)
					this.turn('page', pages);
			}

			data.totalPages = pages;

			return this;
		} else
			return data.totalPages;

	},

	// Sets a page without effect

	_fitPage: function(page, ok) {
		
		var data = this.data(), newView = this.turn('view', page);
		
		if (data.page!=page) {
			this.trigger('turning', [page, newView]);
			if ($.inArray(1, newView)!=-1) this.trigger('first');
			if ($.inArray(data.totalPages, newView)!=-1) this.trigger('last');
		}

		if (!data.pageObjs[page])
			return;

		data.tpage = page;

		this.turn('stop', ok);
		turnMethods._removeFromDOM.call(this);
		turnMethods._makeRange.call(this);
		this.trigger('turned', [page, newView]);

	},
	
	// Turns to a page

	_turnPage: function(page) {

		var current, next,
			data = this.data(),
			view = this.turn('view'),
			newView = this.turn('view', page);
	
		if (data.page!=page) {
			this.trigger('turning', [page, newView]);
			if ($.inArray(1, newView)!=-1) this.trigger('first');
			if ($.inArray(data.totalPages, newView)!=-1) this.trigger('last');
		}

		if (!data.pageObjs[page])
			return;

		data.tpage = page;

		this.turn('stop');

		turnMethods._makeRange.call(this);

		if (data.display=='single') {
			current = view[0];
			next = newView[0];
		} else if (view[1] && page>view[1]) {
			current = view[1];
			next = newView[0];
		} else if (view[0] && page<view[0]) {
			current = view[0];
			next = newView[1];
		}

		if (data.pages[current]) {

			var opts = data.pages[current].data().f.opts;
			data.tpage = next;
			
			if (opts.next!=next) {
				opts.next = next;
				data.pagePlace[next] = opts.page;
				opts.force = true;
			}

			if (data.display=='single')
				data.pages[current].flip('turnPage', (newView[0] > view[0]) ? 'br' : 'bl');
			else
				data.pages[current].flip('turnPage');
		}

	},

	// Gets and sets a page

	page: function(page) {

		page = parseInt(page, 10);

		var data = this.data();

		if (page>0 && page<=data.totalPages) {
			if (!data.done || $.inArray(page, this.turn('view'))!=-1)
				turnMethods._fitPage.call(this, page);
			else
				turnMethods._turnPage.call(this, page);
		
			return this;

		} else
			return data.page;
	
	},

	// Turns to the next view

	next: function() {

		var data = this.data();
		return this.turn('page', turnMethods._view.call(this, data.page).pop() + 1);
	
	},

	// Turns to the previous view

	previous: function() {
		
		var data = this.data();
		return this.turn('page', turnMethods._view.call(this, data.page).shift() - 1);

	},

	// Adds a motion to the internal list

	_addMotionPage: function() {

		var opts = $(this).data().f.opts,
			turn = opts.turn,
			dd = turn.data();

		opts.pageMv = opts.page;
		turnMethods._addMv.call(turn, opts.pageMv);
		dd.pagePlace[opts.next] = opts.page;
		turn.turn('update');

	},

	// This event is called in context of flip

	_start: function(e, opts, corner) {

			var data = opts.turn.data(),
				event = $.Event('start');

			e.stopPropagation();

			opts.turn.trigger(event, [opts, corner]);

			if (event.isDefaultPrevented()) {
				e.preventDefault();
				return;
			}
		
		if (data.display=='single') {

			var left = corner.charAt(1)=='l';
			if ((opts.page==1 && left) || (opts.page==data.totalPages && !left))
				e.preventDefault();
			else {
				if (left) {
					opts.next = (opts.next<opts.page) ? opts.next : opts.page-1;
					opts.force = true;
				} else
					opts.next = (opts.next>opts.page) ? opts.next : opts.page+1;
			}

		}

		turnMethods._addMotionPage.call(this);
	},

	// This event is called in context of flip

	_end: function(e, turned) {
		
		var that = $(this),
			data = that.data().f,
			opts = data.opts,
			turn = opts.turn,
			dd = turn.data();

		e.stopPropagation();

		if (turned || dd.tpage) {

			if (dd.tpage==opts.next || dd.tpage==opts.page) {
				delete dd['tpage'];
				turnMethods._fitPage.call(turn, dd.tpage || opts.next, true);
			}

		} else {
			turnMethods._removeMv.call(turn, opts.pageMv);
			turn.turn('update');
		}
		
	},
	
	// This event is called in context of flip

	_pressed: function() {

		var page,
			that = $(this),
			data = that.data().f,
			turn = data.opts.turn,
			pages = turn.data().pages;
	
		for (page in pages)
			if (page!=data.opts.page)
				pages[page].flip('disable', true);

		return data.time = new Date().getTime();

	},

	// This event is called in context of flip

	_released: function(e, point) {
		
		var that = $(this),
			data = that.data().f;

			e.stopPropagation();

		if ((new Date().getTime())-data.time<200 || point.x<0 || point.x>$(this).width()) {
			e.preventDefault();
			data.opts.turn.data().tpage = data.opts.next;
			data.opts.turn.turn('update');
			$(that).flip('turnPage');
		}

	},

	// This event is called in context of flip
	
	_flip: function() {

		var opts = $(this).data().f.opts;

		opts.turn.trigger('turn', [opts.next]);

	},

	// Calculate the z-index value for pages during the animation

	calculateZ: function(mv) {

		var i, page, nextPage, placePage, dpage,
			that = this,
			data = this.data(),
			view = this.turn('view'),
			currentPage = view[0] || view[1],
			r = {pageZ: {}, partZ: {}, pageV: {}},

			addView = function(page) {
				var view = that.turn('view', page);
				if (view[0]) r.pageV[view[0]] = true;
				if (view[1]) r.pageV[view[1]] = true;
			};
		
			for (i = 0; i<mv.length; i++) {
				page = mv[i];
				nextPage = data.pages[page].data().f.opts.next;
				placePage = data.pagePlace[page];
				addView(page);
				addView(nextPage);
				dpage = (data.pagePlace[nextPage]==nextPage) ? nextPage : page;
				r.pageZ[dpage] = data.totalPages - Math.abs(currentPage-dpage);
				r.partZ[placePage] = data.totalPages*2 + Math.abs(currentPage-dpage);
			}

		return r;
	},

	// Updates the z-index and display property of every page

	update: function() {

		var page,
			data = this.data();

		if (data.pageMv.length && data.pageMv[0]!==0) {

			// Update motion

			var apage,
				pos = this.turn('calculateZ', data.pageMv),
				view = this.turn('view', data.tpage);
		
			if (data.pagePlace[view[0]]==view[0]) apage = view[0];
			else if (data.pagePlace[view[1]]==view[1]) apage = view[1];
		
			for (page in data.pageWrap) {

				if (!has(page, data.pageWrap)) continue;

				data.pageWrap[page].css({display: (pos.pageV[page]) ? '' : 'none', 'z-index': pos.pageZ[page] || 0});

				if (data.pages[page]) {
					data.pages[page].flip('z', pos.partZ[page] || null);

					if (pos.pageV[page])
						data.pages[page].flip('resize');

					if (data.tpage)
						data.pages[page].flip('disable', true); // data.disabled || page!=apage
				}
			}
				
		} else {

			// Update static pages

			for (page in data.pageWrap) {
				if (!has(page, data.pageWrap)) continue;
					var pageLocation = turnMethods._setPageLoc.call(this, page);
					if (data.pages[page])
						data.pages[page].flip('disable', data.disabled || pageLocation!=1).flip('z', null);
			}
		}
	},

	// Sets the z-index and display property of a page
	// It depends on the current view

	_setPageLoc: function(page) {

		var data = this.data(),
			view = this.turn('view');

		if (page==view[0] || page==view[1]) {
			data.pageWrap[page].css({'z-index': data.totalPages, display: ''});
			return 1;
		} else if ((data.display=='single' && page==view[0]+1) || (data.display=='double' && page==view[0]-2 || page==view[1]+2)) {
			data.pageWrap[page].css({'z-index': data.totalPages-1, display: ''});
			return 2;
		} else {
			data.pageWrap[page].css({'z-index': 0, display: 'none'});
			return 0;
		}
	}
},

// Methods and properties for the flip page effect

flipMethods = {

	// Constructor

	init: function(opts) {

		if (opts.gradients) {
			opts.frontGradient = true;
			opts.backGradient = true;
		}

		this.data({f: {}});
		this.flip('options', opts);

		flipMethods._addPageWrapper.call(this);

		return this;
	},

	setData: function(d) {
		
		var data = this.data();

		data.f = $.extend(data.f, d);

		return this;
	},

	options: function(opts) {
		
		var data = this.data().f;

		if (opts) {
			flipMethods.setData.call(this, {opts: $.extend({}, data.opts || flipOptions, opts) });
			return this;
		} else
			return data.opts;

	},

	z: function(z) {

		var data = this.data().f;
		data.opts['z-index'] = z;
		data.fwrapper.css({'z-index': z || parseInt(data.parent.css('z-index'), 10) || 0});

		return this;
	},

	_cAllowed: function() {

		return corners[this.data().f.opts.corners] || this.data().f.opts.corners;

	},

	_cornerActivated: function(e) {
		if (e.originalEvent === undefined) {
			return false;
		}		

		e = (isTouch) ? e.originalEvent.touches : [e];

		var data = this.data().f,
			pos = data.parent.offset(),
			width = this.width(),
			height = this.height(),
			c = {x: Math.max(0, e[0].pageX-pos.left), y: Math.max(0, e[0].pageY-pos.top)},
			csz = data.opts.cornerSize,
			allowedCorners = flipMethods._cAllowed.call(this);

			if (c.x<=0 || c.y<=0 || c.x>=width || c.y>=height) return false;

			if (c.y<csz) c.corner = 't';
			else if (c.y>=height-csz) c.corner = 'b';
			else return false;
			
			if (c.x<=csz) c.corner+= 'l';
			else if (c.x>=width-csz) c.corner+= 'r';
			else return false;

		return ($.inArray(c.corner, allowedCorners)==-1) ? false : c;

	},

	_c: function(corner, opts) {

		opts = opts || 0;
		return ({tl: point2D(opts, opts),
				tr: point2D(this.width()-opts, opts),
				bl: point2D(opts, this.height()-opts),
				br: point2D(this.width()-opts, this.height()-opts)})[corner];

	},

	_c2: function(corner) {

		return {tl: point2D(this.width()*2, 0),
				tr: point2D(-this.width(), 0),
				bl: point2D(this.width()*2, this.height()),
				br: point2D(-this.width(), this.height())}[corner];

	},

	_foldingPage: function(corner) {

		var opts = this.data().f.opts;
		
		if (opts.folding) return opts.folding;
		else if(opts.turn) {
			var data = opts.turn.data();
			if (data.display == 'single')
				return (data.pageObjs[opts.next]) ? data.pageObjs[0] : null;
			else
				return data.pageObjs[opts.next];
		}

	},

	_backGradient: function() {

		var data =	this.data().f,
			turn = data.opts.turn,
			gradient = data.opts.backGradient &&
						(!turn || turn.data().display=='single' || (data.opts.page!=2 && data.opts.page!=turn.data().totalPages-1) );


		if (gradient && !data.bshadow)
			data.bshadow = $('<div/>', divAtt(0, 0, 1)).
				css({'position': '', width: this.width(), height: this.height()}).
					appendTo(data.parent);

		return gradient;

	},

	resize: function(full) {
		
		var data = this.data().f,
			width = this.width(),
			height = this.height(),
			size = Math.round(Math.sqrt(Math.pow(width, 2)+Math.pow(height, 2)));

		if (full) {
			data.wrapper.css({width: size, height: size});
			data.fwrapper.css({width: size, height: size}).
				children(':first-child').
					css({width: width, height: height});

			data.fpage.css({width: height, height: width});

			if (data.opts.frontGradient)
				data.ashadow.css({width: height, height: width});

			if (flipMethods._backGradient.call(this))
				data.bshadow.css({width: width, height: height});
		}

		if (data.parent.is(':visible')) {
			data.fwrapper.css({top: data.parent.offset().top,
				left: data.parent.offset().left});

			if (data.opts.turn)
				data.fparent.css({top: -data.opts.turn.offset().top, left: -data.opts.turn.offset().left});
		}

		this.flip('z', data.opts['z-index']);

	},

	// Prepares the page by adding a general wrapper and another objects

	_addPageWrapper: function() {

		var att,
			data = this.data().f,
			parent = this.parent();

		if (!data.wrapper) {

			var left = this.css('left'),
				top = this.css('top'),
				width = this.width(),
				height = this.height(),
				size = Math.round(Math.sqrt(Math.pow(width, 2)+Math.pow(height, 2)));
			
			data.parent = parent;
			data.fparent = (data.opts.turn) ? data.opts.turn.data().fparent : $('#turn-fwrappers');

			if (!data.fparent) {
				var fparent = $('<div/>', {css: {'pointer-events': 'none'}}).hide();
					fparent.data().flips = 0;

				if (data.opts.turn) {
					fparent.css(divAtt(-data.opts.turn.offset().top, -data.opts.turn.offset().left, 'auto', 'visible').css).
							appendTo(data.opts.turn);
					
					data.opts.turn.data().fparent = fparent;
				} else {
					fparent.css(divAtt(0, 0, 'auto', 'visible').css).
						attr('id', 'turn-fwrappers').
							appendTo($('body'));
				}

				data.fparent = fparent;
			}

			this.css({position: 'absolute', top: 0, left: 0, bottom: 'auto', right: 'auto'});

			data.wrapper = $('<div/>', divAtt(0, 0, this.css('z-index'))).
								appendTo(parent).
									prepend(this);

			data.fwrapper = $('<div/>', divAtt(parent.offset().top, parent.offset().left)).
								hide().
									appendTo(data.fparent);

			data.fpage = $('<div/>', {css: {cursor: 'default'}}).
					appendTo($('<div/>', divAtt(0, 0, 0, 'visible')).
								appendTo(data.fwrapper));

			if (data.opts.frontGradient)
				data.ashadow = $('<div/>', divAtt(0, 0,  1)).
					appendTo(data.fpage);

			// Save data

			flipMethods.setData.call(this, data);

			// Set size
			flipMethods.resize.call(this, true);
		}

	},

	// Takes a 2P point from the screen and applies the transformation

	_fold: function(point) {

		var that = this,
			a = 0,
			alpha = 0,
			beta,
			px,
			gradientEndPointA,
			gradientEndPointB,
			gradientStartV,
			gradientSize,
			gradientOpacity,
			mv = point2D(0, 0),
			df = point2D(0, 0),
			tr = point2D(0, 0),
			width = this.width(),
			height = this.height(),
			folding = flipMethods._foldingPage.call(this),
			tan = Math.tan(alpha),
			data = this.data().f,
			ac = data.opts.acceleration,
			h = data.wrapper.height(),
			o = flipMethods._c.call(this, point.corner),
			top = point.corner.substr(0, 1) == 't',
			left = point.corner.substr(1, 1) == 'l',

			compute = function() {
				var rel = point2D((o.x) ? o.x - point.x : point.x, (o.y) ? o.y - point.y : point.y),
					tan = (Math.atan2(rel.y, rel.x)),
					middle;

				alpha = A90 - tan;
				a = deg(alpha);
				middle = point2D((left) ? width - rel.x/2 : point.x + rel.x/2, rel.y/2);

				var gamma = alpha - Math.atan2(middle.y, middle.x),
					distance =  Math.max(0, Math.sin(gamma) * Math.sqrt(Math.pow(middle.x, 2) + Math.pow(middle.y, 2)));

					tr = point2D(distance * Math.sin(alpha), distance * Math.cos(alpha));

					if (alpha > A90) {
					
						tr.x = tr.x + Math.abs(tr.y * Math.tan(tan));
						tr.y = 0;

						if (Math.round(tr.x*Math.tan(PI-alpha)) < height) {

							point.y = Math.sqrt(Math.pow(height, 2)+2 * middle.x * rel.x);
							if (top) point.y =  height - point.y;
							return compute();

						}
					}
			
				if (alpha>A90) {
					var beta = PI-alpha, dd = h - height/Math.sin(beta);
					mv = point2D(Math.round(dd*Math.cos(beta)), Math.round(dd*Math.sin(beta)));
					if (left) mv.x = - mv.x;
					if (top) mv.y = - mv.y;
				}

				px = Math.round(tr.y/Math.tan(alpha) + tr.x);
			
				var side = width - px,
					sideX = side*Math.cos(alpha*2),
					sideY = side*Math.sin(alpha*2);
					df = point2D(Math.round( (left ? side -sideX : px+sideX)), Math.round((top) ? sideY : height - sideY));
					
				
				// GRADIENTS

					gradientSize = side*Math.sin(alpha);
						var endingPoint = flipMethods._c2.call(that, point.corner),
						far = Math.sqrt(Math.pow(endingPoint.x-point.x, 2)+Math.pow(endingPoint.y-point.y, 2));

					gradientOpacity = (far<width) ? far/width : 1;


				if (data.opts.frontGradient) {

					gradientStartV = gradientSize>100 ? (gradientSize-100)/gradientSize : 0;
					gradientEndPointA = point2D(gradientSize*Math.sin(A90-alpha)/height*100, gradientSize*Math.cos(A90-alpha)/width*100);
				
					if (top) gradientEndPointA.y = 100-gradientEndPointA.y;
					if (left) gradientEndPointA.x = 100-gradientEndPointA.x;
				}

				if (flipMethods._backGradient.call(that)) {

					gradientEndPointB = point2D(gradientSize*Math.sin(alpha)/width*100, gradientSize*Math.cos(alpha)/height*100);
					if (!left) gradientEndPointB.x = 100-gradientEndPointB.x;
					if (!top) gradientEndPointB.y = 100-gradientEndPointB.y;
				}
				//

				tr.x = Math.round(tr.x);
				tr.y = Math.round(tr.y);

				return true;
			},

			transform = function(tr, c, x, a) {
			
				var f = ['0', 'auto'], mvW = (width-h)*x[0]/100, mvH = (height-h)*x[1]/100,
					v = {left: f[c[0]], top: f[c[1]], right: f[c[2]], bottom: f[c[3]]},
					aliasingFk = (a!=90 && a!=-90) ? (left ? -1 : 1) : 0;

					x = x[0] + '% ' + x[1] + '%';

				that.css(v).transform(rotate(a) + translate(tr.x + aliasingFk, tr.y, ac), x);

				data.fpage.parent().css(v);
				data.wrapper.transform(translate(-tr.x + mvW-aliasingFk, -tr.y + mvH, ac) + rotate(-a), x);

				data.fwrapper.transform(translate(-tr.x + mv.x + mvW, -tr.y + mv.y + mvH, ac) + rotate(-a), x);
				data.fpage.parent().transform(rotate(a) + translate(tr.x + df.x - mv.x, tr.y + df.y - mv.y, ac), x);

				if (data.opts.frontGradient)
					gradient(data.ashadow,
							point2D(left?100:0, top?100:0),
							point2D(gradientEndPointA.x, gradientEndPointA.y),
							[[gradientStartV, 'rgba(0,0,0,0)'],
							[((1-gradientStartV)*0.8)+gradientStartV, 'rgba(0,0,0,'+(0.2*gradientOpacity)+')'],
							[1, 'rgba(255,255,255,'+(0.2*gradientOpacity)+')']],
							3,
							alpha);
		
				if (flipMethods._backGradient.call(that))
					gradient(data.bshadow,
							point2D(left?0:100, top?0:100),
							point2D(gradientEndPointB.x, gradientEndPointB.y),
							[[0.8, 'rgba(0,0,0,0)'],
							[1, 'rgba(0,0,0,'+(0.3*gradientOpacity)+')'],
							[1, 'rgba(0,0,0,0)']],
							3);
				
			};

		switch (point.corner) {
			case 'tl' :
				point.x = Math.max(point.x, 1);
				compute();
				transform(tr, [1,0,0,1], [100, 0], a);
				data.fpage.transform(translate(-height, -width, ac) + rotate(90-a*2) , '100% 100%');
				folding.transform(rotate(90) + translate(0, -height, ac), '0% 0%');
			break;
			case 'tr' :
				point.x = Math.min(point.x, width-1);
				compute();
				transform(point2D(-tr.x, tr.y), [0,0,0,1], [0, 0], -a);
				data.fpage.transform(translate(0, -width, ac) + rotate(-90+a*2) , '0% 100%');
				folding.transform(rotate(270) + translate(-width, 0, ac), '0% 0%');
			break;
			case 'bl' :
				point.x = Math.max(point.x, 1);
				compute();
				transform(point2D(tr.x, -tr.y), [1,1,0,0], [100, 100], -a);
				data.fpage.transform(translate(-height, 0, ac) + rotate(-90+a*2), '100% 0%');
				folding.transform(rotate(270) + translate(-width, 0, ac), '0% 0%');
			break;
			case 'br' :
				point.x = Math.min(point.x, width-1);
				compute();
				transform(point2D(-tr.x, -tr.y), [0,1,1,0], [0, 100], a);
				data.fpage.transform(rotate(90-a*2), '0% 0%');
				folding.transform(rotate(90) + translate(0, -height, ac), '0% 0%');

			break;
		}

		data.point = point;
	
	},

	_moveFoldingPage: function(bool) {

		var data = this.data().f,
			folding = flipMethods._foldingPage.call(this);

		if (folding) {
			if (bool) {
				if (!data.fpage.children()[data.ashadow? '1' : '0']) {
					flipMethods.setData.call(this, {backParent: folding.parent()});
					data.fpage.prepend(folding);
				}
			} else {
				if (data.backParent)
					data.backParent.prepend(folding);

			}
		}

	},

	_showFoldedPage: function(c, animate) {

		var folding = flipMethods._foldingPage.call(this),
			dd = this.data(),
			data = dd.f;

		if (!data.point || data.point.corner!=c.corner) {
			var event = $.Event('start');
			this.trigger(event, [data.opts, c.corner]);

			if (event.isDefaultPrevented())
				return false;
		}


		if (folding) {

			if (animate) {

				var that = this, point = (data.point && data.point.corner==c.corner) ? data.point : flipMethods._c.call(this, c.corner, 1);
			
				this.animatef({from: [point.x, point.y], to:[c.x, c.y], duration: 500, frame: function(v) {
					c.x = Math.round(v[0]);
					c.y = Math.round(v[1]);
					flipMethods._fold.call(that, c);
				}});

			} else	{

				flipMethods._fold.call(this, c);
				if (dd.effect && !dd.effect.turning)
					this.animatef(false);

			}

			if (!data.fwrapper.is(':visible')) {
				data.fparent.show().data().flips++;
				flipMethods._moveFoldingPage.call(this, true);
				data.fwrapper.show();

				if (data.bshadow)
					data.bshadow.show();
			}

			return true;
		}

		return false;
	},

	hide: function() {

		var data = this.data().f,
			folding = flipMethods._foldingPage.call(this);

		if ((--data.fparent.data().flips)===0)
			data.fparent.hide();

		this.css({left: 0, top: 0, right: 'auto', bottom: 'auto'}).transform('', '0% 100%');

		data.wrapper.transform('', '0% 100%');

		data.fwrapper.hide();

		if (data.bshadow)
			data.bshadow.hide();

		folding.transform('', '0% 0%');

		return this;
	},

	hideFoldedPage: function(animate) {

		var data = this.data().f;

		if (!data.point) return;

		var that = this,
			p1 = data.point,
			hide = function() {
				data.point = null;
				that.flip('hide');
				that.trigger('end', [false]);
			};

		if (animate) {
			var p4 = flipMethods._c.call(this, p1.corner),
				top = (p1.corner.substr(0,1)=='t'),
				delta = (top) ? Math.min(0, p1.y-p4.y)/2 : Math.max(0, p1.y-p4.y)/2,
				p2 = point2D(p1.x, p1.y+delta),
				p3 = point2D(p4.x, p4.y-delta);
		
			this.animatef({
				from: 0,
				to: 1,
				frame: function(v) {
					var np = bezier(p1, p2, p3, p4, v);
					p1.x = np.x;
					p1.y = np.y;
					flipMethods._fold.call(that, p1);
				},
				complete: hide,
				duration: 800,
				hiding: true
				});

		} else {
			this.animatef(false);
			hide();
		}
	},

	turnPage: function(corner) {

		var that = this,
			data = this.data().f;

		corner = {corner: (data.corner) ? data.corner.corner : corner || flipMethods._cAllowed.call(this)[0]};

		var p1 = data.point || flipMethods._c.call(this, corner.corner, (data.opts.turn) ? data.opts.turn.data().opts.elevation : 0),
			p4 = flipMethods._c2.call(this, corner.corner);

			this.trigger('flip').
				animatef({
					from: 0,
					to: 1,
					frame: function(v) {
						var np = bezier(p1, p1, p4, p4, v);
						corner.x = np.x;
						corner.y = np.y;
						flipMethods._showFoldedPage.call(that, corner);
					},
					
					complete: function() {
						that.trigger('end', [true]);
					},
					duration: data.opts.duration,
					turning: true
				});

			data.corner = null;
	},

	moving: function() {

		return 'effect' in this.data();
	
	},

	isTurning: function() {

		return this.flip('moving') && this.data().effect.turning;
	
	},

	_eventStart: function(e) {

		var data = this.data().f;

		if (!data.disabled && !this.flip('isTurning')) {
			data.corner = flipMethods._cornerActivated.call(this, e);
			if (data.corner && flipMethods._foldingPage.call(this, data.corner)) {
				flipMethods._moveFoldingPage.call(this, true);
				this.trigger('pressed', [data.point]);
				return false;
			} else
				data.corner = null;
		}

	},

	_eventMove: function(e) {

		var data = this.data().f;

		if (!data.disabled) {
			e = (isTouch) ? e.originalEvent.touches : [e];
		
			if (data.corner) {

				var pos = data.parent.offset();

				data.corner.x = e[0].pageX-pos.left;
				data.corner.y = e[0].pageY-pos.top;

				flipMethods._showFoldedPage.call(this, data.corner);
			
			} else if (!this.data().effect && this.is(':visible')) { // roll over
				
				var corner = flipMethods._cornerActivated.call(this, e[0]);
				if (corner) {
					var origin = flipMethods._c.call(this, corner.corner, data.opts.cornerSize/2);
					corner.x = origin.x;
					corner.y = origin.y;
					flipMethods._showFoldedPage.call(this, corner, true);
				} else
					flipMethods.hideFoldedPage.call(this, true);

			}
		}
	},

	_eventEnd: function() {

		var data = this.data().f;

		if (!data.disabled && data.point) {
			var event = $.Event('released');
			this.trigger(event, [data.point]);
			if (!event.isDefaultPrevented())
				flipMethods.hideFoldedPage.call(this, true);
		}

		data.corner = null;

	},

	disable: function(disable) {

		flipMethods.setData.call(this, {'disabled': disable});
		return this;

	}
},

cla = function(that, methods, args) {

	if (!args[0] || typeof(args[0])=='object')
		return methods.init.apply(that, args);
	else if(methods[args[0]] && args[0].toString().substr(0, 1)!='_')
		return methods[args[0]].apply(that, Array.prototype.slice.call(args, 1));
	else
		throw args[0] + ' is an invalid value';
};

$.extend($.fn, {

	flip: function(req, opts) {
		return cla(this, flipMethods, arguments);
	},

	turn: function(req) {
		return cla(this, turnMethods, arguments);
	},

	transform: function(transform, origin) {

		var properties = {};
		
		if (origin)
			properties[vendor+'transform-origin'] = origin;
		
		properties[vendor+'transform'] = transform;
	
		return this.css(properties);

	},

	animatef: function(point) {

		var data = this.data();

		if (data.effect)
			clearInterval(data.effect.handle);

		if (point) {

			if (!point.to.length) point.to = [point.to];
			if (!point.from.length) point.from = [point.from];
			if (!point.easing) point.easing = function (x, t, b, c, data) { return c * Math.sqrt(1 - (t=t/data-1)*t) + b; };

			var j, diff = [],
				len = point.to.length,
				that = this,
				fps = point.fps || 30,
				time = - fps,
				f = function() {
					var j, v = [];
					time = Math.min(point.duration, time + fps);
	
					for (j = 0; j < len; j++)
						v.push(point.easing(1, time, point.from[j], diff[j], point.duration));

					point.frame((len==1) ? v[0] : v);

					if (time==point.duration) {
						clearInterval(data.effect.handle);
						delete data['effect'];
						that.data(data);
						if (point.complete)
							point.complete();
						}
					};

			for (j = 0; j < len; j++)
				diff.push(point.to[j] - point.from[j]);

			data.effect = point;
			data.effect.handle = setInterval(f, fps);
			this.data(data);
			f();
		} else {
			delete data['effect'];
		}
	}
});


$.isTouch = isTouch;

})(jQuery);
Download .txt
gitextract_61qrn7na/

├── changelog.txt
├── demos/
│   ├── bible/
│   │   └── index.html
│   ├── magazine/
│   │   └── index.html
│   └── magazine_single/
│       └── index.html
├── license.txt
├── readme.md
└── turn.js
Condensed preview — 7 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (62K chars).
[
  {
    "path": "changelog.txt",
    "chars": 1033,
    "preview": "TURN.JS\n------------------------------------------------------\nGithub: https://github.com/blasten/turn.js\nReference: htt"
  },
  {
    "path": "demos/bible/index.html",
    "chars": 3361,
    "preview": "<!doctype html>\n<html>\n<head>\n<script type=\"text/javascript\" src=\"http://code.jquery.com/jquery-1.7.1.min.js\"></script>\n"
  },
  {
    "path": "demos/magazine/index.html",
    "chars": 1292,
    "preview": "<!doctype html>\n<html>\n<head>\n<script type=\"text/javascript\" src=\"http://code.jquery.com/jquery-1.7.1.min.js\"></script>\n"
  },
  {
    "path": "demos/magazine_single/index.html",
    "chars": 1291,
    "preview": "<!doctype html>\n<html>\n<head>\n<script type=\"text/javascript\" src=\"http://code.jquery.com/jquery-1.7.1.min.js\"></script>\n"
  },
  {
    "path": "license.txt",
    "chars": 1247,
    "preview": "turn.js 3rd release\nwww.turnjs.com\n\nCopyright (c) 2012, Emmanuel Garcia\nAll rights reserved.\n\nRedistribution and use in "
  },
  {
    "path": "readme.md",
    "chars": 2184,
    "preview": "\n![Bilby Stampede](http://turnjs.com/pics/small-turnjs-letters.png)\n\n**Get the turn.js 4th release on [turnjs.com](http:"
  },
  {
    "path": "turn.js",
    "chars": 44461,
    "preview": "/**\n * turn.js 3rd release\n * www.turnjs.com\n *\n * Copyright (C) 2012, Emmanuel Garcia.\n * All rights reserved.\n *\n * Re"
  }
]

About this extraction

This page contains the full source code of the blasten/turn.js GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 7 files (53.6 KB), approximately 16.4k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!