Compare commits

..

No commits in common. "master" and "v9.1.0" have entirely different histories.

13 changed files with 3934 additions and 3621 deletions

File diff suppressed because it is too large Load Diff

View File

@ -9,8 +9,8 @@ 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',

View File

@ -15,6 +15,8 @@ const webpackConfig = {
}, },
externals: { externals: {
jquery: '$', jquery: '$',
axios: 'axios',
'axios-userscript-adapter': 'axiosGmxhrAdapter'
}, },
module: { module: {
rules: [ rules: [

5327
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{ {
"name": "3cx-tapi", "name": "3cx-tapi",
"description": "3CX CP Tapi and Projectmanager integration", "description": "3CX CP Tapi and Projectmanager integration",
"version": "9.2.2", "version": "9.1.0",
"author": { "author": {
"name": "Daniel Triendl", "name": "Daniel Triendl",
"email": "d.triendl@cp-solutions.at" "email": "d.triendl@cp-solutions.at"
@ -24,32 +24,33 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"chrono-node": "^2.7.7", "axios": "^1.4.0",
"@trim21/gm-fetch": "^0.1.16" "axios-userscript-adapter": "^0.2.0-alpha.2",
"chrono-node": "^2.6.3"
}, },
"devDependencies": { "devDependencies": {
"@types/greasemonkey": "^4.0.7", "@babel/core": "^7.22.5",
"@babel/core": "^7.25.8", "@babel/preset-env": "^7.22.5",
"@babel/preset-env": "^7.25.8", "@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/eslint-plugin": "^8.8.1", "@typescript-eslint/parser": "^5.60.1",
"@typescript-eslint/parser": "^8.8.1", "babel-loader": "^9.1.2",
"babel-loader": "^9.2.1",
"browserslist": "^4.21.9", "browserslist": "^4.21.9",
"css-loader": "^7.1.2", "css-loader": "^6.8.1",
"eslint": "^9.12.0", "eslint": "^8.43.0",
"eslint-plugin-import": "^2.31.0", "eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-node": "11.1.0", "eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "^7.1.0S", "eslint-plugin-promise": "^6.1.1",
"less": "4.2.0", "less": "4.1.3",
"less-loader": "^12.2.0", "less-loader": "^11.1.3",
"style-loader": "^4.0.0", "style-loader": "^3.3.3",
"ts-loader": "^9.5.1", "ts-loader": "^9.4.3",
"typescript": "^5.6.3", "typescript": "^5.1.3",
"userscript-metadata-webpack-plugin": "^0.4.0", "userscript-metadata-webpack-plugin": "^0.4.0",
"webpack": "^5.95.0", "webpack": "^5.88.0",
"webpack-bundle-analyzer": "^4.10.2", "webpack-bundle-analyzer": "^4.9.0",
"webpack-cli": "^5.1.4", "webpack-cli": "^5.1.4",
"webpack-livereload-plugin": "3.0.2", "webpack-livereload-plugin": "3.0.2",
"webpack-merge": "^6.0.1" "webpack-merge": "^5.9.0"
} }
} }

View File

@ -1,7 +1,6 @@
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 '@trim21/gm-fetch'
export class CallHistory { export class CallHistory {
private callerIds: { [number: string]: TapiContact } = {} private callerIds: { [number: string]: TapiContact } = {}
@ -86,10 +85,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

View File

@ -1,6 +1,5 @@
import GM_fetch from '@trim21/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) {
@ -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
View File

@ -0,0 +1,3 @@
declare module 'axios-userscript-adapter'
declare const GM: any

View File

@ -33,9 +33,6 @@
border-bottom: 1px solid #d4d4d4; border-bottom: 1px solid #d4d4d4;
color: #000; color: #000;
} }
.tapi-search-autocomplete-items div p {
margin: 0;
}
.tapi-search-autocomplete-items div:hover, .tapi-search-autocomplete-active { .tapi-search-autocomplete-items div:hover, .tapi-search-autocomplete-active {
/*when hovering an item:*/ /*when hovering an item:*/
background-color: #E7E6E6 !important; background-color: #E7E6E6 !important;

View File

@ -1,8 +1,7 @@
import './search.css' 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 '@trim21/gm-fetch'
export class Search { export class Search {
private currentSearchText = '' private currentSearchText = ''
@ -103,9 +102,9 @@ 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
@ -118,9 +117,8 @@ export class Search {
contacts.forEach(contact => { contacts.forEach(contact => {
var item = document.createElement('div'); var item = document.createElement('div');
item.setAttribute('class', 'tapi-search-autocomplete-item') item.setAttribute('class', 'tapi-search-autocomplete-item')
var p = document.createElement('p') item.appendChild(document.createTextNode(contact.tD_NAME))
p.innerHTML = contact.tD_NAME + '<br>' + contact.tD_MEDIUM + ': ' + contact.tD_NUMBER_TAPI item.appendChild(document.createTextNode(contact.tD_MEDIUM + ': ' + contact.tD_NUMBER_TAPI))
item.appendChild(p)
item.onclick = () => { this.dial(contact.tD_NUMBER_TAPI) } item.onclick = () => { this.dial(contact.tD_NUMBER_TAPI) }
item.onmouseover = () => { this.selectResult(item) } item.onmouseover = () => { this.selectResult(item) }
item.dataset.tapiNumber = contact.tD_NUMBER_TAPI item.dataset.tapiNumber = contact.tD_NUMBER_TAPI

View File

@ -1,6 +1,6 @@
import './status.css'; import './status.css';
import { axios } from './utils';
import { ZcStatus } from './zc-status'; import { ZcStatus } from './zc-status';
import GM_fetch from "@trim21/gm-fetch";
declare function waitForKeyElements(selectorOrFunction: any, callback: any, waitOnce: boolean): any; declare function waitForKeyElements(selectorOrFunction: any, callback: any, waitOnce: boolean): any;
@ -26,18 +26,16 @@ export class Status {
private async checkStatus() { private async checkStatus() {
if (this._enabled) { if (this._enabled) {
try { try {
var response = await GM_fetch('http://cpatapi.cpsrvweb2016.cp-austria.at/availability/' + encodeURIComponent(this._user)); var response = await axios.get<ZcStatus>('http://cpatapi.cpsrvweb2016.cp-austria.at/availability/' + encodeURIComponent(this._user));
if (response.status == 200) { if (response.status == 200) {
var status = await response.json() as ZcStatus; var status = response.data;
if (this._currentStatus !== status.loggedIn) { if (this._currentStatus !== status.loggedIn) {
this._currentStatus = status.loggedIn; this._currentStatus = status.loggedIn;
console.log('New status, loggedIn', this._currentStatus); console.log('New status, loggedIn', this._currentStatus);
var accMenu = document.getElementsByTagName("wc-account-menu")[0]; (document.getElementsByTagName("wcavatar")[0] as HTMLAnchorElement).click();
var avatar = accMenu.getElementsByTagName("app-avatar")[0] as HTMLAnchorElement;
avatar.click();
setTimeout(() => { setTimeout(() => {
var statusId = this._currentStatus ? this._statusOn : this._statusOff; var statusId = this._currentStatus ? this._statusOn : this._statusOff;
console.log('Clicking status', statusId);
(document.getElementById(statusId) as HTMLSpanElement).click(); (document.getElementById(statusId) as HTMLSpanElement).click();
}, 1000); }, 1000);
} }
@ -72,7 +70,7 @@ export class Status {
'<div role="document" class="modal-dialog">' + '<div role="document" class="modal-dialog">' +
' <div class="modal-content">' + ' <div class="modal-content">' +
' <div class="modal-header">' + ' <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>' + ' <h4 class="modal-title float-left">ZeitConsens Status</h4><button id="zc-btnClose" type="button" aria-label="Close" class="close float-right"><span aria-hidden="true">×</span></button>' +
' </div>' + ' </div>' +
' <div class="modal-body">' + ' <div class="modal-body">' +
' <div class="form-group">' + ' <div class="form-group">' +
@ -98,13 +96,13 @@ 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>' +
' <div class="modal-footer">' +
' <button id="zc-btnOk" type="button" class="btn btn-primary">OK </button>' +
' <button id="zc-btnCancel" type="button" class="btn btn-light">Cancel </button>' +
' </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>'; '</div>';
var modal = document.createElement('modal-container'); var modal = document.createElement('modal-container');
@ -112,7 +110,7 @@ export class Status {
modal.classList.add('modal'); modal.classList.add('modal');
modal.classList.add('fade'); modal.classList.add('fade');
modal.innerHTML = html; modal.innerHTML = html;
document.getElementsByTagName('body')[0].appendChild(modal); var body = document.getElementsByTagName('body')[0].appendChild(modal);
var btnClose = document.getElementById('zc-btnClose'); var btnClose = document.getElementById('zc-btnClose');
btnClose.onclick = () => { btnClose.onclick = () => {

View File

@ -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) {

View File

@ -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"
} }