");
60 | var pageWrapper = $("")
61 |
62 | pageWrapper.append(this.prevPage).append(this.pageTitle).append(this.nextPage).insertAfter(ele);
63 | this.prevPage.bind("click", function() {
64 | that.pageData(-1);
65 | });
66 | this.nextPage.bind("click", function() {
67 | that.pageData(1);
68 | });
69 | }
70 |
71 | var that = this;
72 | closer.bind("click", function() {
73 | input.val('');
74 | that.filterData('');
75 | closer.hide();
76 | });
77 | input.bind("keyup", function() {
78 | that.currentPage=0;
79 | that.filterData(this.value)
80 | }).bind("focus", function() {
81 | closer.show();
82 |
83 | }).bind("blur", function() {
84 | closer.show();
85 | });
86 | this.filterData('');
87 | };
88 |
89 | filterList.prototype = {
90 | caseInsensitive: false,
91 | perPage: null,
92 | ele: null,
93 | options: [],
94 | revealElements: false,
95 | totalPages: null,
96 | currentPage: null,
97 | prevPager: null,
98 | nextPager: null,
99 | pageTitle: null,
100 | cbFunc: compareFunc,
101 | currentPage: 0,
102 | availableElements: [],
103 | refresh: function() {
104 | var that = this;
105 | this.ele.children().forEach(function(elem) {
106 | var eachEle = {};
107 | eachEle.target = elem.childNodes[0].tagName !== undefined ? elem.childNodes[0] : elem
108 | eachEle.parent = elem;
109 | that.options.push(eachEle);
110 | });
111 | return this;
112 | },
113 | filterData: function(val) {
114 | var that = this;
115 | that.availableElements = [];
116 | if (val == '' && this.revealElements)
117 | return that.options.forEach(function(elem) {
118 | if ((elem.target.getAttribute("data-ignore") + "").toLowerCase() != "true") {
119 | $(elem.parent).hide();
120 | } else {
121 | that.availableElements.push(elem.parent);
122 | }
123 | }), that.pageData();
124 |
125 | that.options.forEach(function(elem) {
126 | var toCompare = elem.target.getAttribute("data-filter") ? elem.target.getAttribute("data-filter") : elem.target.innerHTML;
127 | if ((elem.target.getAttribute("data-ignore") + "").toLowerCase() == "true")
128 | return that.availableElements.push(elem.parent);
129 |
130 | that.cbFunc(toCompare, val, that.caseInsensitive) ? (that.availableElements.push(elem.parent), $(elem.parent).show()) : $(elem.parent).hide();
131 | });
132 | if(this.perPage)
133 | this.pageData();
134 | },
135 | pageData: function(ind) {
136 | ind = parseInt(ind);
137 | if (isNaN(ind))
138 | ind = 0;
139 | this.currentPage += ind;
140 | var totalPages = Math.ceil((this.availableElements.length / this.perPage));
141 | if(totalPages==0)
142 | totalPages=1;
143 | for (var i = 0; i < this.availableElements.length; i++)
144 | {
145 | if (i >= (this.perPage * this.currentPage) && i < (this.perPage * (this.currentPage + 1)))
146 | $(this.availableElements[i]).show();
147 | else
148 | $(this.availableElements[i]).hide();
149 | }
150 | var dispPage = this.currentPage + 1;
151 | if (dispPage > totalPages)
152 | dispPage = totalPages;
153 | if (dispPage <= 0)
154 | dispPage = 1;
155 | if (this.currentPage > 0)
156 | this.prevPage.css("visibility", "visible")
157 | else
158 | this.prevPage.css("visibility", "hidden");
159 | if (this.currentPage < (totalPages - 1))
160 | this.nextPage.css("visibility", "visible")
161 | else
162 | this.nextPage.css("visibility", "hidden");
163 |
164 | this.pageTitle.html("Page " + (dispPage) + "/" + totalPages).show();
165 | }
166 |
167 | }
168 |
169 | })(af);
170 |
--------------------------------------------------------------------------------
/af-alphatable/af.alphatable.js:
--------------------------------------------------------------------------------
1 | /**
2 | * $.alphaTable - a list table for App Framework apps
3 | *
4 | * @copyright 2011 - Intel
5 | *
6 | */ (function($) {
7 | $.fn["alphatable"] = function(scroller, opts) {
8 | var tmp;
9 | for (var i = 0; i < this.length; i++) {
10 | tmp = new alphaTable(this[i], scroller, opts);
11 |
12 | }
13 | return this.length == 1 ? tmp : this;
14 | };
15 |
16 | var alphaTable = (function() {
17 | var translateOpen = $.feat.cssTransformStart;
18 | var translateClose = $.feat.cssTransformEnd;
19 | var alphaTable = function(el, scroller, opts) {
20 |
21 | if (typeof el == "string") el = document.getElementById(el);
22 | this.container = el.parentNode;
23 | if (!this.container) {
24 | alert("Error finding container for alphaTable " + el);
25 | return;
26 | }
27 | if (this instanceof alphaTable) {
28 | for (j in opts) {
29 | this[j] = opts[j];
30 | }
31 | } else {
32 | return new alphaTable(el, scroller, opts);
33 | }
34 | if (!scroller || typeof(scroller) != "object") {
35 | return alert("Error: Please include an af.scroll object to use this");
36 | }
37 | this.scroller = scroller;
38 |
39 | this.el = el;
40 |
41 | this.setupIndex();
42 | var stickyHeader = $.create("div", {
43 | className: "stickyHeader tableHeader",
44 | html: $(this.el).find(".tableHeader").html()
45 | });
46 | stickyHeader.get(0).style.cssText = ";z-index:9998;position:absolute;top:0px;width:100%;";
47 |
48 | $(this.el).parent().append(stickyHeader);
49 | this.header = stickyHeader;
50 | this.setupLetterBox();
51 | var that = this;
52 |
53 | var prevPos = this.scroller.scrollTop;
54 | var isMoving = false;
55 | this.el.addEventListener("touchmove", function(e) {
56 | var thePos = that.scroller.scrollTop;
57 | if (that.scroller.scrollTop > 0) return;
58 | thePos = Math.abs(thePos);
59 | if (!isMoving) {
60 | for (var i = 0; i < that.offset.length; i++) {
61 | var checkPos = that.offset[i];
62 | var checkPosSuc = that.offset[i+1]; //
63 | if(checkPosSuc==undefined)checkPosSuc = 1000000000000;
64 | if (checkPos >= (thePos) && checkPos <= (thePos + that.boxHeight)) {
65 | isMoving = i;
66 | break;
67 | }
68 | else if(thePos > checkPos && thePos < (checkPosSuc-that.boxHeight) ){
69 | isMoving = i;
70 | break;
71 | }
72 | }
73 | }
74 | var dir = thePos > prevPos;
75 | prevPos = thePos;
76 | if (isMoving >= 0) {
77 | checkPos = that.offset[isMoving];
78 | var moveTo = (thePos - checkPos) + that.boxHeight;
79 | moveTo *= -1;
80 | if (moveTo >= 0) {
81 | if(isMoving > 0 )that.header.html($(that.el).find(".tableHeader").get(isMoving - 1).innerHTML);
82 | else if(isMoving == 0 )that.header.html($(that.el).find(".tableHeader").get(isMoving).innerHTML);
83 | isMoving = false;
84 | } else if (Math.abs(moveTo) >= Math.abs(that.boxHeight)) {
85 | that.header.html($(that.el).find(".tableHeader").get(isMoving).innerHTML);
86 | isMoving = false;
87 | moveTo = 0;
88 | }
89 | that.header.cssTranslate("0," + moveTo + "px");
90 | return;
91 | }
92 | that.header.cssTranslate("0,0");
93 | });
94 | this.getOffsets();
95 | this.boxHeight = numOnly(stickyHeader.computedStyle("height"));
96 |
97 | };
98 | var boxCSS = "position:absolute;top:5%;right:10px;width:20px;font-size:6pt;font-weight:bold;color:#000;opacity:.5;border-radius:5px;text-align:center;z-index:9999;border:1px solid black;background:#666;padding-top:5px;padding-bottom:5px;height:90%;";
99 | alphaTable.prototype = {
100 | listCssClass: "",
101 | letterBox: null,
102 | isMoving: false,
103 | prefix: "",
104 | offsets: [],
105 | boxHeight: 0,
106 | refresh: function() {
107 | this.getOffsets();
108 | },
109 | getOffsets: function() {
110 | var that = this;
111 | var parentTop = $(this.el.parentNode).offset().top;
112 | console.log(parentTop);
113 | var stuff = $(this.el).find(".tableHeader");
114 | that.offset = [];
115 | stuff.each(function() {
116 | that.offset.push($(this).offset().top - parentTop);
117 | });
118 | },
119 | scrollToLetter: function(letter) {
120 | var el = document.getElementById(this.prefix + letter);
121 | if (el) {
122 | var yPos = -el.offsetTop;
123 | this.scroller.scrollTo({
124 | x: 0,
125 | y: yPos
126 | });
127 | }
128 | },
129 | setupIndex: function() {
130 | var arrAlphabet = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
131 | var that = this;
132 | var containerDiv = document.createElement("div");
133 | containerDiv.id = "indexDIV_" + this.el.id;
134 | containerDiv.style.cssText = boxCSS;
135 | containerDiv.className = this.listCssClass;
136 | containerDiv.addEventListener("touchend", function(event) {
137 | that.isMoving = false;
138 | that.clearLetterBox();
139 | }, false);
140 | //To allow updating as we "scroll" with our finger, we need to capture the position on the containerDiv element and calculate the Y coordinates.
141 | //On mobile devices, you can not do an "onmouseover" over multiple items and trigger events.
142 | containerDiv.addEventListener("touchstart", function(event) {
143 |
144 |
145 | if (event.touches[0].target == this) return;
146 | that.isMoving = true;
147 |
148 | var letter = document.elementFromPoint(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
149 | if (!letter || !letter.getAttribute("alphatable-item") || letter.getAttribute("alphatable-item").length == 0)
150 | var letter = event.touches[0].target;
151 |
152 | if (letter.innerHTML.length > 1) return;
153 | that.showLetter(letter.innerHTML);
154 | that.scrollToLetter(letter.innerHTML);
155 | event.preventDefault();
156 | event.stopPropagation();
157 | }, false);
158 | containerDiv.addEventListener("touchmove", function(event) {
159 | var letter = document.elementFromPoint(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
160 | if (!letter || !letter.getAttribute("alphatable-item") || letter.getAttribute("alphatable-item").length == 0)
161 | var letter = event.touches[0].target;
162 | if (letter.innerHTML.length > 1) return;
163 | if (!that.isMoving) return;
164 | that.showLetter(letter.innerHTML);
165 | that.scrollToLetter(letter.innerHTML);
166 | event.preventDefault();
167 | }, false);
168 |
169 | //Create the alphabet
170 | for (i = 0; i < arrAlphabet.length; i++) {
171 | var tmpDiv = document.createElement("div");
172 | tmpDiv.innerHTML = arrAlphabet[i];
173 | tmpDiv.setAttribute("alphatable-item", "true");
174 | containerDiv.appendChild(tmpDiv);
175 | }
176 | this.container.appendChild(containerDiv);
177 |
178 | var clientHeight = numOnly(containerDiv.clientHeight) - numOnly(containerDiv.style.top) - numOnly(containerDiv.style.paddingTop);
179 | this.scroller.scrollTo({
180 | x: 0,
181 | y: 0
182 | }); //There's a bug with webkit and css3. The letterbox would not show until -webkit-transform as applied.
183 | containerDiv = null;
184 |
185 | },
186 | showLetter: function(letter) {
187 | var that = this;
188 | this.letterBox.style.display = "block";
189 | if (this.letterBox.innerHTML != letter) {
190 | that.letterBox.innerHTML = letter;
191 | }
192 |
193 | },
194 | clearLetterBox: function() {
195 | this.letterBox.style.display = "none";
196 | this.letterBox.innerHTML = "";
197 | },
198 | setupLetterBox: function() {
199 | var div = document.createElement("div");
200 | div.style.cssText = $.feat.cssPrefix + "-transform:translate3d(0,0,0);display:none;position:absolute;top:35%;left:35%;height:2em;width:15%;line-height:2em;text-align:center;font-size:2em;color:blue;background:#666;z-index:999999;border:1px solid black;border-raidus:10px;";
201 | div.className = this.letterBoxCssClass;
202 | div.innerHTML = "";
203 | this.letterBox = div;
204 | this.container.appendChild(div);
205 | div = null;
206 |
207 | }
208 | };
209 | return alphaTable;
210 | })();
211 | })(af);
--------------------------------------------------------------------------------
/i18n/i18n.js:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * jquery.i18n.properties
3 | *
4 | * Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and
5 | * MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
6 | *
7 | * @version 1.0.x
8 | * @author Nuno Fernandes
9 | * @url www.codingwithcoffee.com
10 | * @inspiration Localisation assistance for jQuery (http://keith-wood.name/localisation.html)
11 | * by Keith Wood (kbwood{at}iinet.com.au) June 2007
12 | *
13 |
14 |
15 | * @modified - IDM
16 | * @description - changed loading to be asynchronous and use jqMobi
17 |
18 | *****************************************************************************/
19 |
20 | (function($) {
21 | $.i18n = {};
22 |
23 | /** Map holding bundle keys (if mode: 'map') */
24 | $.i18n.map = {};
25 |
26 |
27 | var _filesToLoad=0;
28 | /**
29 | * Load and parse message bundle files (.properties),
30 | * making bundles keys available as javascript variables.
31 | *
32 | * i18n files are named
.js, or _.js or __.js
33 | * Where:
34 | * The argument is a valid ISO Language Code. These codes are the lower-case,
35 | * two-letter codes as defined by ISO-639. You can find a full list of these codes at a
36 | * number of sites, such as: http://www.loc.gov/standards/iso639-2/englangn.html
37 | * The argument is a valid ISO Country Code. These codes are the upper-case,
38 | * two-letter codes as defined by ISO-3166. You can find a full list of these codes at a
39 | * number of sites, such as: http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html
40 | *
41 | * Sample usage for a bundles/Messages.properties bundle:
42 | * $.i18n.properties({
43 | * name: 'Messages',
44 | * language: 'en_US',
45 | * path: 'bundles'
46 | * });
47 | * @param name (string/string[], optional) names of file to load (eg, 'Messages' or ['Msg1','Msg2']). Defaults to "Messages"
48 | * @param language (string, optional) language/country code (eg, 'en', 'en_US', 'pt_PT'). if not specified, language reported by the browser will be used instead.
49 | * @param path (string, optional) path of directory that contains file to load
50 | * @param mode (string, optional) whether bundles keys are available as JavaScript variables/functions or as a map (eg, 'vars' or 'map')
51 | * @param cache (boolean, optional) whether bundles should be cached by the browser, or forcibly reloaded on each page load. Defaults to false (i.e. forcibly reloaded)
52 | * @param encoding (string, optional) the encoding to request for bundles. Property file resource bundles are specified to be in ISO-8859-1 format. Defaults to UTF-8 for backward compatibility.
53 | * @param callback (function, optional) callback function to be called after script is terminated
54 | */
55 | $.i18n.properties = function(settings) {
56 | // set up settings
57 | var defaults = {
58 | name: 'Messages',
59 | language: '',
60 | path: '',
61 | mode: 'vars',
62 | cache: false,
63 | encoding: 'UTF-8',
64 | callback: null
65 | };
66 | settings = $.extend(defaults, settings);
67 | if(settings.language === null || settings.language == '') {
68 | settings.language = $.i18n.browserLang();
69 | }
70 | if(settings.language === null) {settings.language='';}
71 |
72 | // load and parse bundle files
73 | var files = getFiles(settings.name);
74 | _filesToLoad=files.length;
75 | for(i=0; i= 2) {
80 | loadAndParseFile(settings.path + files[i] + '_' + settings.language.substring(0, 2) +'.properties', settings);
81 | _filesToLoad++;
82 | }
83 | // 3. with language code and country code (eg, Messages_pt_PT.properties)
84 | if(settings.language.length >= 5) {
85 | loadAndParseFile(settings.path + files[i] + '_' + settings.language.substring(0, 5) +'.properties', settings);
86 | _filesToLoad++;
87 | }
88 | }
89 |
90 | // call callback
91 | if(settings.callback){
92 | $(document).one("i18n:complete",function(){console.log("wtf");settings.callback();});
93 | }
94 | };
95 |
96 |
97 | /**
98 | * When configured with mode: 'map', allows access to bundle values by specifying its key.
99 | * Eg, jQuery.i18n.prop('com.company.bundles.menu_add')
100 | */
101 | $.i18n.prop = function(key /* Add parameters as function arguments as necessary */) {
102 | var value = $.i18n.map[key];
103 | if (value == null)
104 | return '[' + key + ']';
105 |
106 | // if(arguments.length < 2) // No arguments.
107 | // //if(key == 'spv.lbl.modified') {alert(value);}
108 | // return value;
109 |
110 | // if (!$.isArray(placeHolderValues)) {
111 | // // If placeHolderValues is not an array, make it into one.
112 | // placeHolderValues = [placeHolderValues];
113 | // for (var i=2; i asdf 'p1'
130 | * test.t2, p1 ==> asdf {0} {1}{1}zxcv
131 | * test.t3, p1 ==> This is "a quote" a'{0}'sd{fgh{ij
132 | * test.t4, p1 ==> "'{0}'" p1{a}
133 | * test.t5, p1 ==> "'{0}'" {1}
134 | * test.t6, p1 ==> a {1} b p1 c
135 | * test.t6, p1, p2 ==> a p2 b p1 c
136 | * test.t6, p1, p2, p3 ==> a p2 b p1 c
137 | * test.t7 ==> a quoted \ s tringy x
138 | */
139 |
140 | var i;
141 | if (typeof(value) == 'string') {
142 | // Handle escape characters. Done separately from the tokenizing loop below because escape characters are
143 | // active in quoted strings.
144 | i = 0;
145 | while ((i = value.indexOf('\\', i)) != -1) {
146 | if (value[i+1] == 't')
147 | value = value.substring(0, i) + '\t' + value.substring((i++) + 2); // tab
148 | else if (value[i+1] == 'r')
149 | value = value.substring(0, i) + '\r' + value.substring((i++) + 2); // return
150 | else if (value[i+1] == 'n')
151 | value = value.substring(0, i) + '\n' + value.substring((i++) + 2); // line feed
152 | else if (value[i+1] == 'f')
153 | value = value.substring(0, i) + '\f' + value.substring((i++) + 2); // form feed
154 | else if (value[i+1] == '\\')
155 | value = value.substring(0, i) + '\\' + value.substring((i++) + 2); // \
156 | else
157 | value = value.substring(0, i) + value.substring(i+1); // Quietly drop the character
158 | }
159 |
160 | // Lazily convert the string to a list of tokens.
161 | var arr = [], j, index;
162 | i = 0;
163 | while (i < value.length) {
164 | if (value[i] == '\'') {
165 | // Handle quotes
166 | if (i == value.length-1)
167 | value = value.substring(0, i); // Silently drop the trailing quote
168 | else if (value[i+1] == '\'')
169 | value = value.substring(0, i) + value.substring(++i); // Escaped quote
170 | else {
171 | // Quoted string
172 | j = i + 2;
173 | while ((j = value.indexOf('\'', j)) != -1) {
174 | if (j == value.length-1 || value[j+1] != '\'') {
175 | // Found start and end quotes. Remove them
176 | value = value.substring(0,i) + value.substring(i+1, j) + value.substring(j+1);
177 | i = j - 1;
178 | break;
179 | }
180 | else {
181 | // Found a double quote, reduce to a single quote.
182 | value = value.substring(0,j) + value.substring(++j);
183 | }
184 | }
185 |
186 | if (j == -1) {
187 | // There is no end quote. Drop the start quote
188 | value = value.substring(0,i) + value.substring(i+1);
189 | }
190 | }
191 | }
192 | else if (value[i] == '{') {
193 | // Beginning of an unquoted place holder.
194 | j = value.indexOf('}', i+1);
195 | if (j == -1)
196 | i++; // No end. Process the rest of the line. Java would throw an exception
197 | else {
198 | // Add 1 to the index so that it aligns with the function arguments.
199 | index = parseInt(value.substring(i+1, j));
200 | if (!isNaN(index) && index >= 0) {
201 | // Put the line thus far (if it isn't empty) into the array
202 | var s = value.substring(0, i);
203 | if (s != "")
204 | arr.push(s);
205 | // Put the parameter reference into the array
206 | arr.push(index);
207 | // Start the processing over again starting from the rest of the line.
208 | i = 0;
209 | value = value.substring(j+1);
210 | }
211 | else
212 | i = j + 1; // Invalid parameter. Leave as is.
213 | }
214 | }
215 | else
216 | i++;
217 | }
218 |
219 | // Put the remainder of the no-empty line into the array.
220 | if (value != "")
221 | arr.push(value);
222 | value = arr;
223 |
224 | // Make the array the value for the entry.
225 | $.i18n.map[key] = arr;
226 | }
227 |
228 | if (value.length == 0)
229 | return "";
230 | if (value.lengh == 1 && typeof(value[0]) == "string")
231 | return value[0];
232 |
233 | var s = "";
234 | for (i=0; i=_filesToLoad){
266 | $(document).trigger("i18n:complete");
267 | }
268 | }
269 | });
270 | }
271 |
272 | /** Parse .properties files */
273 | function parseData(data, mode) {
274 | var parsed = '';
275 | var parameters = data.split( /\n/ );
276 | var regPlaceHolder = /(\{\d+\})/g;
277 | var regRepPlaceHolder = /\{(\d+)\}/g;
278 | var unicodeRE = /(\\u.{4})/ig;
279 | for(var i=0; i 0 && parameters[i].match("^#")!="#") { // skip comments
282 | var pair = parameters[i].split('=');
283 | if(pair.length > 0) {
284 | /** Process key & value */
285 | var name = unescape(pair[0]).replace( /^\s\s*/, '' ).replace( /\s\s*$/, '' ); // trim
286 | var value = pair.length == 1 ? "" : pair[1];
287 | // process multi-line values
288 | while(value.match(/\\$/)=="\\") {
289 | value = value.substring(0, value.length - 1);
290 | value += parameters[++i].replace( /\s\s*$/, '' ); // right trim
291 | }
292 | // Put values with embedded '='s back together
293 | for(var s=2;s 0)
342 | } // END: skip comments
343 | }
344 | eval(parsed);
345 | }
346 |
347 | /** Make sure namespace exists (for keys with dots in name) */
348 | // TODO key parts that start with numbers quietly fail. i.e. month.short.1=Jan
349 | function checkKeyNamespace(key) {
350 | var regDot = /\./;
351 | if(regDot.test(key)) {
352 | var fullname = '';
353 | var names = key.split( /\./ );
354 | for(var i=0; i0) {fullname += '.';}
356 | fullname += names[i];
357 | if(eval('typeof '+fullname+' == "undefined"')) {
358 | eval(fullname + '={};');
359 | }
360 | }
361 | }
362 | }
363 |
364 | /** Make sure filename is an array */
365 | function getFiles(names) {
366 | return (names && names.constructor == Array) ? names : [names];
367 | }
368 |
369 | /** Ensure language code is in the format aa_AA. */
370 | function normaliseLanguageCode(lang) {
371 | lang = lang.toLowerCase();
372 | if(lang.length > 3) {
373 | lang = lang.substring(0, 3) + lang.substring(3).toUpperCase();
374 | }
375 | return lang;
376 | }
377 |
378 | /** Unescape unicode chars ('\u00e3') */
379 | function unescapeUnicode(str) {
380 | // unescape unicode codes
381 | var codes = [];
382 | var code = parseInt(str.substr(2), 16);
383 | if (code >= 0 && code < Math.pow(2, 16)) {
384 | codes.push(code);
385 | }
386 | // convert codes to text
387 | var unescaped = '';
388 | for (var i = 0; i < codes.length; ++i) {
389 | unescaped += String.fromCharCode(codes[i]);
390 | }
391 | return unescaped;
392 | }
393 |
394 | /* Cross-Browser Split 1.0.1
395 | (c) Steven Levithan ; MIT License
396 | An ECMA-compliant, uniform cross-browser split method */
397 | var cbSplit;
398 | // avoid running twice, which would break `cbSplit._nativeSplit`'s reference to the native `split`
399 | if (!cbSplit) {
400 | cbSplit = function(str, separator, limit) {
401 | // if `separator` is not a regex, use the native `split`
402 | if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
403 | if(typeof cbSplit._nativeSplit == "undefined")
404 | return str.split(separator, limit);
405 | else
406 | return cbSplit._nativeSplit.call(str, separator, limit);
407 | }
408 |
409 | var output = [],
410 | lastLastIndex = 0,
411 | flags = (separator.ignoreCase ? "i" : "") +
412 | (separator.multiline ? "m" : "") +
413 | (separator.sticky ? "y" : ""),
414 | separator = RegExp(separator.source, flags + "g"), // make `global` and avoid `lastIndex` issues by working with a copy
415 | separator2, match, lastIndex, lastLength;
416 |
417 | str = str + ""; // type conversion
418 | if (!cbSplit._compliantExecNpcg) {
419 | separator2 = RegExp("^" + separator.source + "$(?!\\s)", flags); // doesn't need /g or /y, but they don't hurt
420 | }
421 |
422 | /* behavior for `limit`: if it's...
423 | - `undefined`: no limit.
424 | - `NaN` or zero: return an empty array.
425 | - a positive number: use `Math.floor(limit)`.
426 | - a negative number: no limit.
427 | - other: type-convert, then use the above rules. */
428 | if (limit === undefined || +limit < 0) {
429 | limit = Infinity;
430 | } else {
431 | limit = Math.floor(+limit);
432 | if (!limit) {
433 | return [];
434 | }
435 | }
436 |
437 | while (match = separator.exec(str)) {
438 | lastIndex = match.index + match[0].length; // `separator.lastIndex` is not reliable cross-browser
439 |
440 | if (lastIndex > lastLastIndex) {
441 | output.push(str.slice(lastLastIndex, match.index));
442 |
443 | // fix browsers whose `exec` methods don't consistently return `undefined` for nonparticipating capturing groups
444 | if (!cbSplit._compliantExecNpcg && match.length > 1) {
445 | match[0].replace(separator2, function () {
446 | for (var i = 1; i < arguments.length - 2; i++) {
447 | if (arguments[i] === undefined) {
448 | match[i] = undefined;
449 | }
450 | }
451 | });
452 | }
453 |
454 | if (match.length > 1 && match.index < str.length) {
455 | Array.prototype.push.apply(output, match.slice(1));
456 | }
457 |
458 | lastLength = match[0].length;
459 | lastLastIndex = lastIndex;
460 |
461 | if (output.length >= limit) {
462 | break;
463 | }
464 | }
465 |
466 | if (separator.lastIndex === match.index) {
467 | separator.lastIndex++; // avoid an infinite loop
468 | }
469 | }
470 |
471 | if (lastLastIndex === str.length) {
472 | if (lastLength || !separator.test("")) {
473 | output.push("");
474 | }
475 | } else {
476 | output.push(str.slice(lastLastIndex));
477 | }
478 |
479 | return output.length > limit ? output.slice(0, limit) : output;
480 | };
481 |
482 | cbSplit._compliantExecNpcg = /()??/.exec("")[1] === undefined; // NPCG: nonparticipating capturing group
483 | cbSplit._nativeSplit = String.prototype.split;
484 |
485 | } // end `if (!cbSplit)`
486 | String.prototype.split = function (separator, limit) {
487 | return cbSplit(this, separator, limit);
488 | };
489 |
490 | })(jq);
491 |
--------------------------------------------------------------------------------
/af-carousel/af.carousel.js:
--------------------------------------------------------------------------------
1 | /**
2 | * af.web.carousel - a carousel library for App Framework apps
3 | * @copyright 2011 - Intel
4 | *
5 | */
6 | (function($) {
7 | var cache = [];
8 | var objId=function(obj){
9 | if(!obj.afmCarouselId) obj.afmCarouselId=$.uuid();
10 | return obj.afmCarouselId;
11 | }
12 | $.fn.carousel = function(opts) {
13 | var tmp, id;
14 | for (var i = 0; i < this.length; i++) {
15 | //cache system
16 | id = objId(this[i]);
17 | if(!cache[id]){
18 | tmp = new carousel(this[i], opts);
19 | cache[id] = tmp;
20 | } else {
21 | tmp = cache[id];
22 | }
23 | }
24 | return this.length == 1 ? tmp : this;
25 | };
26 |
27 | var carousel = (function() {
28 | var translateOpen =$.feat.cssTransformStart;
29 | var translateClose = $.feat.cssTransformEnd;
30 |
31 | var carousel = function(containerEl, opts) {
32 | if (typeof containerEl === "string" || containerEl instanceof String) {
33 | this.container = document.getElementById(containerEl);
34 | } else {
35 | this.container = containerEl;
36 | }
37 | if (!this.container) {
38 | alert("Error finding container for carousel " + containerEl);
39 | return;
40 | }
41 | if (this instanceof carousel) {
42 | for (var j in opts) {
43 | if (opts.hasOwnProperty(j)) {
44 | this[j] = opts[j];
45 | }
46 | }
47 | } else {
48 |
49 | return new carousel(containerEl, opts);
50 | }
51 |
52 |
53 | var that = this;
54 | af(this.container).bind('destroy', function(e){
55 | var id = that.container.afmCarouselId;
56 | //window event need to be cleaned up manually, remaining binds are automatically killed in the dom cleanup process
57 | window.removeEventListener("orientationchange", that.orientationHandler, false);
58 | if(cache[id]) delete cache[id];
59 | e.stopPropagation();
60 | });
61 |
62 | this.pagingDiv = this.pagingDiv ? document.getElementById(this.pagingDiv) : null;
63 |
64 |
65 | // initial setup
66 | this.container.style.overflow = "hidden";
67 | if (this.vertical) {
68 | this.horizontal = false;
69 | }
70 |
71 | var el = document.createElement("div");
72 | this.container.appendChild(el);
73 | var $el=$(el);
74 | var $container=$(this.container);
75 | var data = Array.prototype.slice.call(this.container.childNodes);
76 | while(data.length>0)
77 | {
78 | var myEl=data.splice(0,1);
79 | myEl=$container.find(myEl);
80 | if(myEl.get(0)==el)
81 | continue;
82 | $el.append(myEl.get(0));
83 | }
84 | if (this.horizontal) {
85 | el.style.display = "block";
86 | el.style['float']="left";
87 | }
88 | else {
89 | el.style.display = "block";
90 | }
91 |
92 | this.el = el;
93 | this.refreshItems();
94 | var afEl = af(el);
95 | afEl.bind('touchmove', function(e) {that.touchMove(e);});
96 | afEl.bind('touchend', function(e) {that.touchEnd(e);});
97 | afEl.bind('touchstart', function(e) {that.touchStart(e);});
98 | this.orientationHandler = function() {that.onMoveIndex(that.carouselIndex,0);};
99 | window.addEventListener("orientationchange", this.orientationHandler, false);
100 |
101 | };
102 |
103 | carousel.prototype = {
104 | wrap:true,
105 | startX: 0,
106 | startY: 0,
107 | dx: 0,
108 | dy: 0,
109 | glue: false,
110 | myDivWidth: 0,
111 | myDivHeight: 0,
112 | cssMoveStart: 0,
113 | childrenCount: 0,
114 | carouselIndex: 0,
115 | vertical: false,
116 | horizontal: true,
117 | el: null,
118 | movingElement: false,
119 | container: null,
120 | pagingDiv: null,
121 | pagingCssName: "carousel_paging",
122 | pagingCssNameSelected: "carousel_paging_selected",
123 | pagingFunction: null,
124 | lockMove:false,
125 | okToMove: false,
126 |
127 | // handle the moving function
128 | touchStart: function(e) {
129 | this.okToMove = false;
130 | this.myDivWidth = numOnly(this.container.clientWidth);
131 | this.myDivHeight = numOnly(this.container.clientHeight);
132 | this.lockMove=false;
133 | if (e.touches[0].target && e.touches[0].target.type !== undefined) {
134 | var tagname = e.touches[0].target.tagName.toLowerCase();
135 | if (tagname === "select" || tagname === "input" || tagname === "button") // stuff we need to allow
136 | {
137 | return;
138 | }
139 | }
140 | if (e.touches.length === 1) {
141 |
142 | this.movingElement = true;
143 | this.startY = e.touches[0].pageY;
144 | this.startX = e.touches[0].pageX;
145 | var cssMatrix=$.getCssMatrix(this.el);
146 |
147 | if (this.vertical) {
148 | try {
149 | this.cssMoveStart = numOnly(cssMatrix.f);
150 | } catch (ex1) {
151 | this.cssMoveStart = 0;
152 | }
153 | } else {
154 | try {
155 | this.cssMoveStart = numOnly(cssMatrix.e);
156 | } catch (ex1) {
157 | this.cssMoveStart = 0;
158 | }
159 | }
160 | }
161 | },
162 | touchMove: function(e) {
163 | if(!this.movingElement)
164 | return;
165 | if (e.touches.length > 1) {
166 | return this.touchEnd(e);
167 | }
168 |
169 | var rawDelta = {
170 | x: e.touches[0].pageX - this.startX,
171 | y: e.touches[0].pageY - this.startY
172 | };
173 |
174 | if (this.vertical) {
175 | var movePos = { x: 0, y: 0 };
176 | this.dy = e.touches[0].pageY - this.startY;
177 |
178 | this.dy += this.cssMoveStart;
179 | movePos.y = this.dy;
180 |
181 | e.preventDefault();
182 | //e.stopPropagation();
183 | } else {
184 | if ((!this.lockMove&&isHorizontalSwipe(rawDelta.x, rawDelta.y))||Math.abs(this.dx)>5) {
185 |
186 | var movePos = {x: 0,y: 0};
187 | this.dx = e.touches[0].pageX - this.startX;
188 | this.dx += this.cssMoveStart;
189 | e.preventDefault();
190 | // e.stopPropagation();
191 | movePos.x = this.dx;
192 | }
193 | else
194 | return this.lockMove=true;
195 | }
196 |
197 | var totalMoved = this.vertical ? ((this.dy % this.myDivHeight) / this.myDivHeight * 100) * -1 : ((this.dx % this.myDivWidth) / this.myDivWidth * 100) * -1; // get a percentage of movement.
198 |
199 | if (!this.okToMove) {
200 | oldStateOkToMove= this.okToMove;
201 | this.okToMove = this.glue ? Math.abs(totalMoved) > this.glue && Math.abs(totalMoved) < (100 - this.glue) : true;
202 | if (this.okToMove && !oldStateOkToMove) {
203 | $.trigger(this,"movestart",[this.el]);
204 | }
205 | }
206 |
207 | if (this.okToMove && movePos)
208 | this.moveCSS3(this.el, movePos);
209 |
210 | },
211 | touchEnd: function(e) {
212 | if (!this.movingElement) {
213 | return;
214 | }
215 | $.trigger(this,"movestop",[this.el]);
216 | // e.preventDefault();
217 | // e.stopPropagation();
218 | var runFinal = false;
219 | // try {
220 | var cssMatrix=$.getCssMatrix(this.el);
221 | var endPos = this.vertical ? numOnly(cssMatrix.f) : numOnly(cssMatrix.e);
222 |
223 | if (1==2&&endPos > 0) {
224 | this.moveCSS3(this.el, {
225 | x: 0,
226 | y: 0
227 | }, "300");
228 | } else {
229 | var totalMoved = this.vertical ? ((this.dy % this.myDivHeight) / this.myDivHeight * 100) * -1 : ((this.dx % this.myDivWidth) / this.myDivWidth * 100) * -1; // get a percentage of movement.
230 | // Only need
231 | // to drag 3% to trigger an event
232 | var currInd = this.carouselIndex;
233 | if (endPos < this.cssMoveStart && totalMoved > 3) {
234 | currInd++; // move right/down
235 | } else if ((endPos > this.cssMoveStart && totalMoved < 97)) {
236 | currInd--; // move left/up
237 | }
238 | var toMove=currInd;
239 | //Checks for infinite - moves to placeholders
240 | if(this.wrap){
241 | if (currInd > (this.childrenCount - 1)) {
242 | currInd = 0;
243 | toMove=this.childrenCount;
244 | }
245 | if (currInd < 0) {
246 | currInd = this.childrenCount-1;
247 | toMove=-1;
248 | }
249 | }
250 | else {
251 | if(currInd<0)
252 | currInd=0;
253 | if(currInd>this.childrenCount-1)
254 | currInd=this.childrenCount-1;
255 | toMove=currInd;
256 | }
257 |
258 | var movePos = {
259 | x: 0,
260 | y: 0
261 | };
262 | if (this.vertical) {
263 | movePos.y = (toMove * this.myDivHeight * -1);
264 | }
265 | else {
266 | movePos.x = (toMove * this.myDivWidth * -1);
267 | }
268 |
269 | this.moveCSS3(this.el, movePos, "150");
270 |
271 | if (this.pagingDiv && this.carouselIndex !== currInd) {
272 | document.getElementById(this.container.id + "_" + this.carouselIndex).className = this.pagingCssName;
273 | document.getElementById(this.container.id + "_" + currInd).className = this.pagingCssNameSelected;
274 | }
275 | if (this.carouselIndex != currInd)
276 | runFinal = true;
277 | this.carouselIndex = currInd;
278 |
279 | //This is for the infinite ends - will move to the correct position after animation
280 | if(this.wrap){
281 | if(toMove!=currInd){
282 | var that=this;
283 | window.setTimeout(function(){
284 | that.onMoveIndex(currInd,"1ms");
285 | },155);
286 | }
287 | }
288 | }
289 | //} catch (e) {
290 | // console.log(e);
291 | // }
292 | this.dx = 0;
293 | this.movingElement = false;
294 | this.startX = 0;
295 | this.dy = 0;
296 | this.startY = 0;
297 | if (runFinal && this.pagingFunction && typeof this.pagingFunction == "function")
298 | this.pagingFunction(this.carouselIndex);
299 | },
300 | onMoveIndex: function(newInd,transitionTime) {
301 |
302 | this.myDivWidth = numOnly(this.container.clientWidth);
303 | this.myDivHeight = numOnly(this.container.clientHeight);
304 | var runFinal = false;
305 |
306 | if(document.getElementById(this.container.id + "_" + this.carouselIndex))
307 | document.getElementById(this.container.id + "_" + this.carouselIndex).className = this.pagingCssName;
308 |
309 | var newTime = Math.abs(newInd - this.carouselIndex);
310 |
311 | var ind = newInd;
312 | if (ind < 0)
313 | ind = 0;
314 | if (ind > this.childrenCount - 1) {
315 | ind = this.childrenCount - 1;
316 | }
317 | var movePos = {
318 | x: 0,
319 | y: 0
320 | };
321 | if (this.vertical) {
322 | movePos.y = (ind * this.myDivHeight * -1);
323 | }
324 | else {
325 | movePos.x = (ind * this.myDivWidth * -1);
326 | }
327 |
328 | var time =transitionTime?transitionTime: 50 + parseInt((newTime * 20));
329 | this.moveCSS3(this.el, movePos, time);
330 | if (this.carouselIndex != ind)
331 | runFinal = true;
332 | this.carouselIndex = ind;
333 | if (this.pagingDiv) {
334 | var tmpEl = document.getElementById(this.container.id + "_" + this.carouselIndex);
335 | if(tmpEl) tmpEl.className = this.pagingCssNameSelected;
336 | }
337 |
338 | if (runFinal && this.pagingFunction && typeof this.pagingFunction == "function")
339 | this.pagingFunction(currInd);
340 | },
341 |
342 | moveCSS3: function(el, distanceToMove, time, timingFunction) {
343 | if (!time)
344 | time = 0;
345 | else
346 | time = parseInt(time);
347 | if (!timingFunction)
348 | timingFunction = "linear";
349 | el.style[$.feat.cssPrefix+"Transform"] = "translate" + translateOpen + distanceToMove.x + "px," + distanceToMove.y + "px" + translateClose;
350 | el.style[$.feat.cssPrefix+"TransitionDuration"] = time + "ms";
351 | el.style[$.feat.cssPrefix+"BackfaceVisibility"] = "hidden";
352 | el.style[$.feat.cssPrefix+"TransitionTimingFunction"] = timingFunction;
353 | },
354 |
355 | addItem: function(el) {
356 | if (el && el.nodeType) {
357 |
358 | this.container.childNodes[0].appendChild(el);
359 | this.refreshItems();
360 | }
361 | },
362 | refreshItems: function() {
363 | var childrenCounter = 0;
364 | var that = this;
365 | var el = this.el;
366 | $(el).children().find(".prevBuffer").remove();
367 | $(el).children().find(".nextBuffer").remove();
368 | n = el.childNodes[0];
369 | var widthParam;
370 | var heightParam = "100%";
371 | var elems = [];
372 |
373 | for (; n; n = n.nextSibling) {
374 | if (n.nodeType === 1) {
375 | elems.push(n);
376 | childrenCounter++;
377 | }
378 | }
379 | //Let's put the buffers at the start/end
380 | if(this.wrap){
381 | var prep=$(elems[elems.length-1]).clone().get(0);
382 | $(el).prepend(prep);
383 | var tmp=$(elems[0]).clone().get(0);
384 | $(el).append(tmp);
385 | elems.push(tmp);
386 | elems.unshift(prep);
387 | tmp.style.position="absolute";
388 | prep.style.position="absolute";
389 | }
390 |
391 | var param = (100 / childrenCounter) + "%";
392 | this.childrenCount = childrenCounter;
393 | widthParam = parseFloat(100 / childrenCounter) + "%";
394 |
395 | for (var i = 0; i < elems.length; i++) {
396 | if (this.horizontal) {
397 | elems[i].style.width = widthParam;
398 | elems[i].style.height = "100%";
399 | elems[i].style['float']="left";
400 | }
401 | else {
402 | elems[i].style.height = widthParam;
403 | elems[i].style.width = "100%";
404 | elems[i].style.display = "block";
405 | }
406 | }
407 | //Clone the first and put it at the end
408 |
409 |
410 | this.moveCSS3(el, {
411 | x: 0,
412 | y: 0
413 | });
414 | if (this.horizontal) {
415 | el.style.width = Math.ceil((this.childrenCount) * 100) + "%";
416 | el.style.height = "100%";
417 | el.style['min-height'] = "100%"
418 | if(this.wrap){
419 | prep.style.left="-"+widthParam;
420 | tmp.style.left="100%";
421 | }
422 | }
423 | else {
424 | el.style.width = "100%";
425 | el.style.height = Math.ceil((this.childrenCount) * 100) + "%";
426 | el.style['min-height'] = Math.ceil((this.childrenCount) * 100) + "%";
427 | if(this.wrap){
428 | prep.style.top="-"+widthParam;
429 | tmp.style.top="100%";
430 | }
431 | }
432 | // Create the paging dots
433 | if (this.pagingDiv) {
434 | this.pagingDiv.innerHTML = ""
435 | for (i = 0; i < this.childrenCount; i++) {
436 |
437 | var pagingEl = document.createElement("div");
438 | pagingEl.id = this.container.id + "_" + i;
439 | pagingEl.pageId = i;
440 | if (i !== this.carouselIndex) {
441 | pagingEl.className = this.pagingCssName;
442 | }
443 | else {
444 | pagingEl.className = this.pagingCssNameSelected;
445 | }
446 | pagingEl.onclick = function() {
447 | that.onMoveIndex(this.pageId);
448 | };
449 | var spacerEl = document.createElement("div");
450 |
451 | spacerEl.style.width = "20px";
452 | if(this.horizontal){
453 | spacerEl.style.display = "inline-block";
454 | spacerEl.innerHTML = " ";
455 | }
456 | else{
457 | spacerEl.innerHTML=" ";
458 | spacerEl.style.display="block";
459 | }
460 |
461 | this.pagingDiv.appendChild(pagingEl);
462 | if (i + 1 < (this.childrenCount))
463 | this.pagingDiv.appendChild(spacerEl);
464 | pagingEl = null;
465 | spacerEl = null;
466 | }
467 | if(this.horizontal){
468 | this.pagingDiv.style.width = (this.childrenCount) * 50 + "px";
469 | this.pagingDiv.style.height = "25px";
470 | }
471 | else {
472 | this.pagingDiv.style.height = (this.childrenCount) * 50 + "px";
473 | this.pagingDiv.style.width = "25px";
474 | }
475 | }
476 | this.onMoveIndex(this.carouselIndex);
477 |
478 | }
479 |
480 | };
481 | return carousel;
482 | })();
483 |
484 | function isHorizontalSwipe(xAxis, yAxis) {
485 | var X = xAxis;
486 | var Y = yAxis;
487 | var Z = Math.round(Math.sqrt(Math.pow(X,2)+Math.pow(Y,2))); //the distance - rounded - in pixels
488 | var r = Math.atan2(Y,X); //angle in radians
489 | var swipeAngle = Math.round(r*180/Math.PI); //angle in degrees
490 | if ( swipeAngle < 0 ) { swipeAngle = 360 - Math.abs(swipeAngle); } // for negative degree values
491 | if (((swipeAngle <= 215) && (swipeAngle >= 155)) || ((swipeAngle <= 45) && (swipeAngle >= 0)) || ((swipeAngle <= 360) && (swipeAngle >= 315))) // horizontal angles with threshold
492 | {return true; }
493 | else {return false}
494 | }
495 |
496 | })(af);
497 |
--------------------------------------------------------------------------------
/af-alphatable/af.scroller.js:
--------------------------------------------------------------------------------
1 | /**
2 | * af.scroller
3 | * created by appMobi with modifications by Carlos Ouro @ Badoo and Intel
4 | * Supports iOS native touch scrolling
5 | * Optimizations and bug improvements by Intel
6 | * @copyright Intel
7 | */ (function ($) {
8 | var HIDE_REFRESH_TIME = 75; // hide animation of pull2ref duration in ms
9 | var cache = [];
10 | var objId = function (obj) {
11 | if (!obj.afScrollerId) obj.afScrollerId = $.uuid();
12 | return obj.afScrollerId;
13 | };
14 | $.fn["scroller"] = function (opts) {
15 | var tmp, id;
16 | for (var i = 0; i < this.length; i++) {
17 | //cache system
18 | id = objId(this[i]);
19 | if (!cache[id]) {
20 | if (!opts) opts = {};
21 | if (!$.feat.nativeTouchScroll) opts.useJsScroll = true;
22 |
23 | tmp = scroller(this[i], opts);
24 | cache[id] = tmp;
25 | } else {
26 | tmp = cache[id];
27 | }
28 | }
29 | return this.length == 1 ? tmp : this;
30 | };
31 | var boundTouchLayer = false;
32 |
33 | function checkConsistency(id) {
34 | if (!cache[id].el) {
35 | delete cache[id];
36 | return false;
37 | }
38 | return true;
39 | }
40 |
41 | function bindTouchLayer() {
42 | //use a single bind for all scrollers
43 | if (af.os.android && !af.os.chrome && af.os.webkit) {
44 | var androidFixOn = false;
45 | //connect to touchLayer to detect editMode
46 | $.bind($.touchLayer, ['cancel-enter-edit', 'exit-edit'], function (focusEl) {
47 | if (androidFixOn) {
48 | androidFixOn = false;
49 | //dehactivate on scroller
50 | for (var el in cache)
51 | if (checkConsistency(el) && cache[el].androidFormsMode) cache[el].stopFormsMode();
52 | }
53 | });
54 | }
55 | boundTouchLayer = true;
56 | }
57 | var scroller = (function () {
58 | var translateOpen = $.feat.cssTransformStart;
59 | var translateClose = $.feat.cssTransformEnd;
60 | var jsScroller, nativeScroller;
61 |
62 | //initialize and js/native mode selector
63 | var scroller = function (elID, opts) {
64 |
65 | var el;
66 |
67 | if (!boundTouchLayer && $.touchLayer && $.isObject($.touchLayer)) bindTouchLayer();
68 | else if (!$.touchLayer || !$.isObject($.touchLayer)) $.touchLayer = {};
69 | if (typeof elID == "string" || elID instanceof String) {
70 | el = document.getElementById(elID);
71 | } else {
72 | el = elID;
73 | }
74 | if (!el) {
75 | alert("Could not find element for scroller " + elID);
76 | return;
77 | }
78 | if (af.os.desktop)
79 | return new scrollerCore(el, opts);
80 | else if (opts.useJsScroll) return new jsScroller(el, opts);
81 | return new nativeScroller(el, opts);
82 |
83 | };
84 |
85 | //parent abstract class (common functionality)
86 | var scrollerCore = function (el, opts) {
87 | this.el = el;
88 | this.afEl = $(this.el);
89 | for (var j in opts) {
90 | this[j] = opts[j];
91 | }
92 | };
93 | scrollerCore.prototype = {
94 | //core default properties
95 | refresh: false,
96 | refreshContent: "Pull to Refresh",
97 | refreshHangTimeout: 2000,
98 | refreshHeight: 60,
99 | refreshElement: null,
100 | refreshCancelCB: null,
101 | refreshRunning: false,
102 | scrollTop: 0,
103 | scrollLeft: 0,
104 | preventHideRefresh: true,
105 | verticalScroll: true,
106 | horizontalScroll: false,
107 | refreshTriggered: false,
108 | moved: false,
109 | eventsActive: false,
110 | rememberEventsActive: false,
111 | scrollingLocked: false,
112 | autoEnable: true,
113 | blockFormsFix: false,
114 | loggedPcentY: 0,
115 | loggedPcentX: 0,
116 | infinite: false,
117 | infiniteEndCheck: false,
118 | infiniteTriggered: false,
119 | scrollSkip: false,
120 | scrollTopInterval: null,
121 | scrollLeftInterval: null,
122 | bubbles:true,
123 | _scrollTo: function (params, time) {
124 | time = parseInt(time, 10);
125 | if (time === 0 || isNaN(time)) {
126 | this.el.scrollTop = Math.abs(params.y);
127 | this.el.scrollLeft = Math.abs(params.x);
128 | return;
129 | }
130 | var singleTick = 10;
131 | var distPerTick = (this.el.scrollTop - params.y) / Math.ceil(time / singleTick);
132 | var distLPerTick = (this.el.scrollLeft - params.x) / Math.ceil(time / singleTick);
133 | var self = this;
134 | var toRunY = Math.ceil(this.el.scrollTop - params.y) / distPerTick;
135 | var toRunX = Math.ceil(this.el.scrollLeft - params.x) / distPerTick;
136 | var xRun =0, yRun = 0;
137 | self.scrollTopInterval = window.setInterval(function () {
138 | self.el.scrollTop -= distPerTick;
139 | yRun++;
140 | if (yRun >= toRunY) {
141 | self.el.scrollTop = params.y;
142 | clearInterval(self.scrollTopInterval);
143 | }
144 | }, singleTick);
145 |
146 | self.scrollLeftInterval = window.setInterval(function () {
147 | self.el.scrollLeft -= distLPerTick;
148 | xRun++;
149 | if (xRun >= toRunX) {
150 | self.el.scrollLeft = params.x;
151 | clearInterval(self.scrollLeftInterval);
152 | }
153 | }, singleTick);
154 | },
155 | enable: function () {},
156 | disable: function () {},
157 | hideScrollbars: function () {},
158 | addPullToRefresh: function () {},
159 | /**
160 | * We do step animations for 'native' - iOS is acceptable and desktop browsers are fine
161 | * instead of css3
162 | */
163 | _scrollToTop: function (time) {
164 | this._scrollTo({
165 | x: 0,
166 | y: 0
167 | }, time);
168 | },
169 | _scrollToBottom: function (time) {
170 | this._scrollTo({
171 | x: 0,
172 | y: this.el.scrollHeight - this.el.offsetHeight
173 | }, time);
174 | },
175 | scrollToBottom: function (time) {
176 | return this._scrollToBottom(time);
177 | },
178 | scrollToTop: function (time) {
179 | return this._scrollToTop(time);
180 | },
181 |
182 | //methods
183 | init: function (el, opts) {
184 | this.el = el;
185 | this.afEl = $(this.el);
186 | this.defaultProperties();
187 | for (var j in opts) {
188 | this[j] = opts[j];
189 | }
190 | //assign self destruct
191 | var that = this;
192 | var orientationChangeProxy = function () {
193 | //no need to readjust if disabled...
194 | if (that.eventsActive) that.adjustScroll();
195 | };
196 | this.afEl.bind('destroy', function () {
197 | that.disable(true); //with destroy notice
198 | var id = that.el.afScrollerId;
199 | if (cache[id]) delete cache[id];
200 | $.unbind($.touchLayer, 'orientationchange-reshape', orientationChangeProxy);
201 | });
202 | $.bind($.touchLayer, 'orientationchange-reshape', orientationChangeProxy);
203 | },
204 | needsFormsFix: function (focusEl) {
205 | return this.useJsScroll && this.isEnabled() && this.el.style.display != "none" && $(focusEl).closest(this.afEl).size() > 0;
206 | },
207 | handleEvent: function (e) {
208 | if (!this.scrollingLocked) {
209 | switch (e.type) {
210 | case 'touchstart':
211 | clearInterval(this.scrollTopInterval);
212 | this.preventHideRefresh = !this.refreshRunning; // if it's not running why prevent it xD
213 | this.moved = false;
214 | this.onTouchStart(e);
215 | if(!this.bubbles)
216 | e.stopPropagation();
217 | break;
218 | case 'touchmove':
219 |
220 | this.onTouchMove(e);
221 | if(!this.bubbles)
222 | e.stopPropagation();
223 | break;
224 | case 'touchend':
225 | this.onTouchEnd(e);
226 | if(!this.bubbles)
227 | e.stopPropagation();
228 | break;
229 | case 'scroll':
230 | this.onScroll(e);
231 | break;
232 | }
233 | }
234 | },
235 | coreAddPullToRefresh: function (rEl) {
236 | if (rEl) this.refreshElement = rEl;
237 | //Add the pull to refresh text. Not optimal but keeps from others overwriting the content and worrying about italics
238 | //add the refresh div
239 | var afEl;
240 | if (this.refreshElement === null) {
241 | var orginalEl = document.getElementById(this.container.id + "_pulldown");
242 | if (orginalEl !== null) {
243 | afEl = af(orginalEl);
244 | } else {
245 | afEl = af("" + this.refreshContent + "
");
246 | }
247 | } else {
248 | afEl = af(this.refreshElement);
249 | }
250 | var el = afEl.get();
251 |
252 | this.refreshContainer = af("");
253 | $(this.el).prepend(this.refreshContainer.append(el, 'top'));
254 | this.refreshContainer = this.refreshContainer[0];
255 | },
256 | fireRefreshRelease: function (triggered, allowHide) {
257 | if (!this.refresh || !triggered) return;
258 |
259 | var autoCancel = $.trigger(this, 'refresh-release', [triggered]) !== false;
260 | this.preventHideRefresh = false;
261 | this.refreshRunning = true;
262 | if (autoCancel) {
263 | var that = this;
264 | if (this.refreshHangTimeout > 0) this.refreshCancelCB = setTimeout(function () {
265 | that.hideRefresh();
266 | }, this.refreshHangTimeout);
267 | }
268 | },
269 | setRefreshContent: function (content) {
270 | af(this.container).find(".afscroll_refresh").html(content);
271 | },
272 | lock: function () {
273 | if (this.scrollingLocked) return;
274 | this.scrollingLocked = true;
275 | this.rememberEventsActive = this.eventsActive;
276 | if (!this.eventsActive) {
277 | this.initEvents();
278 | }
279 | },
280 | unlock: function () {
281 | if (!this.scrollingLocked) return;
282 | this.scrollingLocked = false;
283 | if (!this.rememberEventsActive) {
284 | this.removeEvents();
285 | }
286 | },
287 | scrollToItem: function (el, where) { //TODO: add functionality for x position
288 | if (!$.is$(el)) el = $(el);
289 | var newTop,itemPos,panelTop,itemTop;
290 | if (where == 'bottom') {
291 | itemPos = el.offset();
292 | newTop = itemPos.top - this.afEl.offset().bottom + itemPos.height;
293 | newTop += 4; //add a small space
294 | } else {
295 | itemTop = el.offset().top;
296 | newTop = itemTop - document.body.scrollTop;
297 | panelTop = this.afEl.offset().top;
298 | if (document.body.scrollTop < panelTop) {
299 | newTop -= panelTop;
300 | }
301 | newTop -= 4; //add a small space
302 | }
303 |
304 | this.scrollBy({
305 | y: newTop,
306 | x: 0
307 | }, 0);
308 | },
309 | setPaddings: function (top, bottom) {
310 | var el = $(this.el);
311 | var curTop = numOnly(el.css('paddingTop'));
312 | el.css('paddingTop', top + "px").css('paddingBottom', bottom + "px");
313 | //don't let padding mess with scroll
314 | this.scrollBy({
315 | y: top - curTop,
316 | x: 0
317 | });
318 | },
319 | //freak of mathematics, but for our cases it works
320 | divide: function (a, b) {
321 | return b !== 0 ? a / b : 0;
322 | },
323 | isEnabled: function () {
324 | return this.eventsActive;
325 | },
326 | addInfinite: function () {
327 | this.infinite = true;
328 | },
329 | clearInfinite: function () {
330 | this.infiniteTriggered = false;
331 | this.scrollSkip = true;
332 | }
333 | };
334 |
335 | //extend to jsScroller and nativeScroller (constructs)
336 | jsScroller = function (el, opts) {
337 | this.init(el, opts);
338 | //test
339 | //this.refresh=true;
340 | this.container = this.el.parentNode;
341 | this.container.afScrollerId = el.afScrollerId;
342 | this.afEl = $(this.container);
343 |
344 | if (this.container.style.overflow != 'hidden') this.container.style.overflow = 'hidden';
345 |
346 | this.addPullToRefresh(null, true);
347 | if (this.autoEnable) this.enable(true);
348 | var scrollDiv;
349 | //create vertical scroll
350 | if (this.verticalScroll && this.verticalScroll === true && this.scrollBars === true) {
351 | scrollDiv = createScrollBar(5, 20);
352 | scrollDiv.style.top = "0px";
353 | if (this.vScrollCSS) scrollDiv.className = this.vScrollCSS;
354 | //scrollDiv.style.opacity = "0";
355 | scrollDiv.style.display='none';
356 | this.container.appendChild(scrollDiv);
357 | this.vscrollBar = scrollDiv;
358 | scrollDiv = null;
359 | }
360 | //create horizontal scroll
361 | if (this.horizontalScroll && this.horizontalScroll === true && this.scrollBars === true) {
362 | scrollDiv = createScrollBar(20, 5);
363 | scrollDiv.style.bottom = "0px";
364 |
365 |
366 | if (this.hScrollCSS) scrollDiv.className = this.hScrollCSS;
367 | //scrollDiv.style.opacity = "0";
368 | scrollDiv.style.display='none';
369 | this.container.appendChild(scrollDiv);
370 | this.hscrollBar = scrollDiv;
371 | scrollDiv = null;
372 | }
373 | if (this.horizontalScroll) this.el.style['float'] = "left";
374 |
375 | this.el.hasScroller = true;
376 |
377 | };
378 | nativeScroller = function (el, opts) {
379 |
380 | if(opts.nativeParent){
381 | el=el.parentNode;
382 | }
383 | this.init(el, opts);
384 |
385 | var $el = $(el);
386 |
387 | if (opts.noParent !== true) {
388 | var oldParent = $el.parent();
389 |
390 | $el.css('height', oldParent.height()).css("width", oldParent.width());
391 | $el.insertBefore($el.parent());
392 | //$el.parent().parent().append($el);
393 | oldParent.remove();
394 | }
395 | this.container = this.el;
396 | $el.css("-webkit-overflow-scrolling", "touch");
397 | if(opts.autoEnable)
398 | this.enable();
399 | };
400 | nativeScroller.prototype = new scrollerCore();
401 | jsScroller.prototype = new scrollerCore();
402 |
403 |
404 |
405 |
406 | ///Native scroller
407 | nativeScroller.prototype.defaultProperties = function () {
408 |
409 | this.refreshContainer = null;
410 | this.dY = this.cY = 0;
411 | this.dX = this.cX = 0;
412 | this.cancelPropagation = false;
413 | this.loggedPcentY = 0;
414 | this.loggedPcentX = 0;
415 | var that = this;
416 | this.adjustScrollOverflowProxy_ = function () {
417 | that.afEl.css('overflow', 'auto');
418 | that.afEl.parent().css("overflow","hidden");
419 | };
420 | };
421 | nativeScroller.prototype.enable = function (firstExecution) {
422 | if (this.eventsActive) return;
423 | this.eventsActive = true;
424 | //unlock overflow
425 | this.el.style.overflow = 'auto';
426 | this.el.parentNode.style.overflow="hidden";
427 | //set current scroll
428 |
429 | if (!firstExecution) this.adjustScroll();
430 | //set events
431 | this.el.addEventListener('touchstart', this, false);
432 | this.el.addEventListener('scroll', this, false);
433 | };
434 | nativeScroller.prototype.disable = function (destroy) {
435 | if (!this.eventsActive) return;
436 | //log current scroll
437 | this.logPos(this.el.scrollLeft, this.el.scrollTop);
438 | //lock overflow
439 | if (!destroy) {
440 | this.el.style.overflow = 'hidden';
441 | }
442 | //remove events
443 | this.el.removeEventListener('touchstart', this, false);
444 | this.el.removeEventListener('touchmove', this, false);
445 | this.el.removeEventListener('touchend', this, false);
446 | this.el.removeEventListener('scroll', this, false);
447 | this.eventsActive = false;
448 | };
449 | nativeScroller.prototype.addPullToRefresh = function (el, leaveRefresh) {
450 | this.el.removeEventListener('touchstart', this, false);
451 | this.el.addEventListener('touchstart', this, false);
452 | if (!leaveRefresh) this.refresh = true;
453 | if (this.refresh && this.refresh === true) {
454 | this.coreAddPullToRefresh(el);
455 | this.refreshContainer.style.position = "absolute";
456 | this.refreshContainer.style.top = "-60px";
457 | this.refreshContainer.style.height = "60px";
458 | this.refreshContainer.style.display = "block";
459 | }
460 | };
461 | nativeScroller.prototype.onTouchStart = function (e) {
462 |
463 |
464 | if(this.el.scrollTop===0)
465 | this.el.scrollTop=1;
466 | if(this.el.scrollTop===(this.el.scrollHeight - this.el.clientHeight))
467 | this.el.scrollTop-=1;
468 |
469 | if(this.horizontalScroll){
470 | if(this.el.scrollLeft===0)
471 | this.el.scrollLeft=1;
472 | if(this.el.scrollLeft===(this.el.scrollWidth-this.el.clientWidth))
473 | this.el.scrollLeft-=1;
474 | }
475 | if (this.refreshCancelCB) clearTimeout(this.refreshCancelCB);
476 | //get refresh ready
477 | this.el.addEventListener('touchmove', this,false);
478 | this.dY = e.touches[0].pageY;
479 | if (this.refresh || this.infinite) {
480 |
481 |
482 | if (this.refresh && this.dY < 0) {
483 | this.showRefresh();
484 |
485 | }
486 | }
487 |
488 | };
489 | nativeScroller.prototype.onTouchMove = function (e) {
490 |
491 | var newcY = e.touches[0].pageY - this.dY;
492 | var newcX = e.touches[0].pageX - this.dX;
493 | if(this.hasVertScroll&&this.el.clientHeight==this.el.scrollHeight){
494 | e.preventDefault();
495 |
496 | }
497 | if(this.hasHorScroll&&this.el.clientWidth==this.el.scrollWidth){
498 | e.preventDefault();
499 |
500 | }
501 |
502 | if (!this.moved) {
503 | $.trigger(this, "scrollstart", [this.el]);
504 | $.trigger($.touchLayer, "scrollstart", [this.el]);
505 | this.el.addEventListener('touchend', this, false);
506 | this.moved = true;
507 | }
508 |
509 | var difY = newcY - this.cY;
510 | var difX = newcX-this.cX;
511 |
512 | //check for trigger
513 | if (this.refresh && (this.el.scrollTop) < 0) {
514 | this.showRefresh();
515 | //check for cancel
516 | } else if (this.refreshTriggered && this.refresh && (this.el.scrollTop > this.refreshHeight)) {
517 | this.refreshTriggered = false;
518 | if (this.refreshCancelCB) clearTimeout(this.refreshCancelCB);
519 | this.hideRefresh(false);
520 | $.trigger(this, 'refresh-cancel');
521 | }
522 |
523 | this.cY = newcY;
524 | this.cX = newcX;
525 | };
526 | nativeScroller.prototype.showRefresh = function () {
527 | if (!this.refreshTriggered) {
528 | this.refreshTriggered = true;
529 | $.trigger(this, 'refresh-trigger');
530 | }
531 | };
532 | nativeScroller.prototype.onTouchEnd = function (e) {
533 |
534 | var triggered = this.el.scrollTop <= -(this.refreshHeight);
535 |
536 | this.fireRefreshRelease(triggered, true);
537 | if (triggered&&this.refresh) {
538 | //lock in place
539 | this.refreshContainer.style.position = "relative";
540 | this.refreshContainer.style.top = "0px";
541 | }
542 |
543 | this.dY = this.cY = 0;
544 | this.el.removeEventListener('touchmove', this, false);
545 | this.el.removeEventListener('touchend', this, false);
546 | this.infiniteEndCheck = true;
547 | if (this.infinite && !this.infiniteTriggered && (Math.abs(this.el.scrollTop) >= (this.el.scrollHeight - this.el.clientHeight))) {
548 | this.infiniteTriggered = true;
549 | $.trigger(this, "infinite-scroll");
550 | this.infiniteEndCheck = true;
551 | }
552 | this.touchEndFired = true;
553 | //pollyfil for scroll end since webkit doesn't give any events during the "flick"
554 | var max = 200;
555 | var self = this;
556 | var currPos = {
557 | top: this.el.scrollTop,
558 | left: this.el.scrollLeft
559 | };
560 | var counter = 0;
561 | self.nativePolling = setInterval(function () {
562 | counter++;
563 | if (counter >= max) {
564 | clearInterval(self.nativePolling);
565 | return;
566 | }
567 | if (self.el.scrollTop != currPos.top || self.el.scrollLeft != currPos.left) {
568 | clearInterval(self.nativePolling);
569 | $.trigger($.touchLayer, 'scrollend', [self.el]); //notify touchLayer of this elements scrollend
570 | $.trigger(self, "scrollend", [self.el]);
571 | }
572 |
573 | }, 20);
574 | };
575 | nativeScroller.prototype.hideRefresh = function (animate) {
576 |
577 | if (this.preventHideRefresh) return;
578 |
579 | var that = this;
580 | var endAnimationCb = function (canceled) {
581 | if (!canceled) { //not sure if this should be the correct logic....
582 | that.el.style[$.feat.cssPrefix + "Transform"] = "none";
583 | that.el.style[$.feat.cssPrefix + "TransitionProperty"] = "none";
584 | that.el.scrollTop = 0;
585 | that.logPos(that.el.scrollLeft, 0);
586 | }
587 | that.refreshContainer.style.top = "-60px";
588 | that.refreshContainer.style.position = "absolute";
589 | that.dY = that.cY = 0;
590 | $.trigger(that, "refresh-finish");
591 | };
592 |
593 | if (animate === false || !that.afEl.css3Animate) {
594 | endAnimationCb();
595 | } else {
596 | that.afEl.css3Animate({
597 | y: (that.el.scrollTop - that.refreshHeight) + "px",
598 | x: "0%",
599 | time: HIDE_REFRESH_TIME + "ms",
600 | complete: endAnimationCb
601 | });
602 | }
603 | this.refreshTriggered = false;
604 | //this.el.addEventListener('touchend', this, false);
605 | };
606 | nativeScroller.prototype.hideScrollbars = function () {};
607 | nativeScroller.prototype.scrollTo = function (pos, time) {
608 | this.logPos(pos.x, pos.y);
609 | pos.x *= -1;
610 | pos.y *= -1;
611 | return this._scrollTo(pos, time);
612 | };
613 | nativeScroller.prototype.scrollBy = function (pos, time) {
614 | pos.x += this.el.scrollLeft;
615 | pos.y += this.el.scrollTop;
616 | this.logPos(this.el.scrollLeft, this.el.scrollTop);
617 | return this._scrollTo(pos, time);
618 | };
619 | nativeScroller.prototype.scrollToBottom = function (time) {
620 | //this.el.scrollTop = this.el.scrollHeight;
621 | this._scrollToBottom(time);
622 | this.logPos(this.el.scrollLeft, this.el.scrollTop);
623 | };
624 | nativeScroller.prototype.onScroll = function (e) {
625 | if (this.infinite && this.touchEndFired) {
626 | this.touchEndFired = false;
627 | return;
628 | }
629 | if (this.scrollSkip) {
630 | this.scrollSkip = false;
631 | return;
632 | }
633 |
634 | if (this.infinite) {
635 | if (!this.infiniteTriggered && (Math.abs(this.el.scrollTop) >= (this.el.scrollHeight - this.el.clientHeight))) {
636 | this.infiniteTriggered = true;
637 | $.trigger(this, "infinite-scroll");
638 | this.infiniteEndCheck = true;
639 | }
640 | }
641 |
642 |
643 | var that = this;
644 | if (this.infinite && this.infiniteEndCheck && this.infiniteTriggered) {
645 |
646 | this.infiniteEndCheck = false;
647 | $.trigger(that, "infinite-scroll-end");
648 | }
649 | };
650 | nativeScroller.prototype.logPos = function (x, y) {
651 |
652 |
653 | this.loggedPcentX = this.divide(x, (this.el.scrollWidth));
654 | this.loggedPcentY = this.divide(y, (this.el.scrollHeight));
655 | this.scrollLeft = x;
656 | this.scrollTop = y;
657 |
658 | if (isNaN(this.loggedPcentX))
659 | this.loggedPcentX = 0;
660 | if (isNaN(this.loggedPcentY))
661 | this.loggedPcentY = 0;
662 |
663 | };
664 | nativeScroller.prototype.adjustScroll = function () {
665 | this.adjustScrollOverflowProxy_();
666 |
667 | this.el.scrollLeft = this.loggedPcentX * (this.el.scrollWidth);
668 | this.el.scrollTop = this.loggedPcentY * (this.el.scrollHeight);
669 | this.logPos(this.el.scrollLeft, this.el.scrollTop);
670 | };
671 |
672 |
673 |
674 | //JS scroller
675 | jsScroller.prototype.defaultProperties = function () {
676 |
677 | this.boolScrollLock = false;
678 | this.currentScrollingObject = null;
679 | this.elementInfo = null;
680 | this.verticalScroll = true;
681 | this.horizontalScroll = false;
682 | this.scrollBars = true;
683 | this.vscrollBar = null;
684 | this.hscrollBar = null;
685 | this.hScrollCSS = "scrollBar";
686 | this.vScrollCSS = "scrollBar";
687 | this.firstEventInfo = null;
688 | this.moved = false;
689 | this.preventPullToRefresh = true;
690 | this.isScrolling = false;
691 | this.androidFormsMode = false;
692 | this.refreshSafeKeep = false;
693 |
694 | this.lastScrollbar = "";
695 | this.finishScrollingObject = null;
696 | this.container = null;
697 | this.scrollingFinishCB = null;
698 | this.loggedPcentY = 0;
699 | this.loggedPcentX = 0;
700 |
701 | };
702 |
703 | function createScrollBar(width, height) {
704 | var scrollDiv = document.createElement("div");
705 | scrollDiv.style.position = 'absolute';
706 | scrollDiv.style.width = width + "px";
707 | scrollDiv.style.height = height + "px";
708 | scrollDiv.style[$.feat.cssPrefix + 'BorderRadius'] = "2px";
709 | scrollDiv.style.borderRadius = "2px";
710 | scrollDiv.style.display="none";
711 | scrollDiv.className = 'scrollBar';
712 | scrollDiv.style.background = "black";
713 | return scrollDiv;
714 | }
715 | jsScroller.prototype.enable = function (firstExecution) {
716 | if (this.eventsActive) return;
717 | this.eventsActive = true;
718 | if (!firstExecution) this.adjustScroll();
719 | else
720 | this.scrollerMoveCSS({
721 | x: 0,
722 | y: 0
723 | }, 0);
724 | //add listeners
725 | this.container.addEventListener('touchstart', this, false);
726 | this.container.addEventListener('touchmove', this, false);
727 | this.container.addEventListener('touchend', this, false);
728 |
729 | };
730 | jsScroller.prototype.adjustScroll = function () {
731 | //set top/left
732 | var size = this.getViewportSize();
733 | this.scrollerMoveCSS({
734 | x: Math.round(this.loggedPcentX * (this.el.clientWidth - size.w)),
735 | y: Math.round(this.loggedPcentY * (this.el.clientHeight - size.h))
736 | }, 0);
737 | };
738 | jsScroller.prototype.disable = function () {
739 | if (!this.eventsActive) return;
740 | //log top/left
741 | var cssMatrix = this.getCSSMatrix(this.el);
742 | this.logPos((numOnly(cssMatrix.e) - numOnly(this.container.scrollLeft)), (numOnly(cssMatrix.f) - numOnly(this.container.scrollTop)));
743 | //remove event listeners
744 | this.container.removeEventListener('touchstart', this, false);
745 | this.container.removeEventListener('touchmove', this, false);
746 | this.container.removeEventListener('touchend', this, false);
747 | this.eventsActive = false;
748 | };
749 | jsScroller.prototype.addPullToRefresh = function (el, leaveRefresh) {
750 | if (!leaveRefresh) this.refresh = true;
751 | if (this.refresh && this.refresh === true) {
752 | this.coreAddPullToRefresh(el);
753 | this.el.style.overflow = 'visible';
754 | }
755 | };
756 | jsScroller.prototype.hideScrollbars = function () {
757 | if (this.hscrollBar) {
758 | this.hscrollBar.style.display="none";
759 | this.hscrollBar.style[$.feat.cssPrefix + 'TransitionDuration'] = "0ms";
760 | }
761 | if (this.vscrollBar) {
762 | this.vscrollBar.style.display="none";
763 | this.vscrollBar.style[$.feat.cssPrefix + 'TransitionDuration'] = "0ms";
764 | }
765 | };
766 |
767 | jsScroller.prototype.getViewportSize = function () {
768 | var style = window.getComputedStyle(this.container);
769 | if (isNaN(numOnly(style.paddingTop))) alert((typeof style.paddingTop) + '::' + style.paddingTop + ':');
770 | return {
771 | h: (this.container.clientHeight > window.innerHeight ? window.innerHeight : this.container.clientHeight - numOnly(style.paddingTop) - numOnly(style.paddingBottom)),
772 | w: (this.container.clientWidth > window.innerWidth ? window.innerWidth : this.container.clientWidth - numOnly(style.paddingLeft) - numOnly(style.paddingRight))
773 | };
774 | };
775 |
776 | jsScroller.prototype.onTouchStart = function (event) {
777 |
778 | this.moved = false;
779 | this.currentScrollingObject = null;
780 |
781 | if (!this.container) return;
782 | if (this.refreshCancelCB) {
783 | clearTimeout(this.refreshCancelCB);
784 | this.refreshCancelCB = null;
785 | }
786 | if (this.scrollingFinishCB) {
787 | clearTimeout(this.scrollingFinishCB);
788 | this.scrollingFinishCB = null;
789 | }
790 |
791 |
792 | //disable if locked
793 | if (event.touches.length != 1 || this.boolScrollLock) return;
794 |
795 | // Allow interaction to legit calls, like select boxes, etc.
796 | if (event.touches[0].target && event.touches[0].target.type !== undefined) {
797 | var tagname = event.touches[0].target.tagName.toLowerCase();
798 | var tagtype=event.touches[0].target.type.toLowerCase();
799 |
800 | if (tagname == "select" ) // stuff we need to allow
801 | // access to legit calls
802 | return;
803 |
804 | }
805 |
806 | //default variables
807 | var scrollInfo = {
808 | //current position
809 | top: 0,
810 | left: 0,
811 | //current movement
812 | speedY: 0,
813 | speedX: 0,
814 | absSpeedY: 0,
815 | absSpeedX: 0,
816 | deltaY: 0,
817 | deltaX: 0,
818 | absDeltaY: 0,
819 | absDeltaX: 0,
820 | y: 0,
821 | x: 0,
822 | duration: 0
823 | };
824 |
825 | //element info
826 | this.elementInfo = {};
827 | var size = this.getViewportSize();
828 | this.elementInfo.bottomMargin = size.h;
829 | this.elementInfo.maxTop = (this.el.clientHeight - this.elementInfo.bottomMargin);
830 | if (this.elementInfo.maxTop < 0) this.elementInfo.maxTop = 0;
831 | this.elementInfo.divHeight = this.el.clientHeight;
832 | this.elementInfo.rightMargin = size.w;
833 | this.elementInfo.maxLeft = (this.el.clientWidth - this.elementInfo.rightMargin);
834 | if (this.elementInfo.maxLeft < 0) this.elementInfo.maxLeft = 0;
835 | this.elementInfo.divWidth = this.el.clientWidth;
836 | this.elementInfo.hasVertScroll = this.verticalScroll || this.elementInfo.maxTop > 0;
837 | this.elementInfo.hasHorScroll = this.elementInfo.maxLeft > 0;
838 | this.elementInfo.requiresVScrollBar = this.vscrollBar && this.elementInfo.hasVertScroll;
839 | this.elementInfo.requiresHScrollBar = this.hscrollBar && this.elementInfo.hasHorScroll;
840 |
841 | //save event
842 | this.saveEventInfo(event);
843 | this.saveFirstEventInfo(event);
844 |
845 | //get the current top
846 | var cssMatrix = this.getCSSMatrix(this.el);
847 | scrollInfo.top = numOnly(cssMatrix.f) - numOnly(this.container.scrollTop);
848 | scrollInfo.left = numOnly(cssMatrix.e) - numOnly(this.container.scrollLeft);
849 |
850 | this.container.scrollTop = this.container.scrollLeft = 0;
851 | this.currentScrollingObject = this.el;
852 |
853 | //get refresh ready
854 | if (this.refresh && scrollInfo.top === 0) {
855 | this.refreshContainer.style.display = "block";
856 | this.refreshHeight = this.refreshContainer.firstChild.clientHeight;
857 | this.refreshContainer.firstChild.style.top = (-this.refreshHeight) + 'px';
858 | this.refreshContainer.style.overflow = 'visible';
859 | this.preventPullToRefresh = false;
860 | } else if (scrollInfo.top < 0) {
861 | this.preventPullToRefresh = true;
862 | if (this.refresh) this.refreshContainer.style.overflow = 'hidden';
863 | }
864 |
865 | //set target
866 | scrollInfo.x = scrollInfo.left;
867 | scrollInfo.y = scrollInfo.top;
868 |
869 | //vertical scroll bar
870 | if (this.setVScrollBar(scrollInfo, 0, 0)) {
871 | if (this.container.clientWidth > window.innerWidth)
872 | this.vscrollBar.style.right = "0px";
873 | else
874 | this.vscrollBar.style.right = "0px";
875 | this.vscrollBar.style[$.feat.cssPrefix + "Transition"] = '';
876 | // this.vscrollBar.style.opacity = 1;
877 | }
878 |
879 | //horizontal scroll
880 | if (this.setHScrollBar(scrollInfo, 0, 0)) {
881 | if (this.container.clientHeight > window.innerHeight)
882 | this.hscrollBar.style.top = (window.innerHeight - numOnly(this.hscrollBar.style.height)) + "px";
883 | else
884 | this.hscrollBar.style.bottom = numOnly(this.hscrollBar.style.height);
885 | this.hscrollBar.style[$.feat.cssPrefix + "Transition"] = '';
886 | // this.hscrollBar.style.opacity = 1;
887 | }
888 |
889 | //save scrollInfo
890 | this.lastScrollInfo = scrollInfo;
891 | this.hasMoved = false;
892 |
893 | this.scrollerMoveCSS(this.lastScrollInfo, 0);
894 |
895 |
896 | };
897 | jsScroller.prototype.getCSSMatrix = function (el) {
898 | if (this.androidFormsMode) {
899 | //absolute mode
900 | var top = parseInt(el.style.marginTop,10);
901 | var left = parseInt(el.style.marginLeft,10);
902 | if (isNaN(top)) top = 0;
903 | if (isNaN(left)) left = 0;
904 | return {
905 | f: top,
906 | e: left
907 | };
908 | } else {
909 | //regular transform
910 |
911 | var obj = $.getCssMatrix(el);
912 | return obj;
913 | }
914 | };
915 | jsScroller.prototype.saveEventInfo = function (event) {
916 | this.lastEventInfo = {
917 | pageX: event.touches[0].pageX,
918 | pageY: event.touches[0].pageY,
919 | time: event.timeStamp
920 | };
921 | };
922 | jsScroller.prototype.saveFirstEventInfo = function (event) {
923 | this.firstEventInfo = {
924 | pageX: event.touches[0].pageX,
925 | pageY: event.touches[0].pageY,
926 | time: event.timeStamp
927 | };
928 | };
929 | jsScroller.prototype.setVScrollBar = function (scrollInfo, time, timingFunction) {
930 |
931 | if (!this.elementInfo.requiresVScrollBar) return false;
932 | var newHeight = (parseFloat(this.elementInfo.bottomMargin / this.elementInfo.divHeight) * this.elementInfo.bottomMargin) + "px";
933 | if(numOnly(newHeight)>this.elementInfo.bottomMargin)
934 | newHeight=this.elementInfo.bottomMargin+"px";
935 | if (newHeight != this.vscrollBar.style.height) this.vscrollBar.style.height = newHeight;
936 |
937 | var pos = (this.elementInfo.bottomMargin - numOnly(this.vscrollBar.style.height)) - (((this.elementInfo.maxTop + scrollInfo.y) / this.elementInfo.maxTop) * (this.elementInfo.bottomMargin - numOnly(this.vscrollBar.style.height)));
938 | if (pos > this.elementInfo.bottomMargin) pos = this.elementInfo.bottomMargin;
939 |
940 | if (pos < 0) pos = 0;
941 | this.scrollbarMoveCSS(this.vscrollBar, {
942 | x: 0,
943 | y: pos
944 | }, time, timingFunction);
945 | return true;
946 | };
947 | jsScroller.prototype.setHScrollBar = function (scrollInfo, time, timingFunction) {
948 | if (!this.elementInfo.requiresHScrollBar) return false;
949 | var newWidth = (parseFloat(this.elementInfo.rightMargin / this.elementInfo.divWidth) * this.elementInfo.rightMargin) + "px";
950 | if (newWidth != this.hscrollBar.style.width) this.hscrollBar.style.width = newWidth;
951 | var pos = (this.elementInfo.rightMargin - numOnly(this.hscrollBar.style.width)) - (((this.elementInfo.maxLeft + scrollInfo.x) / this.elementInfo.maxLeft) * (this.elementInfo.rightMargin - numOnly(this.hscrollBar.style.width)));
952 |
953 | if (pos > this.elementInfo.rightMargin) pos = this.elementInfo.rightMargin;
954 | if (pos < 0) pos = 0;
955 |
956 | this.scrollbarMoveCSS(this.hscrollBar, {
957 | x: pos,
958 | y: 0
959 | }, time, timingFunction);
960 | return true;
961 | };
962 |
963 | jsScroller.prototype.onTouchMove = function (event) {
964 |
965 |
966 | if (this.currentScrollingObject === null) return;
967 | //event.preventDefault();
968 | var scrollInfo = this.calculateMovement(event);
969 | this.calculateTarget(scrollInfo);
970 |
971 | this.lastScrollInfo = scrollInfo;
972 | if (!this.moved) {
973 | $.trigger(this, "scrollstart");
974 | $.trigger($.touchLayer, "scrollstart", [this.el]);
975 | if (this.elementInfo.requiresVScrollBar) this.vscrollBar.style.display="block";
976 | if (this.elementInfo.requiresHScrollBar) this.hscrollBar.style.display="block";
977 | }
978 | this.moved = true;
979 |
980 |
981 | if (this.refresh && scrollInfo.top === 0) {
982 | this.refreshContainer.style.display = "block";
983 | this.refreshHeight = this.refreshContainer.firstChild.clientHeight;
984 | this.refreshContainer.firstChild.style.top = (-this.refreshHeight) + 'px';
985 | this.refreshContainer.style.overflow = 'visible';
986 | this.preventPullToRefresh = false;
987 | } else if (scrollInfo.top < 0) {
988 | this.preventPullToRefresh = true;
989 | if (this.refresh) this.refreshContainer.style.overflow = 'hidden';
990 | }
991 |
992 |
993 | this.saveEventInfo(event);
994 | if (this.isScrolling===false){ // && (this.lastScrollInfo.x != this.lastScrollInfo.left || this.lastScrollInfo.y != this.lastScrollInfo.top)) {
995 | this.isScrolling = true;
996 | if (this.onScrollStart) this.onScrollStart();
997 | }
998 | //proceed normally
999 | var cssMatrix = this.getCSSMatrix(this.el);
1000 | this.lastScrollInfo.top = numOnly(cssMatrix.f);
1001 | this.lastScrollInfo.left = numOnly(cssMatrix.e);
1002 |
1003 | this.recalculateDeltaY(this.lastScrollInfo);
1004 | this.recalculateDeltaX(this.lastScrollInfo);
1005 |
1006 | //boundaries control
1007 | this.checkYboundary(this.lastScrollInfo);
1008 | if (this.elementInfo.hasHorScroll) this.checkXboundary(this.lastScrollInfo);
1009 |
1010 |
1011 | //pull to refresh elastic
1012 |
1013 | var positiveOverflow = this.lastScrollInfo.y > 0 && this.lastScrollInfo.deltaY > 0;
1014 | var negativeOverflow = this.lastScrollInfo.y < -this.elementInfo.maxTop && this.lastScrollInfo.deltaY < 0;
1015 | if (positiveOverflow || negativeOverflow) {
1016 | var overflow = positiveOverflow ? this.lastScrollInfo.y : -this.lastScrollInfo.y - this.elementInfo.maxTop;
1017 | var pcent = (this.container.clientHeight - overflow) / this.container.clientHeight;
1018 | if (pcent < 0.5) pcent = 0.5;
1019 | //cur top, maxTop or 0?
1020 | var baseTop = 0;
1021 | if ((positiveOverflow && this.lastScrollInfo.top > 0) || (negativeOverflow && this.lastScrollInfo.top < -this.elementInfo.maxTop)) {
1022 | baseTop = this.lastScrollInfo.top;
1023 | } else if (negativeOverflow) {
1024 | baseTop = -this.elementInfo.maxTop;
1025 | }
1026 | var changeY = this.lastScrollInfo.deltaY * pcent;
1027 | var absChangeY = Math.abs(this.lastScrollInfo.deltaY * pcent);
1028 | if (absChangeY < 1) changeY = positiveOverflow ? 1 : -1;
1029 | this.lastScrollInfo.y = baseTop + changeY;
1030 | }
1031 |
1032 | if(this.elementInfo.hasHorScroll){
1033 | positiveOverflow = this.lastScrollInfo.x > 0 && this.lastScrollInfo.deltaX > 0;
1034 | negativeOverflow = this.lastScrollInfo.x < -this.elementInfo.maxLeft && this.lastScrollInfo.deltaX < 0;
1035 | if (positiveOverflow || negativeOverflow) {
1036 | var overflow = positiveOverflow ? this.lastScrollInfo.x : -this.lastScrollInfo.x - this.elementInfo.maxLeft;
1037 | var pcent = (this.container.clientWidth - overflow) / this.container.clientWidth;
1038 | if (pcent < 0.5) pcent = 0.5;
1039 | //cur top, maxTop or 0?
1040 | var baseTop = 0;
1041 | if ((positiveOverflow && this.lastScrollInfo.left > 0) || (negativeOverflow && this.lastScrollInfo.left < -this.elementInfo.maxLeft)) {
1042 | baseTop = this.lastScrollInfo.left;
1043 | } else if (negativeOverflow) {
1044 | baseTop = -this.elementInfo.maxLeft;
1045 | }
1046 | var changeX = this.lastScrollInfo.deltaX * pcent;
1047 | var absChangeX = Math.abs(this.lastScrollInfo.deltaX * pcent);
1048 | if (absChangeX < 1) changeX = positiveOverflow ? 1 : -1;
1049 | this.lastScrollInfo.x = baseTop + changeX;
1050 | }
1051 | }
1052 |
1053 | //move
1054 |
1055 | this.scrollerMoveCSS(this.lastScrollInfo, 0);
1056 | this.setVScrollBar(this.lastScrollInfo, 0, 0);
1057 | this.setHScrollBar(this.lastScrollInfo, 0, 0);
1058 |
1059 | //check refresh triggering
1060 | if (this.refresh && !this.preventPullToRefresh) {
1061 | if (!this.refreshTriggered && this.lastScrollInfo.top > this.refreshHeight) {
1062 | this.refreshTriggered = true;
1063 | $.trigger(this, 'refresh-trigger');
1064 | } else if (this.refreshTriggered && this.lastScrollInfo.top < this.refreshHeight) {
1065 | this.refreshTriggered = false;
1066 | $.trigger(this, 'refresh-cancel');
1067 | }
1068 | }
1069 |
1070 | if (this.infinite && !this.infiniteTriggered) {
1071 | if ((Math.abs(this.lastScrollInfo.top) >= (this.el.clientHeight - this.container.clientHeight))) {
1072 | this.infiniteTriggered = true;
1073 | $.trigger(this, "infinite-scroll");
1074 | }
1075 | }
1076 |
1077 | };
1078 |
1079 |
1080 |
1081 | jsScroller.prototype.calculateMovement = function (event, last) {
1082 | //default variables
1083 | var scrollInfo = {
1084 | //current position
1085 | top: 0,
1086 | left: 0,
1087 | //current movement
1088 | speedY: 0,
1089 | speedX: 0,
1090 | absSpeedY: 0,
1091 | absSpeedX: 0,
1092 | deltaY: 0,
1093 | deltaX: 0,
1094 | absDeltaY: 0,
1095 | absDeltaX: 0,
1096 | y: 0,
1097 | x: 0,
1098 | duration: 0
1099 | };
1100 |
1101 | var prevEventInfo = last ? this.firstEventInfo : this.lastEventInfo;
1102 | var pageX = last ? event.pageX : event.touches[0].pageX;
1103 | var pageY = last ? event.pageY : event.touches[0].pageY;
1104 | var time = last ? event.time : event.timeStamp;
1105 |
1106 | scrollInfo.deltaY = this.elementInfo.hasVertScroll ? pageY - prevEventInfo.pageY : 0;
1107 | scrollInfo.deltaX = this.elementInfo.hasHorScroll ? pageX - prevEventInfo.pageX : 0;
1108 | scrollInfo.time = time;
1109 |
1110 |
1111 | scrollInfo.duration = time - prevEventInfo.time;
1112 | return scrollInfo;
1113 | };
1114 |
1115 | jsScroller.prototype.calculateTarget = function (scrollInfo) {
1116 | scrollInfo.y = this.lastScrollInfo.y + scrollInfo.deltaY;
1117 | scrollInfo.x = this.lastScrollInfo.x + scrollInfo.deltaX;
1118 | };
1119 | jsScroller.prototype.checkYboundary = function (scrollInfo) {
1120 | var minTop = this.container.clientHeight / 2;
1121 | var maxTop = this.elementInfo.maxTop + minTop;
1122 | //y boundaries
1123 | if (scrollInfo.y > minTop) scrollInfo.y = minTop;
1124 | else if (-scrollInfo.y > maxTop) scrollInfo.y = -maxTop;
1125 | else return;
1126 | this.recalculateDeltaY(scrollInfo);
1127 | };
1128 | jsScroller.prototype.checkXboundary = function (scrollInfo) {
1129 | //x boundaries
1130 |
1131 | var minLeft=this.container.clientWidth/2;
1132 | var maxLeft=this.elementInfo.maxLeft+minLeft;
1133 |
1134 | if (scrollInfo.x > minLeft) scrollInfo.x = minLeft;
1135 | else if (-scrollInfo.x > maxLeft) scrollInfo.x = -maxLeft;
1136 | else return;
1137 |
1138 | this.recalculateDeltaX(scrollInfo);
1139 | };
1140 | jsScroller.prototype.recalculateDeltaY = function (scrollInfo) {
1141 | //recalculate delta
1142 | var oldAbsDeltaY = Math.abs(scrollInfo.deltaY);
1143 | scrollInfo.deltaY = scrollInfo.y - scrollInfo.top;
1144 | newAbsDeltaY = Math.abs(scrollInfo.deltaY);
1145 | //recalculate duration at same speed
1146 | scrollInfo.duration = scrollInfo.duration * newAbsDeltaY / oldAbsDeltaY;
1147 |
1148 | };
1149 | jsScroller.prototype.recalculateDeltaX = function (scrollInfo) {
1150 | //recalculate delta
1151 | var oldAbsDeltaX = Math.abs(scrollInfo.deltaX);
1152 | scrollInfo.deltaX = scrollInfo.x - scrollInfo.left;
1153 | newAbsDeltaX = Math.abs(scrollInfo.deltaX);
1154 | //recalculate duration at same speed
1155 | scrollInfo.duration = scrollInfo.duration * newAbsDeltaX / oldAbsDeltaX;
1156 |
1157 | };
1158 |
1159 | jsScroller.prototype.hideRefresh = function (animate) {
1160 | var that = this;
1161 | if (this.preventHideRefresh) return;
1162 | this.scrollerMoveCSS({
1163 | x: 0,
1164 | y: 0,
1165 | complete: function () {
1166 | $.trigger(that, "refresh-finish");
1167 | }
1168 | }, HIDE_REFRESH_TIME);
1169 | this.refreshTriggered = false;
1170 | };
1171 |
1172 | jsScroller.prototype.setMomentum = function (scrollInfo) {
1173 | var deceleration = 0.0012;
1174 |
1175 | //calculate movement speed
1176 | scrollInfo.speedY = this.divide(scrollInfo.deltaY, scrollInfo.duration);
1177 | scrollInfo.speedX = this.divide(scrollInfo.deltaX, scrollInfo.duration);
1178 |
1179 | scrollInfo.absSpeedY = Math.abs(scrollInfo.speedY);
1180 | scrollInfo.absSpeedX = Math.abs(scrollInfo.speedX);
1181 |
1182 | scrollInfo.absDeltaY = Math.abs(scrollInfo.deltaY);
1183 | scrollInfo.absDeltaX = Math.abs(scrollInfo.deltaX);
1184 |
1185 |
1186 | //set momentum
1187 | if (scrollInfo.absDeltaY > 0) {
1188 | scrollInfo.deltaY = (scrollInfo.deltaY < 0 ? -1 : 1) * (scrollInfo.absSpeedY * scrollInfo.absSpeedY) / (2 * deceleration);
1189 | scrollInfo.absDeltaY = Math.abs(scrollInfo.deltaY);
1190 | scrollInfo.duration = scrollInfo.absSpeedY / deceleration;
1191 | scrollInfo.speedY = scrollInfo.deltaY / scrollInfo.duration;
1192 | scrollInfo.absSpeedY = Math.abs(scrollInfo.speedY);
1193 | if (scrollInfo.absSpeedY < deceleration * 100 || scrollInfo.absDeltaY < 5) scrollInfo.deltaY = scrollInfo.absDeltaY = scrollInfo.duration = scrollInfo.speedY = scrollInfo.absSpeedY = 0;
1194 | } else if (scrollInfo.absDeltaX) {
1195 | scrollInfo.deltaX = (scrollInfo.deltaX < 0 ? -1 : 1) * (scrollInfo.absSpeedX * scrollInfo.absSpeedX) / (2 * deceleration);
1196 | scrollInfo.absDeltaX = Math.abs(scrollInfo.deltaX);
1197 | scrollInfo.duration = scrollInfo.absSpeedX / deceleration;
1198 | scrollInfo.speedX = scrollInfo.deltaX / scrollInfo.duration;
1199 | scrollInfo.absSpeedX = Math.abs(scrollInfo.speedX);
1200 | if (scrollInfo.absSpeedX < deceleration * 100 || scrollInfo.absDeltaX < 5) scrollInfo.deltaX = scrollInfo.absDeltaX = scrollInfo.duration = scrollInfo.speedX = scrollInfo.absSpeedX = 0;
1201 | } else scrollInfo.duration = 0;
1202 | };
1203 |
1204 |
1205 | jsScroller.prototype.onTouchEnd = function (event) {
1206 |
1207 |
1208 | if (this.currentScrollingObject === null || !this.moved) return;
1209 | //event.preventDefault();
1210 | this.finishScrollingObject = this.currentScrollingObject;
1211 | this.currentScrollingObject = null;
1212 |
1213 | var scrollInfo = this.calculateMovement(this.lastEventInfo, true);
1214 |
1215 | if (!this.androidFormsMode) {
1216 | this.setMomentum(scrollInfo);
1217 | }
1218 | this.calculateTarget(scrollInfo);
1219 |
1220 | //get the current top
1221 | var cssMatrix = this.getCSSMatrix(this.el);
1222 | scrollInfo.top = numOnly(cssMatrix.f);
1223 | scrollInfo.left = numOnly(cssMatrix.e);
1224 |
1225 | //boundaries control
1226 | this.checkYboundary(scrollInfo);
1227 |
1228 | if (this.elementInfo.hasHorScroll) this.checkXboundary(scrollInfo);
1229 |
1230 |
1231 | var triggered = !this.preventPullToRefresh && (scrollInfo.top > this.refreshHeight || scrollInfo.y > this.refreshHeight);
1232 | this.fireRefreshRelease(triggered, scrollInfo.top > 0);
1233 |
1234 | //refresh hang in
1235 | if (this.refresh && triggered) {
1236 | scrollInfo.y = this.refreshHeight;
1237 | scrollInfo.duration = HIDE_REFRESH_TIME;
1238 | //top boundary
1239 | } else if (scrollInfo.y >= 0) {
1240 | scrollInfo.y = 0;
1241 | if (scrollInfo.top >= 0) scrollInfo.duration = HIDE_REFRESH_TIME;
1242 | //lower boundary
1243 | } else if (-scrollInfo.y > this.elementInfo.maxTop || this.elementInfo.maxTop === 0) {
1244 | scrollInfo.y = -this.elementInfo.maxTop;
1245 | if (-scrollInfo.top > this.elementInfo.maxTop) scrollInfo.duration = HIDE_REFRESH_TIME;
1246 | //all others
1247 | }
1248 | ;
1249 | if(this.elementInfo.hasHorScroll){
1250 | if(scrollInfo.x>=0)
1251 | {
1252 | scrollInfo.x=0;
1253 | if(scrollInfo.left>=0) scrollInfo.duration=HIDE_REFRESH_TIME;
1254 | }
1255 | else if(-scrollInfo.x>this.elementInfo.maxLeft||this.elementInfo.maxLeft===0){
1256 | scrollInfo.x=-this.elementInfo.maxLeft;
1257 | if(-scrollInfo.left>this.elementInfo.maxLeft) scrollInfo.duration=HIDE_REFRESH_TIME;
1258 | }
1259 | }
1260 |
1261 | if (this.androidFormsMode) scrollInfo.duration = 0;
1262 |
1263 | this.scrollerMoveCSS(scrollInfo, scrollInfo.duration, "cubic-bezier(0.33,0.66,0.66,1)");
1264 | this.setVScrollBar(scrollInfo, scrollInfo.duration, "cubic-bezier(0.33,0.66,0.66,1)");
1265 | this.setHScrollBar(scrollInfo, scrollInfo.duration, "cubic-bezier(0.33,0.66,0.66,1)");
1266 | this.setFinishCalback(scrollInfo.duration);
1267 | if (this.infinite && !this.infiniteTriggered) {
1268 | if ((Math.abs(scrollInfo.y) >= (this.el.clientHeight - this.container.clientHeight))) {
1269 | this.infiniteTriggered = true;
1270 | $.trigger(this, "infinite-scroll");
1271 | }
1272 | }
1273 | };
1274 |
1275 | //finish callback
1276 | jsScroller.prototype.setFinishCalback = function (duration) {
1277 | var that = this;
1278 | this.scrollingFinishCB = setTimeout(function () {
1279 | that.hideScrollbars();
1280 | $.trigger($.touchLayer, 'scrollend', [that.el]); //notify touchLayer of this elements scrollend
1281 | $.trigger(that, "scrollend", [that.el]);
1282 | that.isScrolling = false;
1283 | that.elementInfo = null; //reset elementInfo when idle
1284 | if (that.infinite) $.trigger(that, "infinite-scroll-end");
1285 | }, duration);
1286 | };
1287 |
1288 | //Android Forms Fix
1289 | jsScroller.prototype.startFormsMode = function () {
1290 | if (this.blockFormsFix) return;
1291 | //get prev values
1292 | var cssMatrix = this.getCSSMatrix(this.el);
1293 | //toggle vars
1294 | this.refreshSafeKeep = this.refresh;
1295 | this.refresh = false;
1296 | this.androidFormsMode = true;
1297 | //set new css rules
1298 | this.el.style[$.feat.cssPrefix + "Transform"] = "none";
1299 | this.el.style[$.feat.cssPrefix + "Transition"] = "none";
1300 | this.el.style[$.feat.cssPrefix + "Perspective"] = "none";
1301 |
1302 | //set position
1303 | this.scrollerMoveCSS({
1304 | x: numOnly(cssMatrix.e),
1305 | y: numOnly(cssMatrix.f)
1306 | }, 0);
1307 |
1308 | //container
1309 | this.container.style[$.feat.cssPrefix + "Perspective"] = "none";
1310 | this.container.style[$.feat.cssPrefix + "BackfaceVisibility"] = "visible";
1311 | //scrollbars
1312 | if (this.vscrollBar) {
1313 | this.vscrollBar.style[$.feat.cssPrefix + "Transform"] = "none";
1314 | this.vscrollBar.style[$.feat.cssPrefix + "Transition"] = "none";
1315 | this.vscrollBar.style[$.feat.cssPrefix + "Perspective"] = "none";
1316 | this.vscrollBar.style[$.feat.cssPrefix + "BackfaceVisibility"] = "visible";
1317 | }
1318 | if (this.hscrollBar) {
1319 | this.hscrollBar.style[$.feat.cssPrefix + "Transform"] = "none";
1320 | this.hscrollBar.style[$.feat.cssPrefix + "Transition"] = "none";
1321 | this.hscrollBar.style[$.feat.cssPrefix + "Perspective"] = "none";
1322 | this.hscrollBar.style[$.feat.cssPrefix + "BackfaceVisibility"] = "visible";
1323 | }
1324 |
1325 | };
1326 | jsScroller.prototype.stopFormsMode = function () {
1327 | if (this.blockFormsFix) return;
1328 | //get prev values
1329 | var cssMatrix = this.getCSSMatrix(this.el);
1330 | //toggle vars
1331 | this.refresh = this.refreshSafeKeep;
1332 | this.androidFormsMode = false;
1333 | //set new css rules
1334 | this.el.style[$.feat.cssPrefix + "Perspective"] = 1000;
1335 | this.el.style.marginTop = 0;
1336 | this.el.style.marginLeft = 0;
1337 | this.el.style[$.feat.cssPrefix + "Transition"] = '0ms linear'; //reactivate transitions
1338 | //set position
1339 | this.scrollerMoveCSS({
1340 | x: numOnly(cssMatrix.e),
1341 | y: numOnly(cssMatrix.f)
1342 | }, 0);
1343 | //container
1344 | this.container.style[$.feat.cssPrefix + "Perspective"] = 1000;
1345 | this.container.style[$.feat.cssPrefix + "BackfaceVisibility"] = "hidden";
1346 | //scrollbars
1347 | if (this.vscrollBar) {
1348 | this.vscrollBar.style[$.feat.cssPrefix + "Perspective"] = 1000;
1349 | this.vscrollBar.style[$.feat.cssPrefix + "BackfaceVisibility"] = "hidden";
1350 | }
1351 | if (this.hscrollBar) {
1352 | this.hscrollBar.style[$.feat.cssPrefix + "Perspective"] = 1000;
1353 | this.hscrollBar.style[$.feat.cssPrefix + "BackfaceVisibility"] = "hidden";
1354 | }
1355 |
1356 | };
1357 |
1358 |
1359 |
1360 | jsScroller.prototype.scrollerMoveCSS = function (distanceToMove, time, timingFunction) {
1361 | if (!time) time = 0;
1362 | if (!timingFunction) timingFunction = "linear";
1363 | time = numOnly(time);
1364 | if (this.el && this.el.style) {
1365 |
1366 | //do not touch the DOM if disabled
1367 | if (this.eventsActive) {
1368 | if (this.androidFormsMode) {
1369 | this.el.style.marginTop = Math.round(distanceToMove.y) + "px";
1370 | this.el.style.marginLeft = Math.round(distanceToMove.x) + "px";
1371 | } else {
1372 |
1373 | this.el.style[$.feat.cssPrefix + "Transform"] = "translate" + translateOpen + distanceToMove.x + "px," + distanceToMove.y + "px" + translateClose;
1374 | this.el.style[$.feat.cssPrefix + "TransitionDuration"] = time + "ms";
1375 | this.el.style[$.feat.cssPrefix + "TransitionTimingFunction"] = timingFunction;
1376 | }
1377 | }
1378 | // Position should be updated even when the scroller is disabled so we log the change
1379 | this.logPos(distanceToMove.x, distanceToMove.y);
1380 | }
1381 | };
1382 | jsScroller.prototype.logPos = function (x, y) {
1383 |
1384 | var size;
1385 | if (!this.elementInfo) {
1386 | size = this.getViewportSize();
1387 | } else {
1388 | size = {
1389 | h: this.elementInfo.bottomMargin,
1390 | w: this.elementInfo.rightMargin
1391 | };
1392 | }
1393 |
1394 | this.loggedPcentX = this.divide(x, (this.el.clientWidth - size.w));
1395 | this.loggedPcentY = this.divide(y, (this.el.clientHeight - size.h));
1396 | this.scrollTop = y;
1397 | this.scrollLeft = x;
1398 | };
1399 | jsScroller.prototype.scrollbarMoveCSS = function (el, distanceToMove, time, timingFunction) {
1400 | if (!time) time = 0;
1401 | if (!timingFunction) timingFunction = "linear";
1402 |
1403 | if (el && el.style) {
1404 | if (this.androidFormsMode) {
1405 | el.style.marginTop = Math.round(distanceToMove.y) + "px";
1406 | el.style.marginLeft = Math.round(distanceToMove.x) + "px";
1407 | } else {
1408 | el.style[$.feat.cssPrefix + "Transform"] = "translate" + translateOpen + distanceToMove.x + "px," + distanceToMove.y + "px" + translateClose;
1409 | el.style[$.feat.cssPrefix + "TransitionDuration"] = time + "ms";
1410 | el.style[$.feat.cssPrefix + "TransitionTimingFunction"] = timingFunction;
1411 | }
1412 | }
1413 | };
1414 | jsScroller.prototype.scrollTo = function (pos, time) {
1415 | if (!time) time = 0;
1416 | this.scrollerMoveCSS(pos, time);
1417 | };
1418 | jsScroller.prototype.scrollBy = function (pos, time) {
1419 | var cssMatrix = this.getCSSMatrix(this.el);
1420 | var startTop = numOnly(cssMatrix.f);
1421 | var startLeft = numOnly(cssMatrix.e);
1422 | this.scrollTo({
1423 | y: startTop - pos.y,
1424 | x: startLeft - pos.x
1425 | }, time);
1426 | };
1427 | jsScroller.prototype.scrollToBottom = function (time) {
1428 | this.scrollTo({
1429 | y: -1 * (this.el.clientHeight - this.container.clientHeight),
1430 | x: 0
1431 | }, time);
1432 | };
1433 | jsScroller.prototype.scrollToTop = function (time) {
1434 | this.scrollTo({
1435 | x: 0,
1436 | y: 0
1437 | }, time);
1438 | };
1439 | return scroller;
1440 | })();
1441 | })(af);
--------------------------------------------------------------------------------