├── demo ├── 1.html ├── 2.html ├── 3.html └── index.html ├── .brackets.json ├── .gitattributes ├── package.json ├── styles └── style.css ├── README.md └── scripts └── coffce-pjax.js /demo/1.html: -------------------------------------------------------------------------------- 1 |

1.html

-------------------------------------------------------------------------------- /demo/2.html: -------------------------------------------------------------------------------- 1 |

2.html

-------------------------------------------------------------------------------- /demo/3.html: -------------------------------------------------------------------------------- 1 |

3.html

-------------------------------------------------------------------------------- /.brackets.json: -------------------------------------------------------------------------------- 1 | { 2 | "sbruchmann.staticpreview.basepath": "G:/轮子/coffce-pjax/" 3 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coffce-pjax", 3 | "version": "0.0.4", 4 | "description": "A simple pjax library", 5 | "main": "scripts/coffce-pjax.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/Coffcer/Coffce-PJAX.git" 12 | }, 13 | "keywords": [ 14 | "pjax", 15 | "coffce" 16 | ], 17 | "author": "coffce", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/Coffcer/Coffce-PJAX/issues" 21 | }, 22 | "homepage": "https://github.com/Coffcer/Coffce-PJAX" 23 | } 24 | -------------------------------------------------------------------------------- /styles/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | html { 5 | height: 100%; 6 | background-color: #EFEFEF; 7 | } 8 | body { 9 | margin: 0; 10 | height: 100%; 11 | overflow: hidden; 12 | } 13 | #container { 14 | position: relative; 15 | height: 50%; 16 | border-bottom: solid 1px #C1C1C1; 17 | } 18 | #container p { 19 | position: absolute; 20 | top: 0; 21 | bottom: 0; 22 | margin: auto; 23 | height: 40px; 24 | width: 100%; 25 | color: #555; 26 | text-align: center; 27 | font: 30px "microsoft yahei"; 28 | transition: all .3s; 29 | } 30 | #main { 31 | padding: 40px; 32 | height: 50%; 33 | text-align: center; 34 | border-top: solid 1px #FFF; 35 | } 36 | #main a { 37 | margin: 0 20px; 38 | color: #1075BF; 39 | text-decoration: none; 40 | font-family: "microsoft yahei"; 41 | } -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | COFFCE-PJAX-DEMO 6 | 7 | 8 | 9 |
10 |
11 | 1.html 12 | 2.html 13 | 3.html 14 |
15 | 16 | 17 | 55 | 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | coffce-pjax 2 | === 3 | coffce-pjax可以将页面所有的跳转替换为AJAX请求,把网站改造成单页面应用。
4 | note: 由于浏览器限制,pjax需要在服务器环境下使用,即不要使用file://xxx.html运行。 5 | 6 | ###有何用处: 7 | * 可以在页面切换间平滑过渡,增加Loading动画。 8 | * 可以在各个页面间传递数据,不依赖URL。 9 | * 可以选择性的保留状态,如音乐网站,切换页面时不会停止播放歌曲。 10 | * 所有的标签都可以用来跳转,不仅仅是a标签。 11 | * 避免了公共JS的反复执行,如无需在各个页面打开时都判断是否登录过等等。 12 | * 减少了请求体积,节省流量,加快页面响应速度。 13 | * 平滑降级到低版本浏览器上,对SEO也不会有影响。 14 | 15 | ###兼容性: 16 | * Chrome, Firefox, Safari, Android Browser, IE8+等。 17 | * 在IE8和IE9上使用URL Hash,即地址栏的#号。 18 | * 在更低版本的浏览器和搜索引擎蜘蛛上,保持默认跳转,不受影响。 19 | 20 | 如何使用 21 | --- 22 | ####安装: 23 | npm install coffce-pjax 24 | 25 | #### 引入 26 | ``` javascript 27 | // 使用全局变量 28 | var pjax = window.CoffcePJAX 29 | ``` 30 | 31 | ``` javascript 32 | // 使用commonJS或AMD 33 | var pjax = require("coffce-pjax"); 34 | ``` 35 | ####简单配置: 36 | ``` javascript 37 | pjax.init({ 38 | // 替换新页面内容的容器 39 | container: "body", 40 | // 是否在低版本浏览器上使用Hash 41 | hash: true 42 | }); 43 | ``` 44 | ####完整配置: 45 | ``` javascript 46 | pjax.init({ 47 | // 选择器,支持querySelector选择器 48 | selector: "a", 49 | // 要替换内容的容器,可为选择器字符串或DOM对象 50 | container: "body", 51 | // 是否在前进后退时开启本地缓存功能 52 | cache : true, 53 | // 是否对低版本浏览器启用hash方案,不启用此项的低版本浏览器则会按照普通模式跳转 54 | hash: false, 55 | // 是否允许跳转到当前相同URL,相当于刷新 56 | same: true, 57 | // 调试模式,console.log调试信息 58 | debug: false, 59 | 60 | // 各个执行阶段的过滤函数,返回false则停止pjax执行 61 | filter: { 62 | // 选择器过滤,如果querySelector无法满足需求,可以在此函数里二次过滤 63 | selector: function(a) {}, 64 | // 接收到ajax请求返回的内容时触发 65 | content: function(title, html) {} 66 | }, 67 | // 各个阶段的自定义函数,将代替默认函数 68 | custom: { 69 | // 自定义更换页面函数,可以在此实现动画效果等 70 | append: function(html, container) {} 71 | }, 72 | // 要监听的事件,相当于pjax.on(...),事件列表看下面 73 | events: {} 74 | }); 75 | ``` 76 | 77 | 接口 78 | --- 79 | ```javascript 80 | /** 81 | * 初始化 82 | * @param {Object} options 配置,详情见上面↑ 83 | */ 84 | pjax.init(config); 85 | ``` 86 | 87 | ```javascript 88 | // 注销插件,一般来说你不需要使用这个方法 89 | pjax.destroy(); 90 | ``` 91 | 92 | ```javascript 93 | /** 94 | * 使用pjax跳转到指定页面 95 | * @param {String} url 96 | * @param {Object} data 要传到新页面的参数,可以为null或undefined 97 | * @param {Function} callback 请求成功时的回调,可以为null或undefined 98 | */ 99 | pjax.turn(url, data, callback); 100 | ``` 101 | 102 | ```javascript 103 | /** 104 | * 监听事件,事件类型见下面↓ 105 | * @param {String} type 事件类型 106 | * @param {Function} listener 回调 107 | * @param {String} url 只监听某个url,可以是相对和绝对路径 108 | */ 109 | pjax.on(type, listener); 110 | pjax.on(type, url, listener); 111 | ``` 112 | 113 | ```javascript 114 | /** 115 | * 解除监听 116 | * @param {String} type 事件类型 117 | * @param {String} url 只监听某个url,可以是相对和绝对路径 118 | */ 119 | pjax.off(type); 120 | pjax.off(type, url); 121 | ``` 122 | 123 | ```javascript 124 | /** 125 | * 触发事件 126 | * @param {String} type 事件类型 127 | * @param {Object} args 参数 128 | */ 129 | pjax.trigger(type, args); 130 | ``` 131 | 132 | 事件 133 | --- 134 | ####监听事件 135 | ```javascript 136 | // 通过接口监听 137 | pjax.on(type, url, function); 138 | pjax.on(type, function); 139 | ``` 140 | ```javsctipy 141 | // 通过配置监听 142 | pjax.init({ 143 | // .... 144 | events: { 145 | type: function(){} 146 | } 147 | }); 148 | ``` 149 | 150 | ####事件类型 151 | **init**
152 | 在每个页面加载完成后触发,有一个object参数:{ title, html } 153 | 154 | **end**
155 | 在每个页面离开前触发 156 | 157 | **ajaxBegin**
158 | 在请求开始时触发。有一个object参数: { url, fnb, data, xhr }, url表示新页面的url,fnb表示是否由浏览器前进后退触发,data表示传到新页面的数据,xhr是请求的XMLHttpRequest()实例 159 | 160 | **ajaxSuccess**
161 | 在请求成功后触发。参数与begin一样。 162 | 163 | **ajaxError**
164 | 在请求失败后触发。参数与begin一样。 165 | 166 | 167 | 特性 168 | --- 169 | * 优先使用标签上的data-coffce-pjax-href,其次使用href 170 | * 标签上若有data-coffce-pjax属性,将作为data属性传递到新页面 171 | 172 | ```html 173 | // 将跳转到b.html,并传递字符串data 174 | 175 | ``` 176 | 177 | 服务端配合 178 | --- 179 | * 对于PJAX请求,服务端并不需要返回完整的HTML,只返回变动的Content部分即可。对于普通请求(一般由浏览器地址栏直接打开),则需要返回完整的HTML。 180 | * coffce-pjax在发送请求时,会带上请求头COFFCE-PJAX:true,你可以依此来判断当前请求是PJAX请求还是普通请求。 181 | * 由于没有返回完整的HTML,服务端应该将document.title放在请求头COFFCE-PJAX-TITLE里。 182 | 183 | 注意: 184 | ------ 185 | 作者很懒,没有认真测试过,接口也可能随时变动,使用需自己小心。 186 | 187 | License 188 | ----- 189 | MIT -------------------------------------------------------------------------------- /scripts/coffce-pjax.js: -------------------------------------------------------------------------------- 1 | /*jshint eqnull: true, expr: true, sub: true, browser: true, devel: true*/ 2 | /*global define, module */ 3 | 4 | /*! 5 | * Coffce-Pjax 6 | * 将页面所有的跳转替换为ajax请求,把网站改造成单页面应用 7 | * 兼容Chrome, Firefox, Safari, Android Browser, IE8+等 8 | * 在IE8和IE9上使用URL Hash,即地址栏的#号,你也可以选择不启用 9 | * 在更低版本的浏览器和搜索引擎蜘蛛上,保持默认跳转,不受影响 10 | */ 11 | 12 | (function (window, undefined) { 13 | "use strict"; 14 | 15 | // 配置 16 | var config = { 17 | // 选择器,支持querySelector选择器 18 | selector: "a", 19 | // 要替换内容的容器,可为选择器字符串或DOM对象 20 | container: "body", 21 | // 是否在前进后退时开启本地缓存功能 22 | cache: true, 23 | // 是否对低版本浏览器启用hash方案 24 | hash: false, 25 | // 是否允许跳转到当前相同URL,相当于刷新 26 | same: true, 27 | // 调试模式,console.log调试信息 28 | debug: false, 29 | // 各个执行阶段的过滤函数,返回false则停止pjax执行 30 | filter: { 31 | // params: element 32 | // 选择器过滤,如果querySelector无法满足需求,可以在此函数里二次过滤 33 | selector: null, 34 | // params: title, html 35 | // 接收到ajax请求返回的内容时触发 36 | content: null 37 | }, 38 | // 各个阶段的自定义函数,将替换默认实现 39 | custom: { 40 | // params: html, container 41 | // 自定义更换页面函数,可以在此实现动画效果等 42 | append: null 43 | }, 44 | // 事件监听,合并到CoffcePJAX.on()里 45 | events: null 46 | }; 47 | 48 | // 使用模式 枚举 49 | var SUPPORT = { 50 | // 不支持 51 | PASS: 0, 52 | // 使用Hash 53 | HASH: 1, 54 | // 使用HTML History API 55 | HTML5: 2 56 | }; 57 | 58 | // 浏览器支持情况 59 | var suppost = history.pushState ? SUPPORT.HTML5 : ("onhashchange" in window ? SUPPORT.HASH : SUPPORT.PASS); 60 | 61 | var util = { 62 | /** 63 | * 合并两个对象,浅拷贝 64 | * @param {Object} obj1 65 | * @param {Object} obj2 66 | */ 67 | extend: function (obj1, obj2) { 68 | if (!obj2) return; 69 | 70 | for (var key in obj2) { 71 | if (obj2.hasOwnProperty(key)) { 72 | obj1[key] = obj2[key]; 73 | } 74 | } 75 | 76 | return obj1; 77 | }, 78 | /** 79 | * 输出调试信息,仅在config.debug为true时输出 80 | * @param {String} text 81 | */ 82 | log: function (text) { 83 | config.debug && console.log("coffce-pjax: " + text); 84 | }, 85 | /** 86 | * 获取url中的路径, 如:www.google.com/abcd 返回 /abcd 87 | * @param {String} url 88 | */ 89 | getPath: function (url) { 90 | return url.replace(location.protocol + "//" + location.host, ""); 91 | }, 92 | /** 93 | * 通过相对路径获取完整的url 94 | * @param {String} href 95 | */ 96 | getFullHref: function (href) { 97 | // 利用a标签来获取href,除此之外,a标签还能用来获取许多url相关信息 98 | var a = document.createElement("a"); 99 | a.href = href; 100 | return a.href; 101 | }, 102 | /** 103 | * 判断dom是否匹配选择器 104 | * @param {Object} element 105 | * @param {String} selector 106 | */ 107 | matchSelector: function (element, selector) { 108 | var match = 109 | document.documentElement.webkitMatchesSelector || 110 | document.documentElement.mozMatchesSelector || 111 | document.documentElement.msMatchesSelector || 112 | // 兼容IE8及以下浏览器 113 | function (selector, element) { 114 | // 这是一个好方法,可惜IE8连indexOf都不支持 115 | // return Array.prototype.indexOf.call(document.querySelectorAll(selector), this) !== -1; 116 | 117 | if (element.tagName === selector.toUpperCase()) return true; 118 | 119 | var elements = document.querySelectorAll(selector), 120 | length = elements.length; 121 | 122 | while (length--) { 123 | if (elements[length] === this) return true; 124 | } 125 | 126 | return false; 127 | }; 128 | 129 | // 重写函数自身,使用闭包keep住match函数,不用每次都判断兼容 130 | util.matchSelector = function (element, selector) { 131 | return match.call(element, selector); 132 | }; 133 | 134 | return util.matchSelector(element, selector); 135 | } 136 | }; 137 | 138 | var cache = { 139 | key: function (url) { 140 | return "coffce-pjax[" + url + "]"; 141 | }, 142 | get: function (url) { 143 | var value = sessionStorage.getItem(cache.key(url)); 144 | return value && JSON.parse(value); 145 | }, 146 | set: function (url, value) { 147 | // storage有容量上限,超出限额会报错 148 | try { 149 | sessionStorage.setItem(cache.key(url), JSON.stringify(value)); 150 | } catch (e) { 151 | util.log("超出本地存储容量上线,本次操作将不使用本地缓存"); 152 | } 153 | }, 154 | clear: function () { 155 | var i = sessionStorage.length; 156 | while (i--) { 157 | var key = sessionStorage.key(i); 158 | if (key.indexOf("coffce-pjax") > -1) { 159 | sessionStorage.removeItem(key); 160 | } 161 | } 162 | }, 163 | }; 164 | 165 | var event = { 166 | // 在浏览器前进后退时执行 167 | popstate: function () { 168 | core.fnb = true; 169 | core.turn(location.href, null, null); 170 | }, 171 | // hash改变时执行,由于过滤了手动改变,所以也只在浏览器前进后退时执行 172 | hashchange: function () { 173 | if (!core.fnb) return; 174 | core.turn(location.href.replace("#/", ""), null, null); 175 | }, 176 | click: function (e) { 177 | var element = e.target || e.srcElement; 178 | 179 | // 过滤不匹配选择器的元素 180 | if (!util.matchSelector(element, config.selector)) return; 181 | 182 | // 调用自定义过滤函数 183 | if (config.filter.selector && !config.filter.selector(element)) return; 184 | 185 | // 优先使用data-coffce-pjax-href 186 | var url = element.getAttribute("data-coffce-pjax-href"); 187 | url = url ? util.getFullHref(url) : element.href; 188 | 189 | // 过滤空值 190 | if (url === undefined || url === "") return; 191 | 192 | // 阻止默认跳转, 193 | // 在这上面的return,仍会执行默认跳转,下面的就不会了 194 | e.preventDefault ? e.preventDefault() : (window.event.returnValue = false); 195 | 196 | // 阻止相同链接 197 | if (!config.same && url === location.href) return; 198 | 199 | // 标签上有这个值的话,将作为data传入新页面 200 | var data = element.getAttribute("data-coffce-pjax"); 201 | 202 | core.fnb = false; 203 | core.turn(url, data, null); 204 | }, 205 | bindEvent: function () { 206 | if (suppost === SUPPORT.HTML5) { 207 | window.addEventListener("popstate", event.popstate); 208 | window.addEventListener("click", event.click); 209 | } else { 210 | window.attachEvent("onhashchange", event.hashchange); 211 | document.documentElement.attachEvent("onclick", event.click); 212 | } 213 | }, 214 | unbindEvent: function () { 215 | if (suppost === SUPPORT.HTML5) { 216 | window.removeEventListener("popstate", event.popstate); 217 | window.removeEventListener("click", event.click); 218 | } else { 219 | window.detachEvent("onhashchange", event.hashchange); 220 | document.documentElement.detachEvent("onclick", event.click); 221 | } 222 | } 223 | }; 224 | 225 | var core = { 226 | // Forward And Back,表示当前操作是否由前进和后退触发 227 | fnb: false, 228 | // 显示新页面 229 | show: function (title, html) { 230 | pjax.trigger("end"); 231 | 232 | document.title = title; 233 | 234 | if (config.custom.append) { 235 | config.custom.append(html, config.container); 236 | } else { 237 | config.container.innerHTML = html; 238 | } 239 | 240 | pjax.trigger("init"); 241 | }, 242 | // 跳转到指定页面 243 | turn: function (url, data, callback) { 244 | var eventData = { 245 | url: url, 246 | fnb: core.fnb, 247 | data: data 248 | }; 249 | 250 | //pjax.trigger("begin", eventData); 251 | 252 | // 如果是由前进后退触发,并且开启了缓存,则试着从缓存中获取数据 253 | if (core.fnb && config.cache) { 254 | var value = cache.get(url); 255 | if (value !== null) { 256 | core.show(value.title, value.html); 257 | /*pjax.trigger("success", eventData); 258 | pjax.trigger("end", eventData);*/ 259 | return; 260 | } 261 | } 262 | 263 | // 开始发送请求 264 | var xhr = new XMLHttpRequest(); 265 | 266 | xhr.open("GET", url, true); 267 | xhr.setRequestHeader("COFFCE-PJAX", "true"); 268 | xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); 269 | 270 | eventData.xhr = xhr; 271 | pjax.trigger("ajaxBegin", eventData); 272 | 273 | xhr.onreadystatechange = function () { 274 | if (xhr.readyState === 4) { 275 | // 姑且认为200-300之间都是成功的请求,304是缓存 276 | if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) { 277 | var title = xhr.getResponseHeader("COFFCE-PJAX-TITLE") || document.title, 278 | html = xhr.responseText; 279 | 280 | // 内容过滤器 281 | if (config.filter.content && !config.filter.content(title, html)) { 282 | util.log("filter.content过滤不通过"); 283 | } else { 284 | callback && callback(data); 285 | pjax.trigger("ajaxSuccess", eventData); 286 | 287 | // 显示新页面 288 | core.show(title, html); 289 | 290 | if (!core.fnb) { 291 | // 修改URL 292 | if (suppost === SUPPORT.HTML5) { 293 | history.pushState(null, null, url); 294 | } else { 295 | location.hash = util.getPath(url); 296 | } 297 | 298 | // 添加到缓存 299 | if (config.cache) { 300 | cache.set(url, { 301 | title: title, 302 | html: html 303 | }); 304 | } 305 | } 306 | } 307 | } else { 308 | pjax.trigger("ajaxError", null, eventData); 309 | util.log("请求失败,错误码:" + xhr.status); 310 | } 311 | 312 | core.fnb = true; 313 | } 314 | }; 315 | xhr.send(); 316 | } 317 | }; 318 | 319 | var pjax = { 320 | ready: false, 321 | events: {}, 322 | /** 323 | * 初始化 324 | * @param {Object} options 配置 325 | */ 326 | init: function (options) { 327 | if (suppost === SUPPORT.PASS) { 328 | util.log("不支持该版本的浏览器"); 329 | return; 330 | } 331 | 332 | util.extend(config, options); 333 | 334 | // 将config.container转换为dom 335 | if (typeof config.container === "string") { 336 | var selectorName = config.container; 337 | 338 | config.container = document.querySelector(config.container); 339 | if (config.container === null) { 340 | throw new Error("找不到Element:" + selectorName); 341 | } 342 | } 343 | 344 | // 监听配置里的事件 345 | if (config.events) { 346 | for (var key in config.events) { 347 | pjax.on(key, null, config.events[key]); 348 | } 349 | } 350 | 351 | // 如果一打开就已经带有hash, 则立刻发请求 352 | // 由于hash不会被传到服务器,此时页面多半是首页,如打开www.google.com/#/abcd,其实是打开了www.google.com 353 | if (suppost === SUPPORT.HASH && location.hash.length > 2) { 354 | // 先删了当前内容,防止用户误会 355 | config.container.innerHTML = ""; 356 | pjax.ready = true; 357 | 358 | core.fnd = false; 359 | core.turn(location.href.replace("#/", ""), null, function () { 360 | pjax.trigger("init"); 361 | }); 362 | } 363 | 364 | event.bindEvent(); 365 | 366 | if (!pjax.ready) { 367 | pjax.ready = true; 368 | pjax.trigger("init"); 369 | } 370 | }, 371 | // 注销插件,一般来说你并不需要使用这个方法 372 | destroy: function () { 373 | pjax.events = null; 374 | event.unbindEvent(); 375 | util.clearCache(); 376 | }, 377 | /** 378 | * 使用pjax跳转到指定页面 379 | * @param {String} url 380 | * @param {Object} data 要传到新页面的参数,可以为null 381 | * @param {Function} callback 请求成功时的回调 382 | */ 383 | turn: function (url, data, callback) { 384 | url = util.getFullHref(url); 385 | core.fnb = false; 386 | core.turn(url, data, callback); 387 | }, 388 | /** 389 | * 监听事件 390 | * @param {String} type 事件类型 391 | * @param {String} url 指定监听该事件的页面,null表示所有页面都监听 392 | * @param {Function} listener 回调 393 | */ 394 | on: function (type, url, listener) { 395 | // 只有两个参数,跳过中间的url 396 | if (listener === undefined) { 397 | listener = url; 398 | url = null; 399 | } else if (url) { 400 | url = util.getFullHref(url); 401 | } 402 | 403 | pjax.events[type] = pjax.events[type] || []; 404 | pjax.events[type].push({ 405 | listener: listener, 406 | url: url 407 | }); 408 | }, 409 | /** 410 | * 解除监听 411 | * @param {String} type 事件类型 412 | * @param {String} url 解绑该事件的页面,null表示所有页面都解绑 413 | */ 414 | off: function (type, url) { 415 | if (url) { 416 | var list = pjax.events[type]; 417 | url = util.getFullHref(url); 418 | 419 | for (var i = 0; i < list.length; i++) { 420 | if (list[i].url === url) { 421 | list.splice(i, 1); 422 | i--; 423 | } 424 | } 425 | 426 | if (list.length) return; 427 | } 428 | 429 | delete pjax.events[type]; 430 | }, 431 | /** 432 | * 触发事件 433 | * @param {String} type 事件类型 434 | * @param {Object} args 参数 435 | */ 436 | trigger: function (type, args) { 437 | var list = pjax.events[type]; 438 | if (list) { 439 | for (var i = 0, length = list.length; i < length; i++) { 440 | list[i].listener.call(pjax, args); 441 | } 442 | } 443 | } 444 | }; 445 | 446 | if (typeof define === "function" && define.amd) { 447 | define([], function () { 448 | return pjax; 449 | }); 450 | } else if (typeof module === "object" && typeof exports === "object") { 451 | module.exports = pjax; 452 | } else { 453 | window.CoffcePJAX = pjax; 454 | } 455 | 456 | })(window); --------------------------------------------------------------------------------