FM Helper

El desarrollo para Foroactivo se puede convertir en una tarea un tanto tediosa a la hora de querer realizar cosas un poco más complejas de a lo que se está acostumbrado. Foroactivo es una plataforma limitada por naturaleza. Aunque la edición de plantillas o templates es un gran avance, es cierto que lo limitadas e incompletas que son nos hacen depender mucho de JavaScript para personalizar los foros. La mayor parte de las veces que queremos utilizar códigos JavaScript con una mínima complicación es para obtener información de otras páginas mediante consultas AJAX. De todas estas peticiones, muchas de ellas son muy similares o actúan sobre la misma página, llevándonos a problemas de eficiencia. El día de hoy presentamos FM Helper una librería pensada para el desarrollo en Foroactivo que pretende solucionar muchos de los problemas a la hora de crear Scripts para Foroactivo.

¿Qué es FM Helper?

FM Helper es una librería JavaScript que permite realizar la mayor parte de obtención de información sobre los foros Foroactivo en muy pocas líneas de código. Esta librería se encarga de toda la lógica necesaria a la hora de querer, por ejemplo, obtener la lista de grupos de un foro o la información de un usuario para que tú no necesites tener que reinventar la rueda y poder crear tu script de forma rápida y eficiente. Definido de forma sencilla, FM Helper permite desarrollar de forma sencilla, abstrayendo mucha lógica y líneas de código de igual forma que jQuery abstrae JavaScript.

Lo que se puede hacer con él

La librería simplemente te proporciona las bases para que tú puedas hacer lo que quieras con ella. Desde obtener información de un usuario, pasando por la obtención de los grupos del foro. Algo que quizás pueda resultar interesante a muchos es la posibilidad de añadir scripts al Chatbox.

¿Necesito utilizar FM Helper en mi foro?

No necesariamente. FM Helper es una herramienta para facilitar el desarrollo. Si tu foro ya está creado no merece la pena reescribir tus scripts para implementarlos con FM Helper. También es posible que ninguna de las funciones que proporciona FM Helper te sean de utilidad en tu caso concreto. Deberías primero echarle un vistazo a la documentación para saber si hay algún método de utilidad para ti. Es necesario aclarar que existe la posibilidad de que alguno de los códigos del blog necesiten FM Helper para funcionar. En tal caso esto estaría aclarado en la entrada de presentación del código.

Cómo funciona

FM Helper está compuesto de muchas funciones, cada una con su implementación correspondiente. Quizás lo que más puede llamar la atención es cómo promete eficiencia a la hora de hacer cosas como obtener la lista de grupos de un foro o obtener información de un usuario desde cualquier página del foro. Para hacer esto, FM Helper utiliza peticiones AJAX en segundo plano encapsuladas dentro de objetos Promise, que permiten a tu código llamarse una vez que el valor haya sido obtenido, sin interrumpir ninguna otra parte de tus scripts. Además, muchas de las veces que se implementan peticiones AJAX en Foroactivo es para obtener información que no suele cambiar hasta dentro de mucho. Por ejemplo, los grupos de un foro o, en menor medida, los avatares de los usuarios, no son cosas que se cambien constantemente. Realizar una petición a este tipo de recursos con cada actualización de la página no es para nada eficiente. FM Helper se encarga de solucionar este problema implementando un sistema de cache, que guarda la información y evita tener que hacer más peticiones AJAX. Mola, ¿eh?

Cómo se usa

El funcionamiento de FM Helper es tan simple que no necesitarías más que cinco minutos para ponerte a utilizarlo en tus scripts. Sin embargo, es posible que necesites conocimientos básicos en JavaScript para poder utilizarlo. Si no conoces el funcionamiento de la API Promise de JavaScript, no te preocupes, todos los métodos que la utilizan permiten también utilizar un callback en sus parámetros para usarlo como lo harías en jQuery. Pásate por la documentación para ver todo lo que se puede hacer con él.

Prerequisitos

Desafortunadamente Foroactivo no ha puesto muy fácil el desarrollo de esta librería. Es por ello que para que ciertas partes del plugin funcionen es necesario cumplir los siguientes requisitos:
  • Activar la Toolbar de Foroactivo en tu foro. En caso de que no quieras que se vea activada siempre puedes ocultarla con CSS de la siguiente manera:
    #fa_toolbar {
    	display: none;
    }
  • Activa las menciones para todos los usuarios desde PA → General → Mensajes y Emails→ Configuración → Mensajes (justo al final, antes de Temas) → Autorizar las menciones (@) en los nombres de los miembros.

Instalación

