Compare commits
	
		
			18 Commits
		
	
	
		
			v7.0.1
			...
			6186b14b16
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6186b14b16 | |||
| f578bd2fe1 | |||
| 933b445ed6 | |||
| bbe20d6351 | |||
| 9e5d93bad2 | |||
| b83cef625a | |||
| ad5c8ece12 | |||
| 0455cb1926 | |||
| 3e33155276 | |||
| de34a6c66e | |||
| a4a346b48d | |||
| cd303869c8 | |||
| 4283ee6b5c | |||
|   | fec9885a64 | ||
|   | 29fc426161 | ||
|   | 231d24b26a | ||
|   | f3693162ab | ||
|   | c09bdd856b | 
							
								
								
									
										9
									
								
								.babelrc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.babelrc.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | module.exports = function (api) { | ||||||
|  |   api.cache(true) | ||||||
|  |  | ||||||
|  |   const presets = ['@babel/preset-env'] | ||||||
|  |  | ||||||
|  |   return { | ||||||
|  |     presets, | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								.browserslistrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.browserslistrc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | > 1% | ||||||
|  | not IE 11 | ||||||
|  | not dead | ||||||
							
								
								
									
										13376
									
								
								3CX_TAPI.user.js
									
									
									
									
									
								
							
							
						
						
									
										13376
									
								
								3CX_TAPI.user.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -5,9 +5,9 @@ module.exports = { | |||||||
|   namespace: 'http://cp-solutions.at', |   namespace: 'http://cp-solutions.at', | ||||||
|   version: pkg.version, |   version: pkg.version, | ||||||
|   author: pkg.author, |   author: pkg.author, | ||||||
|   copyright: 'Copyright 2020 CP Solutions GmbH', |   copyright: 'Copyright 2021 CP Solutions GmbH', | ||||||
|   source: pkg.repository.url, |   source: pkg.repository.url, | ||||||
|   downloadURL: 'http://scootaloo.cp-austria.at/gitlist/3cx_tapi.git/raw/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/webclient*', |     'https://192.168.0.154:5001/webclient*', | ||||||
|     'https://cpsolution.my3cx.at:5001/webclient*' |     'https://cpsolution.my3cx.at:5001/webclient*' | ||||||
| @@ -18,8 +18,10 @@ module.exports = { | |||||||
|     `https://cdn.jsdelivr.net/npm/axios-userscript-adapter@${pkg.dependencies['axios-userscript-adapter']}/dist/axiosGmxhrAdapter.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', | ||||||
|     'GM.notification' |     'GM.notification', | ||||||
|  |     'GM.getValue', | ||||||
|  |     'GM.setValue' | ||||||
|   ], |   ], | ||||||
|   connect: [ |   connect: [ | ||||||
|     'cpatapi.cpsrvweb2016.cp-austria.at' |     'cpatapi.cpsrvweb2016.cp-austria.at' | ||||||
| @@ -1,42 +1,38 @@ | |||||||
| const path = require('path') | const path = require('path') | ||||||
| const webpack = require('webpack') | const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') | ||||||
| 
 | 
 | ||||||
| const webpackConfig = { | const webpackConfig = { | ||||||
|   node: { |  | ||||||
|     Buffer: false |  | ||||||
|   }, |  | ||||||
|   resolve: { |   resolve: { | ||||||
|     extensions: ['.js', '.ts'] |     extensions: ['.js', '.ts'] | ||||||
|   }, |   }, | ||||||
|   // performance: {
 |  | ||||||
|   // hints: false
 |  | ||||||
|   // },
 |  | ||||||
|   optimization: { |   optimization: { | ||||||
|     minimize: false |     minimize: false, | ||||||
|  |     moduleIds: 'named', | ||||||
|   }, |   }, | ||||||
|   entry: './src/js/index.js', |   entry: './src/index.js', | ||||||
|   output: { |   output: { | ||||||
|     path: path.resolve(__dirname, '../dist') |     path: path.resolve(__dirname, '../dist') | ||||||
|   }, |   }, | ||||||
|   externals: { |   externals: { | ||||||
|  |     jquery: '$', | ||||||
|     axios: 'axios', |     axios: 'axios', | ||||||
|     'axios-userscript-adapter': 'axiosGmxhrAdapter' |     'axios-userscript-adapter': 'axiosGmxhrAdapter' | ||||||
|   }, |   }, | ||||||
|   module: { |   module: { | ||||||
|     rules: [ |     rules: [ | ||||||
|       { |       { | ||||||
|  |         use: { | ||||||
|  |           loader: 'babel-loader', | ||||||
|  |         }, | ||||||
|         test: /\.js$/, |         test: /\.js$/, | ||||||
|         exclude: /node_modules/, |  | ||||||
|         loader: 'eslint-loader' |  | ||||||
|       }, |       }, | ||||||
|       { |       { | ||||||
|         test: /\.ts$/, |         test: /\.ts$/, | ||||||
|         exclude: /node_modules/, |  | ||||||
|         loader: 'ts-loader' |         loader: 'ts-loader' | ||||||
|       }, |       }, | ||||||
|       { |       { | ||||||
|         test: /\.less$/, |         test: /\.less$/, | ||||||
|         loader: [ |         use: [ | ||||||
|           'style-loader', |           'style-loader', | ||||||
|           'css-loader', |           'css-loader', | ||||||
|           'less-loader', // 将 Less 编译为 CSS
 |           'less-loader', // 将 Less 编译为 CSS
 | ||||||
| @@ -44,16 +40,14 @@ const webpackConfig = { | |||||||
|       }, |       }, | ||||||
|       { |       { | ||||||
|         test: /\.css$/, |         test: /\.css$/, | ||||||
|         loader: [ |         use: [ | ||||||
|           'style-loader', |           'style-loader', | ||||||
|           'css-loader', |           'css-loader', | ||||||
|         ] |         ] | ||||||
|       } |       } | ||||||
|     ] |     ] | ||||||
|   }, |   }, | ||||||
|   plugins: [ |   plugins: process.env.npm_config_report ? [new BundleAnalyzerPlugin()] : [], | ||||||
|     new webpack.HashedModuleIdsPlugin() |  | ||||||
|   ] |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports = webpackConfig | module.exports = webpackConfig | ||||||
							
								
								
									
										37
									
								
								config/webpack.config.dev.cjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								config/webpack.config.dev.cjs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | const path = require('path') | ||||||
|  | const { merge } = require('webpack-merge') | ||||||
|  | const LiveReloadPlugin = require('webpack-livereload-plugin') | ||||||
|  | const UserScriptMetaDataPlugin = require('userscript-metadata-webpack-plugin') | ||||||
|  |  | ||||||
|  | const metadata = require('./metadata.cjs') | ||||||
|  | const webpackConfig = require('./webpack.config.base.cjs') | ||||||
|  |  | ||||||
|  | metadata.require.push( | ||||||
|  |   'file://' + path.resolve(__dirname, '../dist/index.prod.user.js') | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const cfg = merge(webpackConfig, { | ||||||
|  |   entry: { | ||||||
|  |     prod: webpackConfig.entry, | ||||||
|  |     dev: path.resolve(__dirname, './empty.cjs'), | ||||||
|  |   }, | ||||||
|  |   output: { | ||||||
|  |     filename: 'index.[name].user.js', | ||||||
|  |     path: path.resolve(__dirname, '../dist'), | ||||||
|  |   }, | ||||||
|  |   devtool: 'inline-source-map', | ||||||
|  |   watch: true, | ||||||
|  |   watchOptions: { | ||||||
|  |     ignored: /node_modules/, | ||||||
|  |   }, | ||||||
|  |   plugins: [ | ||||||
|  |     new LiveReloadPlugin({ | ||||||
|  |       delay: 500, | ||||||
|  |     }), | ||||||
|  |     new UserScriptMetaDataPlugin({ | ||||||
|  |       metadata, | ||||||
|  |     }), | ||||||
|  |   ], | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | module.exports = cfg | ||||||
| @@ -1,43 +0,0 @@ | |||||||
| const path = require("path"); |  | ||||||
| const { merge } = require("webpack-merge"); |  | ||||||
| const BundleAnalyzerPlugin = require("webpack-bundle-analyzer") |  | ||||||
|   .BundleAnalyzerPlugin; |  | ||||||
| const LiveReloadPlugin = require("webpack-livereload-plugin"); |  | ||||||
| const UserScriptMetaDataPlugin = require("userscript-metadata-webpack-plugin"); |  | ||||||
| const metadata = require("./metadata"); |  | ||||||
|  |  | ||||||
| const webpackConfig = require("./webpack.config.base"); |  | ||||||
|  |  | ||||||
| metadata.require.push( |  | ||||||
|   "file://" + path.resolve(__dirname, "../dist/index.prod.user.js") |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| const cfg = merge(webpackConfig, { |  | ||||||
|   entry: { |  | ||||||
|     prod: webpackConfig.entry, |  | ||||||
|     dev: path.resolve(__dirname, "./empty.js"), |  | ||||||
|   }, |  | ||||||
|   output: { |  | ||||||
|     filename: "index.[name].user.js", |  | ||||||
|     path: path.resolve(__dirname, "../dist"), |  | ||||||
|   }, |  | ||||||
|   devtool: "inline-source-map", |  | ||||||
|   watch: true, |  | ||||||
|   watchOptions: { |  | ||||||
|     ignored: /node_modules/, |  | ||||||
|   }, |  | ||||||
|   plugins: [ |  | ||||||
|     new LiveReloadPlugin({ |  | ||||||
|       delay: 500, |  | ||||||
|     }), |  | ||||||
|     new UserScriptMetaDataPlugin({ |  | ||||||
|       metadata, |  | ||||||
|     }), |  | ||||||
|   ], |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| if (process.env.npm_config_report) { |  | ||||||
|   cfg.plugins.push(new BundleAnalyzerPlugin()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| module.exports = cfg; |  | ||||||
							
								
								
									
										19
									
								
								config/webpack.config.production.cjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								config/webpack.config.production.cjs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | const { merge } = require('webpack-merge') | ||||||
|  | const UserScriptMetaDataPlugin = require('userscript-metadata-webpack-plugin') | ||||||
|  |  | ||||||
|  | const metadata = require('./metadata.cjs') | ||||||
|  | const webpackConfig = require('./webpack.config.base.cjs') | ||||||
|  |  | ||||||
|  | const cfg = merge(webpackConfig, { | ||||||
|  |   mode: 'production', | ||||||
|  |   output: { | ||||||
|  |     filename: metadata.name + '.prod.user.js', | ||||||
|  |   }, | ||||||
|  |   plugins: [ | ||||||
|  |     new UserScriptMetaDataPlugin({ | ||||||
|  |       metadata, | ||||||
|  |     }), | ||||||
|  |   ], | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | module.exports = cfg | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| const { merge } = require("webpack-merge"); |  | ||||||
| const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin |  | ||||||
|  |  | ||||||
| const UserScriptMetaDataPlugin = require('userscript-metadata-webpack-plugin') |  | ||||||
| const metadata = require('./metadata') |  | ||||||
|  |  | ||||||
| const webpackConfig = require('./webpack.config.base') |  | ||||||
| const cfg = merge({}, webpackConfig, { |  | ||||||
|   output: { |  | ||||||
|     filename: 'index.prod.user.js' |  | ||||||
|   }, |  | ||||||
|   plugins: [ |  | ||||||
|     new UserScriptMetaDataPlugin({ |  | ||||||
|       metadata |  | ||||||
|     }) |  | ||||||
|   ] |  | ||||||
| }) |  | ||||||
|  |  | ||||||
| if (process.env.npm_config_report) { |  | ||||||
|   cfg.plugins.push(new BundleAnalyzerPlugin()) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| module.exports = cfg |  | ||||||
							
								
								
									
										15469
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										15469
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										72
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,59 +1,57 @@ | |||||||
| { | { | ||||||
|   "name": "3cp-tapi", |   "name": "3cx-tapi", | ||||||
|   "description": "Build your UserScript with webpack", |   "description": "3CX CP Tapi and Projectmanager integration", | ||||||
|   "version": "7.0.1", |   "version": "9.0.1", | ||||||
|   "author": { |   "author": { | ||||||
|     "name": "Daniel Triendl", |     "name": "Daniel Triendl", | ||||||
|     "email": "d.triendl@cp-solutions.at" |     "email": "d.triendl@cp-solutions.at" | ||||||
|   }, |   }, | ||||||
|   "browserslist": [ |  | ||||||
|     "last 2 version", |  | ||||||
|     "> 1%" |  | ||||||
|   ], |  | ||||||
|   "eslintIgnore": [ |   "eslintIgnore": [ | ||||||
|     "dist/*.js" |     "dist/*.js", | ||||||
|  |     "node_modules" | ||||||
|   ], |   ], | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "lint": "eslint src", |     "lint": "eslint --ext .ts,.js src", | ||||||
|     "preversion": "npm run lint", |     "preversion": "npm run lint", | ||||||
|     "postversion": "git push --follow-tags", |     "postversion": "git push --follow-tags", | ||||||
|     "anylize": "npm_config_report=true npm run build", |     "anylize": "npm_config_report=true npm run build", | ||||||
|     "build": "webpack --mode production --config config/webpack.config.production.js", |     "build": "webpack --mode production --config config/webpack.config.production.cjs", | ||||||
|     "dev": "webpack --mode development --config config/webpack.config.dev.js" |     "dev": "webpack --mode development --config config/webpack.config.dev.cjs" | ||||||
|   }, |   }, | ||||||
|   "repository": { |   "repository": { | ||||||
|     "type": "git", |     "type": "git", | ||||||
|     "url": "http://scootaloo.cp-austria.at/gitlist/3cx_tapi.git" |     "url": "https://source.cp-austria.at/git/CPATRD/3cx_tapi.git" | ||||||
|   }, |   }, | ||||||
|   "private": true, |   "private": true, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "axios": "0.20.0", |     "axios": "0.21.1", | ||||||
|     "axios-userscript-adapter": "0.0.7", |     "axios-userscript-adapter": "0.1.4", | ||||||
|     "chrono-node": "2.1.9", |     "chrono-node": "^2.3.0" | ||||||
|     "jquery": "3.5.1" |  | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@typescript-eslint/eslint-plugin": "4.3.0", |     "@babel/core": "7.14.6", | ||||||
|     "@typescript-eslint/parser": "4.3.0", |     "@babel/preset-env": "7.14.5", | ||||||
|     "css-loader": "4.3.0", |     "@typescript-eslint/eslint-plugin": "4.27.0", | ||||||
|     "eslint": "7.10.0", |     "@typescript-eslint/parser": "4.27.0", | ||||||
|     "eslint-config-standard": "14.1.1", |     "babel-loader": "8.2.2", | ||||||
|     "eslint-loader": "4.0.2", |     "browserslist": "4.16.6", | ||||||
|     "eslint-plugin-import": "2.22.1", |     "css-loader": "5.2.6", | ||||||
|  |     "eslint": "7.29.0", | ||||||
|  |     "eslint-config-standard": "16.0.3", | ||||||
|  |     "eslint-plugin-import": "2.23.4", | ||||||
|     "eslint-plugin-node": "11.1.0", |     "eslint-plugin-node": "11.1.0", | ||||||
|     "eslint-plugin-promise": "4.2.1", |     "eslint-plugin-promise": "5.1.0", | ||||||
|     "eslint-plugin-standard": "4.0.1", |     "eslint-plugin-standard": "4.1.0", | ||||||
|     "less": "3.12.2", |     "less": "4.1.1", | ||||||
|     "less-loader": "7.0.1", |     "less-loader": "10.0.0", | ||||||
|     "style-loader": "1.2.1", |     "style-loader": "2.0.0", | ||||||
|     "ts-loader": "8.0.4", |     "ts-loader": "9.2.3", | ||||||
|     "typescript": "4.0.3", |     "typescript": "4.3.4", | ||||||
|     "userscript-metadata-webpack-plugin": "0.0.6", |     "userscript-metadata-webpack-plugin": "0.1.0", | ||||||
|     "webpack": "4.44.2", |     "webpack": "5.39.1", | ||||||
|     "webpack-bundle-analyzer": "3.9.0", |     "webpack-bundle-analyzer": "4.4.2", | ||||||
|     "webpack-cli": "3.3.12", |     "webpack-cli": "4.7.2", | ||||||
|     "webpack-dev-server": "^3.11.0", |     "webpack-livereload-plugin": "3.0.1", | ||||||
|     "webpack-livereload-plugin": "2.3.0", |     "webpack-merge": "5.8.0" | ||||||
|     "webpack-merge": "5.1.4" |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -43,11 +43,11 @@ npm run build | |||||||
| ## distribution | ## distribution | ||||||
|  |  | ||||||
| ``` | ``` | ||||||
| cp dist/index.prod.user.js 3CX_TAPI.user.js | cp "dist/3CX TAPI.prod.user.js" 3CX_TAPI.user.js | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| And commit 3CX_TAPI.user.js | And commit 3CX_TAPI.user.js | ||||||
|  |  | ||||||
| ## see also | ## see also | ||||||
|  |  | ||||||
| Based on [webpack-userscript-template](https://github.com/Trim21/webpack-userscript-template/. | Based on [webpack-userscript-template](https://github.com/Trim21/webpack-userscript-template/) | ||||||
|   | |||||||
| @@ -6,34 +6,22 @@ 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) { | ||||||
|     if (callerId.tD_NAME !== '') { |     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 !== '') { | ||||||
|       var text = span.textContent |       var text = span.textContent | ||||||
|       span.textContent = callerId.tD_NAME |       span.textContent = callerId.tD_NAME + ' ' + callerId.tD_NUMBER | ||||||
|       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) |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private showTimeManager (call: HTMLElement, date: string, callerId: TapiContact) { |   private showTimeManager (call: HTMLElement, date: string, callerId: TapiContact) { | ||||||
|     if (!callerId.tD_ID) { |  | ||||||
|       return |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     var dateParts = date.match(/^(?<date>.*), (?<duration>[0-9]{2}:[0-9]{2}:[0-9]{2})$/) |     var dateParts = date.match(/^(?<date>.*), (?<duration>[0-9]{2}:[0-9]{2}:[0-9]{2})$/) | ||||||
|     var duration = '00:00:00' |     var duration = '00:00:00' | ||||||
|     if (dateParts) { |     if (dateParts) { | ||||||
|       date = dateParts.groups.date |       date = dateParts.groups.date | ||||||
|       duration = dateParts.groups.duration |       duration = dateParts.groups.duration | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     var parsedDate = chrono.de.parseDate(date) |     var parsedDate = chrono.de.parseDate(date) | ||||||
|     if (!parsedDate) { |     if (!parsedDate) { | ||||||
|       parsedDate = chrono.parseDate(date) |       parsedDate = chrono.parseDate(date) | ||||||
| @@ -55,14 +43,19 @@ export class CallHistory { | |||||||
| 
 | 
 | ||||||
|     var length = (parsedDuration.getHours() * 60 + parsedDuration.getMinutes()).toString() |     var length = (parsedDuration.getHours() * 60 + parsedDuration.getMinutes()).toString() | ||||||
| 
 | 
 | ||||||
|     var toolbar = call.querySelector('.wcToolbarTiles') |     var toolbar = call.querySelector('call-history-options') | ||||||
|  |     var href = 'domizil://PM/Zeitbuchung?' | ||||||
|  |     if (callerId && callerId.tD_ID) { | ||||||
|  |       href += 'KontaktId=' + callerId.tD_ID + '&' | ||||||
|  |     } | ||||||
|  |     href += 'connect=' + connect + '&length=' + length | ||||||
|     var a = document.createElement('a') |     var a = document.createElement('a') | ||||||
|     var href = 'domizil://PM/Zeitbuchung?KontaktId=' + callerId.tD_ID + '&connect=' + connect + '&length=' + length |     a.title = 'PM Zeitbuchung' | ||||||
|     a.dataset.domizilLink = href |     a.dataset.domizilLink = href | ||||||
|     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" width="20" height="20">' + |     a.innerHTML = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 559.98 559.98">' + | ||||||
|       '<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' + | ||||||
| @@ -74,13 +67,17 @@ 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('span') |     var span = element.querySelector(':scope > span') | ||||||
|     var number = extractNumber(span.textContent) |     var number = extractNumber(span.textContent) | ||||||
|     if (!number) { |     if (!number) { | ||||||
|  |       this.updateCallHistoryEntry(element, undefined) | ||||||
|       return |       return | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @@ -3,7 +3,7 @@ import { axios, extractNumber } from './utils' | |||||||
| 
 | 
 | ||||||
| export class CallNotification { | export class CallNotification { | ||||||
|   public async showCallNotification (element: HTMLElement) { |   public async showCallNotification (element: HTMLElement) { | ||||||
|     var number = element.dataset.id |     var number = element.querySelector('.callNumber').textContent | ||||||
|     console.log('TAPI call notification', number) |     console.log('TAPI call notification', number) | ||||||
| 
 | 
 | ||||||
|     number = extractNumber(number) |     number = extractNumber(number) | ||||||
| @@ -21,7 +21,7 @@ export class CallNotification { | |||||||
|     if (response.status === 200) { |     if (response.status === 200) { | ||||||
|       var callerId = response.data |       var callerId = response.data | ||||||
|       if (callerId) { |       if (callerId) { | ||||||
|         notification.text = callerId.tD_NAME + '\r\n' + number |         notification.text = callerId.tD_NAME + '\r\n' + number + ' (' + callerId.tD_MEDIUM + ')' | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
							
								
								
									
										0
									
								
								src/js/decs.d.ts → src/decs.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										0
									
								
								src/js/decs.d.ts → src/decs.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -3,12 +3,13 @@ import * as chrono from 'chrono-node' | |||||||
| import { CallHistory } from './call-history' | import { CallHistory } from './call-history' | ||||||
| import { CallNotification } from './call-notification' | import { CallNotification } from './call-notification' | ||||||
| import { Search } from './search' | import { Search } from './search' | ||||||
|  | import { Status } from './status' | ||||||
| 
 | 
 | ||||||
| console.log('script start') | 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('div.nav-search', (element) => { search.createSearchWindow(element) }, true) | waitForKeyElements('ongoing-call-button', (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
 | ||||||
| @@ -17,3 +18,7 @@ waitForKeyElements('call-view', (element) => { callNotification.showCallNotifica | |||||||
| const callHistory = new CallHistory() | const callHistory = new CallHistory() | ||||||
| // eslint-disable-next-line no-undef
 | // eslint-disable-next-line no-undef
 | ||||||
| waitForKeyElements('.call-history-list call', (element) => { callHistory.showCallHistory(element) }, false) | waitForKeyElements('.call-history-list call', (element) => { callHistory.showCallHistory(element) }, false) | ||||||
|  | 
 | ||||||
|  | const status = new Status() | ||||||
|  | // eslint-disable-next-line no-undef
 | ||||||
|  | waitForKeyElements('wc-account-menu', (element) => { status.showStatus(element) }, false) | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| /** |  | ||||||
|  * @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) { |  | ||||||
|   var match = /(\+?[0-9]+)/.exec(s) |  | ||||||
|   if (!match) { |  | ||||||
|     return undefined |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   var number = match[1] |  | ||||||
|   if (number.startsWith('+')) { |  | ||||||
|     number = number.replace('+', '00') |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return number |  | ||||||
| } |  | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| import { TapiContact } from './tapi-contact' | import { TapiContact } from './tapi-contact' | ||||||
| import { debounce } from './debounce' | import { debounce } from './debounce' | ||||||
| import { axios } from './utils' | import { axios, fireChangeEvents } from './utils' | ||||||
| 
 | 
 | ||||||
| export class Search { | export class Search { | ||||||
|   private currentSearchText = '' |   private currentSearchText = '' | ||||||
| @@ -13,9 +13,14 @@ export class Search { | |||||||
|     form.style.float = 'right' |     form.style.float = 'right' | ||||||
|     form.style.marginRight = '20px' |     form.style.marginRight = '20px' | ||||||
|     form.onsubmit = () => { |     form.onsubmit = () => { | ||||||
|       var items = document.getElementsByClassName('tapi-search-result') |       var items = document.getElementsByClassName('tapi-search-result-selected') | ||||||
|  |       if (items.length === 0) { | ||||||
|  |         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 | ||||||
| @@ -58,7 +63,7 @@ export class Search { | |||||||
|     icon.style.color = 'grey' |     icon.style.color = 'grey' | ||||||
|     searchWrapper.appendChild(icon) |     searchWrapper.appendChild(icon) | ||||||
| 
 | 
 | ||||||
|     element.appendChild(form) |     element.parentElement.insertBefore(form, element) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private removeSearchResults () { |   private removeSearchResults () { | ||||||
| @@ -148,7 +153,7 @@ export class Search { | |||||||
|       resultText.appendChild(line1) |       resultText.appendChild(line1) | ||||||
| 
 | 
 | ||||||
|       var line2 = document.createElement('div') |       var line2 = document.createElement('div') | ||||||
|       line2.appendChild(document.createTextNode(contact.tD_NUMBER_TAPI)) |       line2.appendChild(document.createTextNode(contact.tD_MEDIUM + ': ' + contact.tD_NUMBER_TAPI)) | ||||||
|       resultText.appendChild(line2) |       resultText.appendChild(line2) | ||||||
| 
 | 
 | ||||||
|       resultList.appendChild(li) |       resultList.appendChild(li) | ||||||
| @@ -167,28 +172,15 @@ export class Search { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private dial (number: string) { |   private dial (number: string) { | ||||||
|     var searchInput = document.getElementsByName('searchByNumberInput') |     console.log('TAPI Search dialing', number); | ||||||
|     if (searchInput.length > 0) { |     var searchInput = document.getElementById('dialpad-input'); | ||||||
|       (<HTMLInputElement>searchInput[0]).value = number |     (<HTMLInputElement>searchInput).value = number; | ||||||
|       searchInput[0].focus() |     (<HTMLInputElement>searchInput).focus; | ||||||
|  |     fireChangeEvents(searchInput); | ||||||
| 
 | 
 | ||||||
|       this.fireChangeEvents(searchInput[0]) |     var toaster = document.querySelector('toaster-container'); | ||||||
|  |     if (window.getComputedStyle(toaster, null).display == 'none') { | ||||||
|  |       document.getElementById('menuDialer').click(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 |  | ||||||
|   private fireChangeEvents (element: Element) { |  | ||||||
|     var changeEvent = null |  | ||||||
|     changeEvent = document.createEvent('HTMLEvents') |  | ||||||
|     changeEvent.initEvent('input', true, true) |  | ||||||
|     element.dispatchEvent(changeEvent) |  | ||||||
|     console.debug('input event dispatched for element: ' + element.id) |  | ||||||
|     changeEvent = document.createEvent('HTMLEvents') |  | ||||||
|     changeEvent.initEvent('keyup', true, true) |  | ||||||
|     element.dispatchEvent(changeEvent) |  | ||||||
|     console.debug('keyup event dispatched for element: ' + element.id) |  | ||||||
|     changeEvent = document.createEvent('HTMLEvents') |  | ||||||
|     changeEvent.initEvent('change', true, true) |  | ||||||
|     element.dispatchEvent(changeEvent) |  | ||||||
|     console.debug('change event dispatched for element: ' + element.id) |  | ||||||
|   } |  | ||||||
| } | } | ||||||
							
								
								
									
										19
									
								
								src/status.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/status.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | .tapi-dropdown { | ||||||
|  |     position: relative; | ||||||
|  |     display: inline-block; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .tapi-dropdown-content { | ||||||
|  |     display: none; | ||||||
|  |     position: absolute; | ||||||
|  |     min-width: 200px; | ||||||
|  |     overflow: auto; | ||||||
|  |     box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); | ||||||
|  |     z-index: 1; | ||||||
|  |     color: #000; | ||||||
|  |     background-color: #fff; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .show { | ||||||
|  |     display: block; | ||||||
|  | } | ||||||
							
								
								
									
										157
									
								
								src/status.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								src/status.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,157 @@ | |||||||
|  | import './status.css'; | ||||||
|  | import { axios } from './utils'; | ||||||
|  | import { ZcStatus } from './zc-status'; | ||||||
|  |  | ||||||
|  | declare function waitForKeyElements(selectorOrFunction: any, callback: any, waitOnce: boolean): any; | ||||||
|  |  | ||||||
|  | export class Status { | ||||||
|  |   private _user: string; | ||||||
|  |   private _enabled = false; | ||||||
|  |   private _statusOn = 'menuAvailable'; | ||||||
|  |   private _statusOff = 'menuAway'; | ||||||
|  |   private _currentStatus: boolean = undefined; | ||||||
|  |  | ||||||
|  |   public async showStatus(element: HTMLElement) { | ||||||
|  |     this._user = await GM.getValue('tapi-zc-user', ''); | ||||||
|  |     this._enabled = await GM.getValue('tapi-zc-enabled', false); | ||||||
|  |     this._statusOn = await GM.getValue('tapi-zc-on', '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); | ||||||
|  |  | ||||||
|  |     this.checkStatus(); | ||||||
|  |  | ||||||
|  |     waitForKeyElements("wc-account-menu > div > ul", (element: HTMLElement) => { this.addZcStatusPopup(element) }, true); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private async checkStatus() { | ||||||
|  |     if (this._enabled) { | ||||||
|  |       try { | ||||||
|  |         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.getElementsByTagName("wcavatar")[0] as HTMLAnchorElement).click(); | ||||||
|  |             setTimeout(() => { | ||||||
|  |               var statusId = this._currentStatus ? this._statusOn : this._statusOff; | ||||||
|  |               (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 = | ||||||
|  |     '<div role="document" class="modal-dialog">' + | ||||||
|  |     '  <div class="modal-content">' + | ||||||
|  |     '    <div class="modal-header">' + | ||||||
|  |     '      <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 class="modal-body">' + | ||||||
|  |     '      <div class="form-group">' + | ||||||
|  |     '        <label for="tapi-zc-user">Username</label>' + | ||||||
|  |     '        <input type="text" class="form-control" name="tapi-zc-user" id="tapi-zc-user">' + | ||||||
|  |     '      </div>' + | ||||||
|  |     '      <div class="form-group">' + | ||||||
|  |     '        <label for="tapi-zc-on">Signed in</label>' + | ||||||
|  |     '        <select id="tapi-zc-on" class="form-control">' + | ||||||
|  |     '          <option value="menuAvailable">Available</option>' + | ||||||
|  |     '          <option value="menuOutofoffice">Do Not Disturb</option>' + | ||||||
|  |     '          <option value="menuCustom1">Verfügbar DW</option>' + | ||||||
|  |     '        </select>' + | ||||||
|  |     '      </div>' + | ||||||
|  |     '      <div class="form-group">' + | ||||||
|  |     '        <label for="tapi-zc-off">Signed out</label>' + | ||||||
|  |     '        <select id="tapi-zc-off" class="form-control">' + | ||||||
|  |     '          <option value="menuAway">Away</option>' + | ||||||
|  |     '          <option value="menuOutofoffice">Do Not Disturb</option>' + | ||||||
|  |     '        </select>' + | ||||||
|  |     '      </div>' + | ||||||
|  |     '      <div class="checkbox">' + | ||||||
|  |     '        <label class="i-checks" for="tapi-zc-enabled">' + | ||||||
|  |     '          <input type="checkbox" id="tapi-zc-enabled">' + | ||||||
|  |     '          <i></i><span>Enabled</span>' + | ||||||
|  |     '      </label>' | ||||||
|  |     '      </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>'; | ||||||
|  |     var modal = document.createElement('modal-container'); | ||||||
|  |     modal.id = 'zc-modal'; | ||||||
|  |     modal.classList.add('modal'); | ||||||
|  |     modal.classList.add('fade'); | ||||||
|  |     modal.innerHTML = html; | ||||||
|  |     var body = document.getElementsByTagName('body')[0].appendChild(modal); | ||||||
|  |  | ||||||
|  |     var btnClose = document.getElementById('zc-btnClose'); | ||||||
|  |     btnClose.onclick = () => { | ||||||
|  |       document.getElementById('zc-modal').classList.toggle('show'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     var zcUser = document.getElementById('tapi-zc-user') as HTMLInputElement; | ||||||
|  |     zcUser.value = this._user; | ||||||
|  |     zcUser.onchange = () => { | ||||||
|  |       this._user = zcUser.value; | ||||||
|  |       GM.setValue('tapi-zc-user', this._user); | ||||||
|  |       console.log('tapi-zc-user', this._user); | ||||||
|  |       this._currentStatus = undefined; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     var zcEnabled = document.getElementById('tapi-zc-enabled') as HTMLInputElement; | ||||||
|  |     zcEnabled.checked = this._enabled; | ||||||
|  |     zcEnabled.onchange = () => { | ||||||
|  |       this._enabled = zcEnabled.checked; | ||||||
|  |       GM.setValue('tapi-zc-enabled', this._enabled); | ||||||
|  |       console.log('tapi-zc-enabled', this._enabled); | ||||||
|  |       this._currentStatus = undefined; | ||||||
|  |       this.checkStatus(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     var zcOn = document.getElementById('tapi-zc-on') as HTMLSelectElement; | ||||||
|  |     zcOn.value = this._statusOn; | ||||||
|  |     zcOn.onchange = () => { | ||||||
|  |       this._statusOn = zcOn.value; | ||||||
|  |       GM.setValue('tapi-zc-on', this._statusOn); | ||||||
|  |       console.log('tapi-zc-on', this._statusOn); | ||||||
|  |       this._currentStatus = undefined; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     var zcOff = document.getElementById('tapi-zc-off') as HTMLSelectElement; | ||||||
|  |     zcOff.value = this._statusOff; | ||||||
|  |     zcOff.onchange = () => { | ||||||
|  |       this._statusOff = zcOff.value; | ||||||
|  |       GM.setValue('tapi-zc-off', this._statusOff); | ||||||
|  |       console.log('tapi-zc-off', this._statusOff); | ||||||
|  |       this._currentStatus = undefined; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -4,4 +4,5 @@ export interface TapiContact { | |||||||
|   tD_NAME: string; |   tD_NAME: string; | ||||||
|   tD_NUMBER?: string; |   tD_NUMBER?: string; | ||||||
|   tD_NUMBER_TAPI?: string; |   tD_NUMBER_TAPI?: string; | ||||||
|  |   tD_MEDIUM?: string; | ||||||
| } | } | ||||||
							
								
								
									
										49
									
								
								src/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/utils.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | /** | ||||||
|  |  * @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) { | ||||||
|  |   var match = /(\+?[0-9]{4,})/.exec(s) | ||||||
|  |   if (!match) { | ||||||
|  |     return undefined | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   var number = match[1] | ||||||
|  |   if (number.startsWith('+')) { | ||||||
|  |     number = number.replace('+', '00') | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return number | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function fireChangeEvents (element: Element) { | ||||||
|  |   var changeEvent = null | ||||||
|  |   changeEvent = document.createEvent('HTMLEvents') | ||||||
|  |   changeEvent.initEvent('input', true, true) | ||||||
|  |   element.dispatchEvent(changeEvent) | ||||||
|  |   console.debug('input event dispatched for element: ' + element.id) | ||||||
|  |   changeEvent = document.createEvent('HTMLEvents') | ||||||
|  |   changeEvent.initEvent('keyup', true, true) | ||||||
|  |   element.dispatchEvent(changeEvent) | ||||||
|  |   console.debug('keyup event dispatched for element: ' + element.id) | ||||||
|  |   changeEvent = document.createEvent('HTMLEvents') | ||||||
|  |   changeEvent.initEvent('change', true, true) | ||||||
|  |   element.dispatchEvent(changeEvent) | ||||||
|  |   console.debug('change event dispatched for element: ' + element.id) | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								src/zc-status.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/zc-status.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | export class ZcStatus { | ||||||
|  |   public user: string; | ||||||
|  |   public loggedIn: boolean; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user