Created
June 6, 2014 09:00
-
-
Save zhoumengkang/4bdbb205495a1772b0fe to your computer and use it in GitHub Desktop.
phpwind官方的wind.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* HeadJS The only script in your <HEAD> | |
* Author Tero Piirainen (tipiirai) | |
* Maintainer Robert Hoffmann (itechnology) | |
* License MIT / http://bit.ly/mit-license | |
* | |
* Version 0.99 | |
* http://headjs.com | |
*/ | |
/* modify : head ==> Wind */ | |
; (function (win, undefined) { | |
"use strict"; | |
var doc = win.document, | |
domWaiters = [], | |
queue = [], // waiters for the "head ready" event | |
handlers = {}, // user functions waiting for events | |
assets = {}, // loadable items in various states | |
isAsync = "async" in doc.createElement("script") || "MozAppearance" in doc.documentElement.style || win.opera, | |
isHeadReady, | |
isDomReady, | |
/*** public API ***/ | |
headVar = win.head_conf && win.head_conf.head || "Wind", | |
api = win[headVar] = (win[headVar] || function () { api.ready.apply(null, arguments); }), | |
// states | |
PRELOADING = 1, | |
PRELOADED = 2, | |
LOADING = 3, | |
LOADED = 4; | |
// Method 1: simply load and let browser take care of ordering | |
if (isAsync) { | |
api.load = function () { | |
///<summary> | |
/// INFO: use cases | |
/// head.load("http://domain.com/file.js","http://domain.com/file.js", callBack) | |
/// head.load({ label1: "http://domain.com/file.js" }, { label2: "http://domain.com/file.js" }, callBack) | |
///</summary> | |
var args = arguments, | |
callback = args[args.length - 1], | |
items = {}; | |
if (!isFunction(callback)) { | |
callback = null; | |
} | |
each(args, function (item, i) { | |
if (item !== callback) { | |
item = getAsset(item); | |
items[item.name] = item; | |
load(item, callback && i === args.length - 2 ? function () { | |
if (allLoaded(items)) { | |
one(callback); | |
} | |
} : null); | |
} | |
}); | |
return api; | |
}; | |
// Method 2: preload with text/cache hack | |
} else { | |
api.load = function () { | |
var args = arguments, | |
rest = [].slice.call(args, 1), | |
next = rest[0]; | |
// wait for a while. immediate execution causes some browsers to ignore caching | |
if (!isHeadReady) { | |
queue.push(function () { | |
api.load.apply(null, args); | |
}); | |
return api; | |
} | |
// multiple arguments | |
if (!!next) { | |
/* Preload with text/cache hack (not good!) | |
* http://blog.getify.com/on-script-loaders/ | |
* http://www.nczonline.net/blog/2010/12/21/thoughts-on-script-loaders/ | |
* If caching is not configured correctly on the server, then items could load twice ! | |
*************************************************************************************/ | |
each(rest, function (item) { | |
if (!isFunction(item)) { | |
preLoad(getAsset(item)); | |
} | |
}); | |
// execute | |
load(getAsset(args[0]), isFunction(next) ? next : function () { | |
api.load.apply(null, rest); | |
}); | |
} | |
else { | |
// single item | |
load(getAsset(args[0])); | |
} | |
return api; | |
}; | |
} | |
// INFO: for retro compatibility | |
api.js = api.load; | |
api.test = function (test, success, failure, callback) { | |
///<summary> | |
/// INFO: use cases: | |
/// head.test(condition, null , "file.NOk" , callback); | |
/// head.test(condition, "fileOk.js", null , callback); | |
/// head.test(condition, "fileOk.js", "file.NOk" , callback); | |
/// head.test(condition, "fileOk.js", ["file.NOk", "file.NOk"], callback); | |
/// head.test({ | |
/// test : condition, | |
/// success : [{ label1: "file1Ok.js" }, { label2: "file2Ok.js" }], | |
/// failure : [{ label1: "file1NOk.js" }, { label2: "file2NOk.js" }], | |
/// callback: callback | |
/// ); | |
/// head.test({ | |
/// test : condition, | |
/// success : ["file1Ok.js" , "file2Ok.js"], | |
/// failure : ["file1NOk.js", "file2NOk.js"], | |
/// callback: callback | |
/// ); | |
///</summary> | |
var obj = (typeof test === 'object') ? test : { | |
test: test, | |
success: !!success ? isArray(success) ? success : [success] : false, | |
failure: !!failure ? isArray(failure) ? failure : [failure] : false, | |
callback: callback || noop | |
}; | |
// Test Passed ? | |
var passed = !!obj.test; | |
// Do we have a success case | |
if (passed && !!obj.success) { | |
obj.success.push(obj.callback); | |
api.load.apply(null, obj.success); | |
} | |
// Do we have a fail case | |
else if (!passed && !!obj.failure) { | |
obj.failure.push(obj.callback); | |
api.load.apply(null, obj.failure); | |
} | |
else { | |
callback(); | |
} | |
return api; | |
}; | |
api.ready = function (key, callback) { | |
///<summary> | |
/// INFO: use cases: | |
/// head.ready(callBack) | |
/// head.ready(document , callBack) | |
/// head.ready("file.js", callBack); | |
/// head.ready("label" , callBack); | |
///</summary> | |
// DOM ready check: head.ready(document, function() { }); | |
if (key === doc) { | |
if (isDomReady) { | |
one(callback); | |
} | |
else { | |
domWaiters.push(callback); | |
} | |
return api; | |
} | |
// shift arguments | |
if (isFunction(key)) { | |
callback = key; | |
key = "ALL"; | |
} | |
// make sure arguments are sane | |
if (typeof key !== 'string' || !isFunction(callback)) { | |
return api; | |
} | |
// This can also be called when we trigger events based on filenames & labels | |
var asset = assets[key]; | |
// item already loaded --> execute and return | |
if (asset && asset.state === LOADED || key === 'ALL' && allLoaded() && isDomReady) { | |
one(callback); | |
return api; | |
} | |
var arr = handlers[key]; | |
if (!arr) { | |
arr = handlers[key] = [callback]; | |
} | |
else { | |
arr.push(callback); | |
} | |
return api; | |
}; | |
// perform this when DOM is ready | |
api.ready(doc, function () { | |
if (allLoaded()) { | |
each(handlers.ALL, function (callback) { | |
one(callback); | |
}); | |
} | |
if (api.feature) { | |
api.feature("domloaded", true); | |
} | |
}); | |
/* private functions | |
*********************/ | |
function noop() { | |
// does nothing | |
} | |
function each(arr, callback) { | |
if (!arr) { | |
return; | |
} | |
// arguments special type | |
if (typeof arr === 'object') { | |
arr = [].slice.call(arr); | |
} | |
// do the job | |
for (var i = 0, l = arr.length; i < l; i++) { | |
callback.call(arr, arr[i], i); | |
} | |
} | |
/* A must read: http://bonsaiden.github.com/JavaScript-Garden | |
************************************************************/ | |
function is(type, obj) { | |
var clas = Object.prototype.toString.call(obj).slice(8, -1); | |
return obj !== undefined && obj !== null && clas === type; | |
} | |
function isFunction(item) { | |
return is("Function", item); | |
} | |
function isArray(item) { | |
return is("Array", item); | |
} | |
function toLabel(url) { | |
///<summary>Converts a url to a file label</summary> | |
var items = url.split("/"), | |
name = items[items.length - 1], | |
i = name.indexOf("?"); | |
return i !== -1 ? name.substring(0, i) : name; | |
} | |
// INFO: this look like a "im triggering callbacks all over the place, but only wanna run it one time function" ..should try to make everything work without it if possible | |
// INFO: Even better. Look into promises/defered's like jQuery is doing | |
function one(callback) { | |
///<summary>Execute a callback only once</summary> | |
callback = callback || noop; | |
if (callback._done) { | |
return; | |
} | |
callback(); | |
callback._done = 1; | |
} | |
function getAsset(item) { | |
///<summary> | |
/// Assets are in the form of | |
/// { | |
/// name : label, | |
/// url : url, | |
/// state: state | |
/// } | |
///</summary> | |
var asset = {}; | |
if (typeof item === 'object') { | |
for (var label in item) { | |
if (!!item[label]) { | |
asset = { | |
name: label, | |
url : item[label] | |
}; | |
} | |
} | |
} | |
else { | |
asset = { | |
name: toLabel(item), | |
url : item | |
}; | |
} | |
// is the item already existant | |
var existing = assets[asset.name]; | |
if (existing && existing.url === asset.url) { | |
return existing; | |
} | |
assets[asset.name] = asset; | |
return asset; | |
} | |
function allLoaded(items) { | |
items = items || assets; | |
for (var name in items) { | |
if (items.hasOwnProperty(name) && items[name].state !== LOADED) { | |
return false; | |
} | |
} | |
return true; | |
} | |
function onPreload(asset) { | |
asset.state = PRELOADED; | |
each(asset.onpreload, function (afterPreload) { | |
afterPreload.call(); | |
}); | |
} | |
function preLoad(asset, callback) { | |
if (asset.state === undefined) { | |
asset.state = PRELOADING; | |
asset.onpreload = []; | |
loadAsset({ url: asset.url, type: 'cache' }, function () { | |
onPreload(asset); | |
}); | |
} | |
} | |
function load(asset, callback) { | |
///<summary>Used with normal loading logic</summary> | |
callback = callback || noop; | |
if (asset.state === LOADED) { | |
callback(); | |
return; | |
} | |
// INFO: why would we trigger a ready event when its not really loaded yet ? | |
if (asset.state === LOADING) { | |
api.ready(asset.name, callback); | |
return; | |
} | |
if (asset.state === PRELOADING) { | |
asset.onpreload.push(function () { | |
load(asset, callback); | |
}); | |
return; | |
} | |
asset.state = LOADING; | |
loadAsset(asset, function () { | |
asset.state = LOADED; | |
callback(); | |
// handlers for this asset | |
each(handlers[asset.name], function (fn) { | |
one(fn); | |
}); | |
// dom is ready & no assets are queued for loading | |
// INFO: shouldn't we be doing the same test above ? | |
if (isDomReady && allLoaded()) { | |
each(handlers.ALL, function (fn) { | |
one(fn); | |
}); | |
} | |
}); | |
} | |
/* Parts inspired from: https://github.com/cujojs/curl | |
******************************************************/ | |
function loadAsset(asset, callback) { | |
callback = callback || noop; | |
var ele; | |
if (/\.css[^\.]*$/.test(asset.url)) { | |
ele = doc.createElement('link'); | |
ele.type = 'text/' + (asset.type || 'css'); | |
ele.rel = 'stylesheet'; | |
ele.href = asset.url; | |
} | |
else { | |
ele = doc.createElement('script'); | |
ele.type = 'text/' + (asset.type || 'javascript'); | |
ele.src = asset.url; | |
} | |
ele.onload = ele.onreadystatechange = process; | |
ele.onerror = error; | |
/* Good read, but doesn't give much hope ! | |
* http://blog.getify.com/on-script-loaders/ | |
* http://www.nczonline.net/blog/2010/12/21/thoughts-on-script-loaders/ | |
* https://hacks.mozilla.org/2009/06/defer/ | |
*/ | |
// ASYNC: load in parellel and execute as soon as possible | |
ele.async = false; | |
// DEFER: load in parallel but maintain execution order | |
ele.defer = false; | |
function error(event) { | |
event = event || win.event; | |
// need some more detailed error handling here | |
// release event listeners | |
ele.onload = ele.onreadystatechange = ele.onerror = null; | |
// do callback | |
callback(); | |
} | |
function process(event) { | |
event = event || win.event; | |
// IE 7/8 (2 events on 1st load) | |
// 1) event.type = readystatechange, s.readyState = loading | |
// 2) event.type = readystatechange, s.readyState = loaded | |
// IE 7/8 (1 event on reload) | |
// 1) event.type = readystatechange, s.readyState = complete | |
// event.type === 'readystatechange' && /loaded|complete/.test(s.readyState) | |
// IE 9 (3 events on 1st load) | |
// 1) event.type = readystatechange, s.readyState = loading | |
// 2) event.type = readystatechange, s.readyState = loaded | |
// 3) event.type = load , s.readyState = loaded | |
// IE 9 (2 events on reload) | |
// 1) event.type = readystatechange, s.readyState = complete | |
// 2) event.type = load , s.readyState = complete | |
// event.type === 'load' && /loaded|complete/.test(s.readyState) | |
// event.type === 'readystatechange' && /loaded|complete/.test(s.readyState) | |
// IE 10 (3 events on 1st load) | |
// 1) event.type = readystatechange, s.readyState = loading | |
// 2) event.type = load , s.readyState = complete | |
// 3) event.type = readystatechange, s.readyState = loaded | |
// IE 10 (3 events on reload) | |
// 1) event.type = readystatechange, s.readyState = loaded | |
// 2) event.type = load , s.readyState = complete | |
// 3) event.type = readystatechange, s.readyState = complete | |
// event.type === 'load' && /loaded|complete/.test(s.readyState) | |
// event.type === 'readystatechange' && /complete/.test(s.readyState) | |
// Other Browsers (1 event on 1st load) | |
// 1) event.type = load, s.readyState = undefined | |
// Other Browsers (1 event on reload) | |
// 1) event.type = load, s.readyState = undefined | |
// event.type == 'load' && s.readyState = undefined | |
// !doc.documentMode is for IE6/7, IE8+ have documentMode | |
if (event.type === 'load' || (/loaded|complete/.test(ele.readyState) && (!doc.documentMode || doc.documentMode < 9))) { | |
// release event listeners | |
ele.onload = ele.onreadystatechange = ele.onerror = null; | |
// do callback | |
callback(); | |
} | |
// emulates error on browsers that don't create an exception | |
// INFO: timeout not clearing ..why ? | |
//asset.timeout = win.setTimeout(function () { | |
// error({ type: "timeout" }); | |
//}, 3000); | |
} | |
// use insertBefore to keep IE from throwing Operation Aborted (thx Bryan Forbes!) | |
var head = doc['head'] || doc.getElementsByTagName('head')[0]; | |
// but insert at end of head, because otherwise if it is a stylesheet, it will not ovverride values | |
head.insertBefore(ele, head.lastChild); | |
} | |
/* Mix of stuff from jQuery & IEContentLoaded | |
* http://dev.w3.org/html5/spec/the-end.html#the-end | |
***************************************************/ | |
function domReady() { | |
// Make sure body exists, at least, in case IE gets a little overzealous (jQuery ticket #5443). | |
if (!doc.body) { | |
// let's not get nasty by setting a timeout too small.. (loop mania guaranteed if assets are queued) | |
win.clearTimeout(api.readyTimeout); | |
api.readyTimeout = win.setTimeout(domReady, 50); | |
return; | |
} | |
if (!isDomReady) { | |
isDomReady = true; | |
each(domWaiters, function (fn) { | |
one(fn); | |
}); | |
} | |
} | |
function domContentLoaded() { | |
// W3C | |
if (doc.addEventListener) { | |
doc.removeEventListener("DOMContentLoaded", domContentLoaded, false); | |
domReady(); | |
} | |
// IE | |
else if (doc.readyState === "complete") { | |
// we're here because readyState === "complete" in oldIE | |
// which is good enough for us to call the dom ready! | |
doc.detachEvent("onreadystatechange", domContentLoaded); | |
domReady(); | |
} | |
}; | |
// Catch cases where ready() is called after the browser event has already occurred. | |
// we once tried to use readyState "interactive" here, but it caused issues like the one | |
// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 | |
if (doc.readyState === "complete") { | |
domReady(); | |
} | |
// W3C | |
else if (doc.addEventListener) { | |
doc.addEventListener("DOMContentLoaded", domContentLoaded, false); | |
// A fallback to window.onload, that will always work | |
win.addEventListener("load", domReady, false); | |
} | |
// IE | |
else { | |
// Ensure firing before onload, maybe late but safe also for iframes | |
doc.attachEvent("onreadystatechange", domContentLoaded); | |
// A fallback to window.onload, that will always work | |
win.attachEvent("onload", domReady); | |
// If IE and not a frame | |
// continually check to see if the document is ready | |
var top = false; | |
try { | |
top = win.frameElement == null && doc.documentElement; | |
} catch (e) { } | |
if (top && top.doScroll) { | |
(function doScrollCheck() { | |
if (!isDomReady) { | |
try { | |
// Use the trick by Diego Perini | |
// http://javascript.nwbox.com/IEContentLoaded/ | |
top.doScroll("left"); | |
} catch (error) { | |
// let's not get nasty by setting a timeout too small.. (loop mania guaranteed if assets are queued) | |
win.clearTimeout(api.readyTimeout); | |
api.readyTimeout = win.setTimeout(doScrollCheck, 50); | |
return; | |
} | |
// and execute any waiting functions | |
domReady(); | |
} | |
})(); | |
} | |
} | |
/* | |
We wait for 300 ms before asset loading starts. for some reason this is needed | |
to make sure assets are cached. Not sure why this happens yet. A case study: | |
https://github.com/headjs/headjs/issues/closed#issue/83 | |
*/ | |
setTimeout(function () { | |
isHeadReady = true; | |
each(queue, function (fn) { | |
fn(); | |
}); | |
}, 300); | |
// browser type & version | |
var ua = navigator.userAgent.toLowerCase(); | |
ua = /(webkit)[ \/]([\w.]+)/.exec( ua ) || | |
/(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) || | |
/(msie) ([\w.]+)/.exec( ua ) || | |
!/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) || []; | |
if (ua[1] == 'msie') { | |
ua[1] = 'ie'; | |
ua[2] = document.documentMode || ua[2]; | |
} | |
api.browser = { version: ua[2] }; | |
api.browser[ua[1]] = true; | |
// IE specific | |
if (api.browser.ie) { | |
// HTML5 support | |
each("abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video".split("|"), function(el) { | |
doc.createElement(el); | |
}); | |
} | |
})(window); | |
/*********Wind JS*********/ | |
/* | |
* PHPWind JS core | |
* @Copyright : Copyright 2011, phpwind.com | |
* @Descript : PHPWind核心JS | |
* @Author : chaoren1641@gmail.com | |
* @Thanks : head.js (http://headjs.com) | |
* $Id: wind.js 23158 2013-01-06 11:47:46Z hao.lin $ : | |
*/ | |
/* | |
* 防止浏览器不支持console报错 | |
*/ | |
if(!window.console) { | |
window.console = {}; | |
var funs = ["profiles", "memory", "_commandLineAPI", "debug", "error", "info", "log", "warn", "dir", "dirxml", "trace", "assert", "count", "markTimeline", "profile", "profileEnd", "time", "timeEnd", "timeStamp", "group", "groupCollapsed", "groupEnd"]; | |
for(var i = 0;i < funs.length; i++) { | |
console[funs[i]] = function() {}; | |
} | |
} | |
/* | |
*解决ie6下不支持背景缓存 | |
*/ | |
Wind.ready(function() { | |
if (!+'\v1' && !('maxHeight' in document.body.style)) { | |
try{ | |
document.execCommand("BackgroundImageCache", false, true); | |
}catch(e){} | |
} | |
}); | |
/* | |
*wind core | |
*/ | |
(function(win) { | |
var root = win.GV.JS_ROOT || location.origin + '/js/dev/', //在wind.js加载之前定义GV.JS_ROOT | |
ver = win.GV.JS_VERSION.replace(/(\s)/g, '_') || '9.0', | |
//定义常用JS组件别名,使用别名加载 | |
alias = { | |
datePicker : 'ui_libs/datePicker/datePicker', | |
dialog : 'ui_libs/dialog/dialog', | |
dragSort : 'ui_libs/dragSort/dragSort', | |
chosen : 'ui_libs/chosen/chosen', | |
colorPicker : 'ui_libs/colorPicker/colorPicker', | |
global : 'pages/common/global', | |
jquery : 'jquery', | |
region : 'ui_libs/region/region', | |
school : 'ui_libs/school/school', | |
tabs : 'ui_libs/tabs/tabs', | |
//jquery util plugs | |
ajaxForm : 'util_libs/ajaxForm', | |
bgiframe : 'util_libs/bgiframe', | |
dateSelect : 'util_libs/dateSelect', | |
draggable : 'util_libs/draggable', | |
dragsort : 'util_libs/dragsort', | |
dragUpload : 'util_libs/dragUpload', | |
emailAutoMatch : 'util_libs/emailAutoMatch', | |
gallerySlide : 'util_libs/gallerySlide', | |
hotkeys : 'util_libs/hotkeys', | |
hoverdelay : 'util_libs/hoverdelay', | |
lazyload : 'util_libs/lazyload', | |
lazySlide : 'util_libs/lazySlide', | |
localStorage : 'util_libs/localStorage', | |
rangeInsert : 'util_libs/rangeInsert', | |
requestFullScreen : 'util_libs/requestFullScreen', | |
scrollFixed : 'util_libs/scrollFixed', | |
slides : 'util_libs/slides', | |
slidePlayer : 'util_libs/slidePlayer', | |
timeago : 'util_libs/timeago', | |
tablesorter : 'util_libs/tablesorter', | |
textCopy : 'util_libs/textCopy/textCopy', | |
uploadPreview : 'util_libs/uploadPreview', | |
validate : 'util_libs/validate', | |
//windeditor | |
windeditor : 'windeditor/windeditor', | |
//native js util plugs | |
swfupload : 'util_libs/swfupload/swfupload' | |
}, | |
alias_css = { | |
colorPicker : 'ui_libs/colorPicker/style', | |
datePicker : 'ui_libs/datePicker/style', | |
chosen : 'ui_libs/chosen/chosen' | |
}; | |
//add suffix and version | |
for(var i in alias) { | |
if (alias.hasOwnProperty(i)) { | |
alias[i] = root + alias[i] +'.js?v=' + ver; | |
} | |
} | |
for(var i in alias_css) { | |
if (alias_css.hasOwnProperty(i)) { | |
alias_css[i] = root + alias_css[i] +'.css?v=' + ver; | |
} | |
} | |
//css loader | |
win.Wind = win.Wind || {}; | |
//!TODO old webkit and old firefox does not support | |
Wind.css = function(alias/*alias or path*/,callback) { | |
var url = alias_css[alias] ? alias_css[alias] : alias | |
var link = document.createElement('link'); | |
link.rel = 'stylesheet'; | |
link.href = url; | |
link.onload = link.onreadystatechange = function() {//chrome link无onload事件 | |
var state = link.readyState; | |
if (callback && !callback.done && (!state || /loaded|complete/.test(state))) { | |
callback.done = true; | |
callback(); | |
} | |
} | |
document.getElementsByTagName('head')[0].appendChild(link); | |
}; | |
//Using the alias to load the script file | |
Wind.use = function() { | |
var args = arguments,len = args.length; | |
for( var i = 0;i < len;i++ ) { | |
if(typeof args[i] === 'string' && alias[args[i]]) { | |
args[i] = alias[args[i]]; | |
} | |
} | |
Wind.js.apply(null,args); | |
}; | |
//Wind javascript template (author: John Resig http://ejohn.org/blog/javascript-micro-templating/) | |
var cache = {}; | |
Wind.tmpl = function (str, data) { | |
var fn = !/\W/.test(str) ? cache[str] = cache[str] || tmpl(str) : | |
new Function("obj", "var p=[],print=function(){p.push.apply(p,arguments);};" + | |
"with(obj){p.push('" + | |
str.replace(/[\r\t\n]/g, " ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g, "$1\r").replace(/\t=(.*?)%>/g, "',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'") + "');}return p.join('');"); | |
return data ? fn(data) : fn; | |
}; | |
//Wind全局功能函数命名空间 | |
Wind.Util = {} | |
})(window); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment