UNPKG

@slavmak2486/bx24ts

Version:

Library for bitrix24

680 lines (591 loc) 21.8 kB
import { batchCmdElement } from "../types/batchElement"; import { eventElement } from "../types/eventElement"; import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'; import { CallResult } from "../callResult"; import {cloneDeep, get as __get} from 'lodash' import { logger } from "../types/authBaseServe"; import { getAuth } from "../types/getAuth"; // проблемы декларирования методов HTMLElement declare global{ interface Document{ attachEvent(event: string, listener: EventListener): boolean; detachEvent(event: string, listener: EventListener): void; } interface Window{ attachEvent(event: string, listener: EventListener): boolean; detachEvent(event: string, listener: EventListener): void; } } interface elementCbArray{ uid:string, cb:(args:any)=>void } export abstract class baseBX24{ cbArray:elementCbArray[]=[]; AUTH_CONNECTOR=""; CLIENT_ID: string | undefined=""; CLIENT_SECRET: string | undefined=""; isInit=false; DOMAIN: string; PROTOCOL: number; APP_SID: string|boolean=false; PATH="/rest"; LANG=""; AUTH_ID=""; REFRESH_ID=""; MEMBER_ID=""; PLACEMENT=""; IS_ADMIN=false; AUTH_EXPIRES=0; USER_OPTIONS: any; APP_OPTIONS: any; PLACEMENT_OPTIONS: any; url=''; timeoutCall=0; arrEvents:eventElement[]=[]; logger:logger=console; isReadyVal=false; //check getHttpString(value:any, prefix=''):string{ if (value instanceof Date){ return prefix+'='+encodeURIComponent(value.toISOString()); } else if (typeof value=='object'){ const resultObj=[]; for (const field in value){ resultObj.push(this.getHttpString(value[field], prefix+`${prefix!=''?'[':""}${field}${prefix!=''?']':''}`)); } return resultObj.join('&'); } else if (prefix!=''){ return encodeURIComponent(prefix)+'='+encodeURIComponent(value); } return encodeURIComponent(value); } setTimeoutCall(ms:number){ this.timeoutCall=ms; } clearTimeoutCall(){ this.timeoutCall=0; } isFunction(item:any){ return item === null ? false : (typeof (item) == "function" || item instanceof Function); } addEvent(event:string, handler:(params:any)=>void){ this.arrEvents.push({ event:event, handler:handler }); } emitEvent(event:string, params?:any){ const arrHandler=this.arrEvents.filter(el=>{return el.event==event}); for (const idx in arrHandler){ setTimeout(()=>{ arrHandler[idx].handler.call(this, params); }, 10); } } uniqid(){ const charsList = '0123456789abcdefghijklmnopqrstuvwxyz'; let s = ''; for (let i = 0; i <32; i++) s += charsList[Math.round(Math.random()*(charsList.length-1))]; return s; } setCallback(cb?:(args:any)=>void){ const cbId = this.uniqid(); if (cb){ this.cbArray.push({uid:cbId, cb:cb}); } return cbId; } abstract runCallback(e:MessageEvent):void doInit(){ this.emitEvent('init', this); } abstract sendMessage(cmd:string, params:any, cb?:(params:any)=>void):void constructor(){ this.DOMAIN=""; this.PROTOCOL=1; } userOption={ get:(name:string)=>{ return this.USER_OPTIONS[name]; }, set:(name:string, value:any, cb:(params:any)=>void)=>{ this.USER_OPTIONS[name] = value; this.sendMessage('setUserOption', {name:name,value:value}, cb); } } appOption={ get: (name:string)=>{ return this.APP_OPTIONS[name]; }, set:(name:string,value:any,cb:(params:any)=>void)=>{ if (this.isAdmin()){ this.APP_OPTIONS[name] = value; this.sendMessage('setAppOption', {name:name,value:value}, cb); } else{ console.error('Access denied!'); } } } utilReady(){ if (document.readyState === "complete") { return this.runReady(); } let __readyHandler:EventListener; if (document.addEventListener) { __readyHandler=()=>{ document.removeEventListener("DOMContentLoaded", __readyHandler, false); this.runReady(); } document.addEventListener("DOMContentLoaded", __readyHandler, false); window.addEventListener("load", ()=>{this.runReady()}, false); } else if (document.attachEvent) { __readyHandler =()=>{ if (document.readyState === "complete") { document.detachEvent("onreadystatechange", __readyHandler); this.runReady(); } } document.attachEvent("onreadystatechange", __readyHandler); window.attachEvent("onload", ()=>{this.runReady()}); } this.utilReady = () => null; return null; } runReady():void{ if (!this.isReadyVal) { if (!document.body){ setTimeout(this.runReady, 15); return; } this.isReadyVal = true; this.ready = (handler)=>{ if (typeof handler=='function') { setTimeout(handler, 10); } }; this.emitEvent('ready'); } return; } abstract refreshAuth(cb?:(params:any)=>void):void; abstract refreshAuthAsync():Promise<getAuth>; protected callSuccess(xhr:AxiosResponse):boolean{ return typeof xhr.status=='undefined' || (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304 || xhr.status >= 400 && xhr.status < 500 || xhr.status === 1223 || xhr.status === 0; } protected call(url:string, config:{ method:string, data:any, callback?:(params: any)=>void }):Promise<CallResult>{ return new Promise((resolve, reject)=>{ const params=cloneDeep(config.data); params.auth=this.AUTH_ID; if (this.AUTH_CONNECTOR&&!params.auth_connector){ params.auth_connector=this.AUTH_CONNECTOR; } const options:AxiosRequestConfig = { method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' }, data: this.getHttpString(params), url:url }; if (this.timeoutCall){ options.timeout=this.timeoutCall; } axios(options).then(res=>{ const data = res.data; const result = new CallResult(data, config, this, res.status); resolve(result); }) .catch((err:AxiosError)=>{ if (!err?.response?.data){ reject(err); } else if (__get(err, ['response','data','error'], undefined)=='expired_token'&&!url.includes('oauth.bitrix.info/oauth/token/')){ try { this.refreshAuth(()=>{ this.call(url, config).then(resolve).catch(reject); }); } catch (error) { reject(error); } } else{ reject(__get(err, ['response','data'], err.message)); } }); }); } getAuth(){ return (this.isInit && this.AUTH_EXPIRES > (new Date()).valueOf()) ? {access_token: this.AUTH_ID, refresh_token: this.REFRESH_ID, expires_in: this.AUTH_EXPIRES, domain: this.DOMAIN, member_id: this.MEMBER_ID} : false; } // callBatch(cmd:batchCmdElement, haltOnError?:boolean):Promise<{[key:string|number]:CallResult}>; // callBatch(cmd:batchCmdElement, cb:(params:{[key:string|number]:CallResult})=>void|boolean, haltOnError?:boolean):void; // callBatch(cmd:batchCmdElement, haltOnError?:boolean):Promise<{[key:string|number]:CallResult}>; // callBatch(cmd:batchCmdElement, cb:(params:{[key:string|number]:CallResult})=>void|boolean, haltOnError?:boolean):void; // callBatch( // cmd:batchCmdElement, // cb?:((params:{[key:string|number]:CallResult})=>void)|boolean, // haltOnError=false):void|Promise<{[key:string|number]:CallResult // }> callBatch<T extends batchCmdElement>(cmd:T, haltOnError?:boolean):Promise<{[key in keyof T]:CallResult}> callBatch<T extends batchCmdElement>(cmd:T, cb:(params:{[key in keyof T]:CallResult})=>void):void callBatch<T extends batchCmdElement>(cmd:T, cb:(params:{[key in keyof T]:CallResult})=>void, haltOnError:boolean):void callBatch<T extends batchCmdElement>( cmd:T, cb?:((params:{[key in keyof T]:CallResult})=>void)|boolean, haltOnError=false ):void|Promise<{[key in keyof T]:CallResult}> { const startCb=cb; const startHaltOnError=haltOnError; if (typeof cb == 'boolean'){ haltOnError=cb; cb=undefined; } else{ cb=cb as (params:{[key in keyof T]:CallResult})=>void; } const comands:Partial<{ [key in keyof T]:string }>={}; let cnt=0; for(const idx in cmd){ const row=cmd[idx]; const method=Array.isArray(row)?row[0]:row.method; const params=Array.isArray(row)?row[1]:row.params; if(method) { cnt++; comands[idx] = `${method}?${this.getHttpString(params)}`; } } if (cnt>0){ const url=this.url?`${this.url}batch.json`:`http${this.PROTOCOL?'s':''}://${this.DOMAIN}${this.PATH}/batch.json`; const params={ cmd:comands as { [key in keyof T]:string }, halt:haltOnError?1:0 }; if (!startCb){ if (this.AUTH_EXPIRES<(new Date()).valueOf()){ return new Promise((resolve, reject)=>{ this.refreshAuthAsync().then(()=>{ this.callBatch(cmd, startHaltOnError).then(res=>{ resolve(res); }) .catch(err=>{ reject(err); }) }) .catch((error:Error)=>{ reject(error); }); }); } else{ return new Promise((resolve, reject)=>{ this.call(url, { method:'batch', data: params, }).then(res=>{ resolve(this.formatResultForBatch(res, cmd)); }) .catch(reject) }); } } else if (typeof startCb=='function'){ if (this.AUTH_EXPIRES<(new Date()).valueOf()){ this.refreshAuthAsync().then(()=>{ this.callBatch(cmd, startCb, startHaltOnError); }) .catch(error=>{ console.error(error); }); } else{ this.call(url, { method:'batch', data:params, callback: startCb }).then(res=>{ if (typeof cb =='function') cb(this.formatResultForBatch(res, cmd, cb)); }) .catch(err=>{ if (err instanceof Error){ throw err; } const result=this.formatResultForBatch( new CallResult(err, { method:'batch', data:params }, this, 500), cmd, cb as (params:any)=>void ); if (typeof cb ==='function') cb(result); return false; }) } } } else{ return; } } formatResultForBatch<T extends CallResult, R extends batchCmdElement>( res:T, calls:R, callback?:(params:any)=>void) :{[key in keyof R]:CallResult} { const data = res.data(); const result:Partial<{[key in keyof R]:CallResult}>={}; for(const idx in calls){ const cmd=calls[idx]; if (data?.result?.[idx]!==undefined|| data?.result_error?.[idx]!==undefined){ result[idx]=new CallResult({ result: data.result?.[idx]||{}, error:data.result_error[idx]||undefined, total:data.result_total[idx], time:data.result_time[idx], next: data.result_next[idx] }, { method:Array.isArray(cmd)?cmd[0]:cmd?.method, data: Array.isArray(cmd)?cmd[1]:cmd?.params, callback:callback }, this, res.status) } else{ result[idx]={ data:()=>({}), total:()=>0, error_description:()=>JSON.stringify(res), answer:data?.result?.[idx], query: { method:Array.isArray(cmd)?cmd[0]:cmd?.method, data: Array.isArray(cmd)?cmd[1]:cmd?.params, callback:callback }, next:()=>false, bx24:this, time:()=>({}), status:res.status, more:()=>false, error:()=>JSON.stringify(res) }; } } return result as { [key in keyof R]: CallResult; }; } callMethod(method:string, params:any):Promise<CallResult>; callMethod(method:string, params:any, cb?:(params:CallResult)=>void):void; callMethod(method:string, params:any, cb?:(params:CallResult)=>void):void|Promise<CallResult>{ const url=this.url?`${this.url}${method}.json`:`http${this.PROTOCOL?'s':''}://${this.DOMAIN}${this.PATH}/${method}.json`; if (!cb){ if (this.AUTH_EXPIRES<(new Date()).valueOf()){ return new Promise((resolve, reject)=>{ try { this.refreshAuth(()=>{ this.callMethod(method, params)?.then(res=>{ resolve(res); }) .catch(err=>{ reject(err); }) }); } catch (error) { reject(error); } }); } else{ return new Promise((resolve)=>{ this.call(url, { method, data:params }).then(res=>{ resolve(res); }) .catch(err=>{ resolve(new CallResult(err, { data:params, method, callback:cb }, this, 500)); }) }); } } else { if (this.AUTH_EXPIRES<(new Date()).valueOf()){ this.refreshAuth(()=>{ this.callMethod(method, params, cb); }); } else{ this.call(url, { method, data:params, callback:cb }).then(res=>{ return cb(res); }) .catch(err=>{ cb(new CallResult({error_description:String(err)}, { data:params, method, callback:cb },this, 500)); }) } } } //Getters isAdmin(){ return this.IS_ADMIN; } getLang(){ return this.LANG; } getDomain(){ return this.DOMAIN; } isReady(){ return this.isReadyVal; } ready(handler:(params:any)=>void){ this.addEvent('ready', handler); } getScrollSize(){ return { scrollWidth: Math.max(document.documentElement.scrollWidth, document.documentElement.offsetWidth), scrollHeight: Math.max(document.documentElement.scrollHeight, document.documentElement.offsetHeight) }; } /////////////////////////////////////////////////////////////////////////////////////// init(callback?:(params:any)=>void){ if(callback) { this.addEvent('init', callback); } } install(callback:(params:any)=>void){ if(callback) { this.addEvent('install', callback); } } callBind(event:string, handler:string, auth_type?:number, callback?:(params: CallResult) => void){ if(!this.isInit){ // var _a = arguments; this.init(()=>{ this.callBind(event, handler, auth_type, callback); }); } else if(this.isAdmin()) { const params = { event: event||'', handler: handler||'', auth_type: (typeof auth_type == 'undefined') ? 0 : auth_type }; return this.callMethod('event.bind', params, callback); } return false; } //select dialog selectAccess = (title:string, value:string[], cb:(params:any)=>void)=>{ if(typeof(value)==='function') { cb = value; value = []; } this.sendMessage('selectAccess', {value, title}, cb); }; selectUser = (title:string, cb:(params:any)=>void)=>{ if(typeof(title)==='function'){ cb = title; title = ''; } this.sendMessage('selectUser', {title: title, mult:false}, cb); }; selectUsers = (title:string, cb:(params:any)=>void)=>{ if(typeof (title)!=='string'){ cb = title; title = ''; } this.sendMessage('selectUser', {title: title, mult:true}, cb); }; selectCRM = (params:{ entityType:string[], multiple?:boolean, value?:string[] }, cb:(params:any)=>void)=>{ this.sendMessage('selectCRM', { entityType: params.entityType, multiple: params.multiple, value: params.value, }, cb); }; //Methods sendMessage installFinish(){ this.sendMessage('setInstallFinish',{}); } resizeWindow(width:number, height:number, cb:(params:any)=>void){ if(width > 0 && height > 0){ this.sendMessage('resizeWindow', {width:width,height:height}, cb); } } fitWindow(cb?:(params:any)=>void){ this.sendMessage('resizeWindow', { width:'100%', height:this.getScrollSize().scrollHeight }, cb); } closeApplication(cb:(params:any)=>void){ this.sendMessage('closeApplication', {}, cb); } reloadWindow(cb:(params:any)=>void){ this.sendMessage('reloadWindow', {}, cb); } setTitle(title:string, cb:(params:any)=>void){ this.sendMessage('setTitle', {title:title}, cb); } scrollParentWindow(scroll:number, cb:(params:any)=>void){ if(scroll>0) { this.sendMessage('setScroll', {scroll:scroll}, cb); } } //placement placement={ info:()=>({ placement:this.PLACEMENT, options:this.PLACEMENT_OPTIONS }), getInterface:(cb?:(params: any) => void)=>{ this.sendMessage('getInterface', {}, cb); }, // call:(method:string, params:any, cb?:(params:CallResult)=>void):void, call:(cmd:string, params?:any, cb?:(params:any)=>void):void=>{ this.sendMessage(cmd, params, cb); }, bindEvent:(eventName:string, cb:(params:any)=>void)=>{ this.sendMessage('placementBindEvent', {event:eventName}, cb); } } }