// Generated by CoffeeScript 2.3.1
(function() {
// 主要的選擇器函式。
var ts;
ts = function(selector, context) {
var nodes, ref, tag;
nodes = [];
// 如果選擇器是文字,但是是標籤(如:`
`)就建立新的元素
if (typeof selector === 'string' && selector[0] === '<') {
tag = selector.match(/<(.*)\/>|<(.*)>/);
nodes = [document.createElement((ref = tag[1]) != null ? ref : tag[2])];
// 如果選擇器是一般的文字,就選取元素。
} else if (typeof selector === 'string' && context === void 0) {
document.querySelectorAll(selector).forEach(function(element) {
return nodes.push(element);
});
// 如果選擇器有上下文選擇器,就透過選擇器找出上下文元素。
} else if (typeof context === 'string') {
nodes = ts(selector).find(context).toArray();
// 如果選擇器是 NodeList 就轉換成元素陣列然後取出來接著繼續。
} else if (selector instanceof NodeList) {
selector.forEach(function(element) {
return nodes.push(element);
});
// 如果選擇器是陣列,就當作是元素陣列,取出來然後繼續。
// 或傳入的是一個選擇器,就取出裡面的元素然後繼續。
} else if (Array.isArray(selector) || (selector != null ? selector.isSelector : void 0) === true) {
nodes = nodes.concat(selector);
selector = selector.selector;
context = selector != null ? selector.context : void 0;
// 如果是單個 DOM 元素,就放入選擇器然後繼續。
} else if (selector instanceof HTMLElement || selector instanceof HTMLDocument || selector instanceof HTMLBodyElement || selector === window) {
nodes = [selector];
}
// 保存目前的選擇器文字與上下文選擇器文字。
nodes.selector = typeof selector === 'string' ? selector : null;
nodes.context = typeof context === 'string' ? context : null;
// 將自訂的選擇器方法插入到節點陣列中,這樣才能夠串連使用。
Object.defineProperties(nodes, ts.fn);
// 將節點陣列標註為是選擇器,這樣才能判斷傳入的是不是我們自己的選擇器。
Object.defineProperty(nodes, 'isSelector', {
value: true
});
return nodes;
};
// 註冊到視窗上。
window.ts = ts;
// 函式鏈。
ts.fn = {};
// 輔助函式。
ts.helper = {};
// 事件輔助函式。
ts.helper.eventAlias = function(event) {
var alias, pair;
pair = event.split('.');
alias = pair[1] !== void 0 ? `.${pair[1]}` : '';
switch (false) {
case pair.indexOf('animationend') === -1:
return `webkitAnimationEnd${alias} mozAnimationEnd${alias} MSAnimationEnd${alias} oanimationend${alias} animationend${alias}`;
case pair.indexOf('transitionend') === -1:
return `webkitTransitionEnd${alias} mozTransitionEnd${alias} oTransitionEnd${alias} msTransitionEnd${alias} transitionend${alias}`;
default:
return event;
}
};
// 是否為物件。
ts.isPlainObject = function(object) {
return Object.prototype.toString.call(object) === '[object Object]';
};
// 是否為可觸控裝置。
ts.isTouchDevice = function() {
return 'ontouchstart' in window || navigator.maxTouchPoints;
};
// 取得裝置資料。
ts.device = () => {
var device;
switch (false) {
case !(window.innerWidth < 767):
device = 'mobile';
break;
case !(window.innerWidth > 767 && window.innerWidth < 991):
device = 'tablet';
break;
case !(window.innerWidth > 991 && window.innerWidth < 1199):
device = 'computer';
break;
case !(window.innerWidth > 1199 && window.innerWidth < 1919):
device = 'large';
}
return {
device: device
};
};
// 從指定坐標取得元素。
ts.fromPoint = (x, y) => {
return ts(document.elementFromPoint(x, y));
};
// 延展物件的函式,與 ES 的 `...` 不同之處在於 extend 並不會替換掉整個子物件,而會以補插的方式執行。
// https://gomakethings.com/vanilla-javascript-version-of-jquery-extend/
ts.extend = function() {
var deep, extended, i, length, merge, obj;
extended = {};
deep = true;
i = 0;
length = arguments.length;
if (Object.prototype.toString.call(arguments[0]) === '[object Boolean]') {
deep = arguments[0];
i++;
}
merge = function(obj) {
var prop;
for (prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') {
extended[prop] = ts.extend(true, extended[prop], obj[prop]);
} else {
extended[prop] = obj[prop];
}
}
}
};
while (i < length) {
obj = arguments[i];
merge(obj);
i++;
}
return extended;
};
// 建立元素
ts.createElement = (html) => {
var div;
div = document.createElement('div');
div.innerHTML = html.trim();
return div.firstChild;
};
// 註冊 Tocas 模塊
ts.register = (module) => {
var name;
name = module.name.toLowerCase();
return ts.fn[name] = {
value: function() {
var $allModules, consoleText, errorHeaderCSS, headerCSS, messageCSS, methodInvoked, moduleNamespace, query, queryArguments, returnedValue;
$allModules = ts(this);
moduleNamespace = `module-${name}`;
query = arguments[0];
queryArguments = Array.prototype.slice.call(arguments, 1);
methodInvoked = typeof query === 'string';
returnedValue = void 0;
consoleText = (args) => {
return `%c${name}%c ${args[0]}`;
};
headerCSS = "background : #EEE;\ncolor : #5A5A5A;\nfont-size : 1em;\npadding : 8px 8px;\nline-height : 5px;\nmargin : 5px 0 5px 0;\nborder-radius: 1000em;";
errorHeaderCSS = `${headerCSS}\nbackground: #CE5F58;\ncolor: #FFF;`;
messageCSS = "font-weight: bold;";
$allModules.each(function(_, index) {
var $module, applyEventNamespace, debug, destroy, element, error, eventNamespace, id, initialize, instance, instantiate, invoke, listener, observeChanges, settings;
element = this;
$module = ts(element);
id = $module.uniqueID();
instance = $module.data(moduleNamespace);
eventNamespace = `.${name}-${id}`;
settings = ts.extend(module.prototype.settings, {
// 消音所有提示,甚至是錯誤訊息。
silent: false,
// 顯示除錯訊息。
debug: true,
// 監聽 DOM 結構異動並自動重整快取。
observeChanges: true
});
settings = ts.isPlainObject(query) ? ts.extend(settings, query) : ts.extend(settings);
applyEventNamespace = (events = '') => {
var newEvents;
newEvents = '';
events.split(' ').forEach((event) => {
return newEvents += `${event}${eventNamespace}`;
});
return newEvents;
};
listener = {
on: function() {
var callback, handlerIndex, newArguments;
newArguments = arguments;
newArguments[0] = applyEventNamespace(newArguments[0]);
newArguments = Array.from(newArguments);
handlerIndex = -1;
newArguments.forEach((el, index) => {
if (typeof el === 'function') {
return handlerIndex = index;
}
});
callback = newArguments[handlerIndex];
newArguments[handlerIndex] = function() {
var args, event, self;
event = arguments[0];
args = Array.prototype.slice.call(arguments, 1);
self = this;
return callback.call(self, self, event, ...args);
};
return $module.on.apply($module, newArguments);
},
off: function() {
var newArguments;
newArguments = arguments;
newArguments[0] = applyEventNamespace(newArguments[0]);
return $module.off.apply($module, newArguments);
},
one: function() {},
//newArguments = arguments
//newArguments[0] = applyEventNamespace newArguments[0]
//$module.one.apply $module, newArguments
trigger: function(callbackName, context) {
callbackName = callbackName[0].toUpperCase() + callbackName.slice(1);
return settings[`on${callbackName}`].apply(context, ...Array.prototype.slice.call(arguments, 2));
}
};
debug = function() {
if (!settings.debug || settings.silent) {
return;
}
return console.info.call(console, consoleText(arguments), headerCSS, messageCSS, "\n", element, ...Array.prototype.slice.call(arguments).slice(1));
};
error = function() {
if (settings.silent) {
return;
}
error = Function.prototype.bind.call(console.error, console, consoleText(arguments), errorHeaderCSS, messageCSS);
return error.apply(console, Array.prototype.slice.call(arguments, 1));
};
instantiate = () => {
debug('instantiate');
module.prototype.beforeCreate();
instance = new module({settings, $allModules, $module, element, listener, id});
$module.data(moduleNamespace, instance);
return instance.created();
};
observeChanges = () => {
var observer;
if (!'MutationObserver' in window) {
return;
}
observer = new MutationObserver((mutations) => {
return instance.updated();
});
return observer.observe(element, {
childList: true,
subtree: true
});
};
initialize = (module) => {
debug('initialize');
if (settings.observeChanges) {
observeChanges();
}
return instantiate();
};
destroy = () => {
debug('destroy');
instance.beforeDestroy();
$module.off().removeData(moduleNamespace);
return instance.destroyed(...queryArguments);
};
invoke = (query, passedArguments, context) => {
var camelCaseQuery;
camelCaseQuery = '';
query.split(' ').forEach((word) => {
return camelCaseQuery += word[0].toUpperCase() + word.slice(1);
});
if (camelCaseQuery === 'Destroy') {
destroy();
return void 0;
}
if (camelCaseQuery === 'Setting') {
if (ts.isPlainObject(queryArguments[0])) {
settings = ts.extend(settings, queryArguments[0]);
instance.settings = settings;
return void 0;
} else {
return instance.settings[queryArguments[0]];
}
}
if (instance[camelCaseQuery] === void 0) {
error('欲呼叫的方法並不存在', query);
return void 0;
}
return instance[camelCaseQuery].apply(context, passedArguments);
};
if (methodInvoked) {
if (instance === void 0) {
initialize();
}
return returnedValue = invoke(query, queryArguments, instance);
} else {
if (instance !== void 0) {
destroy();
}
return initialize();
}
});
if (returnedValue === void 0 || returnedValue instanceof module) {
return $allModules;
}
return returnedValue;
}
};
};
// Get
// 取得選擇器內的指定元素,並且回傳一個 DOM 元素而非選擇器。
ts.fn.get = {
value: function(index = 0) {
return this[index];
}
};
// ToArray
// 將選擇器轉換成帶有節點的一般陣列。
ts.fn.toArray = {
value: function() {
var array;
array = [];
this.forEach(function(element) {
return array.push(element);
});
return array;
}
};
// Each
// 遍歷整個選擇器陣列。
ts.fn.each = {
value: function(callback) {
this.forEach(function(element, index) {
return callback.call(element, element, index);
});
return this;
}
};
// CollectSwap
// 將收集到的元素替換掉目前選擇器內的所有元素。
ts.fn.collectSwap = {
value: function(callback) {
var collection, newSelector;
collection = [];
this.each(function(element, index) {
var result;
result = callback.call(element, element, index);
if (result === void 0 || result === null) {
return;
}
if (result instanceof NodeList) {
return result.forEach(function(el) {
return collection.push(el);
});
} else if (Array.isArray(result)) {
return collection = collection.concat(result);
} else {
if (collection.indexOf(result) === -1) {
return collection.push(result);
}
}
});
// 透過 Set 型態移除重複的節點。
collection = new Set(collection);
// 然後將 Set 轉換成陣列,建立新的選擇器。
newSelector = ts([...collection]);
// 保存選擇器之前的所有節點。
Object.defineProperty(newSelector, 'prevObject', {
value: this
});
// 回傳這個新的選擇器。
return newSelector;
}
};
// Eq
// 取得選擇器的指定元素,然後繼續回傳僅帶有該元素的選擇器。
ts.fn.eq = {
value: function(index) {
return ts(this.get(index));
}
};
// Parent
// 回傳元素的父元素選擇器。
ts.fn.parent = {
value: function() {
return this.collectSwap(function() {
return this.parentNode;
});
}
};
// Parents
// 回傳元素的所有父元素直至指定父元素。
ts.fn.parents = {
value: function(selector) {
return this.collectSwap(function(self) {
var matchedSelector, parents;
parents = [];
matchedSelector = false;
while (self) {
self = self.parentNode;
if (self.nodeType === 9) {
break;
}
parents.push(self);
if (ts(self).is(selector)) {
matchedSelector = true;
break;
}
}
if (selector && !matchedSelector) {
return [];
}
return parents;
});
}
};
// Closest
// 回傳最接近指定的父元素選擇器。
ts.fn.closest = {
value: function(selector) {
return this.collectSwap(function() {
return this.closest(selector);
});
}
};
// Find
// 在目前元素中搜尋指定元素並回傳其選擇器。
ts.fn.find = {
value: function(selector) {
return this.collectSwap(function() {
return this.querySelectorAll(selector);
});
}
};
// Insert Before
// 將選擇器元素安插在指定元素前。
ts.fn.insertBefore = {
value: function(target) {
return this.each(function() {
return ts(target).each((element) => {
return element.parentNode.insertBefore(this, element);
});
});
}
};
// Insert After
// 將選擇器元素安插在指定元素後。
ts.fn.insertAfter = {
value: function(target) {
return this.each(function() {
return ts(target).each((element) => {
return element.parentNode.insertBefore(this, element.nextSibling);
});
});
}
};
// Wrap
// 將元素用指定元素包覆起來。
ts.fn.wrap = {
value: function(element) {
return this.each(function() {
if (this.nextSibling) {
this.parentNode.insertBefore(element, this.nextSibling);
} else {
this.parentNode.appendChild(element);
}
return element.appendChild(this);
});
}
};
// Clone
// 複製元素。
ts.fn.clone = {
value: function() {
return this.collectSwap(function() {
return this.cloneNode(true);
});
}
};
// Append
// 將元素插入在目前選擇器元素的內部最後面。
ts.fn.append = {
value: function(element) {
var shouldClone;
shouldClone = this.length !== 1;
if (element.isSelector !== void 0) {
return this.each(function() {
return element.each((e) => {
return this.appendChild(shouldClone ? e.cloneNode(true) : e);
});
});
} else if (typeof element === 'string') {
return this.each(function() {
return this.insertAdjacentHTML('beforeend', element);
});
} else {
return this.each(function() {
return this.appendChild(shouldClone ? element.cloneNode(true) : element);
});
}
}
};
// AppendTo
// 將目前選擇器元素插入到指定元素的內部最後面。
ts.fn.appendTo = {
value: function(selector) {
return this.each(function() {
return ts(selector).append(this);
});
}
};
// Prepend
// 將元素插入在目前選擇器元素的內部最前面。
ts.fn.prepend = {
value: function(element) {
var shouldClone;
shouldClone = this.length !== 1;
if (element.isSelector !== void 0) {
return this.each(function() {
return element.each((e) => {
return this.prepend(shouldClone ? e.cloneNode(true) : e);
});
});
} else if (typeof element === 'string') {
return this.each(function() {
return this.insertAdjacentHTML('afterbegin', element);
});
} else {
return this.each(function() {
return this.prepend(shouldClone ? element.cloneNode(true) : element);
});
}
}
};
// PrependTo
// 將目前選擇器元素插入到指定元素的內部最前面。
ts.fn.prependTo = {
value: function(selector) {
return this.each(function() {
return ts(selector).prepend(this);
});
}
};
// Remove
// 將選擇器元素從頁面上中移除。
ts.fn.remove = {
value: function() {
return this.each(function() {
var ref;
return (ref = this.parentNode) != null ? ref.removeChild(this) : void 0;
});
}
};
// Is
// 選擇一些元素,然後用來比對目前的選擇器元素是否在這群當中。
ts.fn.is = {
value: function(selector) {
var isInElements, ref;
isInElements = false;
if (selector instanceof HTMLElement) {
return (ref = this.get(0)) != null ? ref.isSameNode(selector) : void 0;
}
this.each(function() {
return ts(selector).each((compareElement) => {
if (this === compareElement) {
return isInElements = true;
}
});
});
return isInElements;
}
};
// Contains
// 是否擁有指定子元素。
ts.fn.contains = {
value: function(selector) {
var ref;
return (ref = this.get(0)) != null ? ref.contains(ts(selector).get()) : void 0;
}
};
// Exists
// 是否存在。
ts.fn.exists = {
value: function() {
return this.length !== 0;
}
};
// Not
// 將指定元素從選擇器中剔除。
ts.fn.not = {
value: function(selector) {
return ts(this.toArray().filter((element) => {
return ts(selector).indexOf(element) === -1;
}));
}
};
// Filter
// 將指定元素從選擇器中保留,簡單說就是 `Not` 的相反。
ts.fn.filter = {
value: function(selector) {
return ts(this.toArray().filter((element) => {
return ts(selector).indexOf(element) !== -1;
}));
}
};
// Slice
// 替元素陣列進行切分。
ts.fn.slice = {
value: function(from, to) {
return ts(this.toArray().slice(from, to));
}
};
// Children
// 取得容器裡的第一層子節點。
ts.fn.children = {
value: function(selector) {
return this.collectSwap(function() {
return this.querySelectorAll(selector != null ? `:scope > ${selector}` : ':scope > *');
});
}
};
// Replace With
// 將元素替換為指定選擇器元素。
ts.fn.replaceWith = {
value: function(selector) {
var element;
element = ts(selector).get();
return this.each(function() {
return this.replaceWith(element);
});
}
};
// Last
// 選擇器中的最後一個元素。
ts.fn.last = {
value: function() {
return this.eq(this.length - 1);
}
};
// Next
// 下一個元素。
ts.fn.next = {
value: function() {
return this.collectSwap(function() {
return this.nextElementSibling;
});
}
};
// Prev
// 上一個元素。
ts.fn.prev = {
value: function() {
return this.collectSwap(function() {
return this.previousElementSibling;
});
}
};
// NextAll
// 這個元素之後的所有同階層元素。
ts.fn.nextAll = {
value: function(selector) {
return this.collectSwap(function() {
var $children, $parent, $self, index;
$self = ts(this);
$parent = $self.parent();
$children = selector != null ? $parent.find(`:scope > ${selector}`) : $parent.find(':scope > *');
index = $self.index();
return $children.slice(index + 1);
});
}
};
// PrevAll
// 這個元素之前的所有同階層元素。
ts.fn.prevAll = {
value: function(selector) {
return this.collectSwap(function() {
var $children, $parent, $self, index;
$self = ts(this);
$parent = $self.parent();
$children = selector != null ? $parent.find(`:scope > ${selector}`) : $parent.find(':scope > *');
index = $self.index();
return $children.slice(0, index);
});
}
};
// AddBack
// 在目前的選擇器節點陣列中加上先前選擇的所有節點。
ts.fn.addBack = {
value: function() {
if (this.prevObject) {
this.prevObject.toArray().forEach((element) => {
return this.push(element);
});
}
return this;
}
};
// Index
// 該元素在容器內的索引。
ts.fn.index = {
value: function() {
var index, node;
node = this.get(0);
index = 0;
if (node == null) {
return -1;
}
while ((node = node.previousElementSibling)) {
index++;
}
return index;
}
};
// Attr
// 取得或是建立新的標籤到目前的選擇器元素。
ts.fn.attr = {
value: function(name, value) {
var ref;
// 如果有 value 就設置簡單鍵值資料。
if (value !== void 0) {
return this.each(function() {
return this.setAttribute(name, value);
});
// 如果傳入的是物件就設置多重資料。
} else if (typeof name === 'object') {
return this.each(function() {
var key, results;
results = [];
for (key in name) {
results.push(this.setAttribute(key, name[key]));
}
return results;
});
} else {
// 不然就取得資料。
return (ref = this.get()) != null ? ref.getAttribute(name) : void 0;
}
}
};
// RemoveAttr
// 移除目前選擇器元素的指定標籤。
ts.fn.removeAttr = {
value: function(name) {
return this.each(function() {
return this.removeAttribute(name);
});
}
};
// AddClass
// 在目前選擇器元素插入新的樣式類別名稱。
ts.fn.addClass = {
value: function(names) {
var name, newNames;
if (typeof names === 'object') {
newNames = '';
for (name in names) {
if (names[name] === true) {
newNames += ` ${name}`;
}
}
names = newNames;
} else {
names = Array.prototype.slice.call(arguments).join(' ');
}
return this.each(function() {
return DOMTokenList.prototype.add.apply(this.classList, names.split(' ').filter(Boolean));
});
}
};
// RemoveClass
// 移除目前選擇器元素的指定樣式類別。
ts.fn.removeClass = {
value: function(names) {
var name, newNames;
if (typeof names === 'object') {
newNames = '';
for (name in names) {
if (names[name] === true) {
newNames += ` ${name}`;
}
}
names = newNames;
} else {
names = Array.prototype.slice.call(arguments).join(' ');
}
return this.each(function() {
return DOMTokenList.prototype.remove.apply(this.classList, names.split(' ').filter(Boolean));
});
}
};
// ToggleClass
// 切換目前選擇器元素的樣式。
ts.fn.toggleClass = {
value: function(names) {
return this.each(function() {
return names.split(' ').forEach(function(name) {
return this.classList.toggle(name);
}, this);
});
}
};
// HasClass
// 回傳選擇器元素是否帶有指定樣式類別,是布林值。
ts.fn.hasClass = {
value: function(name) {
var ref;
return (ref = this.get(0)) != null ? ref.classList.contains(name) : void 0;
}
};
// CSS
// 將選擇器元素套用指定的 CSS 樣式。
ts.fn.css = {
value: function(name, value) {
var key;
// 有 name 也有 value 就設置樣式。
if (typeof name === 'string' && value !== void 0) {
return this.each(function() {
return this.style[name] = value;
});
// 有 name 但沒有 value 就取得樣式。
} else if (typeof name === 'string' && value === void 0) {
if (this.get() != null) {
return document.defaultView.getComputedStyle(this.get(), null).getPropertyValue(name);
} else {
return null;
}
// 有 name 但他是 object,就設置多重樣式。
} else if (typeof name === 'object') {
for (key in name) {
this.each(function() {
return this.style[key] = name[key];
});
}
return this;
}
}
};
// Rect
// 回傳選擇器元素的渲染形狀。
ts.fn.rect = {
value: function() {
var r, ref;
r = (ref = this.get(0)) != null ? ref.getBoundingClientRect() : void 0;
return {
top: r.top,
right: r.right,
bottom: r.bottom,
left: r.left,
width: r.width,
height: r.height,
x: r.x,
y: r.y
};
}
};
// On
// 綁定並註冊一個事件監聽器。
ts.fn.on = {
value: function() {
var data, events, handler, options, selector;
switch (arguments.length) {
// Event 與 Handler。
case 2:
events = arguments[0];
handler = arguments[1];
break;
// Event 與 Selector 與 Handler。
// Event 與 Data 與 Handler。
// Event 與 Handler 與 Options。
case 3:
events = arguments[0];
handler = arguments[2];
switch (typeof arguments[1]) {
case "string":
selector = arguments[1];
break;
case "function":
handler = arguments[1];
options = arguments[2];
break;
default:
data = arguments[1];
}
break;
// Event 與 Selector 與 Data 與 Handler。
// Event 與 Selector 與 Handler 與 Options。
case 4:
events = arguments[0];
selector = arguments[1];
handler = arguments[3];
switch (typeof arguments[2]) {
case "function":
handler = arguments[2];
options = arguments[3];
break;
default:
data = arguments[2];
}
break;
// Event 與 Selector 與 Data 與 Handler 與 Options。
case 5:
events = arguments[0];
selector = arguments[1];
data = arguments[2];
handler = arguments[3];
options = arguments[4];
}
events = ts.helper.eventAlias(events);
// $events.click =
// {
// anonymous: [
// {
// once : true,
// selector: ".button",
// data : {},
// func : func()
// }
// ]
// alias1: [
// {
// once : true,
// selector: ".button",
// data : {},
// func : func()
// }
// ]
// }
return this.each(function() {
if (events[0] === '(' && events[events.length - 1] === ')') {
if (this !== window) {
return;
}
if (window.$media === void 0) {
window.$media = {};
}
if (window.$media[events] === void 0) {
window.$media[events] = [];
window.matchMedia(events).addListener(function(mq) {
var j, len, ref, results, single;
ref = window.$media[events];
results = [];
for (j = 0, len = ref.length; j < len; j++) {
single = ref[j];
results.push(single.func.call(this, mq));
}
return results;
});
}
window.$media[events].push({
data: {},
func: handler
});
return;
}
if (this.addEventListener === void 0) {
return;
}
if (this.$events === void 0) {
this.$events = {};
}
return events.split(' ').forEach(function(eventName) {
var event, eventAlias, hasAlias;
event = eventName.split('.');
// 透過事件的「event.alias」取得「點」後面的別名。
hasAlias = event.length > 1;
eventName = event[0];
eventAlias = hasAlias ? event[1] : null;
// 如果事件還沒在這個物件內產生過,就初始化一個事件結構。
if (this.$events[eventName] === void 0) {
this.$events[eventName] = {
anonymous: []
};
// 然後建立一個管理多個事件的事件管理處理程式。
this.addEventListener(eventName, function(event) {
var alias, calledAlias, closest, context, hasArgs, index, ref, ref1, ref2, results, single;
// 是否有自訂參數。
hasArgs = ((ref = event.detail) != null ? (ref1 = ref.args) != null ? ref1.length : void 0 : void 0) > 0;
// 是否有呼叫事件別名。
calledAlias = (ref2 = event.detail) != null ? ref2.alias : void 0;
// 如果該事件已經被移除則停止後續的反應。
if (this.$events[eventName] === void 0) {
return;
}
// 將被觸發的事件裡面的所有處理程式全部呼叫一次。
results = [];
for (alias in this.$events[eventName]) {
if (calledAlias && calledAlias !== alias) {
continue;
}
index = this.$events[eventName][alias].length;
results.push((function() {
var results1;
results1 = [];
while (index--) {
if (this.$events[eventName] === void 0) {
continue;
}
if (this.$events[eventName][alias] === void 0) {
continue;
}
single = this.$events[eventName][alias][index];
// 設置事件的上下文。
context = this;
// 如果這個事件有選擇器的話,則使用該選擇器為主。
if (single.selector !== void 0) {
selector = single.selector;
closest = ts(event.target).closest(selector);
// 如果找不到指定選擇棄的元素,就不要觸發此事件。
if (closest.length === 0) {
continue;
} else {
// 替換上下文為選擇器元素。
context = closest.get();
}
}
// 將事件預資料放入事件中供處理函式取得。
event.data = single.data;
if (hasArgs) {
single.func.call(context, event, ...event.detail.args);
} else {
single.func.call(context, event);
}
// 如果這個程式只能被呼叫一次就在處理程式呼叫後移除。
if (single.once === true) {
results1.push(this.$events[eventName][alias].splice(index, 1));
} else {
results1.push(void 0);
}
}
return results1;
}).call(this));
}
return results;
});
}
// 將新的事件處理程式註冊到事件清單中。
// 如果有別名,就不要推送到匿名陣列中,我們替這個別名另開物件。
if (hasAlias) {
if (this.$events[eventName][eventAlias] === void 0) {
this.$events[eventName][eventAlias] = [];
}
return this.$events[eventName][eventAlias].push({
func: handler,
selector: selector,
data: data,
once: options != null ? options.once : void 0
});
} else {
// 如果沒有,就照常推進匿名陣列中。
return this.$events[eventName].anonymous.push({
func: handler,
selector: selector,
data: data,
once: options != null ? options.once : void 0
});
}
}, this);
});
}
};
// One
// 綁定一次性的事件監聽器,當被觸發之後就會被移除。
ts.fn.one = {
value: function(events, handler) {
events = ts.helper.eventAlias(events);
return this.each(function() {
return ts(this).on(events, handler, {
once: true
});
});
}
};
// Off
// 註銷事件監聽器。
ts.fn.off = {
value: function(events, handler) {
if (events !== void 0) {
events = ts.helper.eventAlias(events);
}
return this.each(function() {
if ((events != null ? events[0] : void 0) === '(' && events[events.length - 1] === ')') {
if (this !== window) {
return;
}
if (window.$media === void 0) {
return;
}
if (window.$media[events] === void 0) {
return;
}
switch (false) {
case handler === void 0:
window.$media[events].forEach((item, index) => {
if (handler === item.func) {
return window.$media[events].splice(index, 1);
}
});
break;
case handler !== void 0:
window.$media[events] = [];
}
return;
}
if (this.$events === void 0) {
return;
}
if (events === void 0) {
this.$events = {};
return;
}
return events.split(' ').forEach((eventName) => {
var alias, aliasName, event, hasAlias, isAlias, results;
// 將事件名稱由中間的「.」切成兩半。
event = eventName.split('.');
// 如果事件開頭是「.」符號,表示這是個別名,不是事件名稱。
isAlias = eventName[0] === '.';
// 如果事件分切後有兩個項目,表示這個事件有別名。
hasAlias = event.length === 2 && event[0] !== '';
if (hasAlias || isAlias) {
// 如果有別名的話,取得別名。
aliasName = event[1];
}
// 如果此事件不是只有別名的話,取得事件名稱。
eventName = !isAlias ? event[0] : void 0;
switch (false) {
// 當有指定監聽函式時。
case !(handler !== void 0 && this.$events[eventName] !== void 0):
return this.$events[eventName].anonymous.forEach((item, index) => {
if (handler === item.func) {
return this.$events[eventName].anonymous.splice(index, 1);
}
});
// 當本事件名稱不僅是別名時。
case !(!isAlias && hasAlias && this.$events[eventName] !== void 0):
// 移除指定事件的別名監聽函式。
return delete this.$events[eventName][aliasName];
// 當僅有指定別名時。
case !(isAlias && !hasAlias):
// 移除所有與此別名有關的事件監聽器。
results = [];
for (event in this.$events) {
results.push((function() {
var results1;
results1 = [];
for (alias in this.$events[event]) {
if (aliasName === alias) {
results1.push(delete this.$events[event][aliasName]);
} else {
results1.push(void 0);
}
}
return results1;
}).call(this));
}
return results;
break;
// 當僅有指定事件名稱時。
case this.$events[eventName] === void 0:
// 清空該事件的所有事件監聽器。
return delete this.$events[eventName];
}
}, this);
});
}
};
// Trigger
// 觸發指定事件。
ts.fn.trigger = {
value: function(events) {
var customArguments;
events = ts.helper.eventAlias(events);
customArguments = [].slice.call(arguments, 1);
return this.each(function() {
return events.split(' ').forEach((eventName) => {
var alias, event, name;
event = eventName.split('.');
name = event[0];
alias = event.length > 1 ? event[1] : null;
event = new CustomEvent(name, {
detail: {
args: customArguments,
alias: alias
}
});
return this.dispatchEvent(event);
});
});
}
};
// Emulate
// 在指定的秒數過後觸發指定事件,若已被觸發則不再次觸發。
// 這能用以強迫讓某個事件發生。
ts.fn.emulate = {
value: function(event, duration) {
return this.each(function() {
var called;
called = false;
ts(this).one(event, function() {
return called = true;
});
return setTimeout(() => {
if (!called) {
return ts(this).trigger(event);
}
}, duration);
});
}
};
// Text
// 變更或取得選擇器元素的內容文字。
ts.fn.text = {
value: function(text) {
var ref;
if (text !== void 0) {
return this.each(function() {
return this.innerText = text;
});
} else {
return (ref = this.get()) != null ? ref.innerText : void 0;
}
}
};
// Val
// 變更或取得選擇器元素的值。
ts.fn.val = {
value: function(value) {
var ref;
if (value !== void 0) {
return this.each(function() {
return this.value = value;
});
} else {
return (ref = this.get()) != null ? ref.value : void 0;
}
}
};
// HTML
// 變更或取得選擇器元素的 HTML。
ts.fn.html = {
value: function(html) {
var ref;
if (html !== void 0) {
return this.each(function() {
return this.innerHTML = html;
});
} else {
return (ref = this.get()) != null ? ref.innerHTML : void 0;
}
}
};
// Empty
// 將選擇器元素的內容清除,例如值或文字。
ts.fn.empty = {
value: function() {
return this.each(function() {
if (this.value !== void 0) {
this.value = null;
}
if (this.innerHTML !== void 0) {
this.innerHTML = null;
}
if (this.innerText !== void 0) {
return this.innerText = null;
}
});
}
};
// Prop
// 變更或取得選擇器元素的屬性,例如 `.src`、`.width`。
ts.fn.prop = {
value: function(name, value) {
var key, ref;
// 有 name 也有 value 就設置屬性。
if (typeof name === 'string' && value !== void 0) {
return this.each(function() {
return this[name] = value;
});
// 有 name 但沒有 value 就取得屬性。
} else if (typeof name === 'string' && value === void 0) {
return (ref = this.get()) != null ? ref[name] : void 0;
// 有 name 但他是 object,就設置多重屬性。
} else if (typeof name === 'object') {
for (key in name) {
this.each(function() {
return this[key] = name[key];
});
}
return this;
}
}
};
// Data
// 在選擇器元素中存放資料,類似 Attr 但頁面不可見。
ts.fn.data = {
value: function(name, value) {
var key, ref, ref1;
// 有 name 也有 value 就設置資料。
if (typeof name === 'string' && value !== void 0) {
return this.each(function() {
if (this.$data === void 0) {
this.$data = {};
}
return this.$data[name] = value;
});
// 有 name 但沒有 value 就取得資料。
} else if (typeof name === 'string' && value === void 0) {
return (ref = this.get()) != null ? (ref1 = ref.$data) != null ? ref1[name] : void 0 : void 0;
// 有 name 但他是 object,就設置多重樣式。
} else if (typeof name === 'object') {
for (key in name) {
this.each(function() {
if (this.$data === void 0) {
this.$data = {};
}
return this.$data[key] = name[key];
});
}
return this;
}
}
};
// Remove Data
// 移除指定的資料。
ts.fn.removeData = {
value: function(name) {
return this.each(function() {
if (this.$data[name] != null) {
return delete this.$data[name];
}
});
}
};
// Has Timer
// 確認是否有指定的計時器。
ts.fn.hasTimer = {
value: function(name) {
var ref, ref1;
return ((ref = this.get(0)) != null ? (ref1 = ref.$timers) != null ? ref1[name] : void 0 : void 0) != null;
}
};
// Get Timer
// 取得計時器內容。
ts.fn.getTimer = {
value: function(name) {
var ref, ref1;
return (ref = this.get(0)) != null ? (ref1 = ref.$timers) != null ? ref1[name] : void 0 : void 0;
}
};
// Set Timer
// 設置一個新的計時器。
ts.fn.setTimer = {
value: function(options) {
return setTimeout(() => {
options = {...{
name: '',
callback: function() {},
interval: 0,
looping: false,
visible: false
}, ...options};
return this.each(function() {
var timer;
if (this.$timers === void 0) {
this.$timers = {};
}
if (this.$timers[options.name] !== void 0) {
clearInterval(this.$timers[options.name].timer);
}
timer = () => {
var ref;
// 當設置有說明,頁面不可見的時候就不要繼續計時。
if (options.visible && document.hidden) {
return;
}
// 替計時器加上 10 毫秒。
this.$timers[options.name].passed += 10;
// 如果計時器的經過時間還不到使用者設定的時間
// 就返回而不要繼續執行。
if (this.$timers[options.name].passed < options.interval) {
return;
}
// 呼叫回呼函式。
options.callback();
// 如果要循環的話,就在計時器執行後重設時間即可。
if (options.looping) {
return this.$timers[options.name].passed = 0;
} else {
// 不然就移除計時器資訊。
return clearInterval((ref = this.$timers[options.name]) != null ? ref.timer : void 0);
}
};
// 移除在 DOM 元素內的這個計時器物件。
//delete @$timers[options.name]
// 在此元素內初始化計時器物件。
return this.$timers[options.name] = {
timer: setInterval(timer, 10),
passed: 0,
callback: options.callback,
interval: options.interval,
looping: options.looping,
visible: options.visible,
initializer: timer,
paused: false
};
});
}, 0);
}
};
// Pause Timer
// 暫停一個計時器。
ts.fn.pauseTimer = {
value: function(name) {
return this.each(function() {
var ref;
if (((ref = this.$timers) != null ? ref[name] : void 0) == null) {
return;
}
// 清除計數計時器達到暫停效果。
clearInterval(this.$timers[name].timer);
// 表示暫停。
return this.$timers[name].paused = true;
});
}
};
// Play Timer
// 重啟一個計時器。
ts.fn.playTimer = {
value: function(name) {
return this.each(function() {
var ref;
if (((ref = this.$timers) != null ? ref[name] : void 0) == null) {
return;
}
if (!this.$timers[name].paused) {
return;
}
// 重新初始化計數計時器來達到繼續的效果。
this.$timers[name].timer = setInterval(this.$timers[name].initializer, 10);
// 表示重新啟動。
return this.$timers[name].paused = false;
});
}
};
// Remove Timer
// 移除一個計時器。
ts.fn.removeTimer = {
value: function(name) {
return this.each(function() {
var ref;
if (((ref = this.$timers) != null ? ref[name] : void 0) == null) {
return;
}
// 清除計數計時器。
clearInterval(this.$timers[name].timer);
// 移除在 DOM 元素內的計時器物件。
return delete this.$timers[name];
});
}
};
// Repaint
// 讓瀏覽器重繪元素。
ts.fn.repaint = {
value: function() {
return this.each(function() {
return void(this.offsetHeight);
});
}
};
// Unique ID
// 取得為此元素而產生的獨立編號,若無則建立。
ts.fn.uniqueID = {
value: function() {
var id;
id = this.get(0).$uniqueID;
if (id) {
return id;
}
this.get(0).$uniqueID = (Math.random().toString(16) + '000000000').substr(2, 8);
return this.get(0).$uniqueID;
}
};
}).call(this);