tableviews.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /**
  2. * Tableviews
  3. * @param {type} $
  4. * @param {type} window
  5. * @param {type} document
  6. * @returns {undefined}
  7. */
  8. (function($, window, document) {
  9. var CLASS_ACTIVE = $.className('active');
  10. var CLASS_SELECTED = $.className('selected');
  11. var CLASS_GRID_VIEW = $.className('grid-view');
  12. var CLASS_RADIO_VIEW = $.className('table-view-radio');
  13. var CLASS_TABLE_VIEW_CELL = $.className('table-view-cell');
  14. var CLASS_COLLAPSE_CONTENT = $.className('collapse-content');
  15. var CLASS_DISABLED = $.className('disabled');
  16. var CLASS_TOGGLE = $.className('switch');
  17. var CLASS_BTN = $.className('btn');
  18. var CLASS_SLIDER_HANDLE = $.className('slider-handle');
  19. var CLASS_SLIDER_LEFT = $.className('slider-left');
  20. var CLASS_SLIDER_RIGHT = $.className('slider-right');
  21. var CLASS_TRANSITIONING = $.className('transitioning');
  22. var SELECTOR_SLIDER_HANDLE = '.' + CLASS_SLIDER_HANDLE;
  23. var SELECTOR_SLIDER_LEFT = '.' + CLASS_SLIDER_LEFT;
  24. var SELECTOR_SLIDER_RIGHT = '.' + CLASS_SLIDER_RIGHT;
  25. var SELECTOR_SELECTED = '.' + CLASS_SELECTED;
  26. var SELECTOR_BUTTON = '.' + CLASS_BTN;
  27. var overFactor = 0.8;
  28. var cell, a;
  29. var isMoved = isOpened = openedActions = progress = false;
  30. var sliderHandle = sliderActionLeft = sliderActionRight = buttonsLeft = buttonsRight = sliderDirection = sliderRequestAnimationFrame = false;
  31. var timer = translateX = lastTranslateX = sliderActionLeftWidth = sliderActionRightWidth = 0;
  32. var toggleActive = function(isActive) {
  33. if (isActive) {
  34. if (a) {
  35. a.classList.add(CLASS_ACTIVE);
  36. } else if (cell) {
  37. cell.classList.add(CLASS_ACTIVE);
  38. }
  39. } else {
  40. timer && timer.cancel();
  41. if (a) {
  42. a.classList.remove(CLASS_ACTIVE);
  43. } else if (cell) {
  44. cell.classList.remove(CLASS_ACTIVE);
  45. }
  46. }
  47. };
  48. var updateTranslate = function() {
  49. if (translateX !== lastTranslateX) {
  50. if (buttonsRight && buttonsRight.length > 0) {
  51. progress = translateX / sliderActionRightWidth;
  52. if (translateX < -sliderActionRightWidth) {
  53. translateX = -sliderActionRightWidth - Math.pow(-translateX - sliderActionRightWidth, overFactor);
  54. }
  55. for (var i = 0, len = buttonsRight.length; i < len; i++) {
  56. var buttonRight = buttonsRight[i];
  57. if (typeof buttonRight._buttonOffset === 'undefined') {
  58. buttonRight._buttonOffset = buttonRight.offsetLeft;
  59. }
  60. buttonOffset = buttonRight._buttonOffset;
  61. setTranslate(buttonRight, (translateX - buttonOffset * (1 + Math.max(progress, -1))));
  62. }
  63. }
  64. if (buttonsLeft && buttonsLeft.length > 0) {
  65. progress = translateX / sliderActionLeftWidth;
  66. if (translateX > sliderActionLeftWidth) {
  67. translateX = sliderActionLeftWidth + Math.pow(translateX - sliderActionLeftWidth, overFactor);
  68. }
  69. for (var i = 0, len = buttonsLeft.length; i < len; i++) {
  70. var buttonLeft = buttonsLeft[i];
  71. if (typeof buttonLeft._buttonOffset === 'undefined') {
  72. buttonLeft._buttonOffset = sliderActionLeftWidth - buttonLeft.offsetLeft - buttonLeft.offsetWidth;
  73. }
  74. buttonOffset = buttonLeft._buttonOffset;
  75. if (buttonsLeft.length > 1) {
  76. buttonLeft.style.zIndex = buttonsLeft.length - i;
  77. }
  78. setTranslate(buttonLeft, (translateX + buttonOffset * (1 - Math.min(progress, 1))));
  79. }
  80. }
  81. setTranslate(sliderHandle, translateX);
  82. lastTranslateX = translateX;
  83. }
  84. sliderRequestAnimationFrame = requestAnimationFrame(function() {
  85. updateTranslate();
  86. });
  87. };
  88. var setTranslate = function(element, x) {
  89. if (element) {
  90. element.style.webkitTransform = 'translate(' + x + 'px,0)';
  91. }
  92. };
  93. window.addEventListener($.EVENT_START, function(event) {
  94. if (cell) {
  95. toggleActive(false);
  96. }
  97. cell = a = false;
  98. isMoved = isOpened = openedActions = false;
  99. var target = event.target;
  100. var isDisabled = false;
  101. for (; target && target !== document; target = target.parentNode) {
  102. if (target.classList) {
  103. var classList = target.classList;
  104. if ((target.tagName === 'INPUT' && target.type !== 'radio' && target.type !== 'checkbox') || target.tagName === 'BUTTON' || classList.contains(CLASS_TOGGLE) || classList.contains(CLASS_BTN) || classList.contains(CLASS_DISABLED)) {
  105. isDisabled = true;
  106. }
  107. if (classList.contains(CLASS_COLLAPSE_CONTENT)) { //collapse content
  108. break;
  109. }
  110. if (classList.contains(CLASS_TABLE_VIEW_CELL)) {
  111. cell = target;
  112. //TODO swipe to delete close
  113. var selected = cell.parentNode.querySelector(SELECTOR_SELECTED);
  114. if (!cell.parentNode.classList.contains(CLASS_RADIO_VIEW) && selected && selected !== cell) {
  115. $.swipeoutClose(selected);
  116. cell = isDisabled = false;
  117. return;
  118. }
  119. if (!cell.parentNode.classList.contains(CLASS_GRID_VIEW)) {
  120. var link = cell.querySelector('a');
  121. if (link && link.parentNode === cell) { //li>a
  122. a = link;
  123. }
  124. }
  125. var handle = cell.querySelector(SELECTOR_SLIDER_HANDLE);
  126. if (handle) {
  127. toggleEvents(cell);
  128. event.stopPropagation();
  129. }
  130. if (!isDisabled) {
  131. if (handle) {
  132. if (timer) {
  133. timer.cancel();
  134. }
  135. timer = $.later(function() {
  136. toggleActive(true);
  137. }, 100);
  138. } else {
  139. toggleActive(true);
  140. }
  141. }
  142. break;
  143. }
  144. }
  145. }
  146. });
  147. window.addEventListener($.EVENT_MOVE, function(event) {
  148. toggleActive(false);
  149. });
  150. var handleEvent = {
  151. handleEvent: function(event) {
  152. switch (event.type) {
  153. case 'drag':
  154. this.drag(event);
  155. break;
  156. case 'dragend':
  157. this.dragend(event);
  158. break;
  159. case 'flick':
  160. this.flick(event);
  161. break;
  162. case 'swiperight':
  163. this.swiperight(event);
  164. break;
  165. case 'swipeleft':
  166. this.swipeleft(event);
  167. break;
  168. }
  169. },
  170. drag: function(event) {
  171. if (!cell) {
  172. return;
  173. }
  174. if (!isMoved) { //init
  175. sliderHandle = sliderActionLeft = sliderActionRight = buttonsLeft = buttonsRight = sliderDirection = sliderRequestAnimationFrame = false;
  176. sliderHandle = cell.querySelector(SELECTOR_SLIDER_HANDLE);
  177. if (sliderHandle) {
  178. sliderActionLeft = cell.querySelector(SELECTOR_SLIDER_LEFT);
  179. sliderActionRight = cell.querySelector(SELECTOR_SLIDER_RIGHT);
  180. if (sliderActionLeft) {
  181. sliderActionLeftWidth = sliderActionLeft.offsetWidth;
  182. buttonsLeft = sliderActionLeft.querySelectorAll(SELECTOR_BUTTON);
  183. }
  184. if (sliderActionRight) {
  185. sliderActionRightWidth = sliderActionRight.offsetWidth;
  186. buttonsRight = sliderActionRight.querySelectorAll(SELECTOR_BUTTON);
  187. }
  188. cell.classList.remove(CLASS_TRANSITIONING);
  189. isOpened = cell.classList.contains(CLASS_SELECTED);
  190. if (isOpened) {
  191. openedActions = cell.querySelector(SELECTOR_SLIDER_LEFT + SELECTOR_SELECTED) ? 'left' : 'right';
  192. }
  193. }
  194. }
  195. var detail = event.detail;
  196. var direction = detail.direction;
  197. var angle = detail.angle;
  198. if (direction === 'left' && (angle > 150 || angle < -150)) {
  199. if (buttonsRight || (buttonsLeft && isOpened)) { //存在右侧按钮或存在左侧按钮且是已打开状态
  200. isMoved = true;
  201. }
  202. } else if (direction === 'right' && (angle > -30 && angle < 30)) {
  203. if (buttonsLeft || (buttonsRight && isOpened)) { //存在左侧按钮或存在右侧按钮且是已打开状态
  204. isMoved = true;
  205. }
  206. }
  207. if (isMoved) {
  208. event.stopPropagation();
  209. event.detail.gesture.preventDefault();
  210. var translate = event.detail.deltaX;
  211. if (isOpened) {
  212. if (openedActions === 'right') {
  213. translate = translate - sliderActionRightWidth;
  214. } else {
  215. translate = translate + sliderActionLeftWidth;
  216. }
  217. }
  218. if ((translate > 0 && !buttonsLeft) || (translate < 0 && !buttonsRight)) {
  219. if (!isOpened) {
  220. return;
  221. }
  222. translate = 0;
  223. }
  224. if (translate < 0) {
  225. sliderDirection = 'toLeft';
  226. } else if (translate > 0) {
  227. sliderDirection = 'toRight';
  228. } else {
  229. if (!sliderDirection) {
  230. sliderDirection = 'toLeft';
  231. }
  232. }
  233. if (!sliderRequestAnimationFrame) {
  234. updateTranslate();
  235. }
  236. translateX = translate;
  237. }
  238. },
  239. flick: function(event) {
  240. if (isMoved) {
  241. event.stopPropagation();
  242. }
  243. },
  244. swipeleft: function(event) {
  245. if (isMoved) {
  246. event.stopPropagation();
  247. }
  248. },
  249. swiperight: function(event) {
  250. if (isMoved) {
  251. event.stopPropagation();
  252. }
  253. },
  254. dragend: function(event) {
  255. if (!isMoved) {
  256. return;
  257. }
  258. event.stopPropagation();
  259. if (sliderRequestAnimationFrame) {
  260. cancelAnimationFrame(sliderRequestAnimationFrame);
  261. sliderRequestAnimationFrame = null;
  262. }
  263. var detail = event.detail;
  264. isMoved = false;
  265. var action = 'close';
  266. var actionsWidth = sliderDirection === 'toLeft' ? sliderActionRightWidth : sliderActionLeftWidth;
  267. var isToggle = detail.swipe || (Math.abs(translateX) > actionsWidth / 2);
  268. if (isToggle) {
  269. if (!isOpened) {
  270. action = 'open';
  271. } else if (detail.direction === 'left' && openedActions === 'right') {
  272. action = 'open';
  273. } else if (detail.direction === 'right' && openedActions === 'left') {
  274. action = 'open';
  275. }
  276. }
  277. cell.classList.add(CLASS_TRANSITIONING);
  278. var buttons;
  279. if (action === 'open') {
  280. var newTranslate = sliderDirection === 'toLeft' ? -actionsWidth : actionsWidth;
  281. setTranslate(sliderHandle, newTranslate);
  282. buttons = sliderDirection === 'toLeft' ? buttonsRight : buttonsLeft;
  283. if (typeof buttons !== 'undefined') {
  284. var button = null;
  285. for (var i = 0; i < buttons.length; i++) {
  286. button = buttons[i];
  287. setTranslate(button, newTranslate);
  288. }
  289. button.parentNode.classList.add(CLASS_SELECTED);
  290. cell.classList.add(CLASS_SELECTED);
  291. if (!isOpened) {
  292. $.trigger(cell, sliderDirection === 'toLeft' ? 'slideleft' : 'slideright');
  293. }
  294. }
  295. } else {
  296. setTranslate(sliderHandle, 0);
  297. sliderActionLeft && sliderActionLeft.classList.remove(CLASS_SELECTED);
  298. sliderActionRight && sliderActionRight.classList.remove(CLASS_SELECTED);
  299. cell.classList.remove(CLASS_SELECTED);
  300. }
  301. var buttonOffset;
  302. if (buttonsLeft && buttonsLeft.length > 0 && buttonsLeft !== buttons) {
  303. for (var i = 0, len = buttonsLeft.length; i < len; i++) {
  304. var buttonLeft = buttonsLeft[i];
  305. buttonOffset = buttonLeft._buttonOffset;
  306. if (typeof buttonOffset === 'undefined') {
  307. buttonLeft._buttonOffset = sliderActionLeftWidth - buttonLeft.offsetLeft - buttonLeft.offsetWidth;
  308. }
  309. setTranslate(buttonLeft, buttonOffset);
  310. }
  311. }
  312. if (buttonsRight && buttonsRight.length > 0 && buttonsRight !== buttons) {
  313. for (var i = 0, len = buttonsRight.length; i < len; i++) {
  314. var buttonRight = buttonsRight[i];
  315. buttonOffset = buttonRight._buttonOffset;
  316. if (typeof buttonOffset === 'undefined') {
  317. buttonRight._buttonOffset = buttonRight.offsetLeft;
  318. }
  319. setTranslate(buttonRight, -buttonOffset);
  320. }
  321. }
  322. }
  323. };
  324. function toggleEvents(element, isRemove) {
  325. var method = !!isRemove ? 'removeEventListener' : 'addEventListener';
  326. element[method]('drag', handleEvent);
  327. element[method]('dragend', handleEvent);
  328. element[method]('swiperight', handleEvent);
  329. element[method]('swipeleft', handleEvent);
  330. element[method]('flick', handleEvent);
  331. };
  332. /**
  333. * 打开滑动菜单
  334. * @param {Object} el
  335. * @param {Object} direction
  336. */
  337. $.swipeoutOpen = function(el, direction) {
  338. if (!el) return;
  339. var classList = el.classList;
  340. if (classList.contains(CLASS_SELECTED)) return;
  341. if (!direction) {
  342. if (el.querySelector(SELECTOR_SLIDER_RIGHT)) {
  343. direction = 'right';
  344. } else {
  345. direction = 'left';
  346. }
  347. }
  348. var swipeoutAction = el.querySelector($.classSelector(".slider-" + direction));
  349. if (!swipeoutAction) return;
  350. swipeoutAction.classList.add(CLASS_SELECTED);
  351. classList.add(CLASS_SELECTED);
  352. classList.remove(CLASS_TRANSITIONING);
  353. var buttons = swipeoutAction.querySelectorAll(SELECTOR_BUTTON);
  354. var swipeoutWidth = swipeoutAction.offsetWidth;
  355. var translate = (direction === 'right') ? -swipeoutWidth : swipeoutWidth;
  356. var length = buttons.length;
  357. var button;
  358. for (var i = 0; i < length; i++) {
  359. button = buttons[i];
  360. if (direction === 'right') {
  361. setTranslate(button, -button.offsetLeft);
  362. } else {
  363. setTranslate(button, (swipeoutWidth - button.offsetWidth - button.offsetLeft));
  364. }
  365. }
  366. classList.add(CLASS_TRANSITIONING);
  367. for (var i = 0; i < length; i++) {
  368. setTranslate(buttons[i], translate);
  369. }
  370. setTranslate(el.querySelector(SELECTOR_SLIDER_HANDLE), translate);
  371. };
  372. /**
  373. * 关闭滑动菜单
  374. * @param {Object} el
  375. */
  376. $.swipeoutClose = function(el) {
  377. if (!el) return;
  378. var classList = el.classList;
  379. if (!classList.contains(CLASS_SELECTED)) return;
  380. var direction = el.querySelector(SELECTOR_SLIDER_RIGHT + SELECTOR_SELECTED) ? 'right' : 'left';
  381. var swipeoutAction = el.querySelector($.classSelector(".slider-" + direction));
  382. if (!swipeoutAction) return;
  383. swipeoutAction.classList.remove(CLASS_SELECTED);
  384. classList.remove(CLASS_SELECTED);
  385. classList.add(CLASS_TRANSITIONING);
  386. var buttons = swipeoutAction.querySelectorAll(SELECTOR_BUTTON);
  387. var swipeoutWidth = swipeoutAction.offsetWidth;
  388. var length = buttons.length;
  389. var button;
  390. setTranslate(el.querySelector(SELECTOR_SLIDER_HANDLE), 0);
  391. for (var i = 0; i < length; i++) {
  392. button = buttons[i];
  393. if (direction === 'right') {
  394. setTranslate(button, (-button.offsetLeft));
  395. } else {
  396. setTranslate(button, (swipeoutWidth - button.offsetWidth - button.offsetLeft));
  397. }
  398. }
  399. };
  400. window.addEventListener($.EVENT_END, function(event) { //使用touchend来取消高亮,避免一次点击既不触发tap,doubletap,longtap的事件
  401. if (!cell) {
  402. return;
  403. }
  404. toggleActive(false);
  405. sliderHandle && toggleEvents(cell, true);
  406. });
  407. window.addEventListener($.EVENT_CANCEL, function(event) { //使用touchcancel来取消高亮,避免一次点击既不触发tap,doubletap,longtap的事件
  408. if (!cell) {
  409. return;
  410. }
  411. toggleActive(false);
  412. sliderHandle && toggleEvents(cell, true);
  413. });
  414. var radioOrCheckboxClick = function(event) {
  415. var type = event.target && event.target.type || '';
  416. if (type === 'radio' || type === 'checkbox') {
  417. return;
  418. }
  419. var classList = cell.classList;
  420. if (classList.contains($.className('radio'))) {
  421. var input = cell.querySelector('input[type=radio]');
  422. if (input) {
  423. // input.click();
  424. if (!input.disabled && !input.readOnly) {
  425. input.checked = !input.checked;
  426. $.trigger(input, 'change');
  427. }
  428. }
  429. } else if (classList.contains($.className('checkbox'))) {
  430. var input = cell.querySelector('input[type=checkbox]');
  431. if (input) {
  432. // input.click();
  433. if (!input.disabled && !input.readOnly) {
  434. input.checked = !input.checked;
  435. $.trigger(input, 'change');
  436. }
  437. }
  438. }
  439. };
  440. //fixed hashchange(android)
  441. window.addEventListener($.EVENT_CLICK, function(e) {
  442. if (cell && cell.classList.contains($.className('collapse'))) {
  443. e.preventDefault();
  444. }
  445. });
  446. window.addEventListener('doubletap', function(event) {
  447. if (cell) {
  448. radioOrCheckboxClick(event);
  449. }
  450. });
  451. var preventDefaultException = /^(INPUT|TEXTAREA|BUTTON|SELECT)$/;
  452. window.addEventListener('tap', function(event) {
  453. if (!cell) {
  454. return;
  455. }
  456. var isExpand = false;
  457. var classList = cell.classList;
  458. var ul = cell.parentNode;
  459. if (ul && ul.classList.contains(CLASS_RADIO_VIEW)) {
  460. if (classList.contains(CLASS_SELECTED)) {
  461. return;
  462. }
  463. var selected = ul.querySelector('li' + SELECTOR_SELECTED);
  464. if (selected) {
  465. selected.classList.remove(CLASS_SELECTED);
  466. }
  467. classList.add(CLASS_SELECTED);
  468. $.trigger(cell, 'selected', {
  469. el: cell
  470. });
  471. return;
  472. }
  473. if (classList.contains($.className('collapse')) && !cell.parentNode.classList.contains($.className('unfold'))) {
  474. if (!preventDefaultException.test(event.target.tagName)) {
  475. event.detail.gesture.preventDefault();
  476. }
  477. if (!classList.contains(CLASS_ACTIVE)) { //展开时,需要收缩其他同类
  478. var collapse = cell.parentNode.querySelector($.classSelector('.collapse.active'));
  479. if (collapse) {
  480. collapse.classList.remove(CLASS_ACTIVE);
  481. }
  482. isExpand = true;
  483. }
  484. classList.toggle(CLASS_ACTIVE);
  485. if (isExpand) {
  486. //触发展开事件
  487. $.trigger(cell, 'expand');
  488. //scroll
  489. //暂不滚动
  490. // var offsetTop = $.offset(cell).top;
  491. // var scrollTop = document.body.scrollTop;
  492. // var height = window.innerHeight;
  493. // var offsetHeight = cell.offsetHeight;
  494. // var cellHeight = (offsetTop - scrollTop + offsetHeight);
  495. // if (offsetHeight > height) {
  496. // $.scrollTo(offsetTop, 300);
  497. // } else if (cellHeight > height) {
  498. // $.scrollTo(cellHeight - height + scrollTop, 300);
  499. // }
  500. }
  501. } else {
  502. radioOrCheckboxClick(event);
  503. }
  504. });
  505. })(mui, window, document);