Compare commits
	
		
			1 Commits
		
	
	
		
			v9.2.1
			...
			b6124f5ee8
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b6124f5ee8 | 
							
								
								
									
										11852
									
								
								3CX_TAPI.user.js
									
									
									
									
									
								
							
							
						
						
									
										11852
									
								
								3CX_TAPI.user.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -9,11 +9,13 @@ module.exports = { | |||||||
|   source: pkg.repository.url, |   source: pkg.repository.url, | ||||||
|   downloadURL: 'https://source.cp-austria.at/git/CPATRD/3cx_tapi/raw/branch/master/3CX_TAPI.user.js', |   downloadURL: 'https://source.cp-austria.at/git/CPATRD/3cx_tapi/raw/branch/master/3CX_TAPI.user.js', | ||||||
|   match: [ |   match: [ | ||||||
|     'https://192.168.0.154:5001/*', |     'https://192.168.0.154:5001/webclient*', | ||||||
|     'https://cpsolution.my3cx.at:5001/*' |     'https://cpsolution.my3cx.at:5001/webclient*' | ||||||
|   ], |   ], | ||||||
|   require: [ |   require: [ | ||||||
|     'https://cdn.jsdelivr.net/gh/CoeJoder/waitForKeyElements.js@v1.2/waitForKeyElements.js', |     'https://cdn.jsdelivr.net/gh/CoeJoder/waitForKeyElements.js@v1.2/waitForKeyElements.js', | ||||||
|  |     `https://cdn.jsdelivr.net/npm/axios@${pkg.dependencies.axios}/dist/axios.min.js`, | ||||||
|  |     `https://cdn.jsdelivr.net/npm/axios-userscript-adapter@${pkg.dependencies['axios-userscript-adapter']}/dist/axiosGmxhrAdapter.min.js` | ||||||
|   ], |   ], | ||||||
|   grant: [ |   grant: [ | ||||||
|     'GM.xmlHttpRequest', |     'GM.xmlHttpRequest', | ||||||
|   | |||||||
| @@ -15,6 +15,8 @@ const webpackConfig = { | |||||||
|   }, |   }, | ||||||
|   externals: { |   externals: { | ||||||
|     jquery: '$', |     jquery: '$', | ||||||
|  |     axios: 'axios', | ||||||
|  |     'axios-userscript-adapter': 'axiosGmxhrAdapter' | ||||||
|   }, |   }, | ||||||
|   module: { |   module: { | ||||||
|     rules: [ |     rules: [ | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| const path = require('path') | const path = require('path') | ||||||
| const { merge } = require('webpack-merge') | const { merge } = require('webpack-merge') | ||||||
| const LiveReloadPlugin = require('webpack-livereload-plugin') | const LiveReloadPlugin = require('webpack-livereload-plugin') | ||||||
| const { UserScriptMetaDataPlugin } = require('userscript-metadata-webpack-plugin') | const UserScriptMetaDataPlugin = require('userscript-metadata-webpack-plugin') | ||||||
|  |  | ||||||
| const metadata = require('./metadata.cjs') | const metadata = require('./metadata.cjs') | ||||||
| const webpackConfig = require('./webpack.config.base.cjs') | const webpackConfig = require('./webpack.config.base.cjs') | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| const { merge } = require('webpack-merge') | const { merge } = require('webpack-merge') | ||||||
| const { UserScriptMetaDataPlugin } = require('userscript-metadata-webpack-plugin') | const UserScriptMetaDataPlugin = require('userscript-metadata-webpack-plugin') | ||||||
|  |  | ||||||
| const metadata = require('./metadata.cjs') | const metadata = require('./metadata.cjs') | ||||||
| const webpackConfig = require('./webpack.config.base.cjs') | const webpackConfig = require('./webpack.config.base.cjs') | ||||||
|   | |||||||
							
								
								
									
										12564
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										12564
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										57
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,7 +1,7 @@ | |||||||
| { | { | ||||||
|   "name": "3cx-tapi", |   "name": "3cp-tapi", | ||||||
|   "description": "3CX CP Tapi and Projectmanager integration", |   "description": "Build your UserScript with webpack", | ||||||
|   "version": "9.2.1", |   "version": "8.0.0", | ||||||
|   "author": { |   "author": { | ||||||
|     "name": "Daniel Triendl", |     "name": "Daniel Triendl", | ||||||
|     "email": "d.triendl@cp-solutions.at" |     "email": "d.triendl@cp-solutions.at" | ||||||
| @@ -20,35 +20,38 @@ | |||||||
|   }, |   }, | ||||||
|   "repository": { |   "repository": { | ||||||
|     "type": "git", |     "type": "git", | ||||||
|     "url": "https://source.cp-austria.at/git/CPATRD/3cx_tapi.git" |     "url": "http://scootaloo.cp-austria.at/gitlist/3cx_tapi.git" | ||||||
|   }, |   }, | ||||||
|   "private": true, |   "private": true, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "chrono-node": "^2.7.7" |     "axios": "0.21.1", | ||||||
|  |     "axios-userscript-adapter": "0.1.4", | ||||||
|  |     "chrono-node": "^2.3.0" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@types/greasemonkey": "^4.0.7", |     "@babel/core": "7.14.6", | ||||||
|     "@babel/core": "^7.25.8", |     "@babel/preset-env": "7.14.5", | ||||||
|     "@babel/preset-env": "^7.25.8", |     "@typescript-eslint/eslint-plugin": "4.27.0", | ||||||
|     "@typescript-eslint/eslint-plugin": "^8.8.1", |     "@typescript-eslint/parser": "4.27.0", | ||||||
|     "@typescript-eslint/parser": "^8.8.1", |     "babel-loader": "8.2.2", | ||||||
|     "babel-loader": "^9.2.1", |     "browserslist": "4.16.6", | ||||||
|     "browserslist": "^4.21.9", |     "css-loader": "5.2.6", | ||||||
|     "css-loader": "^7.1.2", |     "eslint": "7.29.0", | ||||||
|     "eslint": "^9.12.0", |     "eslint-config-standard": "16.0.3", | ||||||
|     "eslint-plugin-import": "^2.31.0", |     "eslint-plugin-import": "2.23.4", | ||||||
|     "eslint-plugin-node": "11.1.0", |     "eslint-plugin-node": "11.1.0", | ||||||
|     "eslint-plugin-promise": "^7.1.0S", |     "eslint-plugin-promise": "5.1.0", | ||||||
|     "less": "4.2.0", |     "eslint-plugin-standard": "4.1.0", | ||||||
|     "less-loader": "^12.2.0", |     "less": "4.1.1", | ||||||
|     "style-loader": "^4.0.0", |     "less-loader": "10.0.0", | ||||||
|     "ts-loader": "^9.5.1", |     "style-loader": "2.0.0", | ||||||
|     "typescript": "^5.6.3", |     "ts-loader": "9.2.3", | ||||||
|     "userscript-metadata-webpack-plugin": "^0.4.0", |     "typescript": "4.3.4", | ||||||
|     "webpack": "^5.95.0", |     "userscript-metadata-webpack-plugin": "0.1.0", | ||||||
|     "webpack-bundle-analyzer": "^4.10.2", |     "webpack": "5.39.1", | ||||||
|     "webpack-cli": "^5.1.4", |     "webpack-bundle-analyzer": "4.4.2", | ||||||
|     "webpack-livereload-plugin": "3.0.2", |     "webpack-cli": "4.7.2", | ||||||
|     "webpack-merge": "^6.0.1" |     "webpack-livereload-plugin": "3.0.1", | ||||||
|  |     "webpack-merge": "5.8.0" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -43,7 +43,7 @@ npm run build | |||||||
| ## distribution | ## distribution | ||||||
|  |  | ||||||
| ``` | ``` | ||||||
| cp "dist/3CX TAPI.prod.user.js" 3CX_TAPI.user.js | cp dist/index.prod.user.js 3CX_TAPI.user.js | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| And commit 3CX_TAPI.user.js | And commit 3CX_TAPI.user.js | ||||||
|   | |||||||
| @@ -1,18 +1,23 @@ | |||||||
| import * as chrono from 'chrono-node' | import * as chrono from 'chrono-node' | ||||||
| import { TapiContact } from './tapi-contact' | import { TapiContact } from './tapi-contact' | ||||||
| import { extractNumber } from './utils' | import { axios, extractNumber } from './utils' | ||||||
| import GM_fetch from './gm-fetch' |  | ||||||
|  |  | ||||||
| export class CallHistory { | export class CallHistory { | ||||||
|   private callerIds: { [number: string]: TapiContact } = {} |   private callerIds: { [number: string]: TapiContact } = {} | ||||||
|  |  | ||||||
|   private updateCallHistoryEntry (call: HTMLElement, callerId: TapiContact) { |   private updateCallHistoryEntry (call: HTMLElement, callerId: TapiContact) { | ||||||
|     var span = call.querySelector(':scope > span') |     var span = call.querySelector('span') | ||||||
|     this.showTimeManager(call, call.querySelector('.date').textContent, callerId) |     this.showTimeManager(call, span.nextSibling.textContent.trim(), callerId) | ||||||
|  |  | ||||||
|     if (callerId && callerId.tD_NAME !== '') { |     if (callerId && callerId.tD_NAME !== '') { | ||||||
|       var text = span.textContent |       var text = span.textContent | ||||||
|       span.textContent = callerId.tD_NAME + ' ' + callerId.tD_NUMBER |       span.textContent = callerId.tD_NAME | ||||||
|  |       var br = document.createElement('br') | ||||||
|  |       var span2 = document.createElement('span') | ||||||
|  |       span2.style.fontSize = 'small' | ||||||
|  |       span2.textContent = text | ||||||
|  |       span.parentNode.insertBefore(br, span.nextSibling) | ||||||
|  |       span.parentNode.insertBefore(span2, span.nextSibling) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -23,10 +28,10 @@ export class CallHistory { | |||||||
|       date = dateParts.groups.date |       date = dateParts.groups.date | ||||||
|       duration = dateParts.groups.duration |       duration = dateParts.groups.duration | ||||||
|     } |     } | ||||||
|     var parsedDate = chrono.parseDate(date) |  | ||||||
|     var parsedDateDe = chrono.de.parseDate(date) |     var parsedDate = chrono.de.parseDate(date) | ||||||
|     if (parsedDateDe) { |     if (!parsedDate) { | ||||||
|       parsedDate = parsedDateDe |       parsedDate = chrono.parseDate(date) | ||||||
|     } |     } | ||||||
|     if (!parsedDate) { |     if (!parsedDate) { | ||||||
|       return |       return | ||||||
| @@ -45,7 +50,7 @@ export class CallHistory { | |||||||
|  |  | ||||||
|     var length = (parsedDuration.getHours() * 60 + parsedDuration.getMinutes()).toString() |     var length = (parsedDuration.getHours() * 60 + parsedDuration.getMinutes()).toString() | ||||||
|  |  | ||||||
|     var toolbar = call.querySelector('call-history-options') |     var toolbar = call.querySelector('.wcToolbarTiles') | ||||||
|     var href = 'domizil://PM/Zeitbuchung?' |     var href = 'domizil://PM/Zeitbuchung?' | ||||||
|     if (callerId && callerId.tD_ID) { |     if (callerId && callerId.tD_ID) { | ||||||
|       href += 'KontaktId=' + callerId.tD_ID + '&' |       href += 'KontaktId=' + callerId.tD_ID + '&' | ||||||
| @@ -57,7 +62,7 @@ export class CallHistory { | |||||||
|     a.onclick = () => { |     a.onclick = () => { | ||||||
|       window.open(href) |       window.open(href) | ||||||
|     } |     } | ||||||
|     a.innerHTML = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 559.98 559.98">' + |     a.innerHTML = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 559.98 559.98" width="20" height="20">' + | ||||||
|       '<g>' + |       '<g>' + | ||||||
|       '  <g>' + |       '  <g>' + | ||||||
|       '    <path d="M279.99,0C125.601,0,0,125.601,0,279.99c0,154.39,125.601,279.99,279.99,279.99c154.39,0,279.99-125.601,279.99-279.99' + |       '    <path d="M279.99,0C125.601,0,0,125.601,0,279.99c0,154.39,125.601,279.99,279.99,279.99c154.39,0,279.99-125.601,279.99-279.99' + | ||||||
| @@ -69,14 +74,11 @@ export class CallHistory { | |||||||
|       '  </g>' + |       '  </g>' + | ||||||
|       '</g>' + |       '</g>' + | ||||||
|       '</svg>' |       '</svg>' | ||||||
|  |  | ||||||
|     a.classList.add('btn'); |  | ||||||
|     a.classList.add('btn-plain'); |  | ||||||
|     toolbar.insertBefore(a, toolbar.firstChild) |     toolbar.insertBefore(a, toolbar.firstChild) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public async showCallHistory (element: HTMLElement) { |   public async showCallHistory (element: HTMLElement) { | ||||||
|     var span = element.querySelector(':scope > span') |     var span = element.querySelector('span') | ||||||
|     var number = extractNumber(span.textContent) |     var number = extractNumber(span.textContent) | ||||||
|     if (!number) { |     if (!number) { | ||||||
|       this.updateCallHistoryEntry(element, undefined) |       this.updateCallHistoryEntry(element, undefined) | ||||||
| @@ -86,10 +88,10 @@ export class CallHistory { | |||||||
|     if (this.callerIds[number] !== undefined) { |     if (this.callerIds[number] !== undefined) { | ||||||
|       this.updateCallHistoryEntry(element, this.callerIds[number]) |       this.updateCallHistoryEntry(element, this.callerIds[number]) | ||||||
|     } else { |     } else { | ||||||
|       var response = await GM_fetch('http://cpatapi.cpsrvweb2016.cp-austria.at/callerid/' + encodeURIComponent(number)) |       var response = await axios.get<TapiContact>('http://cpatapi.cpsrvweb2016.cp-austria.at/callerid/' + encodeURIComponent(number)) | ||||||
|       var callerId: TapiContact = { tD_NAME: '' } |       var callerId: TapiContact = { tD_NAME: '' } | ||||||
|       if (response.status === 200) { |       if (response.status === 200) { | ||||||
|         callerId = await response.json() as TapiContact |         callerId = response.data | ||||||
|       } |       } | ||||||
|       console.log('TAPI call histroy callerid response', number, response, callerId) |       console.log('TAPI call histroy callerid response', number, response, callerId) | ||||||
|       this.callerIds[number] = callerId |       this.callerIds[number] = callerId | ||||||
|   | |||||||
| @@ -1,10 +1,9 @@ | |||||||
| import GM_fetch from './gm-fetch' |  | ||||||
| import { TapiContact } from './tapi-contact' | import { TapiContact } from './tapi-contact' | ||||||
| import { extractNumber } from './utils' | import { axios, extractNumber } from './utils' | ||||||
|  |  | ||||||
| export class CallNotification { | export class CallNotification { | ||||||
|   public async showCallNotification (element: HTMLElement) { |   public async showCallNotification (element: HTMLElement) { | ||||||
|     var number = element.querySelector('.callNumber').textContent |     var number = element.dataset.id | ||||||
|     console.log('TAPI call notification', number) |     console.log('TAPI call notification', number) | ||||||
|  |  | ||||||
|     number = extractNumber(number) |     number = extractNumber(number) | ||||||
| @@ -14,19 +13,19 @@ export class CallNotification { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     console.log('TAPI searching callerid for', number) |     console.log('TAPI searching callerid for', number) | ||||||
|     var response = await GM_fetch('http://cpatapi.cpsrvweb2016.cp-austria.at/callerid/' + encodeURIComponent(number)) |     var response = await axios.get<TapiContact>('http://cpatapi.cpsrvweb2016.cp-austria.at/callerid/' + encodeURIComponent(number)) | ||||||
|     console.log('TAPI callerid response', response) |     console.log('TAPI callerid response', response) | ||||||
|     var notification = { |     var notification = { | ||||||
|       text: number |       text: number | ||||||
|     } |     } | ||||||
|     if (response.status === 200) { |     if (response.status === 200) { | ||||||
|       var callerId = await response.json() as TapiContact |       var callerId = response.data | ||||||
|       if (callerId) { |       if (callerId) { | ||||||
|         notification.text = callerId.tD_NAME + '\r\n' + number + ' (' + callerId.tD_MEDIUM + ')' |         notification.text = callerId.tD_NAME + '\r\n' + number + ' (' + callerId.tD_MEDIUM + ')' | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // eslint-disable-next-line no-undef |     // eslint-disable-next-line no-undef | ||||||
|     GM.notification(notification.text, 'TAPI Anruf') |     GM.notification(notification) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								src/decs.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/decs.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | declare module 'axios-userscript-adapter' | ||||||
|  |  | ||||||
|  | declare const GM: any | ||||||
| @@ -1,55 +0,0 @@ | |||||||
| import { parseGMResponse } from "./utils"; |  | ||||||
|  |  | ||||||
| export default async function GM_fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> { |  | ||||||
|   const request = new Request(input, init); |  | ||||||
|  |  | ||||||
|   let data: string | undefined; |  | ||||||
|   if (init?.body) { |  | ||||||
|     data = await request.text(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return await XHR(request, init, data); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function XHR(request: Request, init: RequestInit | undefined, data: string | undefined): Promise<Response> { |  | ||||||
|   return new Promise((resolve, reject) => { |  | ||||||
|     if (request.signal && request.signal.aborted) { |  | ||||||
|       return reject(new DOMException("Aborted", "AbortError")); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     GM.xmlHttpRequest({ |  | ||||||
|       url: request.url, |  | ||||||
|       method: gmXHRMethod(request.method.toUpperCase()), |  | ||||||
|       headers: Object.fromEntries(new Headers(init?.headers).entries()), |  | ||||||
|       data: data, |  | ||||||
|       responseType: "blob", |  | ||||||
|       onload(res) { |  | ||||||
|         resolve(parseGMResponse(request, res)); |  | ||||||
|       }, |  | ||||||
|       onabort() { |  | ||||||
|         reject(new DOMException("Aborted", "AbortError")); |  | ||||||
|       }, |  | ||||||
|       ontimeout() { |  | ||||||
|         reject(new TypeError("Network request failed, timeout")); |  | ||||||
|       }, |  | ||||||
|       onerror(err) { |  | ||||||
|         reject(new TypeError("Failed to fetch: " + err.finalUrl)); |  | ||||||
|       }, |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const httpMethods = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "TRACE", "OPTIONS", "CONNECT"] as const; |  | ||||||
|  |  | ||||||
| // a ts type helper to narrow type |  | ||||||
| function includes<T extends U, U>(array: ReadonlyArray<T>, element: U): element is T { |  | ||||||
|   return array.includes(element as T); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function gmXHRMethod(method: string): (typeof httpMethods)[number] { |  | ||||||
|   if (includes(httpMethods, method)) { |  | ||||||
|     return method; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   throw new Error(`unsupported http method ${method}`); |  | ||||||
| } |  | ||||||
| @@ -1,145 +0,0 @@ | |||||||
| export function parseRawHeaders(h: string): Headers { |  | ||||||
|   const s = h.trim(); |  | ||||||
|   if (!s) { |  | ||||||
|     return new Headers(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   const array: [string, string][] = s.split("\r\n").map((value) => { |  | ||||||
|     let s = value.split(":"); |  | ||||||
|     return [s[0].trim(), s[1].trim()]; |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   return new Headers(array); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function parseGMResponse(req: Request, res: GM.Response<any>): Response { |  | ||||||
|   return new ResImpl(res.response as Blob, { |  | ||||||
|     statusCode: res.status, |  | ||||||
|     statusText: res.statusText, |  | ||||||
|     headers: parseRawHeaders(res.responseHeaders), |  | ||||||
|     finalUrl: res.finalUrl, |  | ||||||
|     redirected: res.finalUrl === req.url, |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| interface ResInit { |  | ||||||
|   redirected: boolean; |  | ||||||
|   headers: Headers; |  | ||||||
|   statusCode: number; |  | ||||||
|   statusText: string; |  | ||||||
|   finalUrl: string; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| class ResImpl implements Response { |  | ||||||
|   private _bodyUsed: boolean; |  | ||||||
|   private readonly rawBody: Blob; |  | ||||||
|   private readonly init: ResInit; |  | ||||||
|  |  | ||||||
|   readonly body: ReadableStream<Uint8Array> | null; |  | ||||||
|   readonly headers: Headers; |  | ||||||
|   readonly redirected: boolean; |  | ||||||
|   readonly status: number; |  | ||||||
|   readonly statusText: string; |  | ||||||
|   readonly type: ResponseType; |  | ||||||
|   readonly url: string; |  | ||||||
|  |  | ||||||
|   constructor(body: Blob, init: ResInit) { |  | ||||||
|     this.rawBody = body; |  | ||||||
|     this.init = init; |  | ||||||
|  |  | ||||||
|     //this.body = toReadableStream(body); |  | ||||||
|     const { headers, statusCode, statusText, finalUrl, redirected } = init; |  | ||||||
|     this.headers = headers; |  | ||||||
|     this.status = statusCode; |  | ||||||
|     this.statusText = statusText; |  | ||||||
|     this.url = finalUrl; |  | ||||||
|     this.type = "basic"; |  | ||||||
|     this.redirected = redirected; |  | ||||||
|     this._bodyUsed = false; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   get bodyUsed(): boolean { |  | ||||||
|     return this._bodyUsed; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   get ok(): boolean { |  | ||||||
|     return this.status < 300; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   arrayBuffer(): Promise<ArrayBuffer> { |  | ||||||
|     if (this.bodyUsed) { |  | ||||||
|       throw new TypeError("Failed to execute 'arrayBuffer' on 'Response': body stream already read"); |  | ||||||
|     } |  | ||||||
|     this._bodyUsed = true; |  | ||||||
|     return this.rawBody.arrayBuffer(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   blob(): Promise<Blob> { |  | ||||||
|     if (this.bodyUsed) { |  | ||||||
|       throw new TypeError("Failed to execute 'blob' on 'Response': body stream already read"); |  | ||||||
|     } |  | ||||||
|     this._bodyUsed = true; |  | ||||||
|     // `slice` will use empty string as default value, so need to pass all arguments. |  | ||||||
|     return Promise.resolve(this.rawBody.slice(0, this.rawBody.size, this.rawBody.type)); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   clone(): Response { |  | ||||||
|     if (this.bodyUsed) { |  | ||||||
|       throw new TypeError("Failed to execute 'clone' on 'Response': body stream already read"); |  | ||||||
|     } |  | ||||||
|     return new ResImpl(this.rawBody, this.init); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   formData(): Promise<FormData> { |  | ||||||
|     if (this.bodyUsed) { |  | ||||||
|       throw new TypeError("Failed to execute 'formData' on 'Response': body stream already read"); |  | ||||||
|     } |  | ||||||
|     this._bodyUsed = true; |  | ||||||
|     return this.rawBody.text().then(decode); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   async json(): Promise<any> { |  | ||||||
|     if (this.bodyUsed) { |  | ||||||
|       throw new TypeError("Failed to execute 'json' on 'Response': body stream already read"); |  | ||||||
|     } |  | ||||||
|     this._bodyUsed = true; |  | ||||||
|     return JSON.parse(await this.rawBody.text()); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   text(): Promise<string> { |  | ||||||
|     if (this.bodyUsed) { |  | ||||||
|       throw new TypeError("Failed to execute 'text' on 'Response': body stream already read"); |  | ||||||
|     } |  | ||||||
|     this._bodyUsed = true; |  | ||||||
|     return this.rawBody.text(); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function decode(body: string) { |  | ||||||
|   const form = new FormData(); |  | ||||||
|  |  | ||||||
|   body |  | ||||||
|     .trim() |  | ||||||
|     .split("&") |  | ||||||
|     .forEach(function (bytes) { |  | ||||||
|       if (bytes) { |  | ||||||
|         const split = bytes.split("="); |  | ||||||
|         const name = split.shift()?.replace(/\+/g, " "); |  | ||||||
|         const value = split.join("=").replace(/\+/g, " "); |  | ||||||
|         form.append(decodeURIComponent(name!), decodeURIComponent(value)); |  | ||||||
|       } |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|   return form; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| function toReadableStream(value: Blob) { |  | ||||||
|   return new ReadableStream({ |  | ||||||
|     start(controller) { |  | ||||||
|       controller.enqueue(value); |  | ||||||
|       controller.close(); |  | ||||||
|     }, |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
| */ |  | ||||||
| @@ -9,7 +9,7 @@ console.log('script start') | |||||||
|  |  | ||||||
| const search = new Search() | const search = new Search() | ||||||
| // eslint-disable-next-line no-undef | // eslint-disable-next-line no-undef | ||||||
| waitForKeyElements('ongoing-call-button', (element) => { search.createSearchWindow(element) }, false) | waitForKeyElements('div.nav-search', (element) => { search.createSearchWindow(element) }, true) | ||||||
|  |  | ||||||
| const callNotification = new CallNotification() | const callNotification = new CallNotification() | ||||||
| // eslint-disable-next-line no-undef | // eslint-disable-next-line no-undef | ||||||
| @@ -21,4 +21,4 @@ waitForKeyElements('.call-history-list call', (element) => { callHistory.showCal | |||||||
|  |  | ||||||
| const status = new Status() | const status = new Status() | ||||||
| // eslint-disable-next-line no-undef | // eslint-disable-next-line no-undef | ||||||
| waitForKeyElements('wc-account-menu', (element) => { status.showStatus(element) }, false) | waitForKeyElements('#status-change', (element) => { status.showStatus(element) }, false) | ||||||
|   | |||||||
| @@ -1,42 +0,0 @@ | |||||||
| .tapi-search-autocomplete { |  | ||||||
|     /*the container must be positioned relative:*/ |  | ||||||
|     position: relative; |  | ||||||
|     display: inline-block; |  | ||||||
|     margin-right: 20px; |  | ||||||
|   } |  | ||||||
| .tapi-search-autocomplete input { |  | ||||||
|     border: 1px solid transparent; |  | ||||||
|     background-color: #f1f1f1; |  | ||||||
|     /*padding: 10px;*/ |  | ||||||
|     /*font-size: 16px;*/ |  | ||||||
| } |  | ||||||
| .tapi-search-autocomplete input[type=text] { |  | ||||||
|     background-color: #f1f1f1; |  | ||||||
|     width: 100%; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .tapi-search-autocomplete-items { |  | ||||||
|     position: absolute; |  | ||||||
|     border: 1px solid #d4d4d4; |  | ||||||
|     border-bottom: none; |  | ||||||
|     border-top: none; |  | ||||||
|     z-index: 99; |  | ||||||
|     /*position the autocomplete items to be the same width as the container:*/ |  | ||||||
|     top: 100%; |  | ||||||
|     left: 0; |  | ||||||
|     right: 0; |  | ||||||
| } |  | ||||||
| .tapi-search-autocomplete-items div { |  | ||||||
|     padding: 10px; |  | ||||||
|     cursor: pointer; |  | ||||||
|     background-color: #fff; |  | ||||||
|     border-bottom: 1px solid #d4d4d4; |  | ||||||
|     color: #000; |  | ||||||
| } |  | ||||||
| .tapi-search-autocomplete-items div p { |  | ||||||
|     margin: 0; |  | ||||||
| } |  | ||||||
| .tapi-search-autocomplete-items div:hover, .tapi-search-autocomplete-active { |  | ||||||
|     /*when hovering an item:*/ |  | ||||||
|     background-color: #E7E6E6 !important; |  | ||||||
| } |  | ||||||
							
								
								
									
										120
									
								
								src/search.ts
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								src/search.ts
									
									
									
									
									
								
							| @@ -1,8 +1,6 @@ | |||||||
| import './search.css' |  | ||||||
| import { TapiContact } from './tapi-contact' | import { TapiContact } from './tapi-contact' | ||||||
| import { debounce } from './debounce' | import { debounce } from './debounce' | ||||||
| import { fireChangeEvents } from './utils' | import { axios, fireChangeEvents } from './utils' | ||||||
| import GM_fetch from './gm-fetch' |  | ||||||
|  |  | ||||||
| export class Search { | export class Search { | ||||||
|   private currentSearchText = '' |   private currentSearchText = '' | ||||||
| @@ -11,29 +9,39 @@ export class Search { | |||||||
|     console.log('Create TAPI Search') |     console.log('Create TAPI Search') | ||||||
|  |  | ||||||
|     var form = document.createElement('form') |     var form = document.createElement('form') | ||||||
|  |     form.style.width = '200px' | ||||||
|  |     form.style.float = 'right' | ||||||
|  |     form.style.marginRight = '20px' | ||||||
|     form.onsubmit = () => { |     form.onsubmit = () => { | ||||||
|       var items = document.getElementsByClassName('tapi-search-autocomplete-active') |       var items = document.getElementsByClassName('tapi-search-result-selected') | ||||||
|       if (items.length === 0) { |       if (items.length === 0) { | ||||||
|         items = document.getElementsByClassName('tapi-search-autocomplete-item') |         items = document.getElementsByClassName('tapi-search-result') | ||||||
|       } |       } | ||||||
|       if (items.length > 0) { |       if (items.length > 0) { | ||||||
|         this.dial((<HTMLElement>items[0]).dataset.tapiNumber) |         this.dial((<HTMLElement>items[0]).dataset.tapiNumber) | ||||||
|       } else { |  | ||||||
|         this.dial((<HTMLInputElement>document.getElementById('tapiSearchInput')).value) |  | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       return false |       return false | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     var searchBox = document.createElement('div') |     var searchBox = document.createElement('div') | ||||||
|     searchBox.classList.add('tapi-search-autocomplete') |     searchBox.classList.add('contact-search-box') | ||||||
|     searchBox.style.width = '200px' |  | ||||||
|     searchBox.id = 'tapiSearchBox' |     searchBox.id = 'tapiSearchBox' | ||||||
|     form.appendChild(searchBox) |     form.appendChild(searchBox) | ||||||
|  |  | ||||||
|  |     var searchWrapper = document.createElement('div') | ||||||
|  |     searchWrapper.classList.add('search-input-wrapper') | ||||||
|  |     searchWrapper.style.position = 'relative' | ||||||
|  |     searchBox.appendChild(searchWrapper) | ||||||
|  |  | ||||||
|     var search = document.createElement('input') |     var search = document.createElement('input') | ||||||
|     search.id = 'tapiSearchInput' |     search.id = 'tapiSearchInput' | ||||||
|     search.autocomplete = 'off' |     search.autocomplete = 'off' | ||||||
|  |     search.classList.add('padder') | ||||||
|  |     search.classList.add('rounded') | ||||||
|  |     search.classList.add('bg-light') | ||||||
|  |     search.classList.add('no-border') | ||||||
|  |     search.classList.add('contact-search-box') | ||||||
|     search.placeholder = 'TAPI Suche' |     search.placeholder = 'TAPI Suche' | ||||||
|     search.onfocus = () => { this.doSearch() } |     search.onfocus = () => { this.doSearch() } | ||||||
|     search.onkeydown = (ev) => { this.doSearchKeyDown(ev) } |     search.onkeydown = (ev) => { this.doSearchKeyDown(ev) } | ||||||
| @@ -42,15 +50,22 @@ export class Search { | |||||||
|       setTimeout(() => { |       setTimeout(() => { | ||||||
|         console.log('TAPI clear search results') |         console.log('TAPI clear search results') | ||||||
|         this.removeSearchResults() |         this.removeSearchResults() | ||||||
|       }, 250) |       }, 500) | ||||||
|     } |     } | ||||||
|     searchBox.appendChild(search) |     searchWrapper.appendChild(search) | ||||||
|  |  | ||||||
|     element.parentElement.insertBefore(form, element) |     var icon = document.createElement('span') | ||||||
|  |     icon.classList.add('fa') | ||||||
|  |     icon.classList.add('fa-search') | ||||||
|  |     icon.classList.add('form-control-feedback') | ||||||
|  |     icon.style.color = 'grey' | ||||||
|  |     searchWrapper.appendChild(icon) | ||||||
|  |  | ||||||
|  |     element.appendChild(form) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private removeSearchResults () { |   private removeSearchResults () { | ||||||
|     var resultList = document.getElementById('tapi-search-autocomplete-list') |     var resultList = document.getElementById('tapiResults') | ||||||
|     if (resultList) { |     if (resultList) { | ||||||
|       resultList.parentNode.removeChild(resultList) |       resultList.parentNode.removeChild(resultList) | ||||||
|     } |     } | ||||||
| @@ -59,12 +74,12 @@ export class Search { | |||||||
|  |  | ||||||
|   private doSearchKeyDown (ev: KeyboardEvent) { |   private doSearchKeyDown (ev: KeyboardEvent) { | ||||||
|     if (ev.key === 'ArrowUp') { |     if (ev.key === 'ArrowUp') { | ||||||
|       let items = document.getElementsByClassName('tapi-search-autocomplete-active') |       let items = document.getElementsByClassName('tapi-search-result-selected') | ||||||
|       if (items.length > 0) { |       if (items.length > 0) { | ||||||
|         var prev = <Element>items[0].previousSibling |         var prev = <Element>items[0].previousSibling | ||||||
|       } |       } | ||||||
|       if (!prev) { |       if (!prev) { | ||||||
|         items = document.getElementsByClassName('tapi-search-autocomplete-item') |         items = document.getElementsByClassName('tapi-search-result') | ||||||
|         if (items.length > 0) { |         if (items.length > 0) { | ||||||
|           prev = items[items.length - 1] |           prev = items[items.length - 1] | ||||||
|         } |         } | ||||||
| @@ -74,12 +89,12 @@ export class Search { | |||||||
|         prev.scrollIntoView(true) |         prev.scrollIntoView(true) | ||||||
|       } |       } | ||||||
|     } else if (ev.key === 'ArrowDown') { |     } else if (ev.key === 'ArrowDown') { | ||||||
|       let items = document.getElementsByClassName('tapi-search-autocomplete-active') |       let items = document.getElementsByClassName('tapi-search-result-selected') | ||||||
|       if (items.length > 0) { |       if (items.length > 0) { | ||||||
|         var next = <Element>items[0].nextSibling |         var next = <Element>items[0].nextSibling | ||||||
|       } |       } | ||||||
|       if (!next) { |       if (!next) { | ||||||
|         items = document.getElementsByClassName('tapi-search-autocomplete-item') |         items = document.getElementsByClassName('tapi-search-result') | ||||||
|         if (items.length > 0) { |         if (items.length > 0) { | ||||||
|           next = items[0] |           next = items[0] | ||||||
|         } |         } | ||||||
| @@ -103,51 +118,64 @@ export class Search { | |||||||
|       return |       return | ||||||
|     } |     } | ||||||
|     console.log('Searching TAPI') |     console.log('Searching TAPI') | ||||||
|     var response = await GM_fetch('http://cpatapi.cpsrvweb2016.cp-austria.at/search?query=' + encodeURIComponent(searchText)) |     var response = await axios.get<TapiContact[]>('http://cpatapi.cpsrvweb2016.cp-austria.at/search?query=' + encodeURIComponent(searchText)) | ||||||
|     console.log('TAPI Search response', response) |     console.log('TAPI Search response', response) | ||||||
|     var contacts = await response.json() as TapiContact[] |     var contacts = response.data | ||||||
|     console.log('TAPI Contacts', contacts) |     console.log('TAPI Contacts', contacts) | ||||||
|     this.removeSearchResults() |     this.removeSearchResults() | ||||||
|     this.currentSearchText = searchText |     this.currentSearchText = searchText | ||||||
|  |  | ||||||
|     var results = document.createElement('div'); |     var resultList = document.createElement('ul') | ||||||
|     results.setAttribute('id', 'tapi-search-autocomplete-list') |     resultList.id = 'tapiResults' | ||||||
|     results.setAttribute('class', 'tapi-search-autocomplete-items') |     resultList.classList.add('search-nav-absolute') | ||||||
|     document.getElementById('tapiSearchBox').appendChild(results) |     resultList.classList.add('search-nav-ul') | ||||||
|  |     document.getElementById('tapiSearchBox').appendChild(resultList) | ||||||
|  |  | ||||||
|  |     resultList.innerHTML = '' | ||||||
|     contacts.forEach(contact => { |     contacts.forEach(contact => { | ||||||
|       var item = document.createElement('div'); |       var li = document.createElement('li') | ||||||
|       item.setAttribute('class', 'tapi-search-autocomplete-item') |       li.classList.add('tapi-search-result') | ||||||
|       var p = document.createElement('p') |       li.classList.add('search-result') | ||||||
|       p.innerHTML = contact.tD_NAME + '<br>' + contact.tD_MEDIUM + ': ' + contact.tD_NUMBER_TAPI |       li.classList.add('pointer') | ||||||
|       item.appendChild(p) |       li.onmouseover = () => { this.selectResult(li) } | ||||||
|       item.onclick = () => { this.dial(contact.tD_NUMBER_TAPI) } |       li.dataset.tapiNumber = contact.tD_NUMBER_TAPI | ||||||
|       item.onmouseover = () => { this.selectResult(item) } |       li.onclick = () => { this.dial(contact.tD_NUMBER_TAPI) } | ||||||
|       item.dataset.tapiNumber = contact.tD_NUMBER_TAPI |       li.style.listStyle = 'outside none none' // display: flex; align-items: center; | ||||||
|       results.appendChild(item); |  | ||||||
|  |       var resultText = document.createElement('div') | ||||||
|  |       resultText.classList.add('search-result-txt') | ||||||
|  |       li.appendChild(resultText) | ||||||
|  |  | ||||||
|  |       var line1 = document.createElement('div') | ||||||
|  |       line1.appendChild(document.createTextNode(contact.tD_NAME)) | ||||||
|  |       resultText.appendChild(line1) | ||||||
|  |  | ||||||
|  |       var line2 = document.createElement('div') | ||||||
|  |       line2.appendChild(document.createTextNode(contact.tD_MEDIUM + ': ' + contact.tD_NUMBER_TAPI)) | ||||||
|  |       resultText.appendChild(line2) | ||||||
|  |  | ||||||
|  |       resultList.appendChild(li) | ||||||
|     }) |     }) | ||||||
|   }, 200) |   }, 200) | ||||||
|  |  | ||||||
|   private selectResult (item: Element) { |   private selectResult (resultLi: Element) { | ||||||
|     console.log('Select item', item) |     var items = document.getElementsByClassName('tapi-search-result') | ||||||
|     var items = document.getElementsByClassName('tapi-search-autocomplete-active') |     for (var item of items) { | ||||||
|     for (var i of items) { |       item.classList.remove('bg-light') | ||||||
|       i.classList.remove('tapi-search-autocomplete-active') |       item.classList.remove('tapi-search-result-selected') | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     item.classList.add('tapi-search-autocomplete-active') |     resultLi.classList.add('bg-light') | ||||||
|  |     resultLi.classList.add('tapi-search-result-selected') | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private dial (number: string) { |   private dial (number: string) { | ||||||
|     console.log('TAPI Search dialing', number); |     var searchInput = document.getElementsByName('searchByNumberInput') | ||||||
|     var searchInput = document.getElementById('dialpad-input'); |     if (searchInput.length > 0) { | ||||||
|     (<HTMLInputElement>searchInput).value = number; |       (<HTMLInputElement>searchInput[0]).value = number | ||||||
|     (<HTMLInputElement>searchInput).focus; |       searchInput[0].focus() | ||||||
|     fireChangeEvents(searchInput); |  | ||||||
|  |  | ||||||
|     var toaster = document.querySelector('toaster-container'); |       fireChangeEvents(searchInput[0]) | ||||||
|     if (window.getComputedStyle(toaster, null).display == 'none') { |  | ||||||
|       document.getElementById('menuDialer').click(); |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,7 +11,6 @@ | |||||||
|     box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); |     box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); | ||||||
|     z-index: 1; |     z-index: 1; | ||||||
|     color: #000; |     color: #000; | ||||||
|     background-color: #fff; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| .show { | .show { | ||||||
|   | |||||||
							
								
								
									
										116
									
								
								src/status.ts
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								src/status.ts
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | |||||||
| import GM_fetch from './gm-fetch'; |  | ||||||
| import './status.css'; | import './status.css'; | ||||||
|  | import { axios } from './utils'; | ||||||
| import { ZcStatus } from './zc-status'; | import { ZcStatus } from './zc-status'; | ||||||
|  |  | ||||||
| declare function waitForKeyElements(selectorOrFunction: any, callback: any, waitOnce: boolean): any; | declare function waitForKeyElements(selectorOrFunction: any, callback: any, waitOnce: boolean): any; | ||||||
| @@ -18,63 +18,20 @@ export class Status { | |||||||
|     this._statusOff = await GM.getValue('tapi-zc-off', 'menuAvailable'); |     this._statusOff = await GM.getValue('tapi-zc-off', 'menuAvailable'); | ||||||
|     console.log('tapi-zc-user', this._user, 'tapi-zc-enabled', this._enabled, 'tapi-zc-on', this._statusOn, 'tapi-zc-off', this._statusOff); |     console.log('tapi-zc-user', this._user, 'tapi-zc-enabled', this._enabled, 'tapi-zc-on', this._statusOn, 'tapi-zc-off', this._statusOff); | ||||||
|  |  | ||||||
|     this.checkStatus(); |     var div = document.createElement('div'); | ||||||
|  |     div.classList.add('tapi-dropdown'); | ||||||
|  |  | ||||||
|     waitForKeyElements("wc-account-menu > div > ul", (element: HTMLElement) => { this.addZcStatusPopup(element) }, true); |     var button = document.createElement('button'); | ||||||
|  |     button.id = 'tapi-zc-button'; | ||||||
|  |     button.classList.add('btn'); | ||||||
|  |     button.classList.add('btn-default'); | ||||||
|  |     button.innerText = 'ZeitConsens'; | ||||||
|  |     button.onclick = () => { | ||||||
|  |       document.getElementById('tapi-zc-dropdown').classList.toggle('show'); | ||||||
|     } |     } | ||||||
|  |     div.appendChild(button); | ||||||
|   private async checkStatus() { |  | ||||||
|     if (this._enabled) { |  | ||||||
|       try { |  | ||||||
|         var response = await GM_fetch('http://cpatapi.cpsrvweb2016.cp-austria.at/availability/' + encodeURIComponent(this._user)); |  | ||||||
|         if (response.status == 200) { |  | ||||||
|           var status = await response.json() as ZcStatus; |  | ||||||
|           if (this._currentStatus !== status.loggedIn) { |  | ||||||
|             this._currentStatus = status.loggedIn; |  | ||||||
|             console.log('New status, loggedIn', this._currentStatus); |  | ||||||
|             var accMenu = document.getElementsByTagName("wc-account-menu")[0]; |  | ||||||
|             var avatar = accMenu.getElementsByTagName("app-avatar")[0] as HTMLAnchorElement; |  | ||||||
|             avatar.click(); |  | ||||||
|             setTimeout(() => { |  | ||||||
|               var statusId = this._currentStatus ? this._statusOn : this._statusOff; |  | ||||||
|               console.log('Clicking status', statusId); |  | ||||||
|               (document.getElementById(statusId) as HTMLSpanElement).click(); |  | ||||||
|             }, 1000); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       } catch (error) { |  | ||||||
|         console.log(error); |  | ||||||
|       } |  | ||||||
|       setTimeout(() => this.checkStatus(), 30000); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   private addZcStatusPopup(element: HTMLElement) { |  | ||||||
|     var divider = document.createElement('li'); |  | ||||||
|     divider.classList.add('divider'); |  | ||||||
|     divider.classList.add('dropdown-divider'); |  | ||||||
|     element.appendChild(divider); |  | ||||||
|  |  | ||||||
|     var menu = document.createElement('li'); |  | ||||||
|     element.appendChild(menu); |  | ||||||
|  |  | ||||||
|     var link = document.createElement('a'); |  | ||||||
|     link.id = 'tapi-zc-button'; |  | ||||||
|     link.innerText = 'ZeitConsens'; |  | ||||||
|     link.classList.add('dropdown-item'); |  | ||||||
|     link.classList.add('d-flex'); |  | ||||||
|     link.onclick = () => { |  | ||||||
|       document.getElementById('zc-modal').classList.toggle('show'); |  | ||||||
|     } |  | ||||||
|     menu.appendChild(link); |  | ||||||
|  |  | ||||||
|     var html = |     var html = | ||||||
|     '<div role="document" class="modal-dialog">' + |  | ||||||
|     '  <div class="modal-content">' + |  | ||||||
|     '    <div class="modal-header">' + |  | ||||||
|     '      <h4 class="modal-title">ZeitConsens Status</h4><button id="zc-btnClose" type="button" aria-label="Close" class="btn-close"  data-qa="modal-cross"></button>' + |  | ||||||
|     '    </div>' + |  | ||||||
|     '    <div class="modal-body">' + |  | ||||||
|       '<div class="form-group">' + |       '<div class="form-group">' + | ||||||
|       '  <label for="tapi-zc-user">Username</label>' + |       '  <label for="tapi-zc-user">Username</label>' + | ||||||
|       '  <input type="text" class="form-control" name="tapi-zc-user" id="tapi-zc-user">' + |       '  <input type="text" class="form-control" name="tapi-zc-user" id="tapi-zc-user">' + | ||||||
| @@ -88,7 +45,7 @@ export class Status { | |||||||
|       '  </select>' + |       '  </select>' + | ||||||
|       '</div>' + |       '</div>' + | ||||||
|       '<div class="form-group">' + |       '<div class="form-group">' + | ||||||
|     '        <label for="tapi-zc-off">Signed out</label>' + |       '  <label for="tapi-zc-off">Signed in</label>' + | ||||||
|       '  <select id="tapi-zc-off" class="form-control">' + |       '  <select id="tapi-zc-off" class="form-control">' + | ||||||
|       '    <option value="menuAway">Away</option>' + |       '    <option value="menuAway">Away</option>' + | ||||||
|       '    <option value="menuOutofoffice">Do Not Disturb</option>' + |       '    <option value="menuOutofoffice">Do Not Disturb</option>' + | ||||||
| @@ -98,26 +55,17 @@ export class Status { | |||||||
|       '  <label class="i-checks" for="tapi-zc-enabled">' + |       '  <label class="i-checks" for="tapi-zc-enabled">' + | ||||||
|       '    <input type="checkbox" id="tapi-zc-enabled">' + |       '    <input type="checkbox" id="tapi-zc-enabled">' + | ||||||
|       '    <i></i><span>Enabled</span>' + |       '    <i></i><span>Enabled</span>' + | ||||||
|     '      </label>' + |       '</label>' | ||||||
|     '      </div>' + |  | ||||||
|     '    </div>' + |  | ||||||
|     //'    <div class="modal-footer">' + |  | ||||||
|     //'      <button id="zc-btnOk" type="button" class="btn btn-primary" data-qa="modal-ok">OK </button>' + |  | ||||||
|     //'      <button id="zc-btnCancel" type="button" class="btn btn-border" data-qa="modal-close">Cancel </button>' + |  | ||||||
|     //'    </div>' + |  | ||||||
|     '  </div>' + |  | ||||||
|     '</div>'; |     '</div>'; | ||||||
|     var modal = document.createElement('modal-container'); |  | ||||||
|     modal.id = 'zc-modal'; |  | ||||||
|     modal.classList.add('modal'); |  | ||||||
|     modal.classList.add('fade'); |  | ||||||
|     modal.innerHTML = html; |  | ||||||
|     document.getElementsByTagName('body')[0].appendChild(modal); |  | ||||||
|  |  | ||||||
|     var btnClose = document.getElementById('zc-btnClose'); |     var dropdown = document.createElement('div'); | ||||||
|     btnClose.onclick = () => { |     dropdown.classList.add('tapi-dropdown-content'); | ||||||
|       document.getElementById('zc-modal').classList.toggle('show'); |     dropdown.classList.add('panel-body'); | ||||||
|     } |     dropdown.id = 'tapi-zc-dropdown'; | ||||||
|  |     dropdown.innerHTML = html; | ||||||
|  |     div.appendChild(dropdown); | ||||||
|  |  | ||||||
|  |     element.insertBefore(div, element.firstChild); | ||||||
|  |  | ||||||
|     var zcUser = document.getElementById('tapi-zc-user') as HTMLInputElement; |     var zcUser = document.getElementById('tapi-zc-user') as HTMLInputElement; | ||||||
|     zcUser.value = this._user; |     zcUser.value = this._user; | ||||||
| @@ -155,5 +103,27 @@ export class Status { | |||||||
|       console.log('tapi-zc-off', this._statusOff); |       console.log('tapi-zc-off', this._statusOff); | ||||||
|       this._currentStatus = undefined; |       this._currentStatus = undefined; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     this.checkStatus(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private async checkStatus() { | ||||||
|  |     if (this._enabled) { | ||||||
|  |       var response = await axios.get<ZcStatus>('http://cpatapi.cpsrvweb2016.cp-austria.at/availability/' + encodeURIComponent(this._user)); | ||||||
|  |  | ||||||
|  |       if (response.status == 200) { | ||||||
|  |         var status = response.data; | ||||||
|  |         if (this._currentStatus !== status.loggedIn) { | ||||||
|  |           this._currentStatus = status.loggedIn; | ||||||
|  |           console.log('New status, loggedIn', this._currentStatus); | ||||||
|  |           (document.getElementsByClassName("current-status")[0] as HTMLAnchorElement).click(); | ||||||
|  |           setTimeout(() => { | ||||||
|  |             var statusId = this._currentStatus ? this._statusOn : this._statusOff; | ||||||
|  |             (document.getElementById(statusId) as HTMLAnchorElement).click(); | ||||||
|  |           }, 1000); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       setTimeout(() => this.checkStatus(), 10000); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								src/utils.ts
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								src/utils.ts
									
									
									
									
									
								
							| @@ -1,3 +1,23 @@ | |||||||
|  | /** | ||||||
|  |  * @typedef {Object} AxiosResponse | ||||||
|  |  * @property {Object} data | ||||||
|  |  * @property {Object} headers | ||||||
|  |  * @property {Object} config | ||||||
|  |  * @property {Object} request | ||||||
|  |  * @property {number} code | ||||||
|  |  * @property {string} statusText | ||||||
|  |  */ | ||||||
|  | /** | ||||||
|  |  * @typedef {Object} AxiosError | ||||||
|  |  * @property {AxiosResponse} response | ||||||
|  |  */ | ||||||
|  | import axios from 'axios' | ||||||
|  | import adapter from 'axios-userscript-adapter' | ||||||
|  |  | ||||||
|  | axios.defaults.adapter = adapter | ||||||
|  |  | ||||||
|  | export { axios } | ||||||
|  |  | ||||||
| export function extractNumber (s: string) { | export function extractNumber (s: string) { | ||||||
|   var match = /(\+?[0-9]{4,})/.exec(s) |   var match = /(\+?[0-9]{4,})/.exec(s) | ||||||
|   if (!match) { |   if (!match) { | ||||||
|   | |||||||
| @@ -2,8 +2,8 @@ | |||||||
|   "compilerOptions": { |   "compilerOptions": { | ||||||
|     "outDir": "./dist/", |     "outDir": "./dist/", | ||||||
|     "noImplicitAny": true, |     "noImplicitAny": true, | ||||||
|     "module": "ESNext", |     "module": "es6", | ||||||
|     "target": "ES2022", |     "target": "es6", | ||||||
|     "allowJs": true, |     "allowJs": true, | ||||||
|     "moduleResolution": "node" |     "moduleResolution": "node" | ||||||
|   } |   } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user