├── doc ├── img │ └── iphone.png ├── vendor │ ├── prettify │ │ ├── prettify.css │ │ └── prettify.js │ ├── zepto │ │ └── dimensions.js │ └── fingerblast │ │ └── fingerblast.js ├── md │ └── getting-started.md ├── js │ └── doc.js ├── css │ └── doc.css └── index.html ├── img └── icon-search.png ├── demo ├── vendor │ └── ionicons │ │ └── fonts │ │ ├── ionicons.eot │ │ ├── ionicons.ttf │ │ └── ionicons.woff ├── js │ └── demo.js └── index.html ├── .gitignore ├── js ├── pro.js ├── os.js ├── transition.js ├── debounce.js ├── requestAnimationFrame.js ├── fixed.js ├── scrollfix.js ├── tab.js ├── data.js ├── countable.js ├── lazyload.js ├── deletable.js ├── spinner.js ├── touch.js ├── dialog.js ├── event.js ├── carousel.js ├── ajax.js └── tmpl.js ├── package.json ├── task └── amdify.js ├── bower.json ├── Modfile.js └── README.md /doc/img/iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeamDev/Pro/HEAD/doc/img/iphone.png -------------------------------------------------------------------------------- /img/icon-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeamDev/Pro/HEAD/img/icon-search.png -------------------------------------------------------------------------------- /demo/vendor/ionicons/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeamDev/Pro/HEAD/demo/vendor/ionicons/fonts/ionicons.eot -------------------------------------------------------------------------------- /demo/vendor/ionicons/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeamDev/Pro/HEAD/demo/vendor/ionicons/fonts/ionicons.ttf -------------------------------------------------------------------------------- /demo/vendor/ionicons/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeamDev/Pro/HEAD/demo/vendor/ionicons/fonts/ionicons.woff -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Files to ignore 2 | .DS_Store 3 | .localized 4 | Thumbs.db 5 | *.log 6 | *.sass-cache 7 | 8 | # Folders to ignore 9 | .idea 10 | .hg 11 | .svn 12 | .CVS 13 | .cache 14 | tmp 15 | node_modules 16 | -------------------------------------------------------------------------------- /js/pro.js: -------------------------------------------------------------------------------- 1 | define([ 2 | './scrollfix', 3 | './tab', 4 | './dialog', 5 | './spinner', 6 | './carousel', 7 | './lazyload', 8 | './countable', 9 | './deletable' 10 | ],function () { 11 | return $; 12 | }); 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Pro", 3 | "description": "Framework for mobile platform", 4 | "version": "1.0.0", 5 | "author": { 6 | "name": "yuanyan", 7 | "url": "http://madscript.com" 8 | }, 9 | "dependencies": {}, 10 | "devDependencies": {} 11 | } -------------------------------------------------------------------------------- /task/amdify.js: -------------------------------------------------------------------------------- 1 | exports.run = function(){ 2 | exports.files.forEach(function(file){ 3 | var origin = exports.file.read(file); 4 | var amdify = ''; 5 | if(file.indexOf('zepto') != -1){ 6 | amdify = "define(function(){\n" + origin + "\n});\n"; 7 | }else{ 8 | amdify = "define(['./zepto'], function(){\n" + origin + "\n});\n"; 9 | } 10 | 11 | exports.log(file); 12 | exports.file.write(file, amdify); 13 | }) 14 | }; -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pro", 3 | "version": "0.0.0", 4 | "homepage": "https://github.com/AlloyTeam/Pro", 5 | "authors": [ 6 | "yuanyan " 7 | ], 8 | "description": "Framework for mobile platform.", 9 | "keywords": [ 10 | "mobile" 11 | ], 12 | "license": "MIT", 13 | "ignore": [ 14 | "**/.*", 15 | "node_modules", 16 | "bower_components", 17 | "doc", 18 | "demo", 19 | "task", 20 | "vendor", 21 | "package.json", 22 | "Modfile.js", 23 | "*.md" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /doc/vendor/prettify/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#999}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:teal}.atv{color:#d14}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} -------------------------------------------------------------------------------- /js/os.js: -------------------------------------------------------------------------------- 1 | define(['./zepto'], function(){ 2 | var ua = navigator.userAgent.toLowerCase(); 3 | function platform (os){ 4 | var ver = ('' + (new RegExp(os + '(\\d+((\\.|_)\\d+)*)').exec(ua) || [,0])[1]).replace(/_/g, '.'); 5 | // undefined < 3 === false, but null < 3 === true 6 | return parseFloat(ver) || undefined; 7 | } 8 | 9 | $.os = { 10 | // iPad UA contains 'cpu os', and iPod/iPhone UA contains 'iphone os' 11 | ios: platform('os '), 12 | // WTF? ZTE UserAgent: ZTEU880E_TD/1.0 Linux/2.6.35 Android/2.3 Release/12.15.2011 Browser/AppleWebKit533.1 FlyFlow/2.4 baidubrowser/042_1.8.4.2_dio 13 | android: platform('android[/ ]') 14 | }; 15 | }); 16 | -------------------------------------------------------------------------------- /js/transition.js: -------------------------------------------------------------------------------- 1 | define(['./zepto'], function(){ 2 | 3 | // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 4 | // ============================================================ 5 | 6 | function transitionEnd() { 7 | var el = document.createElement('div'); 8 | 9 | var transEndEventNames = { 10 | 'WebkitTransition' : 'webkitTransitionEnd', 11 | 'transition' : 'transitionend' 12 | }; 13 | 14 | for (var name in transEndEventNames) { 15 | if (el.style[name] !== undefined) { 16 | return { end: transEndEventNames[name] } 17 | } 18 | } 19 | } 20 | 21 | // http://blog.alexmaccaw.com/css-transitions 22 | $.fn.emulateTransitionEnd = function (duration) { 23 | var called = false, $el = this; 24 | $(this).one($.support.transition.end, function () { called = true }); 25 | var callback = function () { if (!called) $($el).trigger($.support.transition.end) }; 26 | setTimeout(callback, duration); 27 | return this 28 | }; 29 | 30 | $.support.transition = transitionEnd() 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /js/debounce.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Debounces a function by the given threshold. 3 | * @method debounce(fn, wait, [ immediate || true ]) 4 | * @param {Function} function to wrap 5 | * @param {Number} timeout in ms (`100`) 6 | * @param {Boolean} whether to execute at the beginning (`true`) 7 | * @example 8 | * 9 | * window.onresize = debounce(resize, 200); 10 | * function resize(e) { 11 | * console.log('height', window.innerHeight); 12 | * console.log('width', window.innerWidth); 13 | * } 14 | * 15 | */ 16 | define(['./zepto'], function(){ 17 | 18 | $.debounce = function (func, threshold, execAsap){ 19 | var timeout; 20 | if (false !== execAsap) execAsap = true; 21 | 22 | return function debounced(){ 23 | var obj = this, args = arguments; 24 | 25 | function delayed () { 26 | if (!execAsap) { 27 | func.apply(obj, args); 28 | } 29 | timeout = null; 30 | } 31 | 32 | if (timeout) { 33 | clearTimeout(timeout); 34 | } else if (execAsap) { 35 | func.apply(obj, args); 36 | } 37 | 38 | timeout = setTimeout(delayed, threshold || 100); 39 | }; 40 | } 41 | }); 42 | -------------------------------------------------------------------------------- /doc/vendor/zepto/dimensions.js: -------------------------------------------------------------------------------- 1 | define(['../../../js/pro'], function () { 2 | var ioDim = function(dimension, includeBorder) { 3 | return function (includeMargin) { 4 | var sides, size, elem; 5 | if (this) { 6 | elem = this; 7 | size = elem[dimension](); 8 | sides = { 9 | width: ["left", "right"], 10 | height: ["top", "bottom"] 11 | }; 12 | sides[dimension].forEach(function(side) { 13 | size += parseInt(elem.css("padding-" + side), 10); 14 | if (includeBorder) { 15 | size += parseInt(elem.css("border-" + side + "-width"), 10); 16 | } 17 | if (includeMargin) { 18 | size += parseInt(elem.css("margin-" + side), 10); 19 | } 20 | }); 21 | return size; 22 | } else { 23 | return null; 24 | } 25 | } 26 | }; 27 | ["width", "height"].forEach(function(dimension) { 28 | var Dimension = dimension.substr(0,1).toUpperCase() + dimension.substr(1); 29 | $.fn["inner" + Dimension] = ioDim(dimension, false); 30 | $.fn["outer" + Dimension] = ioDim(dimension, true); 31 | }); 32 | }); -------------------------------------------------------------------------------- /js/requestAnimationFrame.js: -------------------------------------------------------------------------------- 1 | define(function(){ 2 | // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 3 | // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating 4 | 5 | // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel 6 | 7 | // MIT license 8 | (function() { 9 | var lastTime = 0; 10 | var vendors = ['ms', 'moz', 'webkit', 'o']; 11 | for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 12 | window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 13 | window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] 14 | || window[vendors[x]+'CancelRequestAnimationFrame']; 15 | } 16 | 17 | if (!window.requestAnimationFrame) 18 | window.requestAnimationFrame = function(callback, element) { 19 | var currTime = new Date().getTime(); 20 | var timeToCall = Math.max(0, 16 - (currTime - lastTime)); 21 | var id = window.setTimeout(function() { callback(currTime + timeToCall); }, 22 | timeToCall); 23 | lastTime = currTime + timeToCall; 24 | return id; 25 | }; 26 | 27 | if (!window.cancelAnimationFrame) 28 | window.cancelAnimationFrame = function(id) { 29 | clearTimeout(id); 30 | }; 31 | }()); 32 | }); 33 | 34 | -------------------------------------------------------------------------------- /Modfile.js: -------------------------------------------------------------------------------- 1 | // More info about Modfile at https://github.com/modulejs/modjs/ 2 | 3 | module.exports = { 4 | version: ">=0.4.3", 5 | plugins: { 6 | amdify: './task/amdify' 7 | }, 8 | tasks: { 9 | server: { 10 | port: 3000 11 | }, 12 | download: { 13 | options: { 14 | dest: "js/" 15 | }, 16 | zepto: { 17 | src: "http://rawgithub.com/madrobby/zepto/master/src/zepto.js" 18 | }, 19 | event: { 20 | src: "http://rawgithub.com/madrobby/zepto/master/src/event.js" 21 | }, 22 | ajax: { 23 | src: "http://rawgithub.com/madrobby/zepto/master/src/ajax.js" 24 | }, 25 | data: { 26 | src: "http://rawgithub.com/madrobby/zepto/master/src/data.js" 27 | }, 28 | touch: { 29 | src: "http://rawgithub.com/madrobby/zepto/master/src/touch.js" 30 | }, 31 | requirejs: { 32 | src: "http://requirejs.org/docs/release/2.1.10/comments/require.js", 33 | dest: 'vendor/requirejs/' 34 | }, 35 | 'requirejs-tmpl': { 36 | src: "http://rawgithub.com/modulejs/requirejs-tmpl/master/tmpl.js" 37 | } 38 | }, 39 | amdify: { 40 | src: "js/{zepto,event,ajax,data,touch}.js" 41 | } 42 | }, 43 | targets: { 44 | vendor: ["download", "amdify"] 45 | } 46 | }; -------------------------------------------------------------------------------- /js/fixed.js: -------------------------------------------------------------------------------- 1 | define(['./os', './event'], function(){ 2 | 3 | var os = $.os; 4 | // Why not use feature detecting? It's performance care and we already know only the iOS 4.3 not support fixed 5 | $.support.positionFixed = !(os.ios < 5); 6 | 7 | $.fn.emulateFixed = function (options) { 8 | var $this = $(this); 9 | if ($this.attr('isFixed') || $.support.positionFixed) return this; 10 | 11 | return this.each(function() { 12 | var $el = $(this); 13 | $el.attr('isFixed', true); 14 | 15 | var styles = $.extend($el.css(['top', 'left', 'bottom', 'right']), options || {}); 16 | $.each(styles, function(k, v) { 17 | styles[k] = parseFloat(v) 18 | }); 19 | 20 | function positionFixed() { 21 | var properties = { 22 | position: 'absolute' 23 | }; 24 | 25 | if(styles.left == 0 && styles.right == 0) { 26 | properties.left = 0; 27 | properties.width = '100%'; 28 | }else{ 29 | properties.left = isNaN(styles.right) ? (styles.left || 0): document.body.offsetWidth - $el.width() - styles.right; 30 | } 31 | 32 | if(styles.top === 0 && styles.bottom === 0) { 33 | properties.height = '100%'; 34 | } 35 | 36 | properties.top = window.pageYOffset + ( isNaN(styles.bottom) ? (styles.top || 0): window.innerHeight - $el.height() - styles.bottom ); 37 | 38 | $el.css(properties); 39 | } 40 | 41 | positionFixed(); 42 | // TODO: events debounce 43 | $(window).on('scroll.fixed', positionFixed); 44 | $(window).on('resize.fixed', positionFixed); 45 | }) 46 | }; 47 | 48 | // TODO: how to disable emulate fixed 49 | }); 50 | -------------------------------------------------------------------------------- /js/scrollfix.js: -------------------------------------------------------------------------------- 1 | // https://developers.google.com/mobile/articles/webapp_fixed_ui 2 | // https://github.com/filamentgroup/Overthrow/ 3 | // http://bradfrostweb.com/blog/mobile/fixed-position/ 4 | 5 | define(['./os', './event'], function(){ 6 | 7 | var os = $.os; 8 | function scrollFix() { 9 | 10 | $('.js-no-bounce').on('touchmove', function(event){ 11 | event.preventDefault(); 12 | }); 13 | 14 | var $page = $('.ui-page'); 15 | var $content = $('.ui-page-content', $page); 16 | if(!$content[0] || !$page[0]) return; 17 | 18 | // Variables to track inputs 19 | var startTopScroll; 20 | 21 | // Handle the start of interactions 22 | $(document).on('touchstart', '.ui-page', function(event){ 23 | var page = event.currentTarget; 24 | startTopScroll = page.scrollTop; 25 | 26 | if(startTopScroll <= 0) 27 | page.scrollTop = 1; 28 | 29 | if(startTopScroll + page.offsetHeight >= page.scrollHeight) 30 | page.scrollTop = page.scrollHeight - page.offsetHeight - 1; 31 | 32 | }).on('touchmove', '.ui-page', function(event){ 33 | var page = event.currentTarget; 34 | // TODO cache element select 35 | var content = page.querySelector('.ui-page-content'); 36 | // Offset value have include content and border 37 | if( content.offsetHeight < page.clientHeight || 38 | content.offsetWidth < page.clientWidth){ 39 | // your element have overflow 40 | return event.preventDefault(); 41 | } 42 | }) 43 | } 44 | 45 | // Add ScrollFix only for iOS 46 | if(os.ios >= 5 ) { 47 | scrollFix(); 48 | }else{ 49 | var html = document.documentElement; 50 | html.className = html.className + ' ' + 'js-no-overflow-scrolling'; 51 | } 52 | }); 53 | -------------------------------------------------------------------------------- /js/tab.js: -------------------------------------------------------------------------------- 1 | define(['./event', './data', './touch'], function(){ 2 | 3 | var activeClass = 'js-active'; 4 | var showEvent = 'show:tab'; 5 | var shownEvent = 'shown:tab'; 6 | 7 | function Tab(element) { 8 | this.element = $(element) 9 | } 10 | 11 | Tab.prototype.show = function () { 12 | var $this = this.element; 13 | if ($this.hasClass(activeClass)) return; 14 | 15 | var $parent = $this.parent(); 16 | var selector = $this.data('target'); 17 | var previous = $parent.find('.' + activeClass)[0]; 18 | var e = $.Event(showEvent, { 19 | relatedTarget: previous 20 | }); 21 | 22 | $this.trigger(e); 23 | 24 | if (e.isDefaultPrevented()) return; 25 | 26 | var $target = $(selector); 27 | 28 | this.activate($this, $parent); 29 | this.activate($target, $target.parent(), function () { 30 | $this.trigger({ 31 | type: shownEvent, 32 | relatedTarget: previous 33 | }) 34 | }) 35 | }; 36 | 37 | Tab.prototype.activate = function ($element, $container, callback) { 38 | // Why use helper class? js-active class is also used in inner container. 39 | var helperClass = 'zepto-tab-' + Date.now(); 40 | $container.addClass(helperClass); 41 | var $active = $('.' + helperClass + '>.'+ activeClass, $container); 42 | $container.removeClass(helperClass); 43 | $active.removeClass(activeClass); 44 | $element.addClass(activeClass); 45 | callback && callback() 46 | }; 47 | 48 | $.Tab = Tab; 49 | 50 | $.fn.tab = function ( option ) { 51 | return this.each(function () { 52 | var $this = $(this); 53 | var data = $this.data('tab'); 54 | 55 | if (!data) $this.data('tab', (data = new Tab(this))); 56 | if (typeof option == 'string') data[option]() 57 | }) 58 | }; 59 | 60 | $(document).on('tap.tab.data-api', '[data-toggle="tab"]', function (e) { 61 | e.preventDefault(); 62 | $(this).tab('show'); 63 | }) 64 | }); 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Pro 2 | === 3 | > Framework for mobile platform. 4 | 5 | ## Features 6 | * Mobile Only 7 | * High performance 8 | * Accessibility Support 9 | * Custom build support 10 | 11 | ## Screenshot 12 | 13 | ![screenshot1](https://f.cloud.github.com/assets/677114/2280325/a3db2e1e-9f87-11e3-85bd-6ca4e58a433e.png) 14 | 15 | ![screenshot2](https://f.cloud.github.com/assets/677114/2280329/a796fb1e-9f87-11e3-86fe-9f88657827c1.png) 16 | 17 | ## Demo 18 | 19 | Scan below QR code or visit [http://url.cn/NDKvRr](http://url.cn/NDKvRr) on your handset. 20 | 21 | ![qrcode](https://f.cloud.github.com/assets/677114/2168855/86661b22-954c-11e3-951d-ffe40ad41d16.png) 22 | 23 | ## Basic template 24 | 25 | Copy the HTML below to begin working with a minimal PRO document. 26 | 27 | ```html 28 | 29 | 30 | 31 | 32 | PRO Template 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 | PRO Template 43 |
44 | 45 | 51 | 52 | 53 |
54 |
55 |

