uibase.js 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170
  1. /*
  2. Copyright 2012, KISSY UI Library v1.30dev
  3. MIT Licensed
  4. build time: Jan 6 17:21
  5. */
  6. /**
  7. * @fileOverview UIBase.Align
  8. * @author yiminghe@gmail.com , qiaohua@taobao.com
  9. */
  10. KISSY.add('uibase/align', function(S, UA, DOM, Node) {
  11. /**
  12. * inspired by closure library by Google
  13. * @see http://yiminghe.iteye.com/blog/1124720
  14. */
  15. /**
  16. * 得到影响元素显示的父亲元素
  17. */
  18. function getOffsetParent(element) {
  19. // ie 这个也不是完全可行
  20. /**
  21. <div style="width: 50px;height: 100px;overflow: hidden">
  22. <div style="width: 50px;height: 100px;position: relative;" id="d6">
  23. 元素 6 高 100px 宽 50px<br/>
  24. </div>
  25. </div>
  26. **/
  27. // if (UA['ie']) {
  28. // return element.offsetParent;
  29. // }
  30. var body = element.ownerDocument.body,
  31. positionStyle = DOM.css(element, 'position'),
  32. skipStatic = positionStyle == 'fixed' || positionStyle == 'absolute';
  33. for (var parent = element.parentNode;
  34. parent && parent != body;
  35. parent = parent.parentNode) {
  36. positionStyle = DOM.css(parent, 'position');
  37. skipStatic = skipStatic && positionStyle == 'static';
  38. var parentOverflow = DOM.css(parent, "overflow");
  39. // 必须有 overflow 属性,可能会隐藏掉子孙元素
  40. if (parentOverflow != 'visible' && (
  41. // 元素初始为 fixed absolute ,遇到 父亲不是 定位元素忽略
  42. // 否则就可以
  43. !skipStatic ||
  44. positionStyle == 'fixed' ||
  45. positionStyle == 'absolute' ||
  46. positionStyle == 'relative'
  47. )) {
  48. return parent;
  49. }
  50. }
  51. return null;
  52. }
  53. /**
  54. * 获得元素的显示部分的区域
  55. */
  56. function getVisibleRectForElement(element) {
  57. var visibleRect = {
  58. left:0,
  59. right:Infinity,
  60. top:0,
  61. bottom:Infinity
  62. };
  63. for (var el = element; el = getOffsetParent(el);) {
  64. var clientWidth = el.clientWidth;
  65. if (
  66. // clientWidth is zero for inline block elements in IE.
  67. (!UA['ie'] || clientWidth !== 0)
  68. // on WEBKIT, body element can have clientHeight = 0 and scrollHeight > 0
  69. // && (!UA['webkit'] || clientHeight != 0 || el != body)
  70. // overflow 不为 visible 则可以限定其内元素
  71. // && (scrollWidth != clientWidth || scrollHeight != clientHeight)
  72. // offsetParent 已经判断过了
  73. //&& DOM.css(el, 'overflow') != 'visible'
  74. ) {
  75. var clientLeft = el.clientLeft,
  76. clientTop = el.clientTop,
  77. pos = DOM.offset(el),
  78. client = {
  79. left:clientLeft,
  80. top:clientTop
  81. };
  82. pos.left += client.left;
  83. pos.top += client.top;
  84. visibleRect.top = Math.max(visibleRect['top'], pos.top);
  85. visibleRect.right = Math.min(visibleRect.right,
  86. pos.left + el.clientWidth);
  87. visibleRect.bottom = Math.min(visibleRect['bottom'],
  88. pos.top + el.clientHeight);
  89. visibleRect.left = Math.max(visibleRect.left, pos.left);
  90. }
  91. }
  92. var scrollX = DOM.scrollLeft(),
  93. scrollY = DOM.scrollTop();
  94. visibleRect.left = Math.max(visibleRect.left, scrollX);
  95. visibleRect.top = Math.max(visibleRect['top'], scrollY);
  96. visibleRect.right = Math.min(visibleRect.right, scrollX + DOM.viewportWidth());
  97. visibleRect.bottom = Math.min(visibleRect['bottom'], scrollY + DOM.viewportHeight());
  98. return visibleRect.top >= 0 && visibleRect.left >= 0 &&
  99. visibleRect.bottom > visibleRect.top &&
  100. visibleRect.right > visibleRect.left ?
  101. visibleRect : null;
  102. }
  103. function isFailed(status) {
  104. for (var s in status) {
  105. if (s.indexOf("fail") === 0) {
  106. return true;
  107. }
  108. }
  109. return false;
  110. }
  111. function positionAtAnchor(alignCfg) {
  112. var offset = alignCfg.offset,
  113. node = alignCfg.node,
  114. points = alignCfg.points,
  115. self = this,
  116. xy,
  117. diff,
  118. p1,
  119. //如果没有view,就是不区分mvc
  120. el = self.get('el'),
  121. p2;
  122. offset = offset || [0,0];
  123. xy = el.offset();
  124. // p1 是 node 上 points[0] 的 offset
  125. // p2 是 overlay 上 points[1] 的 offset
  126. p1 = getAlignOffset(node, points[0]);
  127. p2 = getAlignOffset(el, points[1]);
  128. diff = [p2.left - p1.left, p2.top - p1.top];
  129. xy = {
  130. left: xy.left - diff[0] + (+offset[0]),
  131. top: xy.top - diff[1] + (+offset[1])
  132. };
  133. return positionAtCoordinate.call(self, xy, alignCfg);
  134. }
  135. function positionAtCoordinate(absolutePos, alignCfg) {
  136. var self = this,el = self.get('el');
  137. var status = {};
  138. var elSize = {width:el.outerWidth(),height:el.outerHeight()},
  139. size = S.clone(elSize);
  140. if (!S.isEmptyObject(alignCfg.overflow)) {
  141. var viewport = getVisibleRectForElement(el[0]);
  142. status = adjustForViewport(absolutePos, size, viewport, alignCfg.overflow || {});
  143. if (isFailed(status)) {
  144. return status;
  145. }
  146. }
  147. self.set("x", absolutePos.left);
  148. self.set("y", absolutePos.top);
  149. if (size.width != elSize.width || size.height != elSize.height) {
  150. el.width(size.width);
  151. el.height(size.height);
  152. }
  153. return status;
  154. }
  155. function adjustForViewport(pos, size, viewport, overflow) {
  156. var status = {};
  157. if (pos.left < viewport.left && overflow.adjustX) {
  158. pos.left = viewport.left;
  159. status.adjustX = 1;
  160. }
  161. // Left edge inside and right edge outside viewport, try to resize it.
  162. if (pos.left < viewport.left &&
  163. pos.left + size.width > viewport.right &&
  164. overflow.resizeWidth) {
  165. size.width -= (pos.left + size.width) - viewport.right;
  166. status.resizeWidth = 1;
  167. }
  168. // Right edge outside viewport, try to move it.
  169. if (pos.left + size.width > viewport.right &&
  170. overflow.adjustX) {
  171. pos.left = Math.max(viewport.right - size.width, viewport.left);
  172. status.adjustX = 1;
  173. }
  174. // Left or right edge still outside viewport, fail if the FAIL_X option was
  175. // specified, ignore it otherwise.
  176. if (overflow.failX) {
  177. status.failX = pos.left < viewport.left ||
  178. pos.left + size.width > viewport.right;
  179. }
  180. // Top edge outside viewport, try to move it.
  181. if (pos.top < viewport.top && overflow.adjustY) {
  182. pos.top = viewport.top;
  183. status.adjustY = 1;
  184. }
  185. // Top edge inside and bottom edge outside viewport, try to resize it.
  186. if (pos.top >= viewport.top &&
  187. pos.top + size.height > viewport.bottom &&
  188. overflow.resizeHeight) {
  189. size.height -= (pos.top + size.height) - viewport.bottom;
  190. status.resizeHeight = 1;
  191. }
  192. // Bottom edge outside viewport, try to move it.
  193. if (pos.top + size.height > viewport.bottom &&
  194. overflow.adjustY) {
  195. pos.top = Math.max(viewport.bottom - size.height, viewport.top);
  196. status.adjustY = 1;
  197. }
  198. // Top or bottom edge still outside viewport, fail if the FAIL_Y option was
  199. // specified, ignore it otherwise.
  200. if (overflow.failY) {
  201. status.failY = pos.top < viewport.top ||
  202. pos.top + size.height > viewport.bottom;
  203. }
  204. return status;
  205. }
  206. function flip(points, reg, map) {
  207. var ret = [];
  208. S.each(points, function(p) {
  209. ret.push(p.replace(reg, function(m) {
  210. return map[m];
  211. }));
  212. });
  213. return ret;
  214. }
  215. function flipOffset(offset, index) {
  216. offset[index] = -offset[index];
  217. return offset;
  218. }
  219. function Align() {
  220. }
  221. Align.ATTRS = {
  222. align: {
  223. // 默认不是正中,可以实现自由动画 zoom
  224. // value:{
  225. // node: null, // 参考元素, falsy 值为可视区域, 'trigger' 为触发元素, 其他为指定元素
  226. // points: ['cc','cc'], // ['tr', 'tl'] 表示 overlay 的 tl 与参考节点的 tr 对齐
  227. // offset: [0, 0] // 有效值为 [n, m]
  228. // }
  229. }
  230. };
  231. /**
  232. * 获取 node 上的 align 对齐点 相对于页面的坐标
  233. * @param node
  234. * @param align
  235. */
  236. function getAlignOffset(node, align) {
  237. var V = align.charAt(0),
  238. H = align.charAt(1),
  239. offset, w, h, x, y;
  240. if (node) {
  241. node = Node.one(node);
  242. offset = node.offset();
  243. w = node.outerWidth();
  244. h = node.outerHeight();
  245. } else {
  246. offset = { left: DOM.scrollLeft(), top: DOM.scrollTop() };
  247. w = DOM.viewportWidth();
  248. h = DOM.viewportHeight();
  249. }
  250. x = offset.left;
  251. y = offset.top;
  252. if (V === 'c') {
  253. y += h / 2;
  254. } else if (V === 'b') {
  255. y += h;
  256. }
  257. if (H === 'c') {
  258. x += w / 2;
  259. } else if (H === 'r') {
  260. x += w;
  261. }
  262. return { left: x, top: y };
  263. }
  264. Align.prototype = {
  265. _uiSetAlign: function(v) {
  266. if (S.isPlainObject(v)) {
  267. this.align(v.node, v.points, v.offset, v.overflow);
  268. }
  269. },
  270. /**
  271. * 对齐 Overlay 到 node 的 points 点, 偏移 offset 处
  272. * @param {Element} node 参照元素, 可取配置选项中的设置, 也可是一元素
  273. * @param {String[]} points 对齐方式
  274. * @param {Number[]} [offset] 偏移
  275. */
  276. align: function(node, points, offset, overflow) {
  277. var self = this,
  278. flag = {};
  279. // 后面会改的,先保存下
  280. overflow = S.clone(overflow || {});
  281. offset = offset && [].concat(offset) || [0,0];
  282. if (overflow.failX) {
  283. flag.failX = 1;
  284. }
  285. if (overflow.failY) {
  286. flag.failY = 1;
  287. }
  288. var status = positionAtAnchor.call(self, {
  289. node:node,
  290. points:points,
  291. offset:offset,
  292. overflow:flag
  293. });
  294. // 如果错误调整重试
  295. if (isFailed(status)) {
  296. if (status.failX) {
  297. points = flip(points, /[lr]/ig, {
  298. l:"r",
  299. r:"l"
  300. });
  301. offset = flipOffset(offset, 0);
  302. }
  303. if (status.failY) {
  304. points = flip(points, /[tb]/ig, {
  305. t:"b",
  306. b:"t"
  307. });
  308. offset = flipOffset(offset, 1);
  309. }
  310. }
  311. status = positionAtAnchor.call(self, {
  312. node:node,
  313. points:points,
  314. offset:offset,
  315. overflow:flag
  316. });
  317. if (isFailed(status)) {
  318. delete overflow.failX;
  319. delete overflow.failY;
  320. status = positionAtAnchor.call(self, {
  321. node:node,
  322. points:points,
  323. offset:offset,
  324. overflow:overflow
  325. });
  326. }
  327. },
  328. /**
  329. * 居中显示到可视区域, 一次性居中
  330. */
  331. center: function(node) {
  332. this.set('align', {
  333. node: node,
  334. points: ["cc", "cc"],
  335. offset: [0, 0]
  336. });
  337. }
  338. };
  339. return Align;
  340. }, {
  341. requires:["ua","dom","node"]
  342. });
  343. /**
  344. * 2011-07-13 承玉 note:
  345. * - 增加智能对齐,以及大小调整选项
  346. **//**
  347. * @fileOverview UIBase
  348. * @author yiminghe@gmail.com,lifesinger@gmail.com
  349. * @see http://martinfowler.com/eaaDev/uiArchs.html
  350. */
  351. KISSY.add('uibase/base', function (S, Base, Node) {
  352. var UI_SET = '_uiSet',
  353. SRC_NODE = 'srcNode',
  354. ATTRS = 'ATTRS',
  355. HTML_PARSER = 'HTML_PARSER',
  356. noop = S.noop;
  357. function capitalFirst(s) {
  358. return s.charAt(0).toUpperCase() + s.substring(1);
  359. }
  360. /**
  361. * UIBase for class-based component
  362. * @class
  363. * @namespace
  364. * @name UIBase
  365. * @extends Base
  366. */
  367. function UIBase(config) {
  368. // 读取用户设置的属性值并设置到自身
  369. Base.apply(this, arguments);
  370. // 根据 srcNode 设置属性值
  371. // 按照类层次执行初始函数,主类执行 initializer 函数,扩展类执行构造器函数
  372. initHierarchy(this, config);
  373. // 是否自动渲染
  374. config && config.autoRender && this.render();
  375. }
  376. /**
  377. * 模拟多继承
  378. * init attr using constructors ATTRS meta info
  379. */
  380. function initHierarchy(host, config) {
  381. var c = host.constructor;
  382. while (c) {
  383. // 从 markup 生成相应的属性项
  384. if (config &&
  385. config[SRC_NODE] &&
  386. c.HTML_PARSER) {
  387. if ((config[SRC_NODE] = Node.one(config[SRC_NODE]))) {
  388. applyParser.call(host, config[SRC_NODE], c.HTML_PARSER);
  389. }
  390. }
  391. c = c.superclass && c.superclass.constructor;
  392. }
  393. callMethodByHierarchy(host, "initializer", "constructor");
  394. }
  395. function callMethodByHierarchy(host, mainMethod, extMethod) {
  396. var c = host.constructor,
  397. extChains = [],
  398. ext,
  399. main,
  400. exts,
  401. t;
  402. // define
  403. while (c) {
  404. // 收集扩展类
  405. t = [];
  406. if (exts = c.__ks_exts) {
  407. for (var i = 0; i < exts.length; i++) {
  408. ext = exts[i];
  409. if (ext) {
  410. if (extMethod != "constructor") {
  411. //只调用真正自己构造器原型的定义,继承原型链上的不要管
  412. if (ext.prototype.hasOwnProperty(extMethod)) {
  413. ext = ext.prototype[extMethod];
  414. } else {
  415. ext = null;
  416. }
  417. }
  418. ext && t.push(ext);
  419. }
  420. }
  421. }
  422. // 收集主类
  423. // 只调用真正自己构造器原型的定义,继承原型链上的不要管 !important
  424. // 所以不用自己在 renderUI 中调用 superclass.renderUI 了,UIBase 构造器自动搜寻
  425. // 以及 initializer 等同理
  426. if (c.prototype.hasOwnProperty(mainMethod) && (main = c.prototype[mainMethod])) {
  427. t.push(main);
  428. }
  429. // 原地 reverse
  430. if (t.length) {
  431. extChains.push.apply(extChains, t.reverse());
  432. }
  433. c = c.superclass && c.superclass.constructor;
  434. }
  435. // 初始化函数
  436. // 顺序:父类的所有扩展类函数 -> 父类对应函数 -> 子类的所有扩展函数 -> 子类对应函数
  437. for (i = extChains.length - 1; i >= 0; i--) {
  438. extChains[i] && extChains[i].call(host);
  439. }
  440. }
  441. /**
  442. * 销毁组件
  443. * 顺序: 子类 destructor -> 子类扩展 destructor -> 父类 destructor -> 父类扩展 destructor
  444. */
  445. function destroyHierarchy(host) {
  446. var c = host.constructor,
  447. exts,
  448. d,
  449. i;
  450. while (c) {
  451. // 只触发该类真正的析构器,和父亲没关系,所以不要在子类析构器中调用 superclass
  452. if (c.prototype.hasOwnProperty("destructor")) {
  453. c.prototype.destructor.apply(host);
  454. }
  455. if ((exts = c.__ks_exts)) {
  456. for (i = exts.length - 1; i >= 0; i--) {
  457. d = exts[i] && exts[i].prototype.__destructor;
  458. d && d.apply(host);
  459. }
  460. }
  461. c = c.superclass && c.superclass.constructor;
  462. }
  463. }
  464. function applyParser(srcNode, parser) {
  465. var host = this, p, v;
  466. // 从 parser 中,默默设置属性,不触发事件
  467. for (p in parser) {
  468. if (parser.hasOwnProperty(p)) {
  469. v = parser[p];
  470. // 函数
  471. if (S.isFunction(v)) {
  472. host.__set(p, v.call(host, srcNode));
  473. }
  474. // 单选选择器
  475. else if (S.isString(v)) {
  476. host.__set(p, srcNode.one(v));
  477. }
  478. // 多选选择器
  479. else if (S.isArray(v) && v[0]) {
  480. host.__set(p, srcNode.all(v[0]))
  481. }
  482. }
  483. }
  484. }
  485. UIBase.HTML_PARSER = {};
  486. UIBase.ATTRS = {
  487. // 是否已经渲染完毕
  488. rendered:{
  489. value:false
  490. },
  491. // dom 节点是否已经创建完毕
  492. created:{
  493. value:false
  494. }
  495. };
  496. S.extend(UIBase, Base,
  497. /**
  498. * @lends UIBase.prototype
  499. */
  500. {
  501. /**
  502. * 建立节点,先不放在 dom 树中,为了性能!
  503. */
  504. create:function () {
  505. var self = this;
  506. // 是否生成过节点
  507. if (!self.get("created")) {
  508. self._createDom();
  509. self.fire('createDom');
  510. callMethodByHierarchy(self, "createDom", "__createDom");
  511. self.fire('afterCreateDom');
  512. self.__set("created", true);
  513. }
  514. },
  515. /**
  516. * 渲染组件到 dom 结构
  517. */
  518. render:function () {
  519. var self = this;
  520. // 是否已经渲染过
  521. if (!self.get("rendered")) {
  522. self.create();
  523. self._renderUI();
  524. // 实际上是 beforeRenderUI
  525. self.fire('renderUI');
  526. callMethodByHierarchy(self, "renderUI", "__renderUI");
  527. self.fire('afterRenderUI');
  528. self._bindUI();
  529. // 实际上是 beforeBindUI
  530. self.fire('bindUI');
  531. callMethodByHierarchy(self, "bindUI", "__bindUI");
  532. self.fire('afterBindUI');
  533. self._syncUI();
  534. // 实际上是 beforeSyncUI
  535. self.fire('syncUI');
  536. callMethodByHierarchy(self, "syncUI", "__syncUI");
  537. self.fire('afterSyncUI');
  538. self.__set("rendered", true);
  539. }
  540. return self;
  541. },
  542. /**
  543. * 创建 dom 节点,但不放在 document 中
  544. */
  545. _createDom:noop,
  546. /**
  547. * 节点已经创建完毕,可以放在 document 中了
  548. */
  549. _renderUI:noop,
  550. /**
  551. * @protected
  552. * @function
  553. */
  554. renderUI:noop,
  555. /**
  556. * 根据属性变化设置 UI
  557. */
  558. _bindUI:function () {
  559. var self = this,
  560. attrs = self['__attrs'],
  561. attr, m;
  562. for (attr in attrs) {
  563. if (attrs.hasOwnProperty(attr)) {
  564. m = UI_SET + capitalFirst(attr);
  565. if (self[m]) {
  566. // 自动绑定事件到对应函数
  567. (function (attr, m) {
  568. self.on('after' + capitalFirst(attr) + 'Change', function (ev) {
  569. self[m](ev.newVal, ev);
  570. });
  571. })(attr, m);
  572. }
  573. }
  574. }
  575. },
  576. /**
  577. * @protected
  578. * @function
  579. */
  580. bindUI:noop,
  581. /**
  582. * 根据当前(初始化)状态来设置 UI
  583. */
  584. _syncUI:function () {
  585. var self = this,
  586. attrs = self['__attrs'];
  587. for (var a in attrs) {
  588. if (attrs.hasOwnProperty(a)) {
  589. var m = UI_SET + capitalFirst(a);
  590. //存在方法,并且用户设置了初始值或者存在默认值,就同步状态
  591. if (self[m]
  592. // 用户如果设置了显式不同步,就不同步,比如一些值从 html 中读取,不需要同步再次设置
  593. && attrs[a].sync !== false
  594. && self.get(a) !== undefined) {
  595. self[m](self.get(a));
  596. }
  597. }
  598. }
  599. },
  600. /**
  601. * protected
  602. * @function
  603. */
  604. syncUI:noop,
  605. /**
  606. * 销毁组件
  607. */
  608. destroy:function () {
  609. destroyHierarchy(this);
  610. this.fire('destroy');
  611. this.detach();
  612. }
  613. },
  614. /**
  615. * @lends UIBase
  616. */
  617. {
  618. /**
  619. * 根据基类以及扩展类得到新类
  620. * @param {Function|Function[]} base 基类
  621. * @param {Function[]} exts 扩展类
  622. * @param {Object} px 原型 mix 对象
  623. * @param {Object} sx 静态 mix 对象
  624. * @returns {UIBase} 组合 后 的 新类
  625. */
  626. create:function (base, exts, px, sx) {
  627. if (S.isArray(base)) {
  628. sx = px;
  629. px = exts;
  630. exts = base;///*@type Function[]*/
  631. //debug.....
  632. base = UIBase;
  633. }
  634. base = base || UIBase;
  635. if (S.isObject(exts)) {
  636. sx = px;
  637. px = exts;
  638. exts = [];
  639. }
  640. function C() {
  641. UIBase.apply(this, arguments);
  642. }
  643. S.extend(C, base, px, sx);
  644. if (exts) {
  645. C.__ks_exts = exts;
  646. var desc = {
  647. // ATTRS:
  648. // HMTL_PARSER:
  649. }, constructors = exts.concat(C);
  650. // [ex1,ex2],扩展类后面的优先,ex2 定义的覆盖 ex1 定义的
  651. // 主类最优先
  652. S.each(constructors, function (ext) {
  653. if (ext) {
  654. // 合并 ATTRS/HTML_PARSER 到主类
  655. S.each([ATTRS, HTML_PARSER], function (K) {
  656. if (ext[K]) {
  657. desc[K] = desc[K] || {};
  658. // 不覆盖主类上的定义,因为继承层次上扩展类比主类层次高
  659. // 但是值是对象的话会深度合并
  660. // 注意:最好值是简单对象,自定义 new 出来的对象就会有问题!
  661. S.mix(desc[K], ext[K], true, undefined, true);
  662. }
  663. });
  664. }
  665. });
  666. S.each(desc, function (v, k) {
  667. C[k] = v;
  668. });
  669. var prototype = {};
  670. // 主类最优先
  671. S.each(constructors, function (ext) {
  672. if (ext) {
  673. var proto = ext.prototype;
  674. // 合并功能代码到主类,不覆盖
  675. for (var p in proto) {
  676. // 不覆盖主类,但是主类的父类还是覆盖吧
  677. if (proto.hasOwnProperty(p)) {
  678. prototype[p] = proto[p];
  679. }
  680. }
  681. }
  682. });
  683. S.each(prototype, function (v, k) {
  684. C.prototype[k] = v;
  685. });
  686. }
  687. return C;
  688. }
  689. });
  690. return UIBase;
  691. }, {
  692. requires:["base", "node"]
  693. });
  694. /**
  695. * render 和 create 区别
  696. * render 包括 create ,以及把生成的节点放在 document 中
  697. * create 仅仅包括创建节点
  698. **//**
  699. * @fileOverview UIBase.Box
  700. * @author yiminghe@gmail.com
  701. */
  702. KISSY.add('uibase/box', function () {
  703. /**
  704. * @class
  705. * @memberOf UIBase
  706. * @namespace
  707. */
  708. function Box() {
  709. }
  710. Box.ATTRS =
  711. /**
  712. * @lends UIBase.Box#
  713. */
  714. {
  715. html:{
  716. view:true
  717. },
  718. // 宽度
  719. width:{
  720. view:true
  721. },
  722. // 高度
  723. height:{
  724. view:true
  725. },
  726. // 容器的 class
  727. elCls:{
  728. view:true
  729. },
  730. // 容器的行内样式
  731. elStyle:{
  732. view:true
  733. },
  734. // 其他属性
  735. elAttrs:{
  736. //其他属性
  737. view:true
  738. },
  739. // 插入到该元素前
  740. elBefore:{
  741. view:true
  742. },
  743. el:{
  744. view:true
  745. },
  746. // 渲染该组件的目的容器
  747. render:{
  748. view:true
  749. },
  750. visibleMode:{
  751. value:"display",
  752. view:true
  753. },
  754. // 默认显示,但不触发事件
  755. visible:{
  756. view:true
  757. },
  758. // 从已存在节点开始渲染
  759. srcNode:{
  760. view:true
  761. }
  762. };
  763. Box.HTML_PARSER =
  764. /**
  765. * @private
  766. */
  767. {
  768. el:function (srcNode) {
  769. /**
  770. * 如果需要特殊的对现有元素的装饰行为
  771. */
  772. if (this.decorateInternal) {
  773. this.decorateInternal(srcNode);
  774. }
  775. return srcNode;
  776. }
  777. };
  778. Box.prototype =
  779. /**
  780. * @lends UIBase.Box#
  781. */
  782. {
  783. _uiSetVisible:function (isVisible) {
  784. this.fire(isVisible ? "show" : "hide");
  785. },
  786. /**
  787. * 显示 Overlay
  788. */
  789. show:function () {
  790. var self = this;
  791. self.render();
  792. self.set("visible", true);
  793. },
  794. /**
  795. * 隐藏
  796. */
  797. hide:function () {
  798. this.set("visible", false);
  799. }
  800. };
  801. return Box;
  802. });
  803. /**
  804. * @fileOverview UIBase.Box
  805. * @author yiminghe@gmail.com
  806. */
  807. KISSY.add('uibase/boxrender', function (S, Node) {
  808. var $ = S.all;
  809. /**
  810. * @class
  811. * @memberOf UIBase.Box
  812. */
  813. function BoxRender() {
  814. }
  815. BoxRender.ATTRS =
  816. /**
  817. * @lends UIBase.Box.Render#
  818. */
  819. {
  820. el:{
  821. //容器元素
  822. setter:function (v) {
  823. return $(v);
  824. }
  825. },
  826. // 构建时批量生成,不需要执行单个
  827. elCls:{
  828. sync:false
  829. },
  830. elStyle:{
  831. sync:false
  832. },
  833. width:{
  834. sync:false
  835. },
  836. height:{
  837. sync:false
  838. },
  839. elTagName:{
  840. sync:false,
  841. // 生成标签名字
  842. value:"div"
  843. },
  844. elAttrs:{
  845. sync:false
  846. },
  847. html:{
  848. sync:false
  849. },
  850. elBefore:{
  851. },
  852. render:{},
  853. visible:{
  854. },
  855. visibleMode:{
  856. }
  857. };
  858. BoxRender.construct = constructEl;
  859. function constructEl(cls, style, width, height, tag, attrs, html) {
  860. style = style || {};
  861. html = html || "";
  862. if (typeof html !== "string") {
  863. html = "";
  864. }
  865. if (width) {
  866. style.width = typeof width == "number" ? (width + "px") : width;
  867. }
  868. if (height) {
  869. style.height = typeof height == "number" ? (height + "px") : height;
  870. }
  871. var styleStr = '';
  872. for (var s in style) {
  873. if (style.hasOwnProperty(s)) {
  874. styleStr += s + ":" + style[s] + ";";
  875. }
  876. }
  877. var attrStr = '';
  878. for (var a in attrs) {
  879. if (attrs.hasOwnProperty(a)) {
  880. attrStr += " " + a + "='" + attrs[a] + "'" + " ";
  881. }
  882. }
  883. return "<" + tag + (styleStr ? (" style='" + styleStr + "' ") : "")
  884. + attrStr + (cls ? (" class='" + cls + "' ") : "")
  885. + ">" + html + "<" + "/" + tag + ">";
  886. //return ret;
  887. }
  888. BoxRender.HTML_PARSER =
  889. /**
  890. * @ignore
  891. */
  892. {
  893. html:function (el) {
  894. return el.html();
  895. }
  896. };
  897. BoxRender.prototype =
  898. /**
  899. * @lends UIBase.Box.Render#
  900. */
  901. {
  902. __renderUI:function () {
  903. var self = this;
  904. // 新建的节点才需要摆放定位
  905. if (self.__boxRenderNew) {
  906. var render = self.get("render"),
  907. el = self.get("el"),
  908. elBefore = self.get("elBefore");
  909. if (elBefore) {
  910. el.insertBefore(elBefore);
  911. }
  912. else if (render) {
  913. el.appendTo(render);
  914. }
  915. else {
  916. el.appendTo(document.body);
  917. }
  918. }
  919. },
  920. /**
  921. * 只负责建立节点,如果是 decorate 过来的,甚至内容会丢失
  922. * 通过 render 来重建原有的内容
  923. */
  924. __createDom:function () {
  925. var self = this,
  926. el = self.get("el");
  927. if (!el) {
  928. self.__boxRenderNew = true;
  929. el = new Node(constructEl(self.get("elCls"),
  930. self.get("elStyle"),
  931. self.get("width"),
  932. self.get("height"),
  933. self.get("elTagName"),
  934. self.get("elAttrs"),
  935. self.get("html")));
  936. self.__set("el", el);
  937. }
  938. },
  939. _uiSetElAttrs:function (attrs) {
  940. this.get("el").attr(attrs);
  941. },
  942. _uiSetElCls:function (cls) {
  943. this.get("el").addClass(cls);
  944. },
  945. _uiSetElStyle:function (style) {
  946. this.get("el").css(style);
  947. },
  948. _uiSetWidth:function (w) {
  949. this.get("el").width(w);
  950. },
  951. _uiSetHeight:function (h) {
  952. var self = this;
  953. self.get("el").height(h);
  954. },
  955. _uiSetHtml:function (c) {
  956. this.get("el").html(c);
  957. },
  958. _uiSetVisible:function (isVisible) {
  959. var el = this.get("el"),
  960. visibleMode = this.get("visibleMode");
  961. if (visibleMode == "visibility") {
  962. el.css("visibility", isVisible ? "visible" : "hidden");
  963. } else {
  964. el.css("display", isVisible ? "" : "none");
  965. }
  966. },
  967. show:function () {
  968. var self = this;
  969. self.render();
  970. self.set("visible", true);
  971. },
  972. hide:function () {
  973. this.set("visible", false);
  974. },
  975. __destructor:function () {
  976. //S.log("box __destructor");
  977. var el = this.get("el");
  978. if (el) {
  979. el.detach();
  980. el.remove();
  981. }
  982. }
  983. };
  984. return BoxRender;
  985. }, {
  986. requires:['node']
  987. });
  988. /**
  989. * @fileOverview close extension for kissy dialog
  990. * @author yiminghe@gmail.com
  991. */
  992. KISSY.add("uibase/close", function() {
  993. function Close() {
  994. }
  995. var HIDE = "hide";
  996. Close.ATTRS = {
  997. closable: {
  998. view:true
  999. },
  1000. closeAction:{
  1001. value:HIDE
  1002. }
  1003. };
  1004. var actions = {
  1005. hide:HIDE,
  1006. destroy:"destroy"
  1007. };
  1008. Close.prototype = {
  1009. __bindUI:function() {
  1010. var self = this,
  1011. closeBtn = self.get("view").get("closeBtn");
  1012. closeBtn && closeBtn.on("click", function(ev) {
  1013. self[actions[self.get("closeAction")] || HIDE]();
  1014. ev.preventDefault();
  1015. });
  1016. }
  1017. };
  1018. return Close;
  1019. });/**
  1020. * @fileOverview close extension for kissy dialog
  1021. * @author yiminghe@gmail.com
  1022. */
  1023. KISSY.add("uibase/closerender", function(S, Node) {
  1024. var CLS_PREFIX = 'ext-';
  1025. function Close() {
  1026. }
  1027. Close.ATTRS = {
  1028. closable: { // 是否需要关闭按钮
  1029. value: true
  1030. },
  1031. closeBtn:{
  1032. }
  1033. };
  1034. Close.HTML_PARSER = {
  1035. closeBtn:function(el) {
  1036. return el.one("." + this.get("prefixCls") + CLS_PREFIX + 'close');
  1037. }
  1038. };
  1039. Close.prototype = {
  1040. _uiSetClosable:function(v) {
  1041. var self = this,
  1042. closeBtn = self.get("closeBtn");
  1043. if (closeBtn) {
  1044. if (v) {
  1045. closeBtn.css("display", "");
  1046. } else {
  1047. closeBtn.css("display", "none");
  1048. }
  1049. }
  1050. },
  1051. __renderUI:function() {
  1052. var self = this,
  1053. closeBtn = self.get("closeBtn"),
  1054. el = self.get("el");
  1055. if (!closeBtn && el) {
  1056. closeBtn = new Node("<a " +
  1057. "tabindex='0' " +
  1058. "role='button' " +
  1059. "class='" + this.get("prefixCls") + CLS_PREFIX + "close" + "'>" +
  1060. "<span class='" +
  1061. this.get("prefixCls") + CLS_PREFIX + "close-x" +
  1062. "'>关闭<" + "/span>" +
  1063. "<" + "/a>").appendTo(el);
  1064. self.set("closeBtn", closeBtn);
  1065. }
  1066. },
  1067. __destructor:function() {
  1068. var self = this,
  1069. closeBtn = self.get("closeBtn");
  1070. closeBtn && closeBtn.detach();
  1071. }
  1072. };
  1073. return Close;
  1074. }, {
  1075. requires:["node"]
  1076. });/**
  1077. * @fileOverview constrain extension for kissy
  1078. * @author yiminghe@gmail.com, 乔花<qiaohua@taobao.com>
  1079. */
  1080. KISSY.add("uibase/constrain", function(S, DOM, Node) {
  1081. function Constrain() {
  1082. }
  1083. Constrain.ATTRS = {
  1084. constrain:{
  1085. //不限制
  1086. //true:viewport限制
  1087. //node:限制在节点范围
  1088. value:false
  1089. }
  1090. };
  1091. /**
  1092. * 获取受限区域的宽高, 位置
  1093. * @return {Object | undefined} {left: 0, top: 0, maxLeft: 100, maxTop: 100}
  1094. */
  1095. function _getConstrainRegion(constrain) {
  1096. var ret;
  1097. if (!constrain) {
  1098. return ret;
  1099. }
  1100. var el = this.get("el");
  1101. if (constrain !== true) {
  1102. constrain = Node.one(constrain);
  1103. ret = constrain.offset();
  1104. S.mix(ret, {
  1105. maxLeft: ret.left + constrain.outerWidth() - el.outerWidth(),
  1106. maxTop: ret.top + constrain.outerHeight() - el.outerHeight()
  1107. });
  1108. }
  1109. // 没有指定 constrain, 表示受限于可视区域
  1110. else {
  1111. //不要使用 viewportWidth()
  1112. //The innerWidth attribute, on getting,
  1113. //must return the viewport width including the size of a rendered scroll bar (if any).
  1114. //On getting, the clientWidth attribute returns the viewport width
  1115. //excluding the size of a rendered scroll bar (if any)
  1116. // if the element is the root element
  1117. var vWidth = document.documentElement.clientWidth;
  1118. ret = { left: DOM.scrollLeft(), top: DOM.scrollTop() };
  1119. S.mix(ret, {
  1120. maxLeft: ret.left + vWidth - el.outerWidth(),
  1121. maxTop: ret.top + DOM.viewportHeight() - el.outerHeight()
  1122. });
  1123. }
  1124. return ret;
  1125. }
  1126. Constrain.prototype = {
  1127. __renderUI:function() {
  1128. var self = this,
  1129. attrs = self.getAttrs(),
  1130. xAttr = attrs["x"],
  1131. yAttr = attrs["y"],
  1132. oriXSetter = xAttr["setter"],
  1133. oriYSetter = yAttr["setter"];
  1134. xAttr.setter = function(v) {
  1135. var r = oriXSetter && oriXSetter.call(self, v);
  1136. if (r === undefined) {
  1137. r = v;
  1138. }
  1139. if (!self.get("constrain")) {
  1140. return r;
  1141. }
  1142. var _ConstrainExtRegion = _getConstrainRegion.call(
  1143. self, self.get("constrain"));
  1144. return Math.min(Math.max(r,
  1145. _ConstrainExtRegion.left),
  1146. _ConstrainExtRegion.maxLeft);
  1147. };
  1148. yAttr.setter = function(v) {
  1149. var r = oriYSetter && oriYSetter.call(self, v);
  1150. if (r === undefined) {
  1151. r = v;
  1152. }
  1153. if (!self.get("constrain")) {
  1154. return r;
  1155. }
  1156. var _ConstrainExtRegion = _getConstrainRegion.call(
  1157. self, self.get("constrain"));
  1158. return Math.min(Math.max(r,
  1159. _ConstrainExtRegion.top),
  1160. _ConstrainExtRegion.maxTop);
  1161. };
  1162. self.addAttr("x", xAttr);
  1163. self.addAttr("y", yAttr);
  1164. }
  1165. };
  1166. return Constrain;
  1167. }, {
  1168. requires:["dom","node"]
  1169. });/**
  1170. * @fileOverview 里层包裹层定义,适合mask以及shim
  1171. * @author yiminghe@gmail.com
  1172. */
  1173. KISSY.add("uibase/contentbox", function() {
  1174. function ContentBox() {
  1175. }
  1176. ContentBox.ATTRS = {
  1177. //层内容
  1178. content:{
  1179. view:true,
  1180. sync:false
  1181. },
  1182. contentEl:{
  1183. view:true
  1184. },
  1185. contentElAttrs:{
  1186. view:true
  1187. },
  1188. contentElStyle:{
  1189. view:true
  1190. },
  1191. contentTagName:{
  1192. view:true
  1193. }
  1194. };
  1195. ContentBox.prototype = { };
  1196. return ContentBox;
  1197. });/**
  1198. * @fileOverview 里层包裹层定义,适合mask以及shim
  1199. * @author yiminghe@gmail.com
  1200. */
  1201. KISSY.add("uibase/contentboxrender", function (S, Node, BoxRender) {
  1202. /**
  1203. * @class 内层容器渲染混元类
  1204. * @name Render
  1205. * @memberOf UIBase.ContentBox
  1206. */
  1207. function ContentBoxRender() {
  1208. }
  1209. ContentBoxRender.ATTRS =
  1210. /**
  1211. * @lends UIBase.ContentBox.Render
  1212. */
  1213. {
  1214. /**
  1215. * 内容容器节点
  1216. * @type String|Node
  1217. */
  1218. contentEl:{},
  1219. contentElAttrs:{},
  1220. contentElCls:{},
  1221. contentElStyle:{},
  1222. contentTagName:{
  1223. value:"div"
  1224. },
  1225. /**
  1226. * 内层内容
  1227. * @type String|Node
  1228. */
  1229. content:{
  1230. sync:false
  1231. }
  1232. };
  1233. /*
  1234. ! contentEl 只能由组件动态生成
  1235. */
  1236. ContentBoxRender.HTML_PARSER = {
  1237. content:function (el) {
  1238. return el[0].innerHTML;
  1239. }
  1240. };
  1241. var constructEl = BoxRender.construct;
  1242. ContentBoxRender.prototype = {
  1243. // no need ,shift create work to __createDom
  1244. __renderUI:function () {
  1245. },
  1246. __createDom:function () {
  1247. var self = this,
  1248. contentEl,
  1249. c = self.get("content"),
  1250. el = self.get("el"),
  1251. html = "",
  1252. elChildren = S.makeArray(el[0].childNodes);
  1253. if (elChildren.length) {
  1254. html = el[0].innerHTML
  1255. }
  1256. // el html 和 c 相同,直接 append el的子节点
  1257. if (c == html) {
  1258. c = "";
  1259. }
  1260. contentEl = new Node(constructEl(
  1261. self.get("prefixCls") + "contentbox "
  1262. + (self.get("contentElCls") || ""),
  1263. self.get("contentElStyle"),
  1264. undefined,
  1265. undefined,
  1266. self.get("contentTagName"),
  1267. self.get("contentElAttrs"),
  1268. c)).appendTo(el);
  1269. self.__set("contentEl", contentEl);
  1270. // on content,then read from box el
  1271. if (!c) {
  1272. for (var i = 0, l = elChildren.length; i < l; i++) {
  1273. contentEl.append(elChildren[i]);
  1274. }
  1275. } else if (typeof c !== 'string') {
  1276. contentEl.append(c);
  1277. }
  1278. },
  1279. _uiSetContentElCls:function (cls) {
  1280. this.get("contentEl").addClass(cls);
  1281. },
  1282. _uiSetContentElAttrs:function (attrs) {
  1283. this.get("contentEl").attr(attrs);
  1284. },
  1285. _uiSetContentElStyle:function (v) {
  1286. this.get("contentEl").css(v);
  1287. },
  1288. _uiSetContent:function (c) {
  1289. if (typeof c == "string") {
  1290. this.get("contentEl").html(c);
  1291. } else {
  1292. this.get("contentEl").empty().append(c);
  1293. }
  1294. }
  1295. };
  1296. return ContentBoxRender;
  1297. }, {
  1298. requires:["node", "./boxrender"]
  1299. });/**
  1300. * @fileOverview drag extension for position
  1301. * @author yiminghe@gmail.com
  1302. */
  1303. KISSY.add("uibase/drag", function(S) {
  1304. function Drag() {
  1305. }
  1306. Drag.ATTRS = {
  1307. handlers:{
  1308. value:[]
  1309. },
  1310. draggable:{value:true}
  1311. };
  1312. Drag.prototype = {
  1313. _uiSetHandlers:function(v) {
  1314. if (v && v.length > 0 && this.__drag) {
  1315. this.__drag.set("handlers", v);
  1316. }
  1317. },
  1318. __bindUI:function() {
  1319. var Draggable = S.require("dd/draggable");
  1320. var self = this,
  1321. el = self.get("el");
  1322. if (self.get("draggable") && Draggable) {
  1323. self.__drag = new Draggable({
  1324. node:el
  1325. });
  1326. }
  1327. },
  1328. _uiSetDraggable:function(v) {
  1329. var self = this,
  1330. d = self.__drag;
  1331. if (!d) {
  1332. return;
  1333. }
  1334. if (v) {
  1335. d.detach("drag");
  1336. d.on("drag", self._dragExtAction, self);
  1337. } else {
  1338. d.detach("drag");
  1339. }
  1340. },
  1341. _dragExtAction:function(offset) {
  1342. this.set("xy", [offset.left,offset.top])
  1343. },
  1344. /**
  1345. *
  1346. */
  1347. __destructor:function() {
  1348. //S.log("DragExt __destructor");
  1349. var d = this.__drag;
  1350. d && d.destroy();
  1351. }
  1352. };
  1353. return Drag;
  1354. });/**
  1355. * @fileOverview loading mask support for overlay
  1356. * @author yiminghe@gmail.com
  1357. */
  1358. KISSY.add("uibase/loading", function() {
  1359. function Loading() {
  1360. }
  1361. Loading.prototype = {
  1362. loading:function() {
  1363. this.get("view").loading();
  1364. },
  1365. unloading:function() {
  1366. this.get("view").unloading();
  1367. }
  1368. };
  1369. return Loading;
  1370. });/**
  1371. * @fileOverview loading mask support for overlay
  1372. * @author yiminghe@gmail.com
  1373. */
  1374. KISSY.add("uibase/loadingrender", function(S, Node) {
  1375. function Loading() {
  1376. }
  1377. Loading.prototype = {
  1378. loading:function() {
  1379. var self = this;
  1380. if (!self._loadingExtEl) {
  1381. self._loadingExtEl = new Node("<div " +
  1382. "class='" +
  1383. this.get("prefixCls") +
  1384. "ext-loading'" +
  1385. " style='position: absolute;" +
  1386. "border: none;" +
  1387. "width: 100%;" +
  1388. "top: 0;" +
  1389. "left: 0;" +
  1390. "z-index: 99999;" +
  1391. "height:100%;" +
  1392. "*height: expression(this.parentNode.offsetHeight);" + "'/>")
  1393. .appendTo(self.get("el"));
  1394. }
  1395. self._loadingExtEl.show();
  1396. },
  1397. unloading:function() {
  1398. var lel = this._loadingExtEl;
  1399. lel && lel.hide();
  1400. }
  1401. };
  1402. return Loading;
  1403. }, {
  1404. requires:['node']
  1405. });/**
  1406. * @fileOverview mask extension for kissy
  1407. * @author yiminghe@gmail.com
  1408. */
  1409. KISSY.add("uibase/mask", function() {
  1410. function Mask() {
  1411. }
  1412. Mask.ATTRS = {
  1413. mask:{
  1414. value:false
  1415. }
  1416. };
  1417. Mask.prototype = {
  1418. _uiSetMask:function(v) {
  1419. var self = this;
  1420. if (v) {
  1421. self.on("show", self.get("view")._maskExtShow, self.get("view"));
  1422. self.on("hide", self.get("view")._maskExtHide, self.get("view"));
  1423. } else {
  1424. self.detach("show", self.get("view")._maskExtShow, self.get("view"));
  1425. self.detach("hide", self.get("view")._maskExtHide, self.get("view"));
  1426. }
  1427. }
  1428. };
  1429. return Mask;
  1430. }, {requires:["ua"]});/**
  1431. * @fileOverview mask extension for kissy
  1432. * @author yiminghe@gmail.com
  1433. */
  1434. KISSY.add("uibase/maskrender", function(S, UA, Node) {
  1435. /**
  1436. * 多 position 共享一个遮罩
  1437. */
  1438. var mask,
  1439. ie6 = (UA['ie'] === 6),
  1440. px = "px",
  1441. $ = Node.all,
  1442. win = $(window),
  1443. doc = $(document),
  1444. iframe,
  1445. num = 0;
  1446. function docWidth() {
  1447. return ie6 ? (doc.width() + px) : "100%";
  1448. }
  1449. function docHeight() {
  1450. return ie6 ? (doc.height() + px) : "100%";
  1451. }
  1452. function initMask() {
  1453. mask = $("<div " +
  1454. //"tabindex='-1' " +
  1455. "class='" +
  1456. this.get("prefixCls") + "ext-mask'/>")
  1457. .prependTo("body");
  1458. mask.css({
  1459. "position":ie6 ? "absolute" : "fixed", // mask 不会撑大 docWidth
  1460. left:0,
  1461. top:0,
  1462. width: docWidth(),
  1463. "height": docHeight()
  1464. });
  1465. if (ie6) {
  1466. //ie6 下最好和 mask 平行
  1467. iframe = $("<" + "iframe " +
  1468. //"tabindex='-1' " +
  1469. "style='position:absolute;" +
  1470. "left:" + "0px" + ";" +
  1471. "top:" + "0px" + ";" +
  1472. "background:red;" +
  1473. "width:" + docWidth() + ";" +
  1474. "height:" + docHeight() + ";" +
  1475. "filter:alpha(opacity=0);" +
  1476. "z-index:-1;'/>").insertBefore(mask)
  1477. }
  1478. /**
  1479. * 点 mask 焦点不转移
  1480. */
  1481. mask.unselectable();
  1482. mask.on("mousedown click", function(e) {
  1483. e.halt();
  1484. });
  1485. }
  1486. function Mask() {
  1487. }
  1488. var resizeMask = S.throttle(function() {
  1489. var v = {
  1490. width : docWidth(),
  1491. height : docHeight()
  1492. };
  1493. mask.css(v);
  1494. iframe && iframe.css(v);
  1495. }, 50);
  1496. Mask.prototype = {
  1497. _maskExtShow:function() {
  1498. var self = this;
  1499. if (!mask) {
  1500. initMask.call(self);
  1501. }
  1502. var zIndex = {
  1503. "z-index": self.get("zIndex") - 1
  1504. },
  1505. display = {
  1506. "display":""
  1507. };
  1508. mask.css(zIndex);
  1509. iframe && iframe.css(zIndex);
  1510. num++;
  1511. if (num == 1) {
  1512. mask.css(display);
  1513. iframe && iframe.css(display);
  1514. if (ie6) {
  1515. win.on("resize scroll", resizeMask);
  1516. }
  1517. }
  1518. },
  1519. _maskExtHide:function() {
  1520. num--;
  1521. if (num <= 0) {
  1522. num = 0;
  1523. }
  1524. if (!num) {
  1525. var display = {
  1526. "display":"none"
  1527. };
  1528. mask && mask.css(display);
  1529. iframe && iframe.css(display);
  1530. if (ie6) {
  1531. win.detach("resize scroll", resizeMask);
  1532. }
  1533. }
  1534. },
  1535. __destructor:function() {
  1536. this._maskExtHide();
  1537. }
  1538. };
  1539. return Mask;
  1540. }, {
  1541. requires:["ua","node"]
  1542. });/**
  1543. * @fileOverview position and visible extension,可定位的隐藏层
  1544. * @author yiminghe@gmail.com
  1545. */
  1546. KISSY.add("uibase/position", function(S) {
  1547. function Position() {
  1548. }
  1549. Position.ATTRS = {
  1550. x: {
  1551. view:true
  1552. },
  1553. y: {
  1554. view:true
  1555. },
  1556. xy: {
  1557. // 相对 page 定位, 有效值为 [n, m], 为 null 时, 选 align 设置
  1558. setter: function(v) {
  1559. var self = this,
  1560. xy = S.makeArray(v);
  1561. /*
  1562. 属性内分发特别注意:
  1563. xy -> x,y
  1564. */
  1565. if (xy.length) {
  1566. xy[0] && self.set("x", xy[0]);
  1567. xy[1] && self.set("y", xy[1]);
  1568. }
  1569. return v;
  1570. },
  1571. /**
  1572. * xy 纯中转作用
  1573. */
  1574. getter:function() {
  1575. return [this.get("x"),this.get("y")];
  1576. }
  1577. },
  1578. zIndex: {
  1579. view:true
  1580. }
  1581. };
  1582. Position.prototype = {
  1583. /**
  1584. * 移动到绝对位置上, move(x, y) or move(x) or move([x, y])
  1585. * @param {number|Array.<number>} x
  1586. * @param {number=} y
  1587. */
  1588. move: function(x, y) {
  1589. var self = this;
  1590. if (S.isArray(x)) {
  1591. y = x[1];
  1592. x = x[0];
  1593. }
  1594. self.set("xy", [x,y]);
  1595. }
  1596. };
  1597. return Position;
  1598. });/**
  1599. * @fileOverview position and visible extension,可定位的隐藏层
  1600. * @author yiminghe@gmail.com
  1601. */
  1602. KISSY.add("uibase/positionrender", function() {
  1603. var ZINDEX = 9999;
  1604. function Position() {
  1605. }
  1606. Position.ATTRS = {
  1607. x: {
  1608. // 水平方向绝对位置
  1609. valueFn:function() {
  1610. // 读到这里时,el 一定是已经加到 dom 树中了,否则报未知错误
  1611. // el 不在 dom 树中 offset 报错的
  1612. // 最早读就是在 syncUI 中,一点重复设置(读取自身 X 再调用 _uiSetX)无所谓了
  1613. return this.get("el") && this.get("el").offset().left;
  1614. }
  1615. },
  1616. y: {
  1617. // 垂直方向绝对位置
  1618. valueFn:function() {
  1619. return this.get("el") && this.get("el").offset().top;
  1620. }
  1621. },
  1622. zIndex: {
  1623. value: ZINDEX
  1624. }
  1625. };
  1626. Position.prototype = {
  1627. __renderUI:function() {
  1628. this.get("el").addClass(this.get("prefixCls") + "ext-position");
  1629. },
  1630. _uiSetZIndex:function(x) {
  1631. this.get("el").css("z-index", x);
  1632. },
  1633. _uiSetX:function(x) {
  1634. this.get("el").offset({
  1635. left:x
  1636. });
  1637. },
  1638. _uiSetY:function(y) {
  1639. this.get("el").offset({
  1640. top:y
  1641. });
  1642. }
  1643. };
  1644. return Position;
  1645. });/**
  1646. * @fileOverview resize extension using resizable
  1647. * @author yiminghe@gmail.com
  1648. */
  1649. KISSY.add("uibase/resize", function(S) {
  1650. function Resize() {
  1651. }
  1652. Resize.ATTRS = {
  1653. resize:{
  1654. value:{
  1655. }
  1656. }
  1657. };
  1658. Resize.prototype = {
  1659. __destructor:function() {
  1660. this.resizer && this.resizer.destroy();
  1661. },
  1662. _uiSetResize:function(v) {
  1663. var Resizable = S.require("resizable"),
  1664. self = this;
  1665. if (Resizable) {
  1666. self.resizer && self.resizer.destroy();
  1667. v.node = self.get("el");
  1668. v.autoRender = true;
  1669. if (v.handlers) {
  1670. self.resizer = new Resizable(v);
  1671. }
  1672. }
  1673. }
  1674. };
  1675. return Resize;
  1676. });/**
  1677. * @fileOverview shim for ie6 ,require box-ext
  1678. * @author yiminghe@gmail.com
  1679. */
  1680. KISSY.add("uibase/shimrender", function(S, Node) {
  1681. function Shim() {
  1682. //S.log("shim init");
  1683. }
  1684. Shim.ATTRS = {
  1685. shim:{
  1686. value:true
  1687. }
  1688. };
  1689. Shim.prototype = {
  1690. _uiSetShim:function(v) {
  1691. var self = this,el = self.get("el");
  1692. if (v && !self.__shimEl) {
  1693. self.__shimEl = new Node("<" + "iframe style='position: absolute;" +
  1694. "border: none;" +
  1695. "width: expression(this.parentNode.offsetWidth);" +
  1696. "top: 0;" +
  1697. "opacity: 0;" +
  1698. "filter: alpha(opacity=0);" +
  1699. "left: 0;" +
  1700. "z-index: -1;" +
  1701. "height: expression(this.parentNode.offsetHeight);" + "'/>");
  1702. el.prepend(self.__shimEl);
  1703. } else if (!v && self.__shimEl) {
  1704. self.__shimEl.remove();
  1705. delete self.__shimEl;
  1706. }
  1707. }
  1708. };
  1709. return Shim;
  1710. }, {
  1711. requires:['node']
  1712. });/**
  1713. * @fileOverview support standard mod for component
  1714. * @author yiminghe@gmail.com
  1715. */
  1716. KISSY.add("uibase/stdmod", function() {
  1717. function StdMod() {
  1718. }
  1719. StdMod.ATTRS = {
  1720. header:{
  1721. view:true
  1722. },
  1723. body:{
  1724. view:true
  1725. },
  1726. footer:{
  1727. view:true
  1728. },
  1729. bodyStyle:{
  1730. view:true
  1731. },
  1732. footerStyle:{
  1733. view:true
  1734. },
  1735. headerStyle:{
  1736. view:true
  1737. },
  1738. headerContent:{
  1739. view:true
  1740. },
  1741. bodyContent:{
  1742. view:true
  1743. },
  1744. footerContent:{
  1745. view:true
  1746. }
  1747. };
  1748. StdMod.prototype = {};
  1749. return StdMod;
  1750. });/**
  1751. * @fileOverview support standard mod for component
  1752. * @author yiminghe@gmail.com
  1753. */
  1754. KISSY.add("uibase/stdmodrender", function(S, Node) {
  1755. var CLS_PREFIX = "stdmod-";
  1756. function StdMod() {
  1757. }
  1758. StdMod.ATTRS = {
  1759. header:{
  1760. },
  1761. body:{
  1762. },
  1763. footer:{
  1764. },
  1765. bodyStyle:{
  1766. },
  1767. footerStyle:{
  1768. },
  1769. headerStyle:{
  1770. },
  1771. headerContent:{},
  1772. bodyContent:{},
  1773. footerContent:{}
  1774. };
  1775. StdMod.HTML_PARSER = {
  1776. header:function(el) {
  1777. return el.one("." + this.get("prefixCls") + CLS_PREFIX + "header");
  1778. },
  1779. body:function(el) {
  1780. return el.one("." + this.get("prefixCls") + CLS_PREFIX + "body");
  1781. },
  1782. footer:function(el) {
  1783. return el.one("." + this.get("prefixCls") + CLS_PREFIX + "footer");
  1784. }
  1785. };
  1786. function renderUI(self, part) {
  1787. var el = self.get("contentEl"),
  1788. partEl = self.get(part);
  1789. if (!partEl) {
  1790. partEl = new Node("<div class='" + self.get("prefixCls") + CLS_PREFIX + part + "'/>")
  1791. .appendTo(el);
  1792. self.set(part, partEl);
  1793. }
  1794. }
  1795. StdMod.prototype = {
  1796. _setStdModContent:function(part, v) {
  1797. if (S.isString(v)) {
  1798. this.get(part).html(v);
  1799. } else {
  1800. this.get(part).html("");
  1801. this.get(part).append(v);
  1802. }
  1803. },
  1804. _uiSetBodyStyle:function(v) {
  1805. this.get("body").css(v);
  1806. },
  1807. _uiSetHeaderStyle:function(v) {
  1808. this.get("header").css(v);
  1809. },
  1810. _uiSetFooterStyle:function(v) {
  1811. this.get("footer").css(v);
  1812. },
  1813. _uiSetBodyContent:function(v) {
  1814. this._setStdModContent("body", v);
  1815. },
  1816. _uiSetHeaderContent:function(v) {
  1817. this._setStdModContent("header", v);
  1818. },
  1819. _uiSetFooterContent:function(v) {
  1820. this._setStdModContent("footer", v);
  1821. },
  1822. __renderUI:function() {
  1823. renderUI(this, "header");
  1824. renderUI(this, "body");
  1825. renderUI(this, "footer");
  1826. }
  1827. };
  1828. return StdMod;
  1829. }, {
  1830. requires:['node']
  1831. });/**
  1832. * @fileOverview uibase
  1833. * @author yiminghe@gmail.com
  1834. */
  1835. KISSY.add("uibase", function(S, UIBase, Align, Box, BoxRender, Close, CloseRender, Contrain, Contentbox, ContentboxRender, Drag, Loading, LoadingRender, Mask, MaskRender, Position, PositionRender, ShimRender, Resize, StdMod, StdModRender) {
  1836. Close.Render = CloseRender;
  1837. Loading.Render = LoadingRender;
  1838. Mask.Render = MaskRender;
  1839. Position.Render = PositionRender;
  1840. StdMod.Render = StdModRender;
  1841. Box.Render = BoxRender;
  1842. Contentbox.Render = ContentboxRender;
  1843. S.mix(UIBase, {
  1844. Align:Align,
  1845. Box:Box,
  1846. Close:Close,
  1847. Contrain:Contrain,
  1848. Contentbox:Contentbox,
  1849. Drag:Drag,
  1850. Loading:Loading,
  1851. Mask:Mask,
  1852. Position:Position,
  1853. Shim:{
  1854. Render:ShimRender
  1855. },
  1856. Resize:Resize,
  1857. StdMod:StdMod
  1858. });
  1859. return UIBase;
  1860. }, {
  1861. requires:["uibase/base",
  1862. "uibase/align",
  1863. "uibase/box",
  1864. "uibase/boxrender",
  1865. "uibase/close",
  1866. "uibase/closerender",
  1867. "uibase/constrain",
  1868. "uibase/contentbox",
  1869. "uibase/contentboxrender",
  1870. "uibase/drag",
  1871. "uibase/loading",
  1872. "uibase/loadingrender",
  1873. "uibase/mask",
  1874. "uibase/maskrender",
  1875. "uibase/position",
  1876. "uibase/positionrender",
  1877. "uibase/shimrender",
  1878. "uibase/resize",
  1879. "uibase/stdmod",
  1880. "uibase/stdmodrender"]
  1881. });