Instalar FM Helper en tu foro es muy sencillo. Primero crea un nuevo JS desde la Gestión de JavaScripts de tu foro y márcalo para que no se muestre en ninguna página:
/*! FM HELPER v0.1.8 | Flerex | flerex.dev */
(function(a,b,c){'use strict';console.log('%cFM Helper by %cFlerex%c.blog','font-family: "Open Sans", Arial, sans-serif; font-size: 1.2em;','font-size: 1.5em; text-transform: uppercase; letter-spacing: -1px; font-weight: 800; color: #0d5ad5;','color: #e42e88; text-transform: none; font-size: 1.2em; font-style: italic;'),console.log('https://flerex.dev');const d='FMHELPER_';a.FLX=a.FLX||{},a.FLX.helper=function(){function h(Q){switch(Q.body.id){case'phpbb':return'phpBB3';case'modernbb':return'ModernBB';}return Q.getElementById('ipbwrapper')?'Invision':Q.querySelector('.pun')?'PunBB':Q.body.hasAttribute('bgcolor')?'phpBB2':c}function m(Q){const R='\xE0\xE1\xE4\xE2\xE8\xE9\xEB\xEA\xEC\xED\xEF\xEE\xF2\xF3\xF6\xF4\xF9\xFA\xFC\xFB\xF1\xE7\xB7/_,:;';Q=Q.trim().toLowerCase();for(var T=0,U=R.length;T<U;T++)Q=Q.replace(new RegExp(R.charAt(T),'g'),'aaaaeeeeiiiioooouuuunc------'.charAt(T));return Q.replace(/[^a-z0-9 -]/g,'').replace(/\s+/g,'-').replace(/-+/g,'-')}function n(){return-1!=O.id}function o(){switch(_userdata.user_level){case 2:return'mod';case 1:return'admin';case 0:return-1==_userdata.user_id?'guest':'user';}}function p(){return _userdata.avatar.split('"')[1]}function r(Q,R){return Q=Q.getTime(),R=R.getTime(),Math.floor(Math.abs(Q-R)/8.64e7)}function s(Q,R){if(!localStorage)return!1;const S=d+Q,T=localStorage.getItem(S);if(!T)return null;const U=JSON.parse(T),V=new Date(U.cached_at);return r(V,new Date)>=R?(localStorage.removeItem(S),null):U.content}function t(Q,R){if(!localStorage)return!1;const S={cached_at:new Date().getTime(),content:R};localStorage.setItem(d+Q,JSON.stringify(S))}function u(Q,R){let S,T=null,U=R.querySelector('.tooltip-title'),V=R.querySelector('.tooltip-subtitle');if(!U)return null;let W=U.querySelector('span[style]');return W&&(W=W.style.color),U.firstElementChild&&(S=U.firstElementChild.style.color),V&&(T=V.innerHTML.match(/:\s(.*)/)[1]),new User(Q,U.textContent,c,R.getElementsByTagName('img')[0].src,T,+R.querySelector('.tooltip-counts').firstChild.firstElementChild.textContent,W)}function v(Q){return Array.from(Q).map(R=>new Group(R.href.match(/\/g(\d+)-/)[1],R.textContent,R.style.color))}function w(Q){return Q+'?change_version='+'invision'}function x(Q){return /^\w+\s*:\s+(?:\[\s.+\s\]\s*)+/.test(Q.textContent)}function y(Q){const R=Array.from(Q.body.getElementsByTagName('*')).find(x);return R?R.querySelectorAll('a[href^="/g"]'):null}function z(Q){const R=Array.from(Q.querySelectorAll('#fo_stat div')).find(x);return R?R.querySelectorAll('a[href^="/g"]'):null}function A(...Q){const[R,S]=K(Q),T='groups',U=s(T,S);if(null!==U)return U.forEach(W=>Object.setPrototypeOf(W,Group.prototype)),Promise.resolve(U);const V=D(w('/forum')).then(W=>{let X=z(W)||y(W);if(!X)throw new Error('Could not get the forums legend. Please check if {LEGEND} is set on your index_body template.');if(!X.length)return c;const Y=v(X);return t(T,Y),Y});return R&&V.then(W=>{R.call(this,W)}),V}function B(Q,...R){if(Q===c)throw new Error('User ID missing');const[S,T]=K(R),U='u'+Q,V=s(U,T);if(null!==V)return Object.setPrototypeOf(V,User.prototype),Promise.resolve(V);const W=D('/ajax/index.php',{data:{f:'m',user_id:Q}}).then(X=>{let Y=u(Q,X);return t(U,Y),Y});return S&&W.then(X=>{S.call(this,X)}),W}function C(Q){return'?'+Object.keys(Q).map(R=>encodeURIComponent(R)+'='+encodeURIComponent(Q[R])).join('&')}function D(Q,R={}){return R.hasOwnProperty('data')&&(Q+=C(R.data)),fetch(Q,Object.assign({method:'GET',credentials:'include'},R)).then(S=>S.text()).then(S=>{return new DOMParser().parseFromString(S,'text/html')})}function E(Q){'loading'==b.readyState?b.addEventListener('DOMContentLoaded',Q):Q()}function G(Q){const R=Q.querySelector('div.pagination');return!!R&&Array.from(R.children).filter(S=>{return'A'==S.tagName&&+S.textContent})}function H(Q){const R=Q.querySelector('div.pagination');return!!R&&parseInt(R.firstElementChild.textContent.match(/start = \(start > \d+\) \? \d+ : start;\n {4}start = \(start - \d+\) \* (\d+);/)[1])}function I(Q,R){const S=Q.querySelector('table.ipbtable tbody tr:nth-child(2)').childNodes[1].firstElementChild.firstElementChild;return!!S&&S.style.color==R}function J(Q,R){let S=0;return I(Q,R.color)&&S++,1!=Q.querySelector('table.ipbtable tbody tr:last-child').childElementCount&&(S+=Q.querySelectorAll('table.ipbtable tbody tr').length-3),S}function K(Q){let R=[!1,30];return 2==Q.length?R=Q:'integer'==typeof Q[0]?R[1]=Q[0]:R[0]=Q[0],R}class User{constructor(Q,R,S,T,U,V,W){this.id=Q,this.username=R,this.level=S,this.avatar=T,this.rank=U,this.posts=V,this.color=W}getRankAsText(){if(!this.rank)return'';let Q=new DOMParser().parseFromString(this.rank,'text/html');return Q.body.textContent.trim()}getURL(){return`/u${this.id}`}}class Group{constructor(Q,R,S){this.id=Q,this.name=R,this.color=S}getURL(){return`/g${this.id}-${m(this.name)}`}}const O=new User(_userdata.user_id,_userdata.username,o(),p(),_lang.hasOwnProperty('rank_title')?_lang.rank_title:c,_userdata.user_posts,c),P={isLoggedIn:n,userLevel:o,getGroups:A,getUser:B,slugify:m,attachScriptToChat:function(Q){function R(T,U){'complete'==T.contentDocument.readyState?U():T.addEventListener('load',U)}let S=b.createElement('script');S.type='text/javascript',S.textContent=`;(${Q.toString()})();`,E(function(){const T=b.querySelectorAll('object[data^="/chatbox/index.forum"], iframe[src^="/chatbox/index.forum"]');Array.from(T).foreach(U=>{R(U,function(){U.contentDocument.getElementsByTagName('head')[0].appendChild(S.cloneNode(!0))})})})},getVersion:function(){return h(b)},enableDebugMode:function(){console.warn('%cATTENTION: Debug mode is enabled','color: red; font-weight: bold; font-size: 1.1em;'),console.warn('CSS files are not being cached by browsers');const Q='?debug='+ +new Date;b.querySelectorAll('link[rel="stylesheet"]').forEach(R=>{R.setAttribute('href',R.getAttribute('href')+Q)})},setCache:t,getCache:s,get:D};return n()&&Object.assign(P,{currentUser:function(Q){switch(Q){case'id':return O.id;case'username':case'name':return O.username;case'avatar':return p();case'level':return O.level;case'rank':return O.rank;case'posts':return O.posts;}throw new Error('Argument is not supported')},u:O,user:O}),User.prototype.getGroup=function(){return new Promise(Q=>{A().then(R=>{this.color===c?B(this.id).then(S=>{Q(R.find(T=>T.color==S.color))}):Q(R.find(S=>S.color==this.color))})})},Group.prototype.getMemberAmount=function(...Q){const[R,S]=K(Q),T='gc'+this.id,U=s(T,S);if(null!==U)return Promise.resolve(U);const V=D(w(`/g${this.id}-`)).then(W=>{const X=G(W);if(!X.length){const Y=J(W,this);return t(T,Y),Y}return D(X.pop().href)}).then(W=>{if('number'==typeof W)return W;const X=G(W),Y=X.length*H(W)+J(W,this);return t(T,Y),Y});return R&&V.then(W=>{R.call(this,W)}),V},P}(),'undefined'==typeof a._&&(a._=FLX.helper),'undefined'==typeof a.H&&(a.H=FLX.helper)})(this,document);
Ahora copia la ruta al script que se ha creado. Tan solo dirígete a la plantilla overall_header y busca:
{HOSTING_JS}
Añade después, en una nueva línea pon lo siguiente, sustituyendo la ruta por la URL del script que copiaste anteriormente.
<script type="text/javascript" src="la ruta"></script>
¡Listo! FM Helper ya está disponible para ser utilizado. Nota: Ten en cuenta que, debido a limitaciones de Foroactivo y muy a mi pesar, la librería no está disponible desde la gestión de JS del PA. Para poder utilizarla en tus scripts deberás añadirlos directamente desde la plantilla overall_header, debajo del anterior script o en cualquier otra plantilla del foro.

A tener en cuenta…

  • La versión de tu foro puede ser cualquiera de las disponibles (phpBB3, phpBB2, Invision, punBB o ModernBB). Sin embargo, en el caso de Invision no garantizamos su correcto funcionamiento si se han editado las plantillas.
  • FM Helper solo da soporte a las versiones actuales y anteriores a la actual de los navegadores más comunes. Esto no quiere decir que no pueda funcionar en otros navegadores más antiguos, simplemente que no se harán modificaciones para adaptarse a los mismos. Por lo general, las tecnologías que se utilizan deberían ser compatibles con las últimas versiones de los navegadores desde hace tres años.

¿Podría la librería incluir X funcionalidad?

Posiblemente. Si tienes una idea sobre algo que la librería podría implementar por defecto no dudes en dejar en los comentarios tu sugerencia. Estamos abiertos a cualquier tipo de sugerencia sobre la librería siempre que se sugiera algo que puede ser de uso común y no muy específico.