Hello, world!

56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 | ``` 64 | ## Platform support 65 | 66 | Current version have been tested on the below platforms: 67 | 68 | * iOS 4.0-7.0 69 | * iOS 4.3 (iPad 1) 70 | * iOS 5.1 (iPhone 4) 71 | * iOS 6.1 (iPhone 4S) 72 | * iOS 7.0 (iPhone 5) 73 | * Android 2.3-4.4 74 | * Android 2.3 (ZTE) 75 | * Android 4.0 (HTC Rhyme S510B) 76 | * Android 4.1 (LG Optimus G) 77 | * Android 4.2 (Sony Xperia Z) 78 | * Android 4.3 (Nexus 4) 79 | * Android 4.4 (Nexus 4) 80 | 81 | ## Built with Pro 82 | 83 | * Mobile QQ 84 | -------------------------------------------------------------------------------- /js/data.js: -------------------------------------------------------------------------------- 1 | define(['./zepto'], function(){ 2 | // Zepto.js 3 | // (c) 2010-2014 Thomas Fuchs 4 | // Zepto.js may be freely distributed under the MIT license. 5 | 6 | // The following code is heavily inspired by jQuery's $.fn.data() 7 | 8 | ;(function($){ 9 | var data = {}, dataAttr = $.fn.data, camelize = $.camelCase, 10 | exp = $.expando = 'Zepto' + (+new Date()), emptyArray = [] 11 | 12 | // Get value from node: 13 | // 1. first try key as given, 14 | // 2. then try camelized key, 15 | // 3. fall back to reading "data-*" attribute. 16 | function getData(node, name) { 17 | var id = node[exp], store = id && data[id] 18 | if (name === undefined) return store || setData(node) 19 | else { 20 | if (store) { 21 | if (name in store) return store[name] 22 | var camelName = camelize(name) 23 | if (camelName in store) return store[camelName] 24 | } 25 | return dataAttr.call($(node), name) 26 | } 27 | } 28 | 29 | // Store value under camelized key on node 30 | function setData(node, name, value) { 31 | var id = node[exp] || (node[exp] = ++$.uuid), 32 | store = data[id] || (data[id] = attributeData(node)) 33 | if (name !== undefined) store[camelize(name)] = value 34 | return store 35 | } 36 | 37 | // Read all "data-*" attributes from a node 38 | function attributeData(node) { 39 | var store = {} 40 | $.each(node.attributes || emptyArray, function(i, attr){ 41 | if (attr.name.indexOf('data-') == 0) 42 | store[camelize(attr.name.replace('data-', ''))] = 43 | $.zepto.deserializeValue(attr.value) 44 | }) 45 | return store 46 | } 47 | 48 | $.fn.data = function(name, value) { 49 | return value === undefined ? 50 | // set multiple values via object 51 | $.isPlainObject(name) ? 52 | this.each(function(i, node){ 53 | $.each(name, function(key, value){ setData(node, key, value) }) 54 | }) : 55 | // get value from first element 56 | this.length == 0 ? undefined : getData(this[0], name) : 57 | // set value on all elements 58 | this.each(function(){ setData(this, name, value) }) 59 | } 60 | 61 | $.fn.removeData = function(names) { 62 | if (typeof names == 'string') names = names.split(/\s+/) 63 | return this.each(function(){ 64 | var id = this[exp], store = id && data[id] 65 | if (store) $.each(names || store, function(key){ 66 | delete store[names ? camelize(this) : key] 67 | }) 68 | }) 69 | } 70 | 71 | // Generate extended `remove` and `empty` functions 72 | ;['remove', 'empty'].forEach(function(methodName){ 73 | var origFn = $.fn[methodName] 74 | $.fn[methodName] = function() { 75 | var elements = this.find('*') 76 | if (methodName === 'remove') elements = elements.add(this) 77 | elements.removeData() 78 | return origFn.call(this) 79 | } 80 | }) 81 | })(Zepto) 82 | 83 | }); 84 | -------------------------------------------------------------------------------- /doc/md/getting-started.md: -------------------------------------------------------------------------------- 1 |
2 |

Getting started

3 |

An overview of Pro, how to download and use, basic templates.

4 |
5 | 6 |

Download

7 | 8 |

Pro has a few easy ways to quickly get started, each one appealing to a different skill level and use case. Read through to see what suits your particular needs.

9 | 10 |

Download Pro

11 |

Download Pro Compiled and minified CSS, JavaScript.

12 | 13 |

Download Source Source CSS, JavaScript.

14 | 15 |

Install with Bower

16 |

Install and manage Pro's CSS, JavaScript, using Bower.

17 | 18 | ```bash 19 | bower install pro 20 | ``` 21 | 22 |

Setup

23 | 24 | 3 steps for structuring your Pro application 25 | 26 |
    27 |
  1. 28 |

    Set viewport meta

    29 |

    <name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">

    30 |
  2. 31 |
  3. 32 |

    Set fixed bars

    33 |

    All fixed bars (.ui-top-bar, .ui-bottom-bar) should always be the first thing in the body of the page. This is really important!

    34 |
  4. 35 |
  5. 36 |

    Put content into .ui-page

    37 |

    Anything that's not a -bar should be put in a div with the class ui-page. Put this div after the bars in the body tag.

    38 |
  6. 39 |
40 | 41 |

Basic template

42 | 43 | Start with this basic HTML template, or modify it, adapting them to suit your needs. 44 | 45 | Copy the HTML below to begin working with a minimal Pro document. 46 | 47 | ```html 48 | 49 | 50 | 51 | 52 | Pro Template 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
62 | PRO Template 63 |
64 | 65 | 71 | 72 | 73 |
74 |
75 |

