import { Fascino } from './core.js'
import Utils from './Utils'
/**
* Fascino desde el Navegador <br>
* Esta variable sera la que interactué desde el navegador
* @global
* @namespace _$
* @param {(String|Function|Element|Object)} selector Selector CSS o HTMLElement o Array de HTMLElememnt
* @param {(HTMLElement|document)} context Entorno de selección
* @return {Fascino} Class [Fascino]{@link Fascino}
*/
export function _$(selector, context){
return new Fascino(selector, context);
}
if (typeof window._$ === 'undefined') {
window._$ = _$
}
const U = Utils.Utils,
template = Utils.template,
C = Utils.Colors
_$.template = template;
U.extend(_$, U);
U.extend(_$, C);
U.extend(_$, {
/**
* Añade funciones a Fascino JS
* @memberOf _$
* @public
* @param {String} name Nombre de la función
* @param {Function} callbacks Función a añadir
* @example
* _$.addFn('decir', function(quedigo){
* return this.each((el) => {
* _$(el).html(quedigo)
* })
* })
* // Ahora la usamos
* _$('body').decir('Hola')
*
* // si lo ejecutamos el body contendrá la palabra "Hola"
* @return {Fascino}
*
*/
addFn: function(name, callbacks){
return Fascino.addFn.apply(Fascino, [name, callbacks])
},
/**
* Globaliza la variable $,
* Ojo si usa jQuery no use esta función
* @memberOf _$
* @public
*/
global: () => {
window.$ = _$
},
/**
* Libera la variable $
* @memberOf _$
* @public
*/
setFree$: () => {
if (window.$ === window._$) {
window.$ = undefined
}
},
/**
* Intenta evitar conflicto con jQuery y Otros framework que usen el $
* @memberOf _$
* @public
* @return {Fascino}
*/
noConflict: () => {
if ( window.$ === $ ) {
window.$ = _$
}
return _$
},
/**
* Ejecuta una función cuando el DOM a cargado
* @memberOf _$
* @public
* @param {Function} fn función a ejecutar
* @param {Object} options Opciones para addEventListiner
*/
DOMLoad: function(fn, options) {
if (document.readyState != 'loading') {
if (isFunction(fn)) {
fn()
}
} else {
document.addEventListener('DOMContentLoaded', fn, (options || false))
}
},
/**
* Ejecuta una función cuando window a cargado
* @memberOf _$
* @public
* @param {Function} fn Función a ejecutar
* @return {Fascino}
*/
WLoad: function(fn) {
return _$(window).on('load', fn)
},
/**
* Ejecuta una función cuando la ventana, el documento y sus recursos están a punto de ser descargados
* @memberOf _$
* @public
* @param {Function} fn Función a ejecutar
* @return {Fascino}
*/
beforeunload: function(fn) {
if (typeof fn === 'string') {
return _$(window).on('beforeunload', function(e) {
e.returnValue = fn
return fn
})
} else {
return _$(window).on('beforeunload', fn)
}
},
/**
* Carga perezosa de imágenes
* @memberOf _$
* @public
* @param {Object} o Opciones de carga
* @exclude {String} exclude Selector css de imágenes a excluir
* @return {Fascino} Lista de imágenes cargadas
*/
Lazy: function(o, exclude = '') {
const img = _$('img'),
picture = _$('picture'),
bgImg = _$('[data-lazy-bg]'),
LazyOptions = {
root: document.querySelector('body'),
rootMargin: '0px',
threshold: 1.0
}
var opt = _$.extend({}, LazyOptions, o)
const IO = new IntersectionObserver((entries, imgObserver) => {
entries.forEach((entry) => {
// If the image is not visible.
_$.hooks.run('before.lazy', entry, imgObserver)
if (entry.isIntersecting) {
// If it's visible.
const img = entry.target
if (_$(img).hasData('lazy-bg')) {
_$(img).style('background-image', `url('${_$(img).data('lazy-bg')}')`)
}
if (img.nodeName === 'IMG') {
img.src = _$(img).data('src')
if (_$(img).hasData('srcset')) {
img.srcset = _$(img).data('srcset')
}
}
if (img.nodeName === 'PICTURE') {
let imgp = _$(img).find('img')
imgp.src = _$(imgp).data('src')
if (_$(imgp).hasData('srcset')) {
imgp.srcset = _$(imgp).data('srcset')
}
}
_$(img).fadeIn()
imgObserver.unobserve(entry.target)
}
_$.hooks.run('after.lazy', entry, imgObserver)
})
}, opt)
// Observing the images.
if (img.length > 0) {
img.each((img) => {
if (img.parentNode.nodeName !== 'PICTURE') {
_$(img).fadeOut()
if (img && !_$.empty(exclude)) {
if (!img.matches(exclude)) {
IO.observe(img)
}
} else {
IO.observe(img)
}
}
})
}
if (picture.length > 0) {
picture.each((img) => {
_$(img).fadeOut()
if (img && !_$.empty(exclude)) {
IO.observe(img)
} else {
IO.observe(img)
}
})
}
if (bgImg.length > 0) {
bgImg.each((img) => {
_$(img).fadeOut()
if (img && !_$.empty(exclude)) {
IO.observe(img)
} else {
IO.observe(img)
}
})
}
return img
},
/**
* Sistema de Ganchos de [Fascino JS]{@link Fascino}
* @memberOf _$
* @public
* @namespace Hooks
* @type {Object}
* @example
* // Añadimos una función a anclar
* _$.hooks.add('name.myhooks', function(Elemet) {
* // ...
* })
* // Ejecutamos la Función anclada y pasamos el argumento Element
* _$.hooks.run('name.myhooks', Elemet)
* // Puede pasar la cantidad de argumentos que desee asi
* _$.hooks.run('name.myhooks', Elemet, Args1, Args2)
* // Y en la función add los recibimos de igual manera
* _$.hooks.add('name.myhooks', function(Elemet, Args1, Args2) {
* // ...
* })
* // Para listar todas las funciones ancladas use
* _$.hooks.hook // No se recomienda su uso de esta manera
* // Es recomendable si se require saber si existe o no una función anclada use el método _$.hasProp
* _$.hasProp(_$.hooks.hook, 'name.myhooks') // Retornara true si existe
*/
hooks: {
/**
* Lista de Ganchos anclados
* @memberOf _$.Hooks
* @inner
* @type {Object}
*/
hook: {},
/**
* Añade funciones a los ganchos
* @memberOf _$.Hooks
* @public
* @param {String} name Nombre
* @param {Function} actions función a ejecutar
*/
add: function(name, actions) {
let hook = this.hook
hook[name] = hook[name] || []
hook[name].push(actions)
},
/**
* Ejecuta un Gancho,
* La mayoria de los componente de [Fascino]{@link module:core.Fascino} poseen un gancho para anclarnos a sus funciones
* @memberOf _$.Hooks
* @public
* @param {String} name Nombre del Gancho existente
* @param {...*} args Lista de argumentos que pasar a la función
*/
run: function(name, ...args) {
if (args.length === 0) return
let callbacks = this.hook[name]
if (_$.empty(callbacks)) return
for (let i = 0; i < callbacks.length; i++) {
callbacks[i].apply(this, args)
}
}
}
})
export default {
_$,
Fascino
}