tocas.js 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424
  1. // Generated by CoffeeScript 2.0.0-beta4
  2. (function() {
  3. // 主要的選擇器函式。
  4. var ts;
  5. ts = function(selector, context) {
  6. var nodes, ref, tag;
  7. nodes = [];
  8. // 如果選擇器是文字,但是是標籤(如:`<div>`)就建立新的元素
  9. if (typeof selector === 'string' && selector[0] === '<') {
  10. tag = selector.match(/<(.*)\/>|<(.*)>/);
  11. nodes = [document.createElement((ref = tag[1]) != null ? ref : tag[2])];
  12. // 如果選擇器是一般的文字,就選取元素。
  13. } else if (typeof selector === 'string' && context === void 0) {
  14. document.querySelectorAll(selector).forEach(function(element) {
  15. return nodes.push(element);
  16. });
  17. // 如果選擇器有上下文選擇器,就透過選擇器找出上下文元素。
  18. } else if (typeof context === 'string') {
  19. nodes = ts(selector).find(context).toArray();
  20. // 如果選擇器是 NodeList 就轉換成元素陣列然後取出來接著繼續。
  21. } else if (selector instanceof NodeList) {
  22. selector.forEach(function(element) {
  23. return nodes.push(element);
  24. });
  25. // 如果選擇器是陣列,就當作是元素陣列,取出來然後繼續。
  26. // 或傳入的是一個選擇器,就取出裡面的元素然後繼續。
  27. } else if (Array.isArray(selector) || (selector != null ? selector.isSelector : void 0) === true) {
  28. nodes = nodes.concat(selector);
  29. selector = selector.selector;
  30. context = selector != null ? selector.context : void 0;
  31. // 如果是單個 DOM 元素,就放入選擇器然後繼續。
  32. } else if (selector instanceof HTMLElement || selector instanceof HTMLDocument || selector instanceof HTMLBodyElement || selector === window) {
  33. nodes = [selector];
  34. }
  35. // 保存目前的選擇器文字與上下文選擇器文字。
  36. nodes.selector = typeof selector === 'string' ? selector : null;
  37. nodes.context = typeof context === 'string' ? context : null;
  38. // 將自訂的選擇器方法插入到節點陣列中,這樣才能夠串連使用。
  39. Object.defineProperties(nodes, ts.fn);
  40. // 將節點陣列標註為是選擇器,這樣才能判斷傳入的是不是我們自己的選擇器。
  41. Object.defineProperty(nodes, 'isSelector', {
  42. value: true
  43. });
  44. return nodes;
  45. };
  46. // 註冊到視窗上。
  47. window.ts = ts;
  48. // 函式鏈。
  49. ts.fn = {};
  50. // 輔助函式。
  51. ts.helper = {};
  52. // 事件輔助函式。
  53. ts.helper.eventAlias = function(event) {
  54. var alias, pair;
  55. pair = event.split('.');
  56. alias = pair[1] !== void 0 ? `.${pair[1]}` : '';
  57. switch (false) {
  58. case pair.indexOf('animationend') === -1:
  59. return `webkitAnimationEnd${alias} mozAnimationEnd${alias} MSAnimationEnd${alias} oanimationend${alias} animationend${alias}`;
  60. case pair.indexOf('transitionend') === -1:
  61. return `webkitTransitionEnd${alias} mozTransitionEnd${alias} oTransitionEnd${alias} msTransitionEnd${alias} transitionend${alias}`;
  62. default:
  63. return event;
  64. }
  65. };
  66. // 是否為物件。
  67. ts.isPlainObject = function(object) {
  68. return Object.prototype.toString.call(object) === '[object Object]';
  69. };
  70. // 是否為可觸控裝置。
  71. ts.isTouchDevice = function() {
  72. return 'ontouchstart' in window || navigator.maxTouchPoints;
  73. };
  74. // 延展物件的函式,與 ES 的 `...` 不同之處在於 extend 並不會替換掉整個子物件,而會以補插的方式執行。
  75. // https://gomakethings.com/vanilla-javascript-version-of-jquery-extend/
  76. ts.extend = function() {
  77. var deep, extended, i, length, merge, obj;
  78. extended = {};
  79. deep = true;
  80. i = 0;
  81. length = arguments.length;
  82. if (Object.prototype.toString.call(arguments[0]) === '[object Boolean]') {
  83. deep = arguments[0];
  84. i++;
  85. }
  86. merge = function(obj) {
  87. var prop;
  88. for (prop in obj) {
  89. if (Object.prototype.hasOwnProperty.call(obj, prop)) {
  90. if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') {
  91. extended[prop] = ts.extend(true, extended[prop], obj[prop]);
  92. } else {
  93. extended[prop] = obj[prop];
  94. }
  95. }
  96. }
  97. };
  98. while (i < length) {
  99. obj = arguments[i];
  100. merge(obj);
  101. i++;
  102. }
  103. return extended;
  104. };
  105. // 建立元素
  106. ts.createElement = (html) => {
  107. var div;
  108. div = document.createElement('div');
  109. div.innerHTML = html.trim();
  110. return div.firstChild;
  111. };
  112. // 註冊 Tocas 模塊
  113. ts.register = ({NAME, MODULE_NAMESPACE, Settings}, starter) => {
  114. return ts.fn[NAME] = {
  115. value: function(parameters) {
  116. var $allModules, consoleText, errorHeaderCSS, headerCSS, messageCSS, methodInvoked, query, queryArguments, returnedValue;
  117. $allModules = ts(this);
  118. query = arguments[0];
  119. queryArguments = [].slice.call(arguments, 1);
  120. methodInvoked = typeof query === 'string';
  121. returnedValue = void 0;
  122. consoleText = (args) => {
  123. //currentdate = new Date();
  124. //datetime = "#{currentdate.getFullYear()}/#{(currentdate.getMonth()+1)}/#{currentdate.getDate()}/@#{currentdate.getHours()}:#{currentdate.getMinutes()}:#{currentdate.getSeconds()}"
  125. return `%c${NAME}%c ${args[0]}`;
  126. };
  127. headerCSS = "background : #EEE;\ncolor : #5A5A5A;\nfont-size : 1em;\npadding : 8px 8px;\nline-height : 5px;\nmargin : 5px 0 5px 0;\nborder-radius: 1000em;";
  128. errorHeaderCSS = `${headerCSS}\nbackground: #CE5F58;\ncolor: #FFF;`;
  129. messageCSS = "font-weight: bold;";
  130. $allModules.each(function(_, index) {
  131. var $this, debug, element, error, initialize, instance, instantiate, invoke, module, observeChanges, settings;
  132. $this = ts(this);
  133. element = this;
  134. instance = $this.data(MODULE_NAMESPACE);
  135. settings = ts.isPlainObject(parameters) ? ts.extend(Settings, parameters) : ts.extend(Settings);
  136. debug = function() {
  137. if (!settings.debug || settings.silent) {
  138. return;
  139. }
  140. return console.info.call(console, consoleText(arguments), headerCSS, messageCSS, "\n", ...Array.prototype.slice.call(arguments).slice(1));
  141. };
  142. error = function() {
  143. if (settings.silent) {
  144. return;
  145. }
  146. error = Function.prototype.bind.call(console.error, console, consoleText(arguments), errorHeaderCSS, messageCSS);
  147. return error.apply(console, Array.prototype.slice.call(arguments, 1));
  148. };
  149. instantiate = () => {
  150. module.instantiate();
  151. instance = module;
  152. return $this.data(MODULE_NAMESPACE, instance);
  153. };
  154. initialize = () => {
  155. module.initialize();
  156. if (settings.observeChanges) {
  157. observeChanges();
  158. }
  159. return instantiate();
  160. };
  161. observeChanges = () => {
  162. var observer;
  163. if (!'MutationObserver' in window) {
  164. debug('找不到樹狀結構變更觀測者,略過結構監聽動作', element);
  165. return;
  166. }
  167. observer = new MutationObserver((mutations) => {
  168. //debug 'DOM 樹狀結構已變更,更新快取資料'
  169. return module.refresh();
  170. });
  171. return observer.observe(element, {
  172. childList: true,
  173. subtree: true
  174. });
  175. };
  176. //debug '已設置 DOM 樹狀結構異動觀察者', observer
  177. invoke = (query, passedArguments, context) => {
  178. var camelCaseValue, depth, found, j, len, maxDepth, object, response, value;
  179. object = instance;
  180. maxDepth = void 0;
  181. found = void 0;
  182. response = void 0;
  183. passedArguments = passedArguments || queryArguments;
  184. context = element || context;
  185. if (typeof query === 'string' && object !== void 0) {
  186. query = query.split(/[\. ]/);
  187. maxDepth = query.length - 1;
  188. for (depth = j = 0, len = query.length; j < len; depth = ++j) {
  189. value = query[depth];
  190. camelCaseValue = query;
  191. if (depth !== maxDepth) {
  192. camelCaseValue = value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1);
  193. }
  194. switch (false) {
  195. case !(ts.isPlainObject(object[camelCaseValue]) && depth !== maxDepth):
  196. object = object[camelCaseValue];
  197. break;
  198. case object[camelCaseValue] === void 0:
  199. found = object[camelCaseValue];
  200. break;
  201. case !(ts.isPlainObject(object[value]) && depth !== maxDepth):
  202. object = object[value];
  203. break;
  204. case object[value] === void 0:
  205. found = object[value];
  206. break;
  207. default:
  208. error('欲呼叫的方法並不存在', query);
  209. break;
  210. }
  211. }
  212. }
  213. switch (false) {
  214. case typeof found !== 'function':
  215. response = found.apply(context, passedArguments);
  216. break;
  217. case found === void 0:
  218. response = found;
  219. }
  220. switch (false) {
  221. case response !== $allModules:
  222. returnedValue = $allModules;
  223. break;
  224. default:
  225. returnedValue = response;
  226. }
  227. return found;
  228. };
  229. module = starter({$allModules, $this, element, debug, settings, instance, index});
  230. if (methodInvoked) {
  231. if (instance === void 0) {
  232. initialize();
  233. }
  234. return invoke(query);
  235. } else {
  236. if (instance !== void 0) {
  237. invoke('destroy');
  238. }
  239. return initialize();
  240. }
  241. });
  242. if (returnedValue !== void 0) {
  243. return returnedValue;
  244. } else {
  245. return $allModules;
  246. }
  247. }
  248. };
  249. };
  250. // Get
  251. // 取得選擇器內的指定元素,並且回傳一個 DOM 元素而非選擇器。
  252. ts.fn.get = {
  253. value: function(index = 0) {
  254. return this[index];
  255. }
  256. };
  257. // ToArray
  258. // 將選擇器轉換成帶有節點的一般陣列。
  259. ts.fn.toArray = {
  260. value: function() {
  261. var array;
  262. array = [];
  263. this.forEach(function(element) {
  264. return array.push(element);
  265. });
  266. return array;
  267. }
  268. };
  269. // Each
  270. // 遍歷整個選擇器陣列。
  271. ts.fn.each = {
  272. value: function(callback) {
  273. this.forEach(function(element, index) {
  274. return callback.call(element, element, index);
  275. });
  276. return this;
  277. }
  278. };
  279. // CollectSwap
  280. // 將收集到的元素替換掉目前選擇器內的所有元素。
  281. ts.fn.collectSwap = {
  282. value: function(callback) {
  283. var collection, newSelector;
  284. collection = [];
  285. this.each(function(element, index) {
  286. var result;
  287. result = callback.call(element, element, index);
  288. if (result === void 0 || result === null) {
  289. return;
  290. }
  291. if (result instanceof NodeList) {
  292. return result.forEach(function(el) {
  293. return collection.push(el);
  294. });
  295. } else if (Array.isArray(result)) {
  296. return collection = collection.concat(result);
  297. } else {
  298. if (collection.indexOf(result) === -1) {
  299. return collection.push(result);
  300. }
  301. }
  302. });
  303. // 透過 Set 型態移除重複的節點。
  304. collection = new Set(collection);
  305. // 然後將 Set 轉換成陣列,建立新的選擇器。
  306. newSelector = ts([...collection]);
  307. // 保存選擇器之前的所有節點。
  308. Object.defineProperty(newSelector, 'prevObject', {
  309. value: this
  310. });
  311. // 回傳這個新的選擇器。
  312. return newSelector;
  313. }
  314. };
  315. // Eq
  316. // 取得選擇器的指定元素,然後繼續回傳僅帶有該元素的選擇器。
  317. ts.fn.eq = {
  318. value: function(index) {
  319. return ts(this.get(index));
  320. }
  321. };
  322. // Parent
  323. // 回傳元素的父元素選擇器。
  324. ts.fn.parent = {
  325. value: function() {
  326. return this.collectSwap(function() {
  327. return this.parentNode;
  328. });
  329. }
  330. };
  331. // Closest
  332. // 回傳最接近指定的父元素選擇器。
  333. ts.fn.closest = {
  334. value: function(selector) {
  335. return this.collectSwap(function() {
  336. return this.closest(selector);
  337. });
  338. }
  339. };
  340. // Find
  341. // 在目前元素中搜尋指定元素並回傳其選擇器。
  342. ts.fn.find = {
  343. value: function(selector) {
  344. return this.collectSwap(function() {
  345. return this.querySelectorAll(selector);
  346. });
  347. }
  348. };
  349. // Insert Before
  350. // 將選擇器元素安插在指定元素前。
  351. ts.fn.insertBefore = {
  352. value: function(target) {
  353. return this.each(function() {
  354. return ts(target).each((element) => {
  355. return element.parentNode.insertBefore(this, element);
  356. });
  357. });
  358. }
  359. };
  360. // Insert After
  361. // 將選擇器元素安插在指定元素後。
  362. ts.fn.insertAfter = {
  363. value: function(target) {
  364. return this.each(function() {
  365. return ts(target).each((element) => {
  366. return element.parentNode.insertBefore(this, element.nextSibling);
  367. });
  368. });
  369. }
  370. };
  371. // Wrap
  372. // 將元素用指定元素包覆起來。
  373. ts.fn.wrap = {
  374. value: function(element) {
  375. return this.each(function() {
  376. if (this.nextSibling) {
  377. this.parentNode.insertBefore(element, this.nextSibling);
  378. } else {
  379. this.parentNode.appendChild(element);
  380. }
  381. return element.appendChild(this);
  382. });
  383. }
  384. };
  385. // Clone
  386. // 複製元素。
  387. ts.fn.clone = {
  388. value: function() {
  389. return this.collectSwap(function() {
  390. return this.cloneNode(true);
  391. });
  392. }
  393. };
  394. // Append
  395. // 將元素插入在目前選擇器元素的內部最後面。
  396. ts.fn.append = {
  397. value: function(element) {
  398. var shouldClone;
  399. shouldClone = this.length !== 1;
  400. if (element.isSelector !== void 0) {
  401. return this.each(function() {
  402. return element.each((e) => {
  403. return this.appendChild(shouldClone ? e.cloneNode(true) : e);
  404. });
  405. });
  406. } else if (typeof element === 'string') {
  407. return this.each(function() {
  408. return this.insertAdjacentHTML('beforeend', element);
  409. });
  410. } else {
  411. return this.each(function() {
  412. return this.appendChild(shouldClone ? element.cloneNode(true) : element);
  413. });
  414. }
  415. }
  416. };
  417. // AppendTo
  418. // 將目前選擇器元素插入到指定元素的內部最後面。
  419. ts.fn.appendTo = {
  420. value: function(selector) {
  421. return this.each(function() {
  422. return ts(selector).append(this);
  423. });
  424. }
  425. };
  426. // Prepend
  427. // 將元素插入在目前選擇器元素的內部最前面。
  428. ts.fn.prepend = {
  429. value: function(element) {
  430. var shouldClone;
  431. shouldClone = this.length !== 1;
  432. if (element.isSelector !== void 0) {
  433. return this.each(function() {
  434. return element.each((e) => {
  435. return this.prepend(shouldClone ? e.cloneNode(true) : e);
  436. });
  437. });
  438. } else if (typeof element === 'string') {
  439. return this.each(function() {
  440. return this.insertAdjacentHTML('afterbegin', element);
  441. });
  442. } else {
  443. return this.each(function() {
  444. return this.prepend(shouldClone ? element.cloneNode(true) : element);
  445. });
  446. }
  447. }
  448. };
  449. // PrependTo
  450. // 將目前選擇器元素插入到指定元素的內部最前面。
  451. ts.fn.prependTo = {
  452. value: function(selector) {
  453. return this.each(function() {
  454. return ts(selector).prepend(this);
  455. });
  456. }
  457. };
  458. // Remove
  459. // 將選擇器元素從頁面上中移除。
  460. ts.fn.remove = {
  461. value: function() {
  462. return this.each(function() {
  463. var ref;
  464. return (ref = this.parentNode) != null ? ref.removeChild(this) : void 0;
  465. });
  466. }
  467. };
  468. // Is
  469. // 選擇一些元素,然後用來比對目前的選擇器元素是否在這群當中。
  470. ts.fn.is = {
  471. value: function(selector) {
  472. var compareElements, isInElements;
  473. compareElements = document.querySelectorAll(selector);
  474. isInElements = false;
  475. this.each(function() {
  476. return compareElements.forEach(function(compareElement) {
  477. if (this === compareElement) {
  478. return isInElements = true;
  479. }
  480. }, this);
  481. });
  482. return isInElements;
  483. }
  484. };
  485. // Contains
  486. // 是否擁有指定子元素。
  487. ts.fn.contains = {
  488. value: function(selector) {
  489. var ref;
  490. return (ref = this.get(0)) != null ? ref.contains(ts(selector).get()) : void 0;
  491. }
  492. };
  493. // Not
  494. // 將指定元素從選擇器中剔除。
  495. ts.fn.not = {
  496. value: function(selector) {
  497. return ts(this.toArray().filter((element) => {
  498. return ts(selector).indexOf(element) === -1;
  499. }));
  500. }
  501. };
  502. // Slice
  503. // 替元素陣列進行切分。
  504. ts.fn.slice = {
  505. value: function(from, to) {
  506. return ts(this.toArray().slice(from, to));
  507. }
  508. };
  509. // Children
  510. // 取得容器裡的第一層子節點。
  511. ts.fn.children = {
  512. value: function(selector) {
  513. return this.collectSwap(function() {
  514. return this.querySelectorAll(selector != null ? `:scope > ${selector}` : ':scope > *');
  515. });
  516. }
  517. };
  518. // Replace With
  519. // 將元素替換為指定選擇器元素。
  520. ts.fn.replaceWith = {
  521. value: function(selector) {
  522. var element;
  523. element = ts(selector).get();
  524. return this.each(function() {
  525. return this.replaceWith(element);
  526. });
  527. }
  528. };
  529. // Last
  530. // 選擇器中的最後一個元素。
  531. ts.fn.last = {
  532. value: function() {
  533. return this.eq(this.length - 1);
  534. }
  535. };
  536. // Next
  537. // 下一個元素。
  538. ts.fn.next = {
  539. value: function() {
  540. return this.collectSwap(function() {
  541. return this.nextElementSibling;
  542. });
  543. }
  544. };
  545. // Prev
  546. // 上一個元素。
  547. ts.fn.prev = {
  548. value: function() {
  549. return this.collectSwap(function() {
  550. return this.previousElementSibling;
  551. });
  552. }
  553. };
  554. // NextAll
  555. // 這個元素之後的所有同階層元素。
  556. ts.fn.nextAll = {
  557. value: function(selector) {
  558. return this.collectSwap(function() {
  559. var $children, $parent, $self, index;
  560. $self = ts(this);
  561. $parent = $self.parent();
  562. $children = selector != null ? $parent.find(`:scope > ${selector}`) : $parent.find(':scope > *');
  563. index = $self.index();
  564. return $children.slice(index + 1);
  565. });
  566. }
  567. };
  568. // PrevAll
  569. // 這個元素之前的所有同階層元素。
  570. ts.fn.prevAll = {
  571. value: function(selector) {
  572. return this.collectSwap(function() {
  573. var $children, $parent, $self, index;
  574. $self = ts(this);
  575. $parent = $self.parent();
  576. $children = selector != null ? $parent.find(`:scope > ${selector}`) : $parent.find(':scope > *');
  577. index = $self.index();
  578. return $children.slice(0, index);
  579. });
  580. }
  581. };
  582. // AddBack
  583. // 在目前的選擇器節點陣列中加上先前選擇的所有節點。
  584. ts.fn.addBack = {
  585. value: function() {
  586. if (this.prevObject) {
  587. this.prevObject.toArray().forEach((element) => {
  588. return this.push(element);
  589. });
  590. }
  591. return this;
  592. }
  593. };
  594. // Index
  595. // 該元素在容器內的索引。
  596. ts.fn.index = {
  597. value: function() {
  598. var index, node;
  599. node = this.get(0);
  600. index = 0;
  601. if (node == null) {
  602. return -1;
  603. }
  604. while ((node = node.previousElementSibling)) {
  605. index++;
  606. }
  607. return index;
  608. }
  609. };
  610. // Attr
  611. // 取得或是建立新的標籤到目前的選擇器元素。
  612. ts.fn.attr = {
  613. value: function(name, value) {
  614. var ref;
  615. // 如果有 value 就設置簡單鍵值資料。
  616. if (value !== void 0) {
  617. return this.each(function() {
  618. return this.setAttribute(name, value);
  619. });
  620. // 如果傳入的是物件就設置多重資料。
  621. } else if (typeof name === 'object') {
  622. return this.each(function() {
  623. var key, results;
  624. results = [];
  625. for (key in name) {
  626. results.push(this.setAttribute(key, name[key]));
  627. }
  628. return results;
  629. });
  630. } else {
  631. return (ref = this.get()) != null ? ref.getAttribute(name) : void 0;
  632. }
  633. }
  634. };
  635. // RemoveAttr
  636. // 移除目前選擇器元素的指定標籤。
  637. ts.fn.removeAttr = {
  638. value: function(name) {
  639. return this.each(function() {
  640. return this.removeAttribute(name);
  641. });
  642. }
  643. };
  644. // AddClass
  645. // 在目前選擇器元素插入新的樣式類別名稱。
  646. ts.fn.addClass = {
  647. value: function(names) {
  648. var name, newNames;
  649. if (typeof names === 'object') {
  650. newNames = '';
  651. for (name in names) {
  652. if (names[name] === true) {
  653. newNames += ` ${name}`;
  654. }
  655. }
  656. names = newNames;
  657. } else {
  658. names = Array.prototype.slice.call(arguments).join(' ');
  659. }
  660. return this.each(function() {
  661. return DOMTokenList.prototype.add.apply(this.classList, names.split(' ').filter(Boolean));
  662. });
  663. }
  664. };
  665. // RemoveClass
  666. // 移除目前選擇器元素的指定樣式類別。
  667. ts.fn.removeClass = {
  668. value: function(names) {
  669. var name, newNames;
  670. if (typeof names === 'object') {
  671. newNames = '';
  672. for (name in names) {
  673. if (names[name] === true) {
  674. newNames += ` ${name}`;
  675. }
  676. }
  677. names = newNames;
  678. } else {
  679. names = Array.prototype.slice.call(arguments).join(' ');
  680. }
  681. //console.log @
  682. return this.each(function() {
  683. return DOMTokenList.prototype.remove.apply(this.classList, names.split(' ').filter(Boolean));
  684. });
  685. }
  686. };
  687. // ToggleClass
  688. // 切換目前選擇器元素的樣式。
  689. ts.fn.toggleClass = {
  690. value: function(names) {
  691. return this.each(function() {
  692. return names.split(' ').forEach(function(name) {
  693. return this.classList.toggle(name);
  694. }, this);
  695. });
  696. }
  697. };
  698. // HasClass
  699. // 回傳選擇器元素是否帶有指定樣式類別,是布林值。
  700. ts.fn.hasClass = {
  701. value: function(name) {
  702. var ref;
  703. return (ref = this.get(0)) != null ? ref.classList.contains(name) : void 0;
  704. }
  705. };
  706. // CSS
  707. // 將選擇器元素套用指定的 CSS 樣式。
  708. ts.fn.css = {
  709. value: function(name, value) {
  710. var key;
  711. // 有 name 也有 value 就設置樣式。
  712. if (typeof name === 'string' && value !== void 0) {
  713. return this.each(function() {
  714. return this.style[name] = value;
  715. });
  716. // 有 name 但沒有 value 就取得樣式。
  717. } else if (typeof name === 'string' && value === void 0) {
  718. if (this.get() != null) {
  719. return document.defaultView.getComputedStyle(this.get(), null).getPropertyValue(name);
  720. } else {
  721. return null;
  722. }
  723. // 有 name 但他是 object,就設置多重樣式。
  724. } else if (typeof name === 'object') {
  725. for (key in name) {
  726. this.each(function() {
  727. return this.style[key] = name[key];
  728. });
  729. }
  730. return this;
  731. }
  732. }
  733. };
  734. // Rect
  735. // 回傳選擇器元素的渲染形狀。
  736. ts.fn.rect = {
  737. value: function() {
  738. var ref;
  739. return (ref = this.get(0)) != null ? ref.getBoundingClientRect() : void 0;
  740. }
  741. };
  742. // On
  743. // 綁定並註冊一個事件監聽器。
  744. ts.fn.on = {
  745. value: function() {
  746. var data, events, handler, options, selector;
  747. switch (arguments.length) {
  748. // Event 與 Handler。
  749. case 2:
  750. events = arguments[0];
  751. handler = arguments[1];
  752. break;
  753. // Event 與 Selector 與 Handler。
  754. // Event 與 Data 與 Handler。
  755. // Event 與 Handler 與 Options。
  756. case 3:
  757. events = arguments[0];
  758. handler = arguments[2];
  759. switch (typeof arguments[1]) {
  760. case "string":
  761. selector = arguments[1];
  762. break;
  763. case "function":
  764. handler = arguments[1];
  765. options = arguments[2];
  766. break;
  767. default:
  768. data = arguments[1];
  769. }
  770. break;
  771. // Event 與 Selector 與 Data 與 Handler。
  772. // Event 與 Selector 與 Handler 與 Options。
  773. case 4:
  774. events = arguments[0];
  775. selector = arguments[1];
  776. handler = arguments[3];
  777. switch (typeof arguments[2]) {
  778. case "function":
  779. handler = arguments[2];
  780. options = arguments[3];
  781. break;
  782. default:
  783. data = arguments[2];
  784. }
  785. break;
  786. // Event 與 Selector 與 Data 與 Handler 與 Options。
  787. case 5:
  788. events = arguments[0];
  789. selector = arguments[1];
  790. data = arguments[2];
  791. handler = arguments[3];
  792. options = arguments[4];
  793. }
  794. events = ts.helper.eventAlias(events);
  795. // $events.click =
  796. // {
  797. // anonymous: [
  798. // {
  799. // once : true,
  800. // selector: ".button",
  801. // data : {},
  802. // func : func()
  803. // }
  804. // ]
  805. // alias1: [
  806. // {
  807. // once : true,
  808. // selector: ".button",
  809. // data : {},
  810. // func : func()
  811. // }
  812. // ]
  813. // }
  814. return this.each(function() {
  815. if (this.addEventListener === void 0) {
  816. return;
  817. }
  818. if (this.$events === void 0) {
  819. this.$events = {};
  820. }
  821. return events.split(' ').forEach(function(eventName) {
  822. var event, eventAlias, hasAlias;
  823. event = eventName.split('.');
  824. // 透過事件的「event.alias」取得「點」後面的別名。
  825. hasAlias = event.length > 1;
  826. eventName = event[0];
  827. eventAlias = hasAlias ? event[1] : null;
  828. // 如果事件還沒在這個物件內產生過,就初始化一個事件結構。
  829. if (this.$events[eventName] === void 0) {
  830. this.$events[eventName] = {
  831. anonymous: []
  832. };
  833. // 然後建立一個管理多個事件的事件管理處理程式。
  834. this.addEventListener(eventName, function(event) {
  835. var alias, calledAlias, closest, context, hasArgs, index, ref, ref1, ref2, results, single;
  836. // 是否有自訂參數。
  837. hasArgs = ((ref = event.detail) != null ? (ref1 = ref.args) != null ? ref1.length : void 0 : void 0) > 0;
  838. // 是否有呼叫事件別名。
  839. calledAlias = (ref2 = event.detail) != null ? ref2.alias : void 0;
  840. // 如果該事件已經被移除則停止後續的反應。
  841. if (this.$events[eventName] === void 0) {
  842. return;
  843. }
  844. results = [];
  845. // 將被觸發的事件裡面的所有處理程式全部呼叫一次。
  846. for (alias in this.$events[eventName]) {
  847. if (calledAlias && calledAlias !== alias) {
  848. continue;
  849. }
  850. index = this.$events[eventName][alias].length;
  851. results.push((function() {
  852. var results1;
  853. results1 = [];
  854. while (index--) {
  855. if (this.$events[eventName] === void 0) {
  856. continue;
  857. }
  858. if (this.$events[eventName][alias] === void 0) {
  859. continue;
  860. }
  861. single = this.$events[eventName][alias][index];
  862. // 設置事件的上下文。
  863. context = this;
  864. // 如果這個事件有選擇器的話,則使用該選擇器為主。
  865. if (single.selector !== void 0) {
  866. selector = single.selector;
  867. closest = ts(event.target).closest(selector);
  868. // 如果找不到指定選擇棄的元素,就不要觸發此事件。
  869. if (closest.length === 0) {
  870. continue;
  871. } else {
  872. // 替換上下文為選擇器元素。
  873. context = closest.get();
  874. }
  875. }
  876. // 將事件預資料放入事件中供處理函式取得。
  877. event.data = single.data;
  878. if (hasArgs) {
  879. single.func.call(context, event, ...event.detail.args);
  880. } else {
  881. single.func.call(context, event);
  882. }
  883. // 如果這個程式只能被呼叫一次就在處理程式呼叫後移除。
  884. if (single.once === true) {
  885. results1.push(this.$events[eventName][alias].splice(index, 1));
  886. } else {
  887. results1.push(void 0);
  888. }
  889. }
  890. return results1;
  891. }).call(this));
  892. }
  893. return results;
  894. });
  895. }
  896. // 將新的事件處理程式註冊到事件清單中。
  897. // 如果有別名,就不要推送到匿名陣列中,我們替這個別名另開物件。
  898. if (hasAlias) {
  899. if (this.$events[eventName][eventAlias] === void 0) {
  900. this.$events[eventName][eventAlias] = [];
  901. }
  902. return this.$events[eventName][eventAlias].push({
  903. func: handler,
  904. selector: selector,
  905. data: data,
  906. once: options != null ? options.once : void 0
  907. });
  908. } else {
  909. // 如果沒有,就照常推進匿名陣列中。
  910. return this.$events[eventName].anonymous.push({
  911. func: handler,
  912. selector: selector,
  913. data: data,
  914. once: options != null ? options.once : void 0
  915. });
  916. }
  917. }, this);
  918. });
  919. }
  920. };
  921. // One
  922. // 綁定一次性的事件監聽器,當被觸發之後就會被移除。
  923. ts.fn.one = {
  924. value: function(events, handler) {
  925. events = ts.helper.eventAlias(events);
  926. return this.each(function() {
  927. return ts(this).on(events, handler, {
  928. once: true
  929. });
  930. });
  931. }
  932. };
  933. // Off
  934. // 註銷事件監聽器。
  935. ts.fn.off = {
  936. value: function(events, handler) {
  937. events = ts.helper.eventAlias(events);
  938. return this.each(function() {
  939. if (this.$events === void 0) {
  940. return;
  941. }
  942. return events.split(' ').forEach((eventName) => {
  943. var alias, aliasName, event, hasAlias, isAlias, results;
  944. // 將事件名稱由中間的「.」切成兩半。
  945. event = eventName.split('.');
  946. // 如果事件開頭是「.」符號,表示這是個別名,不是事件名稱。
  947. isAlias = eventName[0] === '.';
  948. // 如果事件分切後有兩個項目,表示這個事件有別名。
  949. hasAlias = event.length === 2 && event[0] !== '';
  950. if (hasAlias || isAlias) {
  951. // 如果有別名的話,取得別名。
  952. aliasName = event[1];
  953. }
  954. // 如果此事件不是只有別名的話,取得事件名稱。
  955. eventName = !isAlias ? event[0] : void 0;
  956. switch (false) {
  957. // 當有指定監聽函式時。
  958. case !(handler !== void 0 && this.$events[eventName] !== void 0):
  959. return this.$events[eventName].anonymous.forEach((item, index) => {
  960. if (handler === item.func) {
  961. return this.$events[eventName].anonymous.splice(index, 1);
  962. }
  963. });
  964. // 當本事件名稱不僅是別名時。
  965. case !(!isAlias && hasAlias && this.$events[eventName] !== void 0):
  966. // 移除指定事件的別名監聽函式。
  967. return delete this.$events[eventName][aliasName];
  968. // 當僅有指定別名時。
  969. case !(isAlias && !hasAlias):
  970. results = [];
  971. // 移除所有與此別名有關的事件監聽器。
  972. for (event in this.$events) {
  973. results.push((function() {
  974. var results1;
  975. results1 = [];
  976. for (alias in this.$events[event]) {
  977. if (aliasName === alias) {
  978. results1.push(delete this.$events[event][aliasName]);
  979. } else {
  980. results1.push(void 0);
  981. }
  982. }
  983. return results1;
  984. }).call(this));
  985. }
  986. return results;
  987. break;
  988. // 當僅有指定事件名稱時。
  989. case this.$events[eventName] === void 0:
  990. // 清空該事件的所有事件監聽器。
  991. return delete this.$events[eventName];
  992. }
  993. }, this);
  994. });
  995. }
  996. };
  997. // Trigger
  998. // 觸發指定事件。
  999. ts.fn.trigger = {
  1000. value: function(events) {
  1001. var customArguments;
  1002. events = ts.helper.eventAlias(events);
  1003. customArguments = [].slice.call(arguments, 1);
  1004. return this.each(function() {
  1005. return events.split(' ').forEach((eventName) => {
  1006. var alias, event, name;
  1007. event = eventName.split('.');
  1008. name = event[0];
  1009. alias = event.length > 1 ? event[1] : null;
  1010. event = new CustomEvent(name, {
  1011. detail: {
  1012. args: customArguments,
  1013. alias: alias
  1014. }
  1015. });
  1016. return this.dispatchEvent(event);
  1017. });
  1018. });
  1019. }
  1020. };
  1021. // Emulate
  1022. // 在指定的秒數過後觸發指定事件,若已被觸發則不再次觸發。
  1023. // 這能用以強迫讓某個事件發生。
  1024. ts.fn.emulate = {
  1025. value: function(event, duration) {
  1026. return this.each(function() {
  1027. var called;
  1028. called = false;
  1029. ts(this).one(event, function() {
  1030. return called = true;
  1031. });
  1032. return setTimeout(() => {
  1033. if (!called) {
  1034. return ts(this).trigger(event);
  1035. }
  1036. }, duration);
  1037. });
  1038. }
  1039. };
  1040. // Text
  1041. // 變更或取得選擇器元素的內容文字。
  1042. ts.fn.text = {
  1043. value: function(text) {
  1044. var ref;
  1045. if (text !== void 0) {
  1046. return this.each(function() {
  1047. return this.innerText = text;
  1048. });
  1049. } else {
  1050. return (ref = this.get()) != null ? ref.innerText : void 0;
  1051. }
  1052. }
  1053. };
  1054. // Val
  1055. // 變更或取得選擇器元素的值。
  1056. ts.fn.val = {
  1057. value: function(value) {
  1058. var ref;
  1059. if (value !== void 0) {
  1060. return this.each(function() {
  1061. return this.value = value;
  1062. });
  1063. } else {
  1064. return (ref = this.get()) != null ? ref.value : void 0;
  1065. }
  1066. }
  1067. };
  1068. // HTML
  1069. // 變更或取得選擇器元素的 HTML。
  1070. ts.fn.html = {
  1071. value: function(html) {
  1072. var ref;
  1073. if (html !== void 0) {
  1074. return this.each(function() {
  1075. return this.innerHTML = html;
  1076. });
  1077. } else {
  1078. return (ref = this.get()) != null ? ref.innerHTML : void 0;
  1079. }
  1080. }
  1081. };
  1082. // Empty
  1083. // 將選擇器元素的內容清除,例如值或文字。
  1084. ts.fn.empty = {
  1085. value: function() {
  1086. return this.each(function() {
  1087. if (this.value !== void 0) {
  1088. this.value = null;
  1089. }
  1090. if (this.innerHTML !== void 0) {
  1091. this.innerHTML = null;
  1092. }
  1093. if (this.innerText !== void 0) {
  1094. return this.innerText = null;
  1095. }
  1096. });
  1097. }
  1098. };
  1099. // Prop
  1100. // 變更或取得選擇器元素的屬性,例如 `.src`、`.width`。
  1101. ts.fn.prop = {
  1102. value: function(name, value) {
  1103. var key, ref;
  1104. // 有 name 也有 value 就設置屬性。
  1105. if (typeof name === 'string' && value !== void 0) {
  1106. return this.each(function() {
  1107. return this[name] = value;
  1108. });
  1109. // 有 name 但沒有 value 就取得屬性。
  1110. } else if (typeof name === 'string' && value === void 0) {
  1111. return (ref = this.get()) != null ? ref[name] : void 0;
  1112. // 有 name 但他是 object,就設置多重屬性。
  1113. } else if (typeof name === 'object') {
  1114. for (key in name) {
  1115. this.each(function() {
  1116. return this[key] = name[key];
  1117. });
  1118. }
  1119. return this;
  1120. }
  1121. }
  1122. };
  1123. // Data
  1124. // 在選擇器元素中存放資料,類似 Attr 但頁面不可見。
  1125. ts.fn.data = {
  1126. value: function(name, value) {
  1127. var key, ref, ref1;
  1128. // 有 name 也有 value 就設置資料。
  1129. if (typeof name === 'string' && value !== void 0) {
  1130. return this.each(function() {
  1131. if (this.$data === void 0) {
  1132. this.$data = {};
  1133. }
  1134. return this.$data[name] = value;
  1135. });
  1136. // 有 name 但沒有 value 就取得資料。
  1137. } else if (typeof name === 'string' && value === void 0) {
  1138. return (ref = this.get()) != null ? (ref1 = ref.$data) != null ? ref1[name] : void 0 : void 0;
  1139. // 有 name 但他是 object,就設置多重樣式。
  1140. } else if (typeof name === 'object') {
  1141. for (key in name) {
  1142. this.each(function() {
  1143. if (this.$data === void 0) {
  1144. this.$data = {};
  1145. }
  1146. return this.$data[key] = name[key];
  1147. });
  1148. }
  1149. return this;
  1150. }
  1151. }
  1152. };
  1153. // Remove Data
  1154. // 移除指定的資料。
  1155. ts.fn.removeData = {
  1156. value: function(name) {
  1157. return this.each(function() {
  1158. if (this.$data[name] != null) {
  1159. return delete this.$data[name];
  1160. }
  1161. });
  1162. }
  1163. };
  1164. // Has Timer
  1165. // 確認是否有指定的計時器。
  1166. ts.fn.hasTimer = {
  1167. value: function(name) {
  1168. var ref, ref1;
  1169. return ((ref = this.get(0)) != null ? (ref1 = ref.$timers) != null ? ref1[name] : void 0 : void 0) != null;
  1170. }
  1171. };
  1172. // Get Timer
  1173. // 取得計時器內容。
  1174. ts.fn.getTimer = {
  1175. value: function(name) {
  1176. var ref, ref1;
  1177. return (ref = this.get(0)) != null ? (ref1 = ref.$timers) != null ? ref1[name] : void 0 : void 0;
  1178. }
  1179. };
  1180. // Set Timer
  1181. // 設置一個新的計時器。
  1182. ts.fn.setTimer = {
  1183. value: function(options) {
  1184. options = Object.assign({}, {
  1185. name: '',
  1186. callback: function() {},
  1187. interval: 0,
  1188. looping: false,
  1189. visible: false
  1190. }, options);
  1191. return this.each(function() {
  1192. var timer;
  1193. if (this.$timers === void 0) {
  1194. this.$timers = {};
  1195. }
  1196. if (this.$timers[options.name] !== void 0) {
  1197. clearInterval(this.$timers[options.name].timer);
  1198. }
  1199. timer = () => {
  1200. var ref;
  1201. // 當設置有說明,頁面不可見的時候就不要繼續計時。
  1202. if (options.visible && document.hidden) {
  1203. return;
  1204. }
  1205. // 替計時器加上 10 毫秒。
  1206. this.$timers[options.name].passed += 10;
  1207. // 如果計時器的經過時間還不到使用者設定的時間
  1208. // 就返回而不要繼續執行。
  1209. if (this.$timers[options.name].passed < options.interval) {
  1210. return;
  1211. }
  1212. // 呼叫回呼函式。
  1213. options.callback();
  1214. // 如果要循環的話,就在計時器執行後重設時間即可。
  1215. if (options.looping) {
  1216. return this.$timers[options.name].passed = 0;
  1217. } else {
  1218. // 不然就移除計時器資訊。
  1219. return clearInterval((ref = this.$timers[options.name]) != null ? ref.timer : void 0);
  1220. }
  1221. };
  1222. // 移除在 DOM 元素內的這個計時器物件。
  1223. //delete @$timers[options.name]
  1224. // 在此元素內初始化計時器物件。
  1225. return this.$timers[options.name] = {
  1226. timer: setInterval(timer, 10),
  1227. passed: 0,
  1228. callback: options.callback,
  1229. interval: options.interval,
  1230. looping: options.looping,
  1231. visible: options.visible,
  1232. initializer: timer,
  1233. paused: false
  1234. };
  1235. });
  1236. }
  1237. };
  1238. // Pause Timer
  1239. // 暫停一個計時器。
  1240. ts.fn.pauseTimer = {
  1241. value: function(name) {
  1242. return this.each(function() {
  1243. var ref;
  1244. if (((ref = this.$timers) != null ? ref[name] : void 0) == null) {
  1245. return;
  1246. }
  1247. // 清除計數計時器達到暫停效果。
  1248. clearInterval(this.$timers[name].timer);
  1249. // 表示暫停。
  1250. return this.$timers[name].paused = true;
  1251. });
  1252. }
  1253. };
  1254. // Play Timer
  1255. // 重啟一個計時器。
  1256. ts.fn.playTimer = {
  1257. value: function(name) {
  1258. return this.each(function() {
  1259. var ref;
  1260. if (((ref = this.$timers) != null ? ref[name] : void 0) == null) {
  1261. return;
  1262. }
  1263. if (!this.$timers[name].paused) {
  1264. return;
  1265. }
  1266. // 重新初始化計數計時器來達到繼續的效果。
  1267. this.$timers[name].timer = setInterval(this.$timers[name].initializer, 10);
  1268. // 表示重新啟動。
  1269. return this.$timers[name].paused = false;
  1270. });
  1271. }
  1272. };
  1273. // Remove Timer
  1274. // 移除一個計時器。
  1275. ts.fn.removeTimer = {
  1276. value: function(name) {
  1277. return this.each(function() {
  1278. var ref;
  1279. if (((ref = this.$timers) != null ? ref[name] : void 0) == null) {
  1280. return;
  1281. }
  1282. // 清除計數計時器。
  1283. clearInterval(this.$timers[name].timer);
  1284. // 移除在 DOM 元素內的計時器物件。
  1285. return delete this.$timers[name];
  1286. });
  1287. }
  1288. };
  1289. // Repaint
  1290. // 讓瀏覽器重繪元素。
  1291. ts.fn.repaint = {
  1292. value: function() {
  1293. return this.each(function() {
  1294. return void(this.offsetHeight);
  1295. });
  1296. }
  1297. };
  1298. }).call(this);