Hello, world!

76 |
77 |
78 | 79 | 80 | 81 | 82 | 83 | ``` 84 | 85 | -------------------------------------------------------------------------------- /demo/js/demo.js: -------------------------------------------------------------------------------- 1 | require([ 2 | '../../js/pro' 3 | ], function(){ 4 | 5 | // CountUp 6 | $('#countup').countable('start'); 7 | 8 | // Spinner 9 | $('[data-spinner]').each(function () { 10 | var $this = $(this); 11 | $this.spinner('show') 12 | }); 13 | 14 | $('#show-body-spinner').on('tap', function(){ 15 | //var $this = $(this); 16 | //var delay = $this.data('delay') || 6000; 17 | 18 | $('body').spinner('show'); 19 | //setTimeout(function(){ 20 | // $('body').spinner('hide'); 21 | //}, delay); 22 | }); 23 | 24 | $('#hide-body-spinner').on('tap', function(){ 25 | $('body').spinner('hide'); 26 | }); 27 | 28 | function initSearch(){ 29 | var $search = $('#my-search'); 30 | var $input = $('#my-search-input'); 31 | $input.on('focus', function(){ 32 | $search.addClass('js-focus') 33 | }).on('input', function(){ 34 | if($input[0].value){ 35 | $search.addClass('js-input') 36 | }else{ 37 | $search.removeClass('js-input') 38 | } 39 | }); 40 | 41 | $('#my-search-reset').on('tap', function(){ 42 | $input[0].value = ''; 43 | $search.removeClass('js-input'); 44 | $input[0].focus(); 45 | }); 46 | 47 | $('#my-search-cancel').on('touchstart', function(evt){ 48 | $input[0].value = ''; 49 | $search.removeClass('js-input'); 50 | $search.removeClass('js-focus'); 51 | 52 | document.activeElement.blur(); 53 | $input[0].blur(); 54 | 55 | evt.stopPropagation(); 56 | evt.preventDefault(); 57 | }); 58 | } 59 | 60 | initSearch(); 61 | 62 | // Tab 63 | $('[data-toggle="tab"]').on('shown:tab', function (e) { 64 | 65 | var target = e.target // activated tab 66 | var relatedTarget = e.relatedTarget // previous tab 67 | 68 | var tab = target.innerText.trim().toLowerCase(); 69 | 70 | if(target.inited) return; 71 | 72 | if(tab == 'counter'){ 73 | 74 | $('[data-countable]').each(function () { 75 | var $this = $(this); 76 | $this.countable('start') 77 | }); 78 | 79 | }else if(tab == 'spinner'){ 80 | 81 | 82 | }else if(tab == 'carousel'){ 83 | 84 | $('[data-ride="carousel"]').each(function () { 85 | var $this = $(this); 86 | $this.carousel($this.data()) 87 | }); 88 | }else if(tab == 'deleter'){ 89 | 90 | $('.my-deletable').deletable() 91 | 92 | }else if(tab == 'lazyload'){ 93 | $('[data-lazy]').lazyload({ 94 | container: $.os.ios > 5? $('#page5-container'): window 95 | }); 96 | } 97 | 98 | target.inited = true; 99 | 100 | }); 101 | 102 | }); 103 | -------------------------------------------------------------------------------- /js/countable.js: -------------------------------------------------------------------------------- 1 | define(['./data', './requestAnimationFrame'], function(){ 2 | 3 | function Counter(element, options) { 4 | 5 | this.$element = $(element); 6 | this.options = options; 7 | 8 | this.frameVal = this.from = Number(options.from); 9 | this.to = Number(options.to); 10 | this.duration = options.duration; 11 | this.decimals = Math.max(0, options.decimals); 12 | this.dec = Math.pow(10, options.decimals); 13 | this.startTime = null; 14 | 15 | var self = this; 16 | 17 | this.count = function(timestamp) { 18 | var from = self.from; 19 | var to = self.to; 20 | var duration = self.duration; 21 | var countDown = from > to; 22 | 23 | if (self.startTime === null) self.startTime = timestamp; 24 | 25 | var progress = timestamp - self.startTime; 26 | 27 | // to ease or not to ease 28 | if (countDown) { 29 | var i = self.easeOutExpo(progress, 0, from - to, duration); 30 | self.frameVal = from - i; 31 | } else { 32 | self.frameVal = self.easeOutExpo(progress, from, to - from, duration); 33 | } 34 | 35 | // decimal 36 | self.frameVal = Math.round(self.frameVal*self.dec)/self.dec; 37 | 38 | // don't go past endVal since progress can exceed duration in the last frame 39 | if (countDown) { 40 | self.frameVal = (self.frameVal < to) ? to : self.frameVal; 41 | } else { 42 | self.frameVal = (self.frameVal > to) ? to : self.frameVal; 43 | } 44 | 45 | // format and print value 46 | var val = self.frameVal.toFixed(self.decimals) 47 | if(self.options.commas){ 48 | val = self.addCommas(val) 49 | } 50 | self.$element.html(val); 51 | 52 | // whether to continue 53 | if (progress < duration) { 54 | requestAnimationFrame(self.count); 55 | } else { 56 | if (self.onComplete != null) self.onComplete(); 57 | } 58 | } 59 | } 60 | 61 | Counter.DEFAULTS = { 62 | commas: false, 63 | decimals: 0, // number of decimal places in number, default 0 64 | duration: 1000 // duration in ms 65 | }; 66 | 67 | Counter.prototype.start = function(callback) { 68 | this.onComplete = callback; 69 | // make sure values are valid 70 | if (!isNaN(this.to) && !isNaN(this.from)) { 71 | requestAnimationFrame(this.count); 72 | } else { 73 | this.$element.html('--'); 74 | console.log('Error: from or to is not a number'); 75 | } 76 | return false; 77 | }; 78 | 79 | // Robert Penner's easeOutExpo 80 | Counter.prototype.easeOutExpo = function(t, b, c, d) { 81 | return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b; 82 | }; 83 | 84 | Counter.prototype.reset = function(){ 85 | this.$element.html(0); 86 | }; 87 | 88 | Counter.prototype.addCommas = function(nStr) { 89 | nStr += ''; 90 | var x, x1, x2, rgx; 91 | x = nStr.split('.'); 92 | x1 = x[0]; 93 | x2 = x.length > 1 ? '.' + x[1] : ''; 94 | rgx = /(\d+)(\d{3})/; 95 | while (rgx.test(x1)) { 96 | x1 = x1.replace(rgx, '$1' + ',' + '$2'); 97 | } 98 | return x1 + x2; 99 | }; 100 | 101 | $.Counter = Counter; 102 | 103 | $.fn.countable = function (option) { 104 | 105 | return $(this).each(function () { 106 | var $this = $(this); 107 | var data = $this.data('counter'); 108 | var options = $.extend({}, Counter.DEFAULTS, $this.data(), typeof option == 'object' && option); 109 | 110 | if (!data) { 111 | data = new Counter(this, options); 112 | $this.data('counter', data) 113 | } 114 | if (typeof option == 'string') data[option](); 115 | else if (options.show) data.show() 116 | }); 117 | }; 118 | 119 | }); 120 | -------------------------------------------------------------------------------- /js/lazyload.js: -------------------------------------------------------------------------------- 1 | define(['./debounce', './event'], function () { 2 | // TODO: skip load invisible element 3 | var debounce = $.debounce; 4 | // cache computing rect avoid re-layout 5 | var cacheId = 0; 6 | var boudingClientRectCache = {}; 7 | 8 | function LazyLoad(elements, options) { 9 | this.elements = elements; 10 | this.options = options; 11 | this.handler = options.handler; 12 | this.container = options.container; 13 | this.$container = $(options.container); 14 | this.onScroll = debounce($.proxy(this.onScroll, this), options.defer, false); 15 | this.onResize = debounce($.proxy(this.onResize, this), options.defer, false) 16 | } 17 | 18 | LazyLoad.DEFAULTS = { 19 | start: true, 20 | attribute: 'data-lazy', 21 | defer: 300, 22 | handler: function (el, lazyData){ 23 | el.setAttribute("src", lazyData); 24 | }, 25 | container: window // container should with -webkit-overflow-scrolling: touch style 26 | }; 27 | 28 | LazyLoad.prototype = { 29 | start: function(){ 30 | this.status = 1; 31 | setTimeout(function(){ 32 | if(!this.inited){ 33 | this.inited = true; 34 | this.containerHeight = this.getContainerHeight(); 35 | $(window).on('resize', this.onResize); 36 | this.$container.on('scroll', this.onScroll); 37 | } 38 | 39 | this.onScroll(); 40 | }.bind(this), this.options.defer) 41 | }, 42 | 43 | add: function(elements){ 44 | elements = $(elements).get(); 45 | this.elements = this.elements.concat(elements) 46 | }, 47 | 48 | getContainerHeight: function(){ 49 | var container = this.container; 50 | // if container is window object 51 | if(container.document){ 52 | return window.innerHeight; 53 | }else{ 54 | var style = window.getComputedStyle(container); 55 | // that equal container.offsetHeight 56 | return parseInt(style.height) + parseInt(style.paddingTop) + parseInt(style.paddingBottom) + parseInt(style.marginTop) + parseInt(style.marginBottom); 57 | } 58 | }, 59 | 60 | onResize: function(evt){ 61 | if(!this.status) return; 62 | this.containerHeight = this.getContainerHeight(); 63 | boudingClientRectCache = {}; 64 | this.onScroll(); 65 | }, 66 | 67 | onScroll: function (evt){ 68 | if(!this.status) return; 69 | var elements = this.elements; 70 | var el; 71 | var lazyData; 72 | for(var i=0, l=elements.length; i< l; i++){ 73 | el = elements[i]; 74 | el.cacheId = el.cacheId || ++cacheId; 75 | if (el && this.elementInViewport(el)) { 76 | 77 | if(!(lazyData = el.lazyData)){ 78 | lazyData = el.getAttribute(this.options.attribute); 79 | // cache value 80 | el.lazyData = lazyData; 81 | } 82 | 83 | if (lazyData) this.handler(el, lazyData); 84 | elements.splice(i, 1, null); 85 | } 86 | } 87 | 88 | this.elements = elements.filter(function(v){return v}); 89 | }, 90 | 91 | elementInViewport: function (el) { 92 | var container = this.container; 93 | var id = el.cacheId; // cached by id 94 | var rect = boudingClientRectCache[id] || $(el).offset(); 95 | var scrollY = this.containerHeight; 96 | 97 | if(container.document){ 98 | scrollY += (container.scrollY || container.pageYOffset); 99 | }else{ 100 | scrollY += (container.scrollTop || window.scrollY ) + (container.offsetTop || window.pageYOffset); 101 | } 102 | 103 | boudingClientRectCache[id] = rect; 104 | return (rect.top >= 0 && rect.top <= scrollY ) || (rect.bottom >= 0 && rect.bottom <= scrollY); 105 | }, 106 | 107 | pause: function(){ 108 | this.status = 0 109 | }, 110 | 111 | destory: function(){ 112 | this.$container.off('scroll', this.onScroll); 113 | $(window).off('resize', this.onResize); 114 | boudingClientRectCache = {}; 115 | this.status = 0; 116 | this.elements = null; 117 | this.container = null; 118 | this.$container = null; 119 | } 120 | }; 121 | 122 | $.LazyLoad = LazyLoad; 123 | 124 | $.fn.lazyload = function(option) { 125 | var elements = this.get(); 126 | var options = $.extend({}, LazyLoad.DEFAULTS, typeof option == 'object' && option); 127 | 128 | var $container = $(options.container); 129 | // assume it's a origin node 130 | options.container = $container[0]; 131 | var data = $container.data('lazyload'); 132 | if (!data) { 133 | data = new LazyLoad(elements, options); 134 | $container.data('lazyload', data) 135 | } 136 | if (typeof option == 'string') data[option](); 137 | else if (options.start) data.start(); 138 | 139 | return data; 140 | }; 141 | }); 142 | -------------------------------------------------------------------------------- /doc/js/doc.js: -------------------------------------------------------------------------------- 1 | require([ 2 | '../vendor/zepto/dimensions' 3 | ], function(){ 4 | 5 | var windowWidth; 6 | var windowHeight; 7 | var pageHeight; 8 | var contentPadding; 9 | var footerHeight; 10 | var noticeBanner; 11 | var componentsList; 12 | var navComponentLinks; 13 | var contentSection; 14 | var currentActive; 15 | var topCache; 16 | var eventListeners; 17 | 18 | var $doc = $(document); 19 | var $win = $(window); 20 | var $body = $(document.body); 21 | var $iphone = $('.iphone'); 22 | 23 | (function main(){ 24 | prettyPrintExample(); 25 | 26 | $win.on('ready resize', initialize); 27 | 28 | // TODO FingerBlast会导致checkbox无法点击 29 | $win.on('ready', function () { 30 | new FingerBlast('.iphone-content'); 31 | }); 32 | 33 | // Spinner 34 | $doc.on('tap', '[data-toggle="spinner"]', function () { 35 | var $this = $('.ui-app'); 36 | $this.spinner('toggle') 37 | }); 38 | 39 | })(); 40 | 41 | function prettyPrintExample(){ 42 | var componentExample = $('.component-example'); 43 | 44 | componentExample.each(function(index, node){ 45 | var $node = $(node); 46 | var preStart = '
';
 47 |             var preEnd = '
'; 48 | var preContent = $node.html().replace(/&/g, '&').replace(//g, ">").replace(/"/g, """).replace(/'/g, "'").trim(); 49 | $node.after( preStart + preContent + preEnd); 50 | }); 51 | 52 | prettyPrint(); 53 | } 54 | 55 | function initialize() { 56 | currentActive = 0; 57 | topCache = []; 58 | noticeBanner = $('.notice-banner'); 59 | navComponentLinks = $('.nav-components-link'); 60 | componentsList = $('.components-list'); 61 | contentSection = $('.component'); 62 | topCache = contentSection.map(function () { return $(this).offset().top }); 63 | windowHeight = $(window).height() / 3; 64 | pageHeight = $(document).height(); 65 | contentPadding = parseInt($('.doc-content').css('padding-bottom')); 66 | footerHeight = $('.doc-footer').outerHeight(false); 67 | 68 | $iphone.initialLeft = $iphone.offset().left; 69 | $iphone.initialTop = $iphone.initialTop || $iphone.offset().top; 70 | $iphone.dockingOffset = ($(window).height() + 20 + $('.doc-masthead').height() - $iphone.height())/2; 71 | 72 | checkDesktopContent(); 73 | calculateScroll(); 74 | 75 | if (!eventListeners) addEventListeners(); 76 | } 77 | 78 | function addEventListeners() { 79 | eventListeners = true; 80 | 81 | noticeBanner.on('click', function () { 82 | $(this).hide(); 83 | }); 84 | 85 | // TODO 会导致checkbox无法点击 86 | $iphone.on('click', function (e) { 87 | e.preventDefault(); 88 | }); 89 | 90 | navComponentLinks.click(function(e) { 91 | e.stopPropagation(); 92 | e.preventDefault(); 93 | // componentsList.toggleClass('active'); 94 | componentsList.removeClass('active'); 95 | $(e.target.parentNode.children[1]).toggleClass('active'); 96 | }); 97 | 98 | $doc.on('click', function () { 99 | componentsList.removeClass('active'); 100 | }); 101 | 102 | $win.on('scroll', calculateScroll); 103 | 104 | } 105 | 106 | function checkDesktopContent() { 107 | windowWidth = $(window).width(); 108 | if (windowWidth <= 768) { 109 | var content = $('.content'); 110 | if (content.length > 1) { 111 | $(content[0]).remove() 112 | } 113 | } 114 | } 115 | 116 | function calculateScroll() { 117 | // if small screen don't worry about this 118 | if (windowWidth <= 768) return 119 | 120 | // Save scrollTop value 121 | var contentSectionItem; 122 | var currentTop = $win.scrollTop(); 123 | 124 | // If page is scrolled to bottom near footers 125 | if(pageHeight - currentTop < footerHeight + contentPadding + 1400) { 126 | $iphone[0].className = "iphone iphone-bottom"; 127 | $iphone[0].setAttribute('style','') 128 | } else if(($iphone.initialTop - currentTop) <= $iphone.dockingOffset) { 129 | $iphone[0].className = "iphone iphone-fixed"; 130 | $iphone.css({top: $iphone.dockingOffset}) 131 | } else { 132 | $iphone[0].className = "iphone"; 133 | $iphone[0].setAttribute('style','') 134 | } 135 | 136 | // Injection of components into phone 137 | for (var l = contentSection.length; l--;) { 138 | if ((topCache[l] - currentTop) < windowHeight) { 139 | if (currentActive == l) return; 140 | currentActive = l; 141 | $body.find('.component.active').removeClass('active'); 142 | contentSectionItem = $(contentSection[l]); 143 | contentSectionItem.addClass('active'); 144 | if(contentSectionItem.attr('id')) { 145 | $iphone.attr("id", contentSectionItem.attr('id') + "InPhone"); 146 | } else { 147 | $iphone.attr("id", "") 148 | } 149 | if (!contentSectionItem.hasClass('informational')) { 150 | updateContent(contentSectionItem.find('.prettyprint').not('.js').text()) 151 | } 152 | break 153 | } 154 | } 155 | 156 | function updateContent(content) { 157 | $('#iwindow').html(content); 158 | } 159 | } 160 | 161 | }); 162 | -------------------------------------------------------------------------------- /js/deletable.js: -------------------------------------------------------------------------------- 1 | define(['./event', './data', './requestAnimationFrame'], function () { 2 | 3 | var getTime = Date.now; 4 | 5 | function pos(e) { 6 | // touch event 7 | var touches = e.targetTouches; 8 | if (touches && (touches.length >= 1)) { 9 | return { 10 | x: touches[0].clientX, 11 | y: touches[0].clientY 12 | }; 13 | } 14 | } 15 | 16 | function Deleter(element, options){ 17 | this.$element = $(element); 18 | this.options = options; 19 | // 0 is init state 20 | // 1 is tap state 21 | // 2 is snap left 22 | // 3 is snap right 23 | this._state = 0; 24 | this._pre = {}; // pre position 25 | this._opened = false; 26 | this._offset = 0; 27 | } 28 | 29 | Deleter.DEFAULTS = { 30 | init: true, 31 | // left/right snap value 32 | left: 60, //px 33 | right: 0, 34 | timeConstant: 125 // ms 35 | }; 36 | 37 | Deleter.prototype.init = function(){ 38 | this.$element.on('touchstart', $.proxy(this.start, this)); 39 | this.$element.on('touchmove', $.proxy(this.move, this)); 40 | this.$element.on('touchend', $.proxy(this.end, this)); 41 | this.autoTranslate = $.proxy(this.autoTranslate, this); 42 | }; 43 | 44 | Deleter.prototype.translate = function (x) { 45 | var move = -Math.round(x); 46 | if(move <= -this.options.right) this.$element.css('-webkit-transform', 'translate3d(' + move + 'px, 0, 0)'); 47 | // make the latest offset value 48 | this._offset = x; 49 | }; 50 | 51 | Deleter.prototype.track = function () { 52 | var now = getTime(); 53 | var elapsed = now - this._timestamp; 54 | this._timestamp = now; 55 | 56 | var delta = this._offset - this._frame; 57 | this._frame = this._offset; 58 | 59 | var v = 1000 * delta / (1 + elapsed); 60 | this._speed = 0.8 * v + 0.2 * this._speed; 61 | }; 62 | 63 | Deleter.prototype.autoTranslate = function () { 64 | 65 | var amplitude = this._amplitude; 66 | var target = this._target; 67 | var options = this.options; 68 | var left = options.left; 69 | var right = options.right; 70 | var timeConstant = options.timeConstant; 71 | 72 | var elapsed, delta; 73 | 74 | if (amplitude) { 75 | elapsed = getTime() - this._timestamp; 76 | delta = amplitude * Math.exp(-elapsed / timeConstant); 77 | 78 | var x = target - delta; 79 | // target stop range 80 | if (delta > 4 || delta < -4) { 81 | this.translate(target - delta); 82 | requestAnimationFrame(this.autoTranslate); 83 | }else{ 84 | // translate to ending position 85 | x = Math.round(x) - 5; 86 | this._opened = x <= left && x > right; 87 | this.translate(this._opened? left: right); 88 | } 89 | } 90 | }; 91 | 92 | Deleter.prototype.start = function (e) { 93 | 94 | this._state = 1; 95 | this._pre = pos(e); 96 | this._speed = this._amplitude = 0; 97 | this._frame = this._offset; 98 | this._timestamp = getTime(); 99 | 100 | clearInterval(this._ticker); 101 | this._ticker = setInterval(this.track, 100); 102 | }; 103 | 104 | Deleter.prototype.move = function (e) { 105 | 106 | if (this._state >= 1) { 107 | 108 | var cur = pos(e); 109 | var pre = this._pre; 110 | var deltaX = pre.x - cur.x; 111 | var deltaY = pre.y - cur.y; 112 | 113 | if ( (deltaX > 10 || deltaX < -10) && deltaY < 10 && deltaY > -10 ) { 114 | 115 | if(!this._opened && deltaX < -10){ 116 | this._state = 0; 117 | return; 118 | } 119 | // update pre position 120 | this._pre = cur; 121 | // update state 122 | this._state = deltaX > 0? 2: 3; 123 | // translate element 124 | this.translate(this._offset + deltaX); 125 | 126 | e.preventDefault(); 127 | e.stopPropagation(); 128 | return false; 129 | } 130 | } 131 | }; 132 | 133 | Deleter.prototype.end = function (e) { 134 | clearInterval(this._ticker); 135 | var state = this._state; 136 | 137 | if(state > 0){ 138 | 139 | var offset = this._offset; 140 | var speed = this._speed; 141 | var amplitude = this._amplitude; 142 | var target = offset; 143 | 144 | // compute target value 145 | if (speed > 10 || speed < -10) { 146 | amplitude = 1.2 * speed; 147 | target = offset + amplitude; 148 | } 149 | 150 | var snap = this.options.left; 151 | // tap or snap right 152 | if(this._opened && (state == 1 || state == 3)){ 153 | snap = this.options.right; 154 | } 155 | // snap value could be 0 156 | target = snap? (Math.round(target / snap) * snap) : 0; 157 | target = (target < -snap) ? -snap : (target > snap) ? snap : target; 158 | 159 | this._amplitude = target - offset; 160 | this._target = target; 161 | this._timestamp = getTime(); 162 | 163 | requestAnimationFrame(this.autoTranslate); 164 | } 165 | 166 | // reset state 167 | this._state = 0; 168 | }; 169 | 170 | $.Deleter = Deleter; 171 | 172 | $.fn.deletable = function(option){ 173 | 174 | return this.each(function(){ 175 | 176 | var $this = $(this); 177 | var data = $this.data('deleter'); 178 | var options = $.extend({}, Deleter.DEFAULTS, $this.data(), typeof option == 'object' && option); 179 | 180 | if (!data) { 181 | data = new Deleter(this, options) 182 | $this.data('deleter', data) 183 | } 184 | 185 | if (typeof option == 'string') data[option]() 186 | else if (options.init) data.init() 187 | 188 | }) 189 | } 190 | 191 | }); 192 | -------------------------------------------------------------------------------- /js/spinner.js: -------------------------------------------------------------------------------- 1 | define(['./event', './data'], function(){ 2 | 3 | var animations = {}; /* Cache animation rules */ 4 | var prefix = '-webkit-'; 5 | var ratio = window.devicePixelRatio || 1; 6 | /** 7 | * Insert a new stylesheet to hold the @keyframe rules. 8 | */ 9 | var sheet = (function() { 10 | var $el = $(' 82 | 83 | 84 | 85 |
86 |
87 |
    88 | 89 | 90 |
91 |
92 |
93 |
    94 | 95 | 96 |
97 |
98 |
99 |
    100 | 101 | 102 | 103 | 104 |
105 |
106 |
107 |
    108 | 109 | 110 | 111 | 112 |
113 |
114 |
115 |
    116 | 117 | 118 |
119 |
120 |
121 | 122 | 146 | 147 | 148 |
149 | 150 |
151 | 152 | 153 |
154 | 155 |

156 | 你已累计消费 157 | 0000 158 | 159 |

160 | 161 | 175 | 176 | 179 | 180 | 183 | 184 | 188 | 189 |
190 | 191 |
192 | 193 | 212 |
213 | 214 |
215 |
216 | 217 |
218 | 219 |
220 |
221 |

按钮

222 |

223 | 224 | 225 | 226 | 227 |

228 | 229 |

块级按钮

230 |

231 | 232 | 233 | 234 | 235 |

236 |
237 | 238 |
239 |

图标按钮

240 |

241 | 242 | 243 | 244 |

245 |
246 | 247 |
248 |
249 | 250 |
251 | 252 |
253 | 254 |
255 | 256 |

Dark

257 |

258 | 259 |

260 | 261 |

Light

262 |

263 | 264 |

265 | 266 |

Trigger

267 |

268 | 271 | 272 | 275 |

276 | 277 |
278 | 279 |
280 | 302 |
303 | 304 |
305 |

CountUp

306 |
307 | 0 308 |
309 | 310 |

CountDown

311 |
312 | 9521 313 |
314 |
315 | 316 | 359 | 360 |
361 | 362 |
363 | 364 |
365 | 366 |
367 | 368 |
369 | 370 |

Blue

371 |
372 |
    373 |
  • 列表 1123
  • 374 |
  • 列表 2
  • 375 |
  • 列表 32
  • 376 |
377 |
378 | 379 |

Gray

380 |
381 |
    382 |
  • 列表 1
  • 383 |
  • 列表 2
  • 384 |
  • 列表 31
  • 385 |
386 |
387 | 388 |
389 | 390 |
391 | 392 |

Notify

393 |

394 | 397 |

398 |
399 | 400 |
401 | 402 |

Alert

403 |

404 | 407 | 408 | 411 | 412 | 415 | 416 | 419 | 420 | 423 | 424 | 427 |

428 | 429 |
430 | 431 |
432 |

Action Sheet

433 |

434 | 437 |

438 |
439 | 440 |
441 |
442 | 443 |
444 | 445 |
446 | 447 |
448 | 449 |

Normal

450 | 451 | 458 | 459 |
460 | 461 |
462 | 463 |

Nature

464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 |

Technics

475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 |
485 | 486 |
487 |
488 | 489 | 490 | 491 | 496 | 497 | 502 | 503 | 514 | 515 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Pro - Framework for mobile platform 6 | 7 | 8 | 9 | 10 | 11 | 12 | 92 | 93 | 94 | 95 | 96 | 106 | 107 | 113 | 114 | 115 |
116 |
117 | 118 |
119 |

Getting started

120 |

An overview of Pro, how to download and use, basic templates.

121 |
122 | 123 |

Download

124 | 125 |

Pro has a few easy ways to quickly get started, each one appealing to a different skill level and use case. Read through to see what suits your particular needs.

126 | 127 |

Download Pro

128 | 129 |

Download Pro Compiled and minified CSS, JavaScript.

130 | 131 |

Download Source Source CSS, JavaScript.

132 | 133 |

Install with Bower

134 | 135 |

Install and manage Pro’s CSS, JavaScript, using Bower.

136 | 137 |
bower install pro
138 | 139 |

Setup

140 | 141 |

3 steps for structuring your Pro application

142 | 143 |
    144 |
  1. 145 |

    Set viewport meta

    146 |

    <name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">

    147 |
  2. 148 |
  3. 149 |

    Set fixed bars

    150 |

    All fixed bars (.ui-top-bar, .ui-bottom-bar) should always be the first thing in the body of the page. This is really important!

    151 |
  4. 152 |
  5. 153 |

    Put content into .ui-page

    154 |

    Anything that’s not a -bar should be put in a div with the class ui-page. Put this div after the bars in the body tag.

    155 |
  6. 156 |
157 | 158 |

Basic template

159 | 160 |

Start with this basic HTML template, or modify it, adapting them to suit your needs.

161 | 162 |

Copy the HTML below to begin working with a minimal Pro document.

163 | 164 |
<!DOCTYPE html>
165 | <html>
166 | <head>
167 |     <meta charset='utf-8'>
168 |     <title>Pro Template</title>
169 |     <meta charset="utf-8">
170 |     <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
171 | 
172 |     <!-- Pro CSS -->
173 |     <link rel="stylesheet" type="text/css" href="css/pro.css">
174 | </head>
175 | <body class="ui-app">
176 | 
177 |     <div class="ui-top-bar js-no-bounce">
178 |         PRO Template
179 |     </div>
180 | 
181 |     <div class="ui-bottom-bar js-no-bounce" role="toolbar" tabindex="0">
182 |         <button class="ui-bottom-bar-button js-active" data-toggle="tab" data-target="#page1">
183 |             <span class="ui-icon"></span>
184 |             <span class="ui-label">CSS</span>
185 |         </button>
186 |         </div>
187 |     </div>
188 | 
189 |     <div id="page1" class="ui-page js-active">
190 |         <div class="ui-page-content">
191 |              <h1>Hello, world!</h1>
192 |         </div>
193 |     </div>
194 | 
195 |     <!-- Pro JS -->
196 |     <script src="js/pro.js"></script>
197 |   </body>
198 | </html>
199 | 200 |
201 |
202 | 203 | 204 |
205 |
206 | 207 |
208 |

Components

209 | 210 |

Bring Pro's components to life with over a dozen custom Zepto plugins. Easily include them all, or one by one.

211 |
212 | 213 |
214 |
215 |
216 | 217 |

按钮

218 |

219 | 220 | 221 | 222 | 223 |

224 | 225 |

块级按钮

226 |

227 | 228 | 229 | 230 | 231 |

232 |
233 |
234 |
235 | 236 | 237 |
238 |

Buttons

239 | 240 |

Buttons 包含三种状态:正常态、激活态、不可用态

241 | 242 |
243 | 244 |

按钮

245 |

246 | 247 | 248 | 249 | 250 |

251 | 252 |

块级按钮

253 |

254 | 255 | 256 | 257 | 258 |

259 | 260 |
261 |
262 | 263 | 282 | 283 | 284 | 310 | 311 |
312 |

Spinner

313 |
314 | 315 | 316 |

Trigger

317 |

318 | 321 | 324 |

325 | 326 |
327 |
328 | 329 | 358 | 359 |
360 |

Counter

361 |
362 | 363 |

CountUp

364 |
365 | 0 366 |
367 | 368 |

CountDown

369 |
370 | 9521 371 |
372 | 373 |
374 |
375 | 376 |
377 |

Deleter

378 | 423 |
424 | 425 |
426 |

Tab

427 |
428 | 429 |

Blue

430 |
431 |
    432 |
  • 列表 1123
  • 433 |
  • 列表 2
  • 434 |
  • 列表 32
  • 435 |
436 |
437 | 438 |

Gray

439 |
440 |
    441 |
  • 列表 1
  • 442 |
  • 列表 2
  • 443 |
  • 列表 31
  • 444 |
445 |
446 | 447 |
448 |
449 | 450 |
451 |

Notify

452 |
453 | 454 |

Notify

455 |

456 | 459 |

460 | 461 | 466 | 467 |
468 |
469 | 470 |
471 |

Alert

472 |
473 | 474 |

Alert

475 |

476 | 479 | 480 | 483 | 484 | 487 | 488 | 491 | 492 | 495 | 496 | 499 |

500 | 501 | 512 | 513 |
514 |
515 | 516 |
517 |

Action Sheet

518 |
519 | 520 |

Action Sheet

521 |

522 | 525 |

526 | 527 | 536 | 537 |
538 |
539 | 540 |
541 |
542 | 543 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | --------------------------------------------------------------------------------