jquery.artdialog.js 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538
  1. /*!
  2. * artDialog 5.0.4
  3. * Date: 2013-07-31
  4. * https://github.com/aui/artDialog
  5. * (c) 2009-2013 TangBin, http://www.planeArt.cn
  6. *
  7. * This is licensed under the GNU LGPL, version 2.1 or later.
  8. * For details, see: http://creativecommons.org/licenses/LGPL/2.1/
  9. */
  10. ;(function (window, undefined) {
  11. var $ = window.art = function (selector, context) {
  12. return new $.fn.constructor(selector, context);
  13. },
  14. quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,
  15. rclass = /[\n\t]/g;
  16. if (window.$ === undefined) {
  17. window.$ = $;
  18. };
  19. $.fn = $.prototype = {
  20. constructor: function (selector, context) {
  21. var match, elem;
  22. context = context || document;
  23. if (!selector) {
  24. return this;
  25. };
  26. if (selector.nodeType) {
  27. this[0] = selector;
  28. return this;
  29. };
  30. if (typeof selector === 'string') {
  31. match = quickExpr.exec(selector);
  32. if (match && match[2]) {
  33. elem = context.getElementById(match[2]);
  34. if (elem && elem.parentNode) this[0] = elem;
  35. return this;
  36. };
  37. };
  38. this[0] = selector;
  39. return this;
  40. },
  41. /**
  42. * 判断样式类是否存在
  43. * @param {String} 名称
  44. * @return {Boolean}
  45. */
  46. hasClass: function (name) {
  47. var className = ' ' + name + ' ';
  48. if ((' ' + this[0].className + ' ').replace(rclass, ' ').indexOf(className) > -1) {
  49. return true;
  50. };
  51. return false;
  52. },
  53. /**
  54. * 添加样式类
  55. * @param {String} 名称
  56. */
  57. addClass: function (name) {
  58. if (!this.hasClass(name)) {
  59. this[0].className += ' ' + name;
  60. };
  61. return this;
  62. },
  63. /**
  64. * 移除样式类
  65. * @param {String} 名称
  66. */
  67. removeClass: function (name) {
  68. var elem = this[0];
  69. if (!name) {
  70. elem.className = '';
  71. } else
  72. if (this.hasClass(name)) {
  73. elem.className = elem.className.replace(name, ' ');
  74. };
  75. return this;
  76. },
  77. /**
  78. * 读写样式<br />
  79. * css(name) 访问第一个匹配元素的样式属性<br />
  80. * css(properties) 把一个"名/值对"对象设置为所有匹配元素的样式属性<br />
  81. * css(name, value) 在所有匹配的元素中,设置一个样式属性的值<br />
  82. */
  83. css: function (name, value) {
  84. var i, elem = this[0], obj = arguments[0];
  85. if (typeof name === 'string') {
  86. if (value === undefined) {
  87. return $.css(elem, name);
  88. } else {
  89. elem.style[name] = value;
  90. };
  91. } else {
  92. for (i in obj) {
  93. elem.style[i] = obj[i];
  94. };
  95. };
  96. return this;
  97. },
  98. /** 显示元素 */
  99. show: function () {
  100. return this.css('display', 'block');
  101. },
  102. /** 隐藏元素 */
  103. hide: function () {
  104. return this.css('display', 'none');
  105. },
  106. /**
  107. * 获取相对文档的坐标
  108. * @return {Object} 返回left、top的数值
  109. */
  110. offset: function () {
  111. var elem = this[0],
  112. box = elem.getBoundingClientRect(),
  113. doc = elem.ownerDocument,
  114. body = doc.body,
  115. docElem = doc.documentElement,
  116. clientTop = docElem.clientTop || body.clientTop || 0,
  117. clientLeft = docElem.clientLeft || body.clientLeft || 0,
  118. top = box.top + (self.pageYOffset || docElem.scrollTop) - clientTop,
  119. left = box.left + (self.pageXOffset || docElem.scrollLeft) - clientLeft;
  120. return {
  121. left: left,
  122. top: top
  123. };
  124. },
  125. /**
  126. * 读写HTML - (不支持文本框)
  127. * @param {String} 内容
  128. */
  129. html: function (content) {
  130. var elem = this[0];
  131. if (content === undefined) return elem.innerHTML;
  132. $.cleanData(elem.getElementsByTagName('*'));
  133. elem.innerHTML = content;
  134. return this;
  135. },
  136. /**
  137. * 移除节点
  138. */
  139. remove: function () {
  140. var elem = this[0];
  141. $.cleanData(elem.getElementsByTagName('*'));
  142. $.cleanData([elem]);
  143. elem.parentNode.removeChild(elem);
  144. return this;
  145. },
  146. /**
  147. * 事件绑定
  148. * @param {String} 类型
  149. * @param {Function} 要绑定的函数
  150. */
  151. bind: function (type, callback) {
  152. $.event.add(this[0], type, callback);
  153. return this;
  154. },
  155. /**
  156. * 移除事件
  157. * @param {String} 类型
  158. * @param {Function} 要卸载的函数
  159. */
  160. unbind: function(type, callback) {
  161. $.event.remove(this[0], type, callback);
  162. return this;
  163. }
  164. };
  165. $.fn.constructor.prototype = $.fn;
  166. /** 检测window */
  167. $.isWindow = function (obj) {
  168. return obj && typeof obj === 'object' && 'setInterval' in obj;
  169. };
  170. /**
  171. * 搜索子元素
  172. * 注意:只支持nodeName或.className的形式,并且只返回第一个元素
  173. * @param {String}
  174. */
  175. $.fn.find = function (expr) {
  176. var value, elem = this[0],
  177. className = expr.split('.')[1];
  178. if (className) {
  179. if (document.getElementsByClassName) {
  180. value = elem.getElementsByClassName(className);
  181. } else {
  182. value = getElementsByClassName(className, elem);
  183. };
  184. } else {
  185. value = elem.getElementsByTagName(expr);
  186. };
  187. return $(value[0]);
  188. };
  189. function getElementsByClassName (className, node, tag) {
  190. node = node || document;
  191. tag = tag || '*';
  192. var i = 0,
  193. j = 0,
  194. classElements = [],
  195. els = node.getElementsByTagName(tag),
  196. elsLen = els.length,
  197. pattern = new RegExp("(^|\\s)" + className + "(\\s|$)");
  198. for (; i < elsLen; i ++) {
  199. if (pattern.test(els[i].className)) {
  200. classElements[j] = els[i];
  201. j ++;
  202. };
  203. };
  204. return classElements;
  205. };
  206. /**
  207. * 遍历
  208. * @param {Object}
  209. * @param {Function}
  210. */
  211. $.each = function (obj, callback) {
  212. var name, i = 0,
  213. length = obj.length,
  214. isObj = length === undefined;
  215. if (isObj) {
  216. for (name in obj) {
  217. if (callback.call(obj[name], name, obj[name]) === false) {
  218. break;
  219. };
  220. };
  221. } else {
  222. for (
  223. var value = obj[0];
  224. i < length && callback.call(value, i, value) !== false;
  225. value = obj[++i]
  226. ) {};
  227. };
  228. return obj;
  229. };
  230. /**
  231. * 读写缓存
  232. * @param {HTMLElement} 元素
  233. * @param {String} 缓存名称
  234. * @param {Any} 数据
  235. * @return {Any} 如果无参数data则返回缓存数据
  236. */
  237. $.data = function (elem, name, data) {
  238. var cache = $.cache,
  239. id = uuid(elem);
  240. if (name === undefined) {
  241. return cache[id];
  242. };
  243. if (!cache[id]) {
  244. cache[id] = {};
  245. };
  246. if (data !== undefined) {
  247. cache[id][name] = data;
  248. };
  249. return cache[id][name];
  250. };
  251. /**
  252. * 删除缓存
  253. * @param {HTMLElement} 元素
  254. * @param {String} 缓存名称
  255. */
  256. $.removeData = function (elem, name) {
  257. var empty = true,
  258. expando = $.expando,
  259. cache = $.cache,
  260. id = uuid(elem),
  261. thisCache = id && cache[id];
  262. if (!thisCache) {
  263. return;
  264. };
  265. if (name) {
  266. delete thisCache[name];
  267. for (var n in thisCache) {
  268. empty = false;
  269. };
  270. if (empty) {
  271. delete $.cache[id];
  272. };
  273. } else {
  274. delete cache[id];
  275. if (elem.removeAttribute) {
  276. elem.removeAttribute(expando);
  277. } else {
  278. elem[expando] = null;
  279. };
  280. };
  281. };
  282. $.uuid = 0;
  283. $.cache = {};
  284. $.expando = '@cache' + (+ new Date);
  285. // 标记元素唯一身份
  286. function uuid (elem) {
  287. var expando = $.expando,
  288. id = elem === window ? 0 : elem[expando];
  289. if (id === undefined) elem[expando] = id = ++ $.uuid;
  290. return id;
  291. };
  292. /**
  293. * 事件机制
  294. * @namespace
  295. * @requires [$.data, $.removeData]
  296. */
  297. $.event = {
  298. /**
  299. * 添加事件
  300. * @param {HTMLElement} 元素
  301. * @param {String} 事件类型
  302. * @param {Function} 要添加的函数
  303. */
  304. add: function (elem, type, callback) {
  305. var cache, listeners,
  306. that = $.event,
  307. data = $.data(elem, '@events') || $.data(elem, '@events', {});
  308. cache = data[type] = data[type] || {};
  309. listeners = cache.listeners = cache.listeners || [];
  310. listeners.push(callback);
  311. if (!cache.handler) {
  312. cache.elem = elem;
  313. cache.handler = that.handler(cache);
  314. elem.addEventListener
  315. ? elem.addEventListener(type, cache.handler, false)
  316. : elem.attachEvent('on' + type, cache.handler);
  317. };
  318. },
  319. /**
  320. * 卸载事件
  321. * @param {HTMLElement} 元素
  322. * @param {String} 事件类型
  323. * @param {Function} 要卸载的函数
  324. */
  325. remove: function (elem, type, callback) {
  326. var i, cache, listeners,
  327. that = $.event,
  328. empty = true,
  329. data = $.data(elem, '@events');
  330. if (!data) {
  331. return;
  332. };
  333. if (!type) {
  334. for (i in data) that.remove(elem, i);
  335. return;
  336. };
  337. cache = data[type];
  338. if (!cache) {
  339. return;
  340. };
  341. listeners = cache.listeners;
  342. if (callback) {
  343. for (i = 0; i < listeners.length; i ++) {
  344. listeners[i] === callback && listeners.splice(i--, 1);
  345. };
  346. } else {
  347. cache.listeners = [];
  348. };
  349. if (cache.listeners.length === 0) {
  350. elem.removeEventListener
  351. ? elem.removeEventListener(type, cache.handler, false)
  352. : elem.detachEvent('on' + type, cache.handler);
  353. delete data[type];
  354. cache = $.data(elem, '@events');
  355. for (var n in cache) {
  356. empty = false;
  357. };
  358. if (empty) {
  359. $.removeData(elem, '@events');
  360. };
  361. };
  362. },
  363. /** @inner 事件句柄 */
  364. handler: function (cache) {
  365. return function (event) {
  366. event = $.event.fix(event || window.event);
  367. for (var i = 0, list = cache.listeners, fn; fn = list[i++];) {
  368. if (fn.call(cache.elem, event) === false) {
  369. event.preventDefault();
  370. event.stopPropagation();
  371. };
  372. };
  373. };
  374. },
  375. /** @inner Event对象兼容处理 */
  376. fix: function (event) {
  377. if (event.target) {
  378. return event;
  379. };
  380. var eventObj = {
  381. target: event.srcElement || document,
  382. preventDefault: function () {event.returnValue = false},
  383. stopPropagation: function () {event.cancelBubble = true}
  384. };
  385. // IE6/7/8 在原生window.event对象写入数据会导致内存无法回收,应当采用拷贝
  386. for (var i in event) {
  387. eventObj[i] = event[i];
  388. }
  389. return eventObj;
  390. }
  391. };
  392. /**
  393. * 清理元素集的事件与缓存
  394. * @requires [$.removeData, $.event]
  395. * @param {HTMLCollection} 元素集
  396. */
  397. $.cleanData = function (elems) {
  398. var i = 0, elem,
  399. len = elems.length,
  400. removeEvent = $.event.remove,
  401. removeData = $.removeData;
  402. for (; i < len; i ++) {
  403. elem = elems[i];
  404. removeEvent(elem);
  405. removeData(elem);
  406. };
  407. };
  408. // 获取css
  409. $.css = 'defaultView' in document && 'getComputedStyle' in document.defaultView ?
  410. function (elem, name) {
  411. return document.defaultView.getComputedStyle(elem, false)[name];
  412. } :
  413. function (elem, name) {
  414. return elem.currentStyle[name] || '';
  415. };
  416. /**
  417. * 获取滚动条位置 - [不支持写入]
  418. * $.fn.scrollLeft, $.fn.scrollTop
  419. * @example 获取文档垂直滚动条:$(document).scrollTop()
  420. * @return {Number} 返回滚动条位置
  421. */
  422. $.each(['Left', 'Top'], function (i, name) {
  423. var method = 'scroll' + name;
  424. $.fn[method] = function () {
  425. var elem = this[0], win;
  426. win = getWindow(elem);
  427. return win ?
  428. ('pageXOffset' in win) ?
  429. win[i ? 'pageYOffset' : 'pageXOffset'] :
  430. win.document.documentElement[method] || win.document.body[method] :
  431. elem[method];
  432. };
  433. });
  434. function getWindow (elem) {
  435. return $.isWindow(elem) ?
  436. elem :
  437. elem.nodeType === 9 ?
  438. elem.defaultView || elem.parentWindow :
  439. false;
  440. };
  441. /**
  442. * 获取窗口或文档尺寸 - [只支持window与document读取]
  443. * @example
  444. 获取文档宽度:$(document).width()
  445. 获取可视范围:$(window).width()
  446. * @return {Number}
  447. */
  448. $.each(['Height', 'Width'], function (i, name) {
  449. var type = name.toLowerCase();
  450. $.fn[type] = function (size) {
  451. var elem = this[0];
  452. if (!elem) {
  453. return size == null ? null : this;
  454. };
  455. return $.isWindow(elem) ?
  456. elem.document.documentElement['client' + name] || elem.document.body['client' + name] :
  457. (elem.nodeType === 9) ?
  458. Math.max(
  459. elem.documentElement['client' + name],
  460. elem.body['scroll' + name], elem.documentElement['scroll' + name],
  461. elem.body['offset' + name], elem.documentElement['offset' + name]
  462. ) : null;
  463. };
  464. });
  465. return $}(window));
  466. ;(function ($, window, undefined) {
  467. // artDialog 只支持 xhtml 1.0 或者以上的 DOCTYPE 声明
  468. if (document.compatMode === 'BackCompat') {
  469. throw new Error('artDialog: Document types require more than xhtml1.0');
  470. };
  471. var _singleton,
  472. _count = 0,
  473. _root = $(document.getElementsByTagName('html')[0]),
  474. _expando = 'artDialog' + (+ new Date),
  475. _isIE6 = window.VBArray && !window.XMLHttpRequest,
  476. _isMobile = 'createTouch' in document && !('onmousemove' in document)
  477. || /(iPhone|iPad|iPod)/i.test(navigator.userAgent),
  478. _isFixed = !_isIE6 && !_isMobile,
  479. _getActive = function () {
  480. try {
  481. // bug: ie8~9, iframe #26
  482. return document.activeElement;
  483. } catch (e) {
  484. }
  485. },
  486. _activeElement = _getActive();
  487. var artDialog = function (config, ok, cancel) {
  488. config = config || {};
  489. if (typeof config === 'string' || config.nodeType === 1) {
  490. config = {content: config, fixed: !_isMobile};
  491. };
  492. var api, defaults = artDialog.defaults;
  493. var elem = config.follow = this.nodeType === 1 && this || config.follow;
  494. // 合并默认配置
  495. for (var i in defaults) {
  496. if (config[i] === undefined) {
  497. config[i] = defaults[i];
  498. };
  499. };
  500. config.id = elem && elem[_expando + 'follow'] || config.id || _expando + _count;
  501. api = artDialog.list[config.id];
  502. if (api) {
  503. if (elem) {
  504. api.follow(elem)
  505. };
  506. api.zIndex().focus();
  507. return api;
  508. };
  509. // 目前主流移动设备对fixed支持不好,禁用此特性
  510. if (!_isFixed) {
  511. config.fixed = false;
  512. };
  513. // !$.isArray(config.button)
  514. if (!config.button || !config.button.push) {
  515. config.button = [];
  516. };
  517. // 确定按钮
  518. if (ok !== undefined) {
  519. config.ok = ok;
  520. };
  521. if (config.ok) {
  522. config.button.push({
  523. id: 'ok',
  524. value: config.okValue,
  525. callback: config.ok,
  526. focus: true
  527. });
  528. };
  529. // 取消按钮
  530. if (cancel !== undefined) {
  531. config.cancel = cancel;
  532. };
  533. if (config.cancel) {
  534. config.button.push({
  535. id: 'cancel',
  536. value: config.cancelValue,
  537. callback: config.cancel
  538. });
  539. };
  540. // 更新 zIndex 全局配置
  541. artDialog.defaults.zIndex = config.zIndex;
  542. _count ++;
  543. return artDialog.list[config.id] = _singleton ?
  544. _singleton._create(config) : new artDialog.fn._create(config);
  545. };
  546. artDialog.version = '5.0.4';
  547. artDialog.fn = artDialog.prototype = {
  548. _create: function (config) {
  549. var dom;
  550. this.closed = false;
  551. this.config = config;
  552. this.dom = dom = this.dom || this._innerHTML(config);
  553. config.skin && dom.wrap.addClass(config.skin);
  554. dom.wrap.css('position', config.fixed ? 'fixed' : 'absolute');
  555. dom.close[config.cancel === false ? 'hide' : 'show']();
  556. dom.content.css('padding', config.padding);
  557. this.button.apply(this, config.button);
  558. this.title(config.title)
  559. .content(config.content)
  560. .size(config.width, config.height)
  561. .time(config.time);
  562. this._reset();
  563. this.zIndex();
  564. config.lock && this.lock();
  565. this._addEvent();
  566. this[config.visible ? 'visible' : 'hidden']().focus();
  567. _singleton = null;
  568. config.initialize && config.initialize.call(this);
  569. return this;
  570. },
  571. /**
  572. * 设置内容
  573. * @param {String, HTMLElement, Object} 内容 (可选)
  574. */
  575. content: function (message) {
  576. var prev, next, parent, display,
  577. that = this,
  578. $content = this.dom.content,
  579. content = $content[0];
  580. if (this._elemBack) {
  581. this._elemBack();
  582. delete this._elemBack;
  583. };
  584. if (typeof message === 'string') {
  585. $content.html(message);
  586. } else
  587. if (message && message.nodeType === 1) {
  588. // 让传入的元素在对话框关闭后可以返回到原来的地方
  589. display = message.style.display;
  590. prev = message.previousSibling;
  591. next = message.nextSibling;
  592. parent = message.parentNode;
  593. this._elemBack = function () {
  594. if (prev && prev.parentNode) {
  595. prev.parentNode.insertBefore(message, prev.nextSibling);
  596. } else if (next && next.parentNode) {
  597. next.parentNode.insertBefore(message, next);
  598. } else if (parent) {
  599. parent.appendChild(message);
  600. };
  601. message.style.display = display;
  602. that._elemBack = null;
  603. };
  604. $content.html('');
  605. content.appendChild(message);
  606. $(message).show();
  607. };
  608. this._reset();
  609. return this;
  610. },
  611. /**
  612. * 设置标题
  613. * @param {String, Boolean} 标题内容. 为 false 则隐藏标题栏
  614. */
  615. title: function (content) {
  616. var dom = this.dom,
  617. outer = dom.outer,
  618. $title = dom.title,
  619. className = 'd-state-noTitle';
  620. if (content === false) {
  621. $title.hide().html('');
  622. outer.addClass(className);
  623. } else {
  624. $title.show().html(content);
  625. outer.removeClass(className);
  626. };
  627. return this;
  628. },
  629. /** @inner 位置居中 */
  630. position: function () {
  631. var dom = this.dom,
  632. wrap = dom.wrap[0],
  633. $window = dom.window,
  634. $document = dom.document,
  635. fixed = this.config.fixed,
  636. dl = fixed ? 0 : $document.scrollLeft(),
  637. dt = fixed ? 0 : $document.scrollTop(),
  638. ww = $window.width(),
  639. wh = $window.height(),
  640. ow = wrap.offsetWidth,
  641. oh = wrap.offsetHeight,
  642. left = (ww - ow) / 2 + dl,
  643. top = (wh - oh) * 382 / 1000 + dt,// 黄金比例
  644. style = wrap.style;
  645. style.left = Math.max(parseInt(left), dl) + 'px';
  646. style.top = Math.max(parseInt(top), dt) + 'px';
  647. if (this._follow) {
  648. this._follow.removeAttribute(_expando + 'follow');
  649. this._follow = null;
  650. }
  651. return this;
  652. },
  653. /**
  654. * 尺寸
  655. * @param {Number, String} 宽度
  656. * @param {Number, String} 高度
  657. */
  658. size: function (width, height) {
  659. var style = this.dom.main[0].style;
  660. if (typeof width === 'number') {
  661. width = width + 'px';
  662. };
  663. if (typeof height === 'number') {
  664. height = height + 'px';
  665. };
  666. style.width = width;
  667. style.height = height;
  668. return this;
  669. },
  670. /**
  671. * 跟随元素
  672. * @param {HTMLElement}
  673. */
  674. follow: function (elem) {
  675. var $elem = $(elem),
  676. config = this.config;
  677. // 隐藏元素不可用
  678. if (!elem || !elem.offsetWidth && !elem.offsetHeight) {
  679. return this.position(this._left, this._top);
  680. };
  681. var fixed = config.fixed,
  682. expando = _expando + 'follow',
  683. dom = this.dom,
  684. $window = dom.window,
  685. $document = dom.document,
  686. winWidth = $window.width(),
  687. winHeight = $window.height(),
  688. docLeft = $document.scrollLeft(),
  689. docTop = $document.scrollTop(),
  690. offset = $elem.offset(),
  691. width = elem.offsetWidth,
  692. height = elem.offsetHeight,
  693. left = fixed ? offset.left - docLeft : offset.left,
  694. top = fixed ? offset.top - docTop : offset.top,
  695. wrap = this.dom.wrap[0],
  696. style = wrap.style,
  697. wrapWidth = wrap.offsetWidth,
  698. wrapHeight = wrap.offsetHeight,
  699. setLeft = left - (wrapWidth - width) / 2,
  700. setTop = top + height,
  701. dl = fixed ? 0 : docLeft,
  702. dt = fixed ? 0 : docTop;
  703. setLeft = setLeft < dl ? left :
  704. (setLeft + wrapWidth > winWidth) && (left - wrapWidth > dl)
  705. ? left - wrapWidth + width
  706. : setLeft;
  707. setTop = (setTop + wrapHeight > winHeight + dt)
  708. && (top - wrapHeight > dt)
  709. ? top - wrapHeight
  710. : setTop;
  711. style.left = parseInt(setLeft) + 'px';
  712. style.top = parseInt(setTop) + 'px';
  713. this._follow && this._follow.removeAttribute(expando);
  714. this._follow = elem;
  715. elem[expando] = config.id;
  716. return this;
  717. },
  718. /**
  719. * 自定义按钮
  720. * @example
  721. button({
  722. value: 'login',
  723. callback: function () {},
  724. disabled: false,
  725. focus: true
  726. }, .., ..)
  727. */
  728. button: function () {
  729. var dom = this.dom,
  730. $buttons = dom.buttons,
  731. elem = $buttons[0],
  732. strongButton = 'd-state-highlight',
  733. listeners = this._listeners = this._listeners || {},
  734. ags = [].slice.call(arguments);
  735. var i = 0, val, value, id, isNewButton, button;
  736. for (; i < ags.length; i ++) {
  737. val = ags[i];
  738. value = val.value;
  739. id = val.id || value;
  740. isNewButton = !listeners[id];
  741. button = !isNewButton ? listeners[id].elem : document.createElement('input');
  742. button.type = 'button';
  743. button.className = 'd-button';
  744. if (!listeners[id]) {
  745. listeners[id] = {};
  746. };
  747. if (value) {
  748. button.value = value;
  749. };
  750. if (val.width) {
  751. button.style.width = val.width;
  752. };
  753. if (val.callback) {
  754. listeners[id].callback = val.callback;
  755. };
  756. if (val.focus) {
  757. this._focus && this._focus.removeClass(strongButton);
  758. this._focus = $(button).addClass(strongButton);
  759. this.focus();
  760. };
  761. button[_expando + 'callback'] = id;
  762. button.disabled = !!val.disabled;
  763. if (isNewButton) {
  764. listeners[id].elem = button;
  765. elem.appendChild(button);
  766. };
  767. };
  768. $buttons[0].style.display = ags.length ? '' : 'none';
  769. return this;
  770. },
  771. /** 显示对话框 */
  772. visible: function () {
  773. //this.dom.wrap.show();
  774. this.dom.wrap.css('visibility', 'visible');
  775. this.dom.outer.addClass('d-state-visible');
  776. if (this._isLock) {
  777. this._lockMask.show();
  778. };
  779. return this;
  780. },
  781. /** 隐藏对话框 */
  782. hidden: function () {
  783. //this.dom.wrap.hide();
  784. this.dom.wrap.css('visibility', 'hidden');
  785. this.dom.outer.removeClass('d-state-visible');
  786. if (this._isLock) {
  787. this._lockMask.hide();
  788. };
  789. return this;
  790. },
  791. /** 关闭对话框 */
  792. close: function () {
  793. if (this.closed) {
  794. return this;
  795. };
  796. var dom = this.dom,
  797. $wrap = dom.wrap,
  798. list = artDialog.list,
  799. beforeunload = this.config.beforeunload;
  800. if (beforeunload && beforeunload.call(this) === false) {
  801. return this;
  802. };
  803. if (artDialog.focus === this) {
  804. artDialog.focus = null;
  805. };
  806. if (this._follow) {
  807. this._follow.removeAttribute(_expando + 'follow');
  808. }
  809. if (this._elemBack) {
  810. this._elemBack();
  811. };
  812. this.time();
  813. this.unlock();
  814. this._removeEvent();
  815. delete list[this.config.id];
  816. if (_singleton) {
  817. $wrap.remove();
  818. // 使用单例模式
  819. } else {
  820. _singleton = this;
  821. dom.title.html('');
  822. dom.content.html('');
  823. dom.buttons.html('');
  824. $wrap[0].className = $wrap[0].style.cssText = '';
  825. dom.outer[0].className = 'd-outer';
  826. $wrap.css({
  827. left: 0,
  828. top: 0,
  829. position: _isFixed ? 'fixed' : 'absolute'
  830. });
  831. for (var i in this) {
  832. if (this.hasOwnProperty(i) && i !== 'dom') {
  833. delete this[i];
  834. };
  835. };
  836. this.hidden();
  837. };
  838. // 恢复焦点,照顾键盘操作的用户
  839. if (_activeElement) {
  840. _activeElement.focus();
  841. }
  842. this.closed = true;
  843. return this;
  844. },
  845. /**
  846. * 定时关闭
  847. * @param {Number} 单位毫秒, 无参数则停止计时器
  848. */
  849. time: function (time) {
  850. var that = this,
  851. timer = this._timer;
  852. timer && clearTimeout(timer);
  853. if (time) {
  854. this._timer = setTimeout(function(){
  855. that._click('cancel');
  856. }, time);
  857. };
  858. return this;
  859. },
  860. /** @inner 设置焦点 */
  861. focus: function () {
  862. var that = this,
  863. isFocus = function () {
  864. var activeElement = _getActive();
  865. return activeElement && that.dom.wrap[0].contains(activeElement);
  866. };
  867. if (!isFocus()) {
  868. _activeElement = _getActive();
  869. }
  870. setTimeout(function () {
  871. if (!isFocus()) {
  872. try {
  873. var elem = that._focus || that.dom.close || taht.dom.wrap;
  874. elem[0].focus();
  875. // IE对不可见元素设置焦点会报错
  876. } catch (e) {};
  877. }
  878. }, 16);
  879. return this;
  880. },
  881. /** 置顶对话框 */
  882. zIndex: function () {
  883. var dom = this.dom,
  884. top = artDialog.focus,
  885. index = artDialog.defaults.zIndex ++;
  886. // 设置叠加高度
  887. dom.wrap.css('zIndex', index);
  888. this._lockMask && this._lockMask.css('zIndex', index - 1);
  889. // 设置最高层的样式
  890. top && top.dom.outer.removeClass('d-state-focus');
  891. artDialog.focus = this;
  892. dom.outer.addClass('d-state-focus');
  893. return this;
  894. },
  895. /** 设置屏锁 */
  896. lock: function () {
  897. if (this._isLock) {
  898. return this;
  899. };
  900. var that = this,
  901. config = this.config,
  902. dom = this.dom,
  903. div = document.createElement('div'),
  904. $div = $(div),
  905. index = artDialog.defaults.zIndex - 1;
  906. this.zIndex();
  907. dom.outer.addClass('d-state-lock');
  908. $div.css({
  909. zIndex: index,
  910. position: 'fixed',
  911. left: 0,
  912. top: 0,
  913. width: '100%',
  914. height: '100%',
  915. overflow: 'hidden'
  916. }).addClass('d-mask');
  917. if (!_isFixed) {
  918. $div.css({
  919. position: 'absolute',
  920. width: $(window).width() + 'px',
  921. height: $(document).height() + 'px'
  922. });
  923. };
  924. $div.bind('dblclick', function () {
  925. that._click('cancel');
  926. });
  927. document.body.appendChild(div);
  928. this._lockMask = $div;
  929. this._isLock = true;
  930. return this;
  931. },
  932. /** 解开屏锁 */
  933. unlock: function () {
  934. if (!this._isLock) {
  935. return this;
  936. };
  937. this._lockMask.unbind();
  938. this._lockMask.hide();
  939. this._lockMask.remove();
  940. this.dom.outer.removeClass('d-state-lock');
  941. this._isLock = false;
  942. return this;
  943. },
  944. // 获取元素
  945. _innerHTML: function (data) {
  946. var body = document.body;
  947. if (!body) {
  948. throw new Error('artDialog: "documents.body" not ready');
  949. };
  950. var wrap = document.createElement('div');
  951. wrap.style.cssText = 'position:absolute;left:0;top:0';
  952. wrap.innerHTML = artDialog._templates
  953. .replace(/{([^}]+)}/g, function ($0, $1) {
  954. var value = data[$1];
  955. return typeof value === 'string' ? value : '';
  956. });
  957. body.insertBefore(wrap, body.firstChild);
  958. var name,
  959. i = 0,
  960. dom = {},
  961. els = wrap.getElementsByTagName('*'),
  962. elsLen = els.length;
  963. for (; i < elsLen; i ++) {
  964. name = els[i].className.split('d-')[1];
  965. if (name) {
  966. dom[name] = $(els[i]);
  967. };
  968. };
  969. dom.window = $(window);
  970. dom.document = $(document);
  971. dom.wrap = $(wrap);
  972. return dom;
  973. },
  974. // 按钮回调函数触发
  975. _click: function (id) {
  976. var fn = this._listeners[id] && this._listeners[id].callback;
  977. return typeof fn !== 'function' || fn.call(this) !== false ?
  978. this.close() : this;
  979. },
  980. // 重置位置
  981. _reset: function () {
  982. var elem = this.config.follow || this._follow;
  983. elem ? this.follow(elem) : this.position();
  984. },
  985. // 事件代理
  986. _addEvent: function () {
  987. var that = this,
  988. dom = this.dom;
  989. // 监听点击
  990. dom.wrap
  991. .bind('click', function (event) {
  992. var target = event.target, callbackID;
  993. // IE BUG
  994. if (target.disabled) {
  995. return false;
  996. };
  997. if (target === dom.close[0]) {
  998. that._click('cancel');
  999. return false;
  1000. } else {
  1001. callbackID = target[_expando + 'callback'];
  1002. callbackID && that._click(callbackID);
  1003. };
  1004. })
  1005. .bind('mousedown', function () {
  1006. that.zIndex();
  1007. });
  1008. },
  1009. // 卸载事件代理
  1010. _removeEvent: function () {
  1011. this.dom.wrap.unbind();
  1012. }
  1013. };
  1014. artDialog.fn._create.prototype = artDialog.fn;
  1015. // 快捷方式绑定触发元素
  1016. $.fn.dialog = $.fn.artDialog = function () {
  1017. var config = arguments;
  1018. this[this.live ? 'live' : 'bind']('click', function () {
  1019. artDialog.apply(this, config);
  1020. return false;
  1021. });
  1022. return this;
  1023. };
  1024. /** 最顶层的对话框API */
  1025. artDialog.focus = null;
  1026. /**
  1027. * 根据 ID 获取某对话框 API
  1028. * @param {String} 对话框 ID
  1029. * @return {Object} 对话框 API (实例)
  1030. */
  1031. artDialog.get = function (id) {
  1032. return id === undefined
  1033. ? artDialog.list
  1034. : artDialog.list[id];
  1035. };
  1036. artDialog.list = {};
  1037. // 全局快捷键
  1038. $(document).bind('keydown', function (event) {
  1039. var target = event.target,
  1040. nodeName = target.nodeName,
  1041. rinput = /^input|textarea$/i,
  1042. api = artDialog.focus,
  1043. keyCode = event.keyCode;
  1044. if (!api || rinput.test(nodeName) && target.type !== 'button') {
  1045. return;
  1046. };
  1047. // ESC
  1048. keyCode === 27 && api._click('cancel');
  1049. });
  1050. // 锁屏限制tab
  1051. function focusin (event) {
  1052. var api = artDialog.focus;
  1053. if (api && api._isLock && !api.dom.wrap[0].contains(event.target)) {
  1054. event.stopPropagation();
  1055. api.dom.outer[0].focus();
  1056. }
  1057. }
  1058. if ($.fn.live) {
  1059. $('body').live('focus', focusin);
  1060. } else if (document.addEventListener) {
  1061. document.addEventListener('focus', focusin, true);
  1062. } else {
  1063. $(document).bind('focusin', focusin);
  1064. }
  1065. // 浏览器窗口改变后重置对话框位置
  1066. $(window).bind('resize', function () {
  1067. var dialogs = artDialog.list;
  1068. for (var id in dialogs) {
  1069. dialogs[id]._reset();
  1070. };
  1071. });
  1072. // XHTML 模板
  1073. // 使用 uglifyjs 压缩能够预先处理"+"号合并字符串
  1074. // @see http://marijnhaverbeke.nl/uglifyjs
  1075. artDialog._templates =
  1076. '<div class="d-outer" role="dialog" tabindex="-1" aria-labelledby="d-title-{id}" aria-describedby="d-content-{id}">'
  1077. + '<table class="d-border">'
  1078. + '<tbody>'
  1079. + '<tr>'
  1080. + '<td class="d-nw"></td>'
  1081. + '<td class="d-n"></td>'
  1082. + '<td class="d-ne"></td>'
  1083. + '</tr>'
  1084. + '<tr>'
  1085. + '<td class="d-w"></td>'
  1086. + '<td class="d-c">'
  1087. + '<div class="d-inner">'
  1088. + '<table class="d-dialog">'
  1089. + '<tbody>'
  1090. + '<tr>'
  1091. + '<td class="d-header">'
  1092. + '<div class="d-titleBar">'
  1093. + '<div id="d-title-{id}" class="d-title"></div>'
  1094. + '<a class="d-close" href="javascript:;" title="{cancelValue}">×</a>'
  1095. + '</div>'
  1096. + '</td>'
  1097. + '</tr>'
  1098. + '<tr>'
  1099. + '<td class="d-main">'
  1100. + '<div id="d-content-{id}" class="d-content"></div>'
  1101. + '</td>'
  1102. + '</tr>'
  1103. + '<tr>'
  1104. + '<td class="d-footer">'
  1105. + '<div class="d-buttons"></div>'
  1106. + '</td>'
  1107. + '</tr>'
  1108. + '</tbody>'
  1109. + '</table>'
  1110. + '</div>'
  1111. + '</td>'
  1112. + '<td class="d-e"></td>'
  1113. + '</tr>'
  1114. + '<tr>'
  1115. + '<td class="d-sw"></td>'
  1116. + '<td class="d-s"></td>'
  1117. + '<td class="d-se"></td>'
  1118. + '</tr>'
  1119. + '</tbody>'
  1120. + '</table>'
  1121. +'</div>';
  1122. /**
  1123. * 默认配置
  1124. */
  1125. artDialog.defaults = {
  1126. // 消息内容
  1127. content: '<div class="d-loading"><span>loading..</span></div>',
  1128. // 标题
  1129. title: 'message',
  1130. // 自定义按钮
  1131. button: null,
  1132. // 确定按钮回调函数
  1133. ok: null,
  1134. // 取消按钮回调函数
  1135. cancel: null,
  1136. // 对话框初始化后执行的函数
  1137. initialize: null,
  1138. // 对话框关闭前执行的函数
  1139. beforeunload: null,
  1140. // 确定按钮文本
  1141. okValue: 'ok',
  1142. // 取消按钮文本
  1143. cancelValue: 'cancel',
  1144. // 内容宽度
  1145. width: 'auto',
  1146. // 内容高度
  1147. height: 'auto',
  1148. // 内容与边界填充距离
  1149. padding: '20px 25px',
  1150. // 皮肤名(多皮肤共存预留接口)
  1151. skin: null,
  1152. // 自动关闭时间(毫秒)
  1153. time: null,
  1154. // 初始化后是否显示对话框
  1155. visible: true,
  1156. // 让对话框跟随某元素
  1157. follow: null,
  1158. // 是否锁屏
  1159. lock: false,
  1160. // 是否固定定位
  1161. fixed: false,
  1162. // 对话框叠加高度值(重要:此值不能超过浏览器最大限制)
  1163. zIndex: 1987
  1164. };
  1165. this.artDialog = $.dialog = $.artDialog = artDialog;
  1166. }(this.art || this.jQuery, this));