├── 2016 ├── 11 │ └── 08 │ │ └── redis不谈缓存和队列 │ │ └── index.html └── 04 │ └── 28 │ └── 如何优雅的设计java异常 │ └── index.html ├── 2017 ├── 10 │ └── 13 │ │ └── java编程最佳实践 │ │ └── index.html ├── 03 │ └── 04 │ │ └── 细思极恐-你真的会写java吗 │ │ └── index.html └── 07 │ └── 09 │ └── 再谈websocket-论架构设计 │ └── index.html ├── 2018 ├── 01 │ └── 25 │ │ └── 正确的打日志姿势 │ │ └── index.html ├── 05 │ └── 09 │ │ └── java 10中的局部类型推断,好像并没什么用!(翻译文章) │ │ └── index.html ├── 06 │ └── 11 │ │ └── 做IT,需要一种情怀,thougthworks │ │ └── index.html └── 08 │ └── 30 │ └── java匠人手法-优雅的处理空值 │ └── index.html ├── 2020 └── 01 │ └── 19 │ └── 2019小结 │ └── index.html ├── aboutme └── index.html ├── archives ├── 2016 │ ├── 11 │ │ └── index.html │ ├── 04 │ │ └── index.html │ └── index.html ├── 2017 │ ├── 10 │ │ └── index.html │ ├── 03 │ │ └── index.html │ ├── 07 │ │ └── index.html │ └── index.html ├── 2018 │ ├── 01 │ │ └── index.html │ ├── 05 │ │ └── index.html │ ├── 06 │ │ └── index.html │ ├── 08 │ │ └── index.html │ └── index.html ├── 2020 │ ├── 01 │ │ └── index.html │ └── index.html └── index.html ├── categories ├── java │ └── index.html └── java匠人手法 │ └── index.html ├── css └── main.css ├── favicon.ico ├── images ├── Supportedbrowser.jpeg ├── WeChat_1499585246.jpeg ├── WeChat_1499585625.jpeg ├── avatar.gif ├── cc-by-nc-nd.svg ├── cc-by-nc-sa.svg ├── cc-by-nc.svg ├── cc-by-nd.svg ├── cc-by-sa.svg ├── cc-by.svg ├── cc-zero.svg ├── compareWebsocketHttp.png ├── default_avatar.jpg ├── httpwebsocket.jpg ├── loading.gif ├── message-flow-simple-broker.png ├── placeholder.gif ├── quote-l.svg ├── quote-r.svg └── searchicon.png ├── index.html ├── js └── src │ ├── affix.js │ ├── bootstrap.js │ ├── hook-duoshuo.js │ ├── motion.js │ ├── post-details.js │ ├── schemes │ └── pisces.js │ ├── scrollspy.js │ └── utils.js ├── lib ├── fancybox │ └── source │ │ ├── blank.gif │ │ ├── fancybox_loading.gif │ │ ├── fancybox_loading@2x.gif │ │ ├── fancybox_overlay.png │ │ ├── fancybox_sprite.png │ │ ├── fancybox_sprite@2x.png │ │ ├── helpers │ │ ├── fancybox_buttons.png │ │ ├── jquery.fancybox-buttons.css │ │ ├── jquery.fancybox-buttons.js │ │ ├── jquery.fancybox-media.js │ │ ├── jquery.fancybox-thumbs.css │ │ └── jquery.fancybox-thumbs.js │ │ ├── jquery.fancybox.css │ │ ├── jquery.fancybox.js │ │ └── jquery.fancybox.pack.js ├── fastclick │ ├── LICENSE │ ├── README.html │ ├── bower.json │ └── lib │ │ ├── fastclick.js │ │ └── fastclick.min.js ├── font-awesome │ ├── HELP-US-OUT.txt │ ├── bower.json │ ├── css │ │ ├── font-awesome.css │ │ ├── font-awesome.css.map │ │ └── font-awesome.min.css │ └── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ └── fontawesome-webfont.woff2 ├── jquery │ └── index.js ├── jquery_lazyload │ ├── CONTRIBUTING.html │ ├── README.html │ ├── bower.json │ ├── jquery.lazyload.js │ └── jquery.scrollstop.js ├── ua-parser-js │ └── dist │ │ ├── ua-parser.min.js │ │ └── ua-parser.pack.js └── velocity │ ├── bower.json │ ├── velocity.js │ ├── velocity.min.js │ ├── velocity.ui.js │ └── velocity.ui.min.js ├── payimage ├── alipay-reward-image.png └── wechat-reward-image.png └── tags ├── exception └── index.html ├── java └── index.html ├── jdk-10 └── index.html ├── logback └── index.html ├── redis └── index.html ├── 日志 └── index.html └── 面试 └── index.html /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrwinx/lrwinx.github.io/beda2a2a4e83cce586623446e8156138ca63647f/favicon.ico -------------------------------------------------------------------------------- /images/Supportedbrowser.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrwinx/lrwinx.github.io/beda2a2a4e83cce586623446e8156138ca63647f/images/Supportedbrowser.jpeg -------------------------------------------------------------------------------- /images/WeChat_1499585246.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrwinx/lrwinx.github.io/beda2a2a4e83cce586623446e8156138ca63647f/images/WeChat_1499585246.jpeg -------------------------------------------------------------------------------- /images/WeChat_1499585625.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrwinx/lrwinx.github.io/beda2a2a4e83cce586623446e8156138ca63647f/images/WeChat_1499585625.jpeg -------------------------------------------------------------------------------- /images/avatar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrwinx/lrwinx.github.io/beda2a2a4e83cce586623446e8156138ca63647f/images/avatar.gif -------------------------------------------------------------------------------- /images/cc-by-nc-nd.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 122 | -------------------------------------------------------------------------------- /images/cc-by-nc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 122 | -------------------------------------------------------------------------------- /images/cc-by-nd.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 118 | -------------------------------------------------------------------------------- /images/cc-by-sa.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 122 | -------------------------------------------------------------------------------- /images/cc-by.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 122 | -------------------------------------------------------------------------------- /images/cc-zero.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 73 | -------------------------------------------------------------------------------- /images/compareWebsocketHttp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrwinx/lrwinx.github.io/beda2a2a4e83cce586623446e8156138ca63647f/images/compareWebsocketHttp.png -------------------------------------------------------------------------------- /images/default_avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrwinx/lrwinx.github.io/beda2a2a4e83cce586623446e8156138ca63647f/images/default_avatar.jpg -------------------------------------------------------------------------------- /images/httpwebsocket.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrwinx/lrwinx.github.io/beda2a2a4e83cce586623446e8156138ca63647f/images/httpwebsocket.jpg -------------------------------------------------------------------------------- /images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrwinx/lrwinx.github.io/beda2a2a4e83cce586623446e8156138ca63647f/images/loading.gif -------------------------------------------------------------------------------- /images/message-flow-simple-broker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrwinx/lrwinx.github.io/beda2a2a4e83cce586623446e8156138ca63647f/images/message-flow-simple-broker.png -------------------------------------------------------------------------------- /images/placeholder.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrwinx/lrwinx.github.io/beda2a2a4e83cce586623446e8156138ca63647f/images/placeholder.gif -------------------------------------------------------------------------------- /images/quote-l.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 14 | -------------------------------------------------------------------------------- /images/quote-r.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | -------------------------------------------------------------------------------- /images/searchicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrwinx/lrwinx.github.io/beda2a2a4e83cce586623446e8156138ca63647f/images/searchicon.png -------------------------------------------------------------------------------- /js/src/affix.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: affix.js v3.3.5 3 | * http://getbootstrap.com/javascript/#affix 4 | * ======================================================================== 5 | * Copyright 2011-2015 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // AFFIX CLASS DEFINITION 14 | // ====================== 15 | 16 | var Affix = function (element, options) { 17 | this.options = $.extend({}, Affix.DEFAULTS, options) 18 | 19 | this.$target = $(this.options.target) 20 | .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) 21 | .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) 22 | 23 | this.$element = $(element) 24 | this.affixed = null 25 | this.unpin = null 26 | this.pinnedOffset = null 27 | 28 | this.checkPosition() 29 | } 30 | 31 | Affix.VERSION = '3.3.5' 32 | 33 | Affix.RESET = 'affix affix-top affix-bottom' 34 | 35 | Affix.DEFAULTS = { 36 | offset: 0, 37 | target: window 38 | } 39 | 40 | Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) { 41 | var scrollTop = this.$target.scrollTop() 42 | var position = this.$element.offset() 43 | var targetHeight = this.$target.height() 44 | 45 | if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false 46 | 47 | if (this.affixed == 'bottom') { 48 | if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom' 49 | return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom' 50 | } 51 | 52 | var initializing = this.affixed == null 53 | var colliderTop = initializing ? scrollTop : position.top 54 | var colliderHeight = initializing ? targetHeight : height 55 | 56 | if (offsetTop != null && scrollTop <= offsetTop) return 'top' 57 | if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' 58 | 59 | return false 60 | } 61 | 62 | Affix.prototype.getPinnedOffset = function () { 63 | if (this.pinnedOffset) return this.pinnedOffset 64 | this.$element.removeClass(Affix.RESET).addClass('affix') 65 | var scrollTop = this.$target.scrollTop() 66 | var position = this.$element.offset() 67 | return (this.pinnedOffset = position.top - scrollTop) 68 | } 69 | 70 | Affix.prototype.checkPositionWithEventLoop = function () { 71 | setTimeout($.proxy(this.checkPosition, this), 1) 72 | } 73 | 74 | Affix.prototype.checkPosition = function () { 75 | if (!this.$element.is(':visible')) return 76 | 77 | var height = this.$element.height() 78 | var offset = this.options.offset 79 | var offsetTop = offset.top 80 | var offsetBottom = offset.bottom 81 | var scrollHeight = Math.max($(document).height(), $(document.body).height()) 82 | 83 | if (typeof offset != 'object') offsetBottom = offsetTop = offset 84 | if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) 85 | if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) 86 | 87 | var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom) 88 | 89 | if (this.affixed != affix) { 90 | if (this.unpin != null) this.$element.css('top', '') 91 | 92 | var affixType = 'affix' + (affix ? '-' + affix : '') 93 | var e = $.Event(affixType + '.bs.affix') 94 | 95 | this.$element.trigger(e) 96 | 97 | if (e.isDefaultPrevented()) return 98 | 99 | this.affixed = affix 100 | this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null 101 | 102 | this.$element 103 | .removeClass(Affix.RESET) 104 | .addClass(affixType) 105 | .trigger(affixType.replace('affix', 'affixed') + '.bs.affix') 106 | } 107 | 108 | if (affix == 'bottom') { 109 | this.$element.offset({ 110 | top: scrollHeight - height - offsetBottom 111 | }) 112 | } 113 | } 114 | 115 | 116 | // AFFIX PLUGIN DEFINITION 117 | // ======================= 118 | 119 | function Plugin(option) { 120 | return this.each(function () { 121 | var $this = $(this) 122 | var data = $this.data('bs.affix') 123 | var options = typeof option == 'object' && option 124 | 125 | if (!data) $this.data('bs.affix', (data = new Affix(this, options))) 126 | if (typeof option == 'string') data[option]() 127 | }) 128 | } 129 | 130 | var old = $.fn.affix 131 | 132 | $.fn.affix = Plugin 133 | $.fn.affix.Constructor = Affix 134 | 135 | 136 | // AFFIX NO CONFLICT 137 | // ================= 138 | 139 | $.fn.affix.noConflict = function () { 140 | $.fn.affix = old 141 | return this 142 | } 143 | 144 | 145 | // AFFIX DATA-API 146 | // ============== 147 | 148 | $(window).on('load', function () { 149 | $('[data-spy="affix"]').each(function () { 150 | var $spy = $(this) 151 | var data = $spy.data() 152 | 153 | data.offset = data.offset || {} 154 | 155 | if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom 156 | if (data.offsetTop != null) data.offset.top = data.offsetTop 157 | 158 | Plugin.call($spy, data) 159 | }) 160 | }) 161 | 162 | }(jQuery); 163 | -------------------------------------------------------------------------------- /js/src/bootstrap.js: -------------------------------------------------------------------------------- 1 | /* global NexT: true */ 2 | 3 | $(document).ready(function () { 4 | 5 | $(document).trigger('bootstrap:before'); 6 | 7 | NexT.utils.isMobile() && window.FastClick.attach(document.body); 8 | 9 | NexT.utils.lazyLoadPostsImages(); 10 | 11 | NexT.utils.registerBackToTop(); 12 | 13 | $('.site-nav-toggle button').on('click', function () { 14 | var $siteNav = $('.site-nav'); 15 | var ON_CLASS_NAME = 'site-nav-on'; 16 | var isSiteNavOn = $siteNav.hasClass(ON_CLASS_NAME); 17 | var animateAction = isSiteNavOn ? 'slideUp' : 'slideDown'; 18 | var animateCallback = isSiteNavOn ? 'removeClass' : 'addClass'; 19 | 20 | $siteNav.stop()[animateAction]('fast', function () { 21 | $siteNav[animateCallback](ON_CLASS_NAME); 22 | }); 23 | }); 24 | 25 | 26 | CONFIG.fancybox && NexT.utils.wrapImageWithFancyBox(); 27 | NexT.utils.embeddedVideoTransformer(); 28 | NexT.utils.addActiveClassToMenuItem(); 29 | 30 | 31 | // Define Motion Sequence. 32 | NexT.motion.integrator 33 | .add(NexT.motion.middleWares.logo) 34 | .add(NexT.motion.middleWares.menu) 35 | .add(NexT.motion.middleWares.postList) 36 | .add(NexT.motion.middleWares.sidebar); 37 | 38 | $(document).trigger('motion:before'); 39 | 40 | // Bootstrap Motion. 41 | CONFIG.motion && NexT.motion.integrator.bootstrap(); 42 | 43 | $(document).trigger('bootstrap:after'); 44 | }); 45 | -------------------------------------------------------------------------------- /js/src/hook-duoshuo.js: -------------------------------------------------------------------------------- 1 | /* global DUOSHUO: true */ 2 | /* jshint camelcase: false */ 3 | 4 | typeof DUOSHUO !== 'undefined' ? 5 | hookTemplate() : 6 | ($('#duoshuo-script')[0].onload = hookTemplate); 7 | 8 | 9 | function hookTemplate() { 10 | var post = DUOSHUO.templates.post; 11 | 12 | DUOSHUO.templates.post = function (e, t) { 13 | var rs = post(e, t); 14 | var agent = e.post.agent; 15 | var userId = e.post.author.user_id; 16 | var admin = ''; 17 | 18 | if (userId && (userId == CONFIG.duoshuo.userId)) { 19 | admin = '' + CONFIG.duoshuo.author + ''; 20 | } 21 | 22 | if (agent && /^Mozilla/.test(agent)) { 23 | rs = rs.replace(/<\/div>
/, admin + getAgentInfo(agent) + '
');
24 | }
25 |
26 | return rs;
27 | };
28 | }
29 |
30 | function getAgentInfo(string) {
31 | $.ua.set(string);
32 |
33 | var UNKNOWN = 'Unknown';
34 | var sua = $.ua;
35 | var separator = isMobile() ? '
' : '';
36 | var osName = sua.os.name || UNKNOWN;
37 | var osVersion = sua.os.version || UNKNOWN;
38 | var browserName = sua.browser.name || UNKNOWN;
39 | var browserVersion = sua.browser.version || UNKNOWN;
40 | var iconMapping = {
41 | os: {
42 | android : 'android',
43 | linux : 'linux',
44 | windows : 'windows',
45 | ios : 'apple',
46 | 'mac os': 'apple',
47 | unknown : 'desktop'
48 | },
49 | browser: {
50 | chrome : 'chrome',
51 | chromium : 'chrome',
52 | firefox : 'firefox',
53 | opera : 'opera',
54 | safari : 'safari',
55 | ie : 'internet-explorer',
56 | wechat : 'wechat',
57 | qq : 'qq',
58 | unknown : 'globe'
59 | }
60 | };
61 | var osIcon = iconMapping.os[osName.toLowerCase()];
62 | var browserIcon = iconMapping.browser[getBrowserKey()];
63 |
64 | return separator +
65 | '' +
66 | '' +
67 | osName + ' ' + osVersion +
68 | '' + separator +
69 | '' +
70 | '' +
71 | browserName + ' ' + browserVersion +
72 | '';
73 |
74 | function getBrowserKey () {
75 | var key = browserName.toLowerCase();
76 |
77 | if (key.match(/WeChat/i)) {
78 | return 'wechat';
79 | }
80 |
81 | if (key.match(/QQBrowser/i)) {
82 | return 'qq';
83 | }
84 |
85 | return key;
86 | }
87 |
88 | function isMobile() {
89 | var userAgent = window.navigator.userAgent;
90 |
91 | var isiPad = userAgent.match(/iPad/i) !== null;
92 | var mobileUA = [
93 | 'iphone', 'android', 'phone', 'mobile',
94 | 'wap', 'netfront', 'x11', 'java', 'opera mobi',
95 | 'opera mini', 'ucweb', 'windows ce', 'symbian',
96 | 'symbianos', 'series', 'webos', 'sony',
97 | 'blackberry', 'dopod', 'nokia', 'samsung',
98 | 'palmsource', 'xda', 'pieplus', 'meizu',
99 | 'midp' ,'cldc' , 'motorola', 'foma',
100 | 'docomo', 'up.browser', 'up.link', 'blazer',
101 | 'helio', 'hosin', 'huawei', 'novarra',
102 | 'coolpad', 'webos', 'techfaith', 'palmsource',
103 | 'alcatel', 'amoi', 'ktouch', 'nexian',
104 | 'ericsson', 'philips', 'sagem', 'wellcom',
105 | 'bunjalloo', 'maui', 'smartphone', 'iemobile',
106 | 'spice', 'bird', 'zte-', 'longcos',
107 | 'pantech', 'gionee', 'portalmmm', 'jig browser',
108 | 'hiptop', 'benq', 'haier', '^lct',
109 | '320x320', '240x320', '176x220'
110 | ];
111 | var pattern = new RegExp(mobileUA.join('|'), 'i');
112 |
113 | return !isiPad && userAgent.match(pattern);
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/js/src/motion.js:
--------------------------------------------------------------------------------
1 | /* global NexT: true */
2 |
3 | $(document).ready(function () {
4 | NexT.motion = {};
5 |
6 | var sidebarToggleLines = {
7 | lines: [],
8 | push: function (line) {
9 | this.lines.push(line);
10 | },
11 | init: function () {
12 | this.lines.forEach(function (line) {
13 | line.init();
14 | });
15 | },
16 | arrow: function () {
17 | this.lines.forEach(function (line) {
18 | line.arrow();
19 | });
20 | },
21 | close: function () {
22 | this.lines.forEach(function (line) {
23 | line.close();
24 | });
25 | }
26 | };
27 |
28 | function SidebarToggleLine(settings) {
29 | this.el = $(settings.el);
30 | this.status = $.extend({}, {
31 | init: {
32 | width: '100%',
33 | opacity: 1,
34 | left: 0,
35 | rotateZ: 0,
36 | top: 0
37 | }
38 | }, settings.status);
39 | }
40 |
41 | SidebarToggleLine.prototype.init = function () {
42 | this.transform('init');
43 | };
44 | SidebarToggleLine.prototype.arrow = function () {
45 | this.transform('arrow');
46 | };
47 | SidebarToggleLine.prototype.close = function () {
48 | this.transform('close');
49 | };
50 | SidebarToggleLine.prototype.transform = function (status) {
51 | this.el.velocity('stop').velocity(this.status[status]);
52 | };
53 |
54 | var sidebarToggleLine1st = new SidebarToggleLine({
55 | el: '.sidebar-toggle-line-first',
56 | status: {
57 | arrow: {width: '50%', rotateZ: '-45deg', top: '2px'},
58 | close: {width: '100%', rotateZ: '-45deg', top: '5px'}
59 | }
60 | });
61 | var sidebarToggleLine2nd = new SidebarToggleLine({
62 | el: '.sidebar-toggle-line-middle',
63 | status: {
64 | arrow: {width: '90%'},
65 | close: {opacity: 0}
66 | }
67 | });
68 | var sidebarToggleLine3rd = new SidebarToggleLine({
69 | el: '.sidebar-toggle-line-last',
70 | status: {
71 | arrow: {width: '50%', rotateZ: '45deg', top: '-2px'},
72 | close: {width: '100%', rotateZ: '45deg', top: '-5px'}
73 | }
74 | });
75 |
76 | sidebarToggleLines.push(sidebarToggleLine1st);
77 | sidebarToggleLines.push(sidebarToggleLine2nd);
78 | sidebarToggleLines.push(sidebarToggleLine3rd);
79 |
80 | var SIDEBAR_WIDTH = '320px';
81 | var SIDEBAR_DISPLAY_DURATION = 200;
82 |
83 | var sidebarToggleMotion = {
84 | toggleEl: $('.sidebar-toggle'),
85 | sidebarEl: $('.sidebar'),
86 | isSidebarVisible: false,
87 | init: function () {
88 | this.toggleEl.on('click', this.clickHandler.bind(this));
89 | this.toggleEl.on('mouseenter', this.mouseEnterHandler.bind(this));
90 | this.toggleEl.on('mouseleave', this.mouseLeaveHandler.bind(this));
91 |
92 | $(document)
93 | .on('sidebar.isShowing', function () {
94 | NexT.utils.isDesktop() && $('body').velocity('stop').velocity(
95 | {paddingRight: SIDEBAR_WIDTH},
96 | SIDEBAR_DISPLAY_DURATION
97 | );
98 | })
99 | .on('sidebar.isHiding', function () {
100 | });
101 | },
102 | clickHandler: function () {
103 | this.isSidebarVisible ? this.hideSidebar() : this.showSidebar();
104 | this.isSidebarVisible = !this.isSidebarVisible;
105 | },
106 | mouseEnterHandler: function () {
107 | if (this.isSidebarVisible) {
108 | return;
109 | }
110 | sidebarToggleLines.arrow();
111 | },
112 | mouseLeaveHandler: function () {
113 | if (this.isSidebarVisible) {
114 | return;
115 | }
116 | sidebarToggleLines.init();
117 | },
118 | showSidebar: function () {
119 | var self = this;
120 |
121 | sidebarToggleLines.close();
122 |
123 | this.sidebarEl.velocity('stop').velocity({
124 | width: SIDEBAR_WIDTH
125 | }, {
126 | display: 'block',
127 | duration: SIDEBAR_DISPLAY_DURATION,
128 | begin: function () {
129 | $('.sidebar .motion-element').velocity(
130 | 'transition.slideRightIn',
131 | {
132 | stagger: 50,
133 | drag: true,
134 | complete: function () {
135 | self.sidebarEl.trigger('sidebar.motion.complete');
136 | }
137 | }
138 | );
139 | },
140 | complete: function () {
141 | self.sidebarEl.addClass('sidebar-active');
142 | self.sidebarEl.trigger('sidebar.didShow');
143 | }
144 | }
145 | );
146 |
147 | this.sidebarEl.trigger('sidebar.isShowing');
148 | },
149 | hideSidebar: function () {
150 | NexT.utils.isDesktop() && $('body').velocity('stop').velocity({paddingRight: 0});
151 | this.sidebarEl.find('.motion-element').velocity('stop').css('display', 'none');
152 | this.sidebarEl.velocity('stop').velocity({width: 0}, {display: 'none'});
153 |
154 | sidebarToggleLines.init();
155 |
156 | this.sidebarEl.removeClass('sidebar-active');
157 | this.sidebarEl.trigger('sidebar.isHiding');
158 |
159 | //在 post 页面下按下隐藏 sidebar 时如果当前选中的是“站点概览”,将 toc 去除 motion 效果
160 | //防止再次打开时会出现在“站点概览”下的 bug
161 | if (!!$('.post-toc-wrap')) {
162 | if ($('.site-overview').css('display') === 'block') {
163 | $('.post-toc-wrap').removeClass('motion-element');
164 | }
165 | }
166 | }
167 | };
168 | sidebarToggleMotion.init();
169 |
170 | NexT.motion.integrator = {
171 | queue: [],
172 | cursor: -1,
173 | add: function (fn) {
174 | this.queue.push(fn);
175 | return this;
176 | },
177 | next: function () {
178 | this.cursor++;
179 | var fn = this.queue[this.cursor];
180 | $.isFunction(fn) && fn(NexT.motion.integrator);
181 | },
182 | bootstrap: function () {
183 | this.next();
184 | }
185 | };
186 |
187 | NexT.motion.middleWares = {
188 | logo: function (integrator) {
189 | var sequence = [];
190 | var $brand = $('.brand');
191 | var $title = $('.site-title');
192 | var $subtitle = $('.site-subtitle');
193 | var $logoLineTop = $('.logo-line-before i');
194 | var $logoLineBottom = $('.logo-line-after i');
195 |
196 | $brand.size() > 0 && sequence.push({
197 | e: $brand,
198 | p: {opacity: 1},
199 | o: {duration: 200}
200 | });
201 |
202 | NexT.utils.isMist() && hasElement([$logoLineTop, $logoLineBottom]) &&
203 | sequence.push(
204 | getMistLineSettings($logoLineTop, '100%'),
205 | getMistLineSettings($logoLineBottom, '-100%')
206 | );
207 |
208 | hasElement($title) && sequence.push({
209 | e: $title,
210 | p: {opacity: 1, top: 0},
211 | o: { duration: 200 }
212 | });
213 |
214 | hasElement($subtitle) && sequence.push({
215 | e: $subtitle,
216 | p: {opacity: 1, top: 0},
217 | o: {duration: 200}
218 | });
219 |
220 | if (sequence.length > 0) {
221 | sequence[sequence.length - 1].o.complete = function () {
222 | integrator.next();
223 | };
224 | $.Velocity.RunSequence(sequence);
225 | } else {
226 | integrator.next();
227 | }
228 |
229 |
230 | function getMistLineSettings (element, translateX) {
231 | return {
232 | e: $(element),
233 | p: {translateX: translateX},
234 | o: {
235 | duration: 500,
236 | sequenceQueue: false
237 | }
238 | };
239 | }
240 |
241 | /**
242 | * Check if $elements exist.
243 | * @param {jQuery|Array} $elements
244 | * @returns {boolean}
245 | */
246 | function hasElement ($elements) {
247 | $elements = Array.isArray($elements) ? $elements : [$elements];
248 | return $elements.every(function ($element) {
249 | return $.isFunction($element.size) && $element.size() > 0;
250 | });
251 | }
252 | },
253 |
254 | menu: function (integrator) {
255 | $('.menu-item').velocity('transition.slideDownIn', {
256 | display: null,
257 | duration: 200,
258 | complete: function () {
259 | integrator.next();
260 | }
261 | });
262 | },
263 |
264 | postList: function (integrator) {
265 | var $post = $('.post');
266 | var hasPost = $post.size() > 0;
267 |
268 | hasPost ? postMotion() : integrator.next();
269 |
270 | function postMotion () {
271 | var postMotionOptions = window.postMotionOptions || {
272 | stagger: 100,
273 | drag: true
274 | };
275 | postMotionOptions.complete = function () {
276 | integrator.next();
277 | };
278 |
279 | $post.velocity('transition.slideDownIn', postMotionOptions);
280 | }
281 | },
282 |
283 | sidebar: function (integrator) {
284 | if (CONFIG.sidebar.display === 'always') {
285 | NexT.utils.displaySidebar();
286 | }
287 | integrator.next();
288 | }
289 | };
290 |
291 | });
292 |
--------------------------------------------------------------------------------
/js/src/post-details.js:
--------------------------------------------------------------------------------
1 | /* global NexT: true */
2 |
3 | $(document).ready(function () {
4 |
5 | initScrollSpy();
6 | NexT.utils.needAffix() && initAffix();
7 | initTOCDimension();
8 |
9 | function initScrollSpy () {
10 | var tocSelector = '.post-toc';
11 | var $tocElement = $(tocSelector);
12 | var activeCurrentSelector = '.active-current';
13 |
14 | $tocElement
15 | .on('activate.bs.scrollspy', function () {
16 | var $currentActiveElement = $(tocSelector + ' .active').last();
17 |
18 | removeCurrentActiveClass();
19 | $currentActiveElement.addClass('active-current');
20 | })
21 | .on('clear.bs.scrollspy', removeCurrentActiveClass);
22 |
23 | $('body').scrollspy({ target: tocSelector });
24 |
25 | function removeCurrentActiveClass () {
26 | $(tocSelector + ' ' + activeCurrentSelector)
27 | .removeClass(activeCurrentSelector.substring(1));
28 | }
29 | }
30 |
31 | function initAffix () {
32 | var headerHeight = $('.header-inner').height();
33 | var footerOffset = parseInt($('.main').css('padding-bottom'), 10);
34 | var sidebarTop = headerHeight + 10;
35 |
36 | $('.sidebar-inner').affix({
37 | offset: {
38 | top: sidebarTop,
39 | bottom: footerOffset
40 | }
41 | });
42 |
43 | $(document)
44 | .on('affixed.bs.affix', function () {
45 | updateTOCHeight(document.body.clientHeight - 100);
46 | });
47 | }
48 |
49 | function initTOCDimension () {
50 | var updateTOCHeightTimer;
51 |
52 | $(window).on('resize', function () {
53 | updateTOCHeightTimer && clearTimeout(updateTOCHeightTimer);
54 |
55 | updateTOCHeightTimer = setTimeout(function () {
56 | var tocWrapperHeight = document.body.clientHeight - 100;
57 |
58 | updateTOCHeight(tocWrapperHeight);
59 | }, 0);
60 | });
61 |
62 | // Initialize TOC Height.
63 | updateTOCHeight(document.body.clientHeight - 100);
64 |
65 | // Initialize TOC Width.
66 | var scrollbarWidth = NexT.utils.getScrollbarWidth();
67 | $('.post-toc').css('width', 'calc(100% + ' + scrollbarWidth + 'px)');
68 | }
69 |
70 | function updateTOCHeight (height) {
71 | height = height || 'auto';
72 | $('.post-toc').css('max-height', height);
73 | }
74 |
75 | });
76 |
77 | $(document).ready(function () {
78 | var html = $('html');
79 | var TAB_ANIMATE_DURATION = 200;
80 | var hasVelocity = $.isFunction(html.velocity);
81 |
82 | $('.sidebar-nav li').on('click', function () {
83 | var item = $(this);
84 | var activeTabClassName = 'sidebar-nav-active';
85 | var activePanelClassName = 'sidebar-panel-active';
86 | if (item.hasClass(activeTabClassName)) {
87 | return;
88 | }
89 |
90 | var currentTarget = $('.' + activePanelClassName);
91 | var target = $('.' + item.data('target'));
92 |
93 | hasVelocity ?
94 | currentTarget.velocity('transition.slideUpOut', TAB_ANIMATE_DURATION, function () {
95 | target
96 | .velocity('stop')
97 | .velocity('transition.slideDownIn', TAB_ANIMATE_DURATION)
98 | .addClass(activePanelClassName);
99 | }) :
100 | currentTarget.animate({ opacity: 0 }, TAB_ANIMATE_DURATION, function () {
101 | currentTarget.hide();
102 | target
103 | .stop()
104 | .css({'opacity': 0, 'display': 'block'})
105 | .animate({ opacity: 1 }, TAB_ANIMATE_DURATION, function () {
106 | currentTarget.removeClass(activePanelClassName);
107 | target.addClass(activePanelClassName);
108 | });
109 | });
110 |
111 | item.siblings().removeClass(activeTabClassName);
112 | item.addClass(activeTabClassName);
113 | });
114 |
115 | $('.post-toc a').on('click', function (e) {
116 | e.preventDefault();
117 | var targetSelector = NexT.utils.escapeSelector(this.getAttribute('href'));
118 | var offset = $(targetSelector).offset().top;
119 |
120 | hasVelocity ?
121 | html.velocity('stop').velocity('scroll', {
122 | offset: offset + 'px',
123 | mobileHA: false
124 | }) :
125 | $('html, body').stop().animate({
126 | scrollTop: offset
127 | }, 500);
128 | });
129 |
130 | // Expand sidebar on post detail page by default, when post has a toc.
131 | NexT.motion.middleWares.sidebar = function () {
132 | var $tocContent = $('.post-toc-content');
133 |
134 | if (CONFIG.sidebar.display === 'post' || CONFIG.sidebar.display === 'always') {
135 | if ($tocContent.length > 0 && $tocContent.html().trim().length > 0) {
136 | NexT.utils.displaySidebar();
137 | }
138 | }
139 | };
140 | });
141 |
--------------------------------------------------------------------------------
/js/src/schemes/pisces.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function () {
2 | var sidebarTop = $('.header-inner').height() + 10;
3 |
4 | $('#sidebar').css({ 'margin-top': sidebarTop }).show();
5 | });
6 |
--------------------------------------------------------------------------------
/js/src/scrollspy.js:
--------------------------------------------------------------------------------
1 | /* ========================================================================
2 | * Bootstrap: scrollspy.js v3.3.2
3 | * http://getbootstrap.com/javascript/#scrollspy
4 | * ========================================================================
5 | * Copyright 2011-2015 Twitter, Inc.
6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
7 | * ======================================================================== */
8 |
9 | /**
10 | * Custom by iissnan
11 | *
12 | * - Add a `clear.bs.scrollspy` event.
13 | * - Esacpe targets selector.
14 | */
15 |
16 |
17 | +function ($) {
18 | 'use strict';
19 |
20 | // SCROLLSPY CLASS DEFINITION
21 | // ==========================
22 |
23 | function ScrollSpy(element, options) {
24 | this.$body = $(document.body)
25 | this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
26 | this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
27 | this.selector = (this.options.target || '') + ' .nav li > a'
28 | this.offsets = []
29 | this.targets = []
30 | this.activeTarget = null
31 | this.scrollHeight = 0
32 |
33 | this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
34 | this.refresh()
35 | this.process()
36 | }
37 |
38 | ScrollSpy.VERSION = '3.3.2'
39 |
40 | ScrollSpy.DEFAULTS = {
41 | offset: 10
42 | }
43 |
44 | ScrollSpy.prototype.getScrollHeight = function () {
45 | return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
46 | }
47 |
48 | ScrollSpy.prototype.refresh = function () {
49 | var that = this
50 | var offsetMethod = 'offset'
51 | var offsetBase = 0
52 |
53 | this.offsets = []
54 | this.targets = []
55 | this.scrollHeight = this.getScrollHeight()
56 |
57 | if (!$.isWindow(this.$scrollElement[0])) {
58 | offsetMethod = 'position'
59 | offsetBase = this.$scrollElement.scrollTop()
60 | }
61 |
62 | this.$body
63 | .find(this.selector)
64 | .map(function () {
65 | var $el = $(this)
66 | var href = $el.data('target') || $el.attr('href')
67 | var $href = /^#./.test(href) && $(NexT.utils.escapeSelector(href)) // Need to escape selector.
68 |
69 | return ($href
70 | && $href.length
71 | && $href.is(':visible')
72 | && [[$href[offsetMethod]().top + offsetBase, href]]) || null
73 | })
74 | .sort(function (a, b) { return a[0] - b[0] })
75 | .each(function () {
76 | that.offsets.push(this[0])
77 | that.targets.push(this[1])
78 | })
79 |
80 |
81 | }
82 |
83 | ScrollSpy.prototype.process = function () {
84 | var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
85 | var scrollHeight = this.getScrollHeight()
86 | var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
87 | var offsets = this.offsets
88 | var targets = this.targets
89 | var activeTarget = this.activeTarget
90 | var i
91 |
92 | if (this.scrollHeight != scrollHeight) {
93 | this.refresh()
94 | }
95 |
96 | if (scrollTop >= maxScroll) {
97 | return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
98 | }
99 |
100 | if (activeTarget && scrollTop < offsets[0]) {
101 | $(this.selector).trigger('clear.bs.scrollspy') // Add a custom event.
102 | this.activeTarget = null
103 | return this.clear()
104 | }
105 |
106 | for (i = offsets.length; i--;) {
107 | activeTarget != targets[i]
108 | && scrollTop >= offsets[i]
109 | && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
110 | && this.activate(targets[i])
111 | }
112 | }
113 |
114 | ScrollSpy.prototype.activate = function (target) {
115 | this.activeTarget = target
116 |
117 | this.clear()
118 |
119 | var selector = this.selector +
120 | '[data-target="' + target + '"],' +
121 | this.selector + '[href="' + target + '"]'
122 |
123 | var active = $(selector)
124 | .parents('li')
125 | .addClass('active')
126 |
127 | if (active.parent('.dropdown-menu').length) {
128 | active = active
129 | .closest('li.dropdown')
130 | .addClass('active')
131 | }
132 |
133 | active.trigger('activate.bs.scrollspy')
134 | }
135 |
136 | ScrollSpy.prototype.clear = function () {
137 | $(this.selector)
138 | .parentsUntil(this.options.target, '.active')
139 | .removeClass('active')
140 | }
141 |
142 |
143 | // SCROLLSPY PLUGIN DEFINITION
144 | // ===========================
145 |
146 | function Plugin(option) {
147 | return this.each(function () {
148 | var $this = $(this)
149 | var data = $this.data('bs.scrollspy')
150 | var options = typeof option == 'object' && option
151 |
152 | if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
153 | if (typeof option == 'string') data[option]()
154 | })
155 | }
156 |
157 | var old = $.fn.scrollspy
158 |
159 | $.fn.scrollspy = Plugin
160 | $.fn.scrollspy.Constructor = ScrollSpy
161 |
162 |
163 | // SCROLLSPY NO CONFLICT
164 | // =====================
165 |
166 | $.fn.scrollspy.noConflict = function () {
167 | $.fn.scrollspy = old
168 | return this
169 | }
170 |
171 |
172 | // SCROLLSPY DATA-API
173 | // ==================
174 |
175 | $(window).on('load.bs.scrollspy.data-api', function () {
176 | $('[data-spy="scroll"]').each(function () {
177 | var $spy = $(this)
178 | Plugin.call($spy, $spy.data())
179 | })
180 | })
181 |
182 | }(jQuery);
183 |
--------------------------------------------------------------------------------
/js/src/utils.js:
--------------------------------------------------------------------------------
1 | /* global NexT: true */
2 |
3 | NexT.utils = NexT.$u = {
4 | /**
5 | * Wrap images with fancybox support.
6 | */
7 | wrapImageWithFancyBox: function () {
8 | $('.content img').not('.group-picture img').each(function () {
9 |
10 | var $image = $(this);
11 | var imageTitle = $image.attr('title');
12 | var $imageWrapLink = $image.parent('a');
13 |
14 | if ($imageWrapLink.size() < 1) {
15 | $imageWrapLink = $image.wrap('').parent('a');
16 | }
17 |
18 | $imageWrapLink.addClass('fancybox');
19 | $imageWrapLink.attr('rel', 'group');
20 |
21 | if (imageTitle) {
22 | $imageWrapLink.append('
' + imageTitle + '
'); 23 | $imageWrapLink.attr('title', imageTitle); //make sure img title tag will show correctly in fancybox 24 | } 25 | }); 26 | 27 | $('.fancybox').fancybox({ 28 | helpers: { 29 | overlay: { 30 | locked: false 31 | } 32 | } 33 | }); 34 | }, 35 | 36 | lazyLoadPostsImages: function () { 37 | $('#posts').find('img').lazyload({ 38 | placeholder: '/images/loading.gif', 39 | effect: 'fadeIn' 40 | }); 41 | }, 42 | 43 | registerBackToTop: function () { 44 | var THRESHOLD = 50; 45 | var $top = $('.back-to-top'); 46 | 47 | $(window).on('scroll', function () { 48 | $top.toggleClass('back-to-top-on', window.pageYOffset > THRESHOLD); 49 | }); 50 | 51 | $top.on('click', function () { 52 | $('body').velocity('scroll'); 53 | }); 54 | }, 55 | 56 | /** 57 | * Transform embedded video to support responsive layout. 58 | * @see http://toddmotto.com/fluid-and-responsive-youtube-and-vimeo-videos-with-fluidvids-js/ 59 | */ 60 | embeddedVideoTransformer: function () { 61 | var $iframes = $('iframe'); 62 | 63 | // Supported Players. Extend this if you need more players. 64 | var SUPPORTED_PLAYERS = [ 65 | 'www.youtube.com', 66 | 'player.vimeo.com', 67 | 'player.youku.com', 68 | 'music.163.com', 69 | 'www.tudou.com' 70 | ]; 71 | var pattern = new RegExp( SUPPORTED_PLAYERS.join('|') ); 72 | 73 | $iframes.each(function () { 74 | var iframe = this; 75 | var $iframe = $(this); 76 | var oldDimension = getDimension($iframe); 77 | var newDimension; 78 | 79 | if (this.src.search(pattern) > 0) { 80 | 81 | // Calculate the video ratio based on the iframe's w/h dimensions 82 | var videoRatio = getAspectRadio(oldDimension.width, oldDimension.height); 83 | 84 | // Replace the iframe's dimensions and position the iframe absolute 85 | // This is the trick to emulate the video ratio 86 | $iframe.width('100%').height('100%') 87 | .css({ 88 | position: 'absolute', 89 | top: '0', 90 | left: '0' 91 | }); 92 | 93 | 94 | // Wrap the iframe in a newFastClick is a simple, easy-to-use library for eliminating the 300ms delay between a physical tap and the firing of a click
event on mobile browsers. The aim is to make your application feel less laggy and more responsive while avoiding any interference with your current logic.
FastClick is developed by FT Labs, part of the Financial Times.
3 | 4 | 5 |According to Google:
6 |7 |9 |…mobile browsers will wait approximately 300ms from the time that you tap the button to fire the click event. The reason for this is that the browser is waiting to see if you are actually performing a double tap.
8 |
The library has been deployed as part of the FT Web App and is tried and tested on the following mobile browsers:
10 |FastClick doesn’t attach any listeners on desktop browsers.
19 |Chrome 32+ on Android with width=device-width
in the viewport meta tag doesn’t have a 300ms delay, therefore listeners aren’t attached.
<meta name="viewport" content="width=device-width, initial-scale=1">
21 |
22 | Same goes for Chrome on Android (all versions) with user-scalable=no
in the viewport meta tag. But be aware that user-scalable=no
also disables pinch zooming, which may be an accessibility concern.
For IE11+, you can use touch-action: manipulation;
to disable double-tap-to-zoom on certain elements (like links and buttons). For IE10 use -ms-touch-action: manipulation
.
Include fastclick.js in your JavaScript bundle or add it to your HTML page like this:
25 |<script type='application/javascript' src='/path/to/fastclick.js'></script>
26 |
27 | The script must be loaded prior to instantiating FastClick on any element of the page.
28 |To instantiate FastClick on the body
, which is the recommended method of use:
if ('addEventListener' in document) {
30 | document.addEventListener('DOMContentLoaded', function() {
31 | FastClick.attach(document.body);
32 | }, false);
33 | }
34 |
35 | Or, if you’re using jQuery:
36 |$(function() {
37 | FastClick.attach(document.body);
38 | });
39 |
40 | If you’re using Browserify or another CommonJS-style module system, the FastClick.attach
function will be returned when you call require('fastclick')
. As a result, the easiest way to use FastClick with these loaders is as follows:
var attachFastClick = require('fastclick');
42 | attachFastClick(document.body);
43 |
44 | Run make
to build a minified version of FastClick using the Closure Compiler REST API. The minified file is saved to build/fastclick.min.js
or you can download a pre-minified version.
Note: the pre-minified version is built using our build service which exposes the FastClick
object through Origami.fastclick
and will have the Browserify/CommonJS API (see above).
var attachFastClick = Origami.fastclick;
47 | attachFastClick(document.body);
48 |
49 | FastClick has AMD (Asynchronous Module Definition) support. This allows it to be lazy-loaded with an AMD loader, such as RequireJS. Note that when using the AMD style require, the full FastClick
object will be returned, not FastClick.attach
var FastClick = require('fastclick');
51 | FastClick.attach(document.body, options);
52 |
53 | You can install FastClick using Component, npm or Bower.
54 |For Ruby, there’s a third-party gem called fastclick-rails. For .NET there’s a NuGet package.
55 |needsclick
Sometimes you need FastClick to ignore certain elements. You can do this easily by adding the needsclick
class.
<a class="needsclick">Ignored by FastClick</a>
57 |
58 | Internally, FastClick uses document.createEvent
to fire a synthetic click
event as soon as touchend
is fired by the browser. It then suppresses the additional click
event created by the browser after that. In some cases, the non-synthetic click
event created by the browser is required, as described in the triggering focus example.
This is where the needsclick
class comes in. Add the class to any element that requires a non-synthetic click.
Another example of when to use the needsclick
class is with dropdowns in Twitter Bootstrap 2.2.2. Bootstrap add its own touchstart
listener for dropdowns, so you want to tell FastClick to ignore those. If you don’t, touch devices will automatically close the dropdown as soon as it is clicked, because both FastClick and Bootstrap execute the synthetic click, one opens the dropdown, the second closes it immediately after.
<a class="dropdown-toggle needsclick" data-toggle="dropdown">Dropdown</a>
62 |
63 | FastClick is designed to cope with many different browser oddities. Here are some examples to illustrate this:
64 |click
handlerThere are no automated tests. The files in tests/
are manual reduced test cases. We’ve had a think about how best to test these cases, but they tend to be very browser/device specific and sometimes subjective which means it’s not so trivial to test.
FastClick is maintained by Rowan Beentje, Matthew Caruana Galizia and Matthew Andrews at FT Labs. All open source code released by FT Labs is licenced under the MIT licence. We welcome comments, feedback and suggestions. Please feel free to raise an issue or pull request.
71 | -------------------------------------------------------------------------------- /lib/fastclick/bower.json: -------------------------------------------------------------------------------- 1 | {"name":"fastclick","main":"lib/fastclick.js","ignore":["**/.*","component.json","package.json","Makefile","tests","examples"]} -------------------------------------------------------------------------------- /lib/fastclick/lib/fastclick.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";function t(e,o){function i(t,e){return function(){return t.apply(e,arguments)}}var r;if(o=o||{},this.trackingClick=!1,this.trackingClickStart=0,this.targetElement=null,this.touchStartX=0,this.touchStartY=0,this.lastTouchIdentifier=0,this.touchBoundary=o.touchBoundary||10,this.layer=e,this.tapDelay=o.tapDelay||200,this.tapTimeout=o.tapTimeout||700,!t.notNeeded(e)){for(var a=["onMouse","onClick","onTouchStart","onTouchMove","onTouchEnd","onTouchCancel"],c=this,s=0,u=a.length;u>s;s++)c[a[s]]=i(c[a[s]],c);n&&(e.addEventListener("mouseover",this.onMouse,!0),e.addEventListener("mousedown",this.onMouse,!0),e.addEventListener("mouseup",this.onMouse,!0)),e.addEventListener("click",this.onClick,!0),e.addEventListener("touchstart",this.onTouchStart,!1),e.addEventListener("touchmove",this.onTouchMove,!1),e.addEventListener("touchend",this.onTouchEnd,!1),e.addEventListener("touchcancel",this.onTouchCancel,!1),Event.prototype.stopImmediatePropagation||(e.removeEventListener=function(t,n,o){var i=Node.prototype.removeEventListener;"click"===t?i.call(e,t,n.hijacked||n,o):i.call(e,t,n,o)},e.addEventListener=function(t,n,o){var i=Node.prototype.addEventListener;"click"===t?i.call(e,t,n.hijacked||(n.hijacked=function(t){t.propagationStopped||n(t)}),o):i.call(e,t,n,o)}),"function"==typeof e.onclick&&(r=e.onclick,e.addEventListener("click",function(t){r(t)},!1),e.onclick=null)}}var e=navigator.userAgent.indexOf("Windows Phone")>=0,n=navigator.userAgent.indexOf("Android")>0&&!e,o=/iP(ad|hone|od)/.test(navigator.userAgent)&&!e,i=o&&/OS 4_\d(_\d)?/.test(navigator.userAgent),r=o&&/OS [6-7]_\d/.test(navigator.userAgent),a=navigator.userAgent.indexOf("BB10")>0;t.prototype.needsClick=function(t){switch(t.nodeName.toLowerCase()){case"button":case"select":case"textarea":if(t.disabled)return!0;break;case"input":if(o&&"file"===t.type||t.disabled)return!0;break;case"label":case"iframe":case"video":return!0}return/\bneedsclick\b/.test(t.className)},t.prototype.needsFocus=function(t){switch(t.nodeName.toLowerCase()){case"textarea":return!0;case"select":return!n;case"input":switch(t.type){case"button":case"checkbox":case"file":case"image":case"radio":case"submit":return!1}return!t.disabled&&!t.readOnly;default:return/\bneedsfocus\b/.test(t.className)}},t.prototype.sendClick=function(t,e){var n,o;document.activeElement&&document.activeElement!==t&&document.activeElement.blur(),o=e.changedTouches[0],n=document.createEvent("MouseEvents"),n.initMouseEvent(this.determineEventType(t),!0,!0,window,1,o.screenX,o.screenY,o.clientX,o.clientY,!1,!1,!1,!1,0,null),n.forwardedTouchEvent=!0,t.dispatchEvent(n)},t.prototype.determineEventType=function(t){return n&&"select"===t.tagName.toLowerCase()?"mousedown":"click"},t.prototype.focus=function(t){var e;o&&t.setSelectionRange&&0!==t.type.indexOf("date")&&"time"!==t.type&&"month"!==t.type?(e=t.value.length,t.setSelectionRange(e,e)):t.focus()},t.prototype.updateScrollParent=function(t){var e,n;if(e=t.fastClickScrollParent,!e||!e.contains(t)){n=t;do{if(n.scrollHeight>n.offsetHeight){e=n,t.fastClickScrollParent=n;break}n=n.parentElement}while(n)}e&&(e.fastClickLastScrollTop=e.scrollTop)},t.prototype.getTargetElementFromEventTarget=function(t){return t.nodeType===Node.TEXT_NODE?t.parentNode:t},t.prototype.onTouchStart=function(t){var e,n,r;if(t.targetTouches.length>1)return!0;if(e=this.getTargetElementFromEventTarget(t.target),n=t.targetTouches[0],o){if(r=window.getSelection(),r.rangeCount&&!r.isCollapsed)return!0;if(!i){if(n.identifier&&n.identifier===this.lastTouchIdentifier)return t.preventDefault(),!1;this.lastTouchIdentifier=n.identifier,this.updateScrollParent(e)}}return this.trackingClick=!0,this.trackingClickStart=t.timeStamp,this.targetElement=e,this.touchStartX=n.pageX,this.touchStartY=n.pageY,t.timeStamp-this.lastClickTimeMake pull requests only one feature or change at the time. For example you have fixed a bug. You also have optimized some code. Optimization is not related to a bug. These should be submitted as separate pull requests. This way I can easily choose what to include. It is also easier to understand the code changes. Commit messages should be descriptive and full sentences.
2 |Do not commit minified versions. Do not touch the version number. Make the pull requests against 1.9.x branch.
3 |Proper commit message is full sentence. It starts with capital letter but does not end with period. Headlines do not end with period. The GitHub default Update filename.js
is not enough. When needed include also longer explanation what the commit does.
Capitalized, short (50 chars or less) summary
5 |
6 | More detailed explanatory text, if necessary. Wrap it to about 72
7 | characters or so. In some contexts, the first line is treated as the
8 | subject of an email and the rest of the text as the body. The blank
9 | line separating the summary from the body is critical (unless you omit
10 | the body entirely); tools like rebase can get confused if you run the
11 | two together.
12 |
When in doubt see Tim Pope’s blogpost A Note About Git Commit Messages
13 |When contributing to open source project it is polite to follow the original authors coding standars. They might be different than yours. It is not a holy war. Just follow then original.
14 |var snake_case = "something";
15 |
16 | function camelCase(options) {
17 | }
18 |
19 | if (true !== false) {
20 | console.log("here be dragons");
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/lib/jquery_lazyload/README.html:
--------------------------------------------------------------------------------
1 | Lazy Load delays loading of images in long web pages. Images outside of viewport wont be loaded before user scrolls to them. This is opposite of image preloading.
2 |Using Lazy Load on long web pages containing many large images makes the page load faster. Browser will be in ready state after loading visible images. In some cases it can also help to reduce server load.
3 |Lazy Load is inspired by YUI ImageLoader Utility by Matt Mlinac.
4 |Lazy Load depends on jQuery. Include them both in end of your HTML code:
5 |<script src="jquery.js" type="text/javascript"></script>
6 | <script src="jquery.lazyload.js" type="text/javascript"></script>
7 |
8 | You must alter your HTML code. URL of the real image must be put into data-original attribute. It is good idea to give Lazy Loaded image a specific class. This way you can easily control which images plugin is binded to. Note that you should have width and height attributes in your image tag.
9 |<img class="lazy" data-original="img/example.jpg" width="640" height="480">
10 |
11 | then in your code do:
12 |$("img.lazy").lazyload();
13 |
14 | This causes all images of class lazy to be lazy loaded.
15 |More information on Lazy Load project page.
16 |You can install with bower or npm.
17 |$ bower install jquery.lazyload
18 | $ npm install jquery-lazyload
19 |
20 | All code licensed under the MIT License. All images licensed under Creative Commons Attribution 3.0 Unported License. In other words you are basically free to do whatever you want. Just don’t remove my name from the source.
21 | -------------------------------------------------------------------------------- /lib/jquery_lazyload/bower.json: -------------------------------------------------------------------------------- 1 | {"name":"jquery_lazyload","version":"1.9.4","homepage":"http://www.appelsiini.net/projects/lazyload","authors":["Mika Tuupola