├── 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);
--------------------------------------------------------------------------------