33 changed files with 1293 additions and 798 deletions
@ -0,0 +1,445 @@ |
|||
///
|
|||
/// Copyright © 2016-2020 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { FormattedData, MapProviders, ReplaceInfo } from '@home/components/widget/lib/maps/map-models'; |
|||
import { |
|||
createLabelFromDatasource, |
|||
hashCode, |
|||
isDefined, |
|||
isDefinedAndNotNull, isFunction, |
|||
isNumber, |
|||
isUndefined, |
|||
padValue |
|||
} from '@core/utils'; |
|||
import { Observable, Observer, of } from 'rxjs'; |
|||
import { map } from 'rxjs/operators'; |
|||
import { Datasource, DatasourceData } from '@shared/models/widget.models'; |
|||
import _ from 'lodash'; |
|||
import { mapProviderSchema, providerSets } from '@home/components/widget/lib/maps/schemes'; |
|||
import { addCondition, mergeSchemes } from '@core/schema-utils'; |
|||
|
|||
export function getProviderSchema(mapProvider: MapProviders, ignoreImageMap = false) { |
|||
const providerSchema = _.cloneDeep(mapProviderSchema); |
|||
if (mapProvider) { |
|||
providerSchema.schema.properties.provider.default = mapProvider; |
|||
} |
|||
if (ignoreImageMap) { |
|||
providerSchema.form[0].items = providerSchema.form[0]?.items.filter(item => item.value !== 'image-map'); |
|||
} |
|||
return mergeSchemes([providerSchema, |
|||
...Object.keys(providerSets)?.map( |
|||
(key: string) => { |
|||
const setting = providerSets[key]; |
|||
return addCondition(setting?.schema, `model.provider === '${setting.name}'`); |
|||
})]); |
|||
} |
|||
|
|||
export function getRatio(firsMoment: number, secondMoment: number, intermediateMoment: number): number { |
|||
return (intermediateMoment - firsMoment) / (secondMoment - firsMoment); |
|||
} |
|||
|
|||
export function interpolateOnLineSegment( |
|||
pointA: FormattedData, |
|||
pointB: FormattedData, |
|||
latKeyName: string, |
|||
lngKeyName: string, |
|||
ratio: number |
|||
): { [key: string]: number } { |
|||
return { |
|||
[latKeyName]: (pointA[latKeyName] + (pointB[latKeyName] - pointA[latKeyName]) * ratio), |
|||
[lngKeyName]: (pointA[lngKeyName] + (pointB[lngKeyName] - pointA[lngKeyName]) * ratio) |
|||
}; |
|||
} |
|||
|
|||
export function findAngle(startPoint: FormattedData, endPoint: FormattedData, latKeyName: string, lngKeyName: string): number { |
|||
if (isUndefined(startPoint) || isUndefined(endPoint)) { |
|||
return 0; |
|||
} |
|||
let angle = -Math.atan2(endPoint[latKeyName] - startPoint[latKeyName], endPoint[lngKeyName] - startPoint[lngKeyName]); |
|||
angle = angle * 180 / Math.PI; |
|||
return parseInt(angle.toFixed(2), 10); |
|||
} |
|||
|
|||
|
|||
export function getDefCenterPosition(position) { |
|||
if (typeof (position) === 'string') { |
|||
return position.split(','); |
|||
} |
|||
if (typeof (position) === 'object') { |
|||
return position; |
|||
} |
|||
return [0, 0]; |
|||
} |
|||
|
|||
|
|||
const imageAspectMap = {}; |
|||
|
|||
function imageLoader(imageUrl: string): Observable<HTMLImageElement> { |
|||
return new Observable((observer: Observer<HTMLImageElement>) => { |
|||
const image = document.createElement('img'); // support IE
|
|||
image.style.position = 'absolute'; |
|||
image.style.left = '-99999px'; |
|||
image.style.top = '-99999px'; |
|||
image.onload = () => { |
|||
observer.next(image); |
|||
document.body.removeChild(image); |
|||
observer.complete(); |
|||
}; |
|||
image.onerror = err => { |
|||
observer.error(err); |
|||
document.body.removeChild(image); |
|||
observer.complete(); |
|||
}; |
|||
document.body.appendChild(image); |
|||
image.src = imageUrl; |
|||
}); |
|||
} |
|||
|
|||
export function aspectCache(imageUrl: string): Observable<number> { |
|||
if (imageUrl?.length) { |
|||
const hash = hashCode(imageUrl); |
|||
let aspect = imageAspectMap[hash]; |
|||
if (aspect) { |
|||
return of(aspect); |
|||
} |
|||
return imageLoader(imageUrl).pipe(map(image => { |
|||
aspect = image.width / image.height; |
|||
imageAspectMap[hash] = aspect; |
|||
return aspect; |
|||
})); |
|||
} |
|||
} |
|||
|
|||
export type TranslateFunc = (key: string, defaultTranslation?: string) => string; |
|||
|
|||
const varsRegex = /\${([^}]*)}/g; |
|||
const linkActionRegex = /<link-act name=['"]([^['"]*)['"]>([^<]*)<\/link-act>/g; |
|||
const buttonActionRegex = /<button-act name=['"]([^['"]*)['"]>([^<]*)<\/button-act>/g; |
|||
|
|||
function createLinkElement(actionName: string, actionText: string): string { |
|||
return `<a href="javascript:void(0);" class="tb-custom-action" data-action-name=${actionName}>${actionText}</a>`; |
|||
} |
|||
|
|||
function createButtonElement(actionName: string, actionText: string) { |
|||
return `<button mat-button class="tb-custom-action" data-action-name=${actionName}>${actionText}</button>`; |
|||
} |
|||
|
|||
function parseTemplate(template: string, data: { $datasource?: Datasource, [key: string]: any }, |
|||
translateFn?: TranslateFunc) { |
|||
let res = ''; |
|||
try { |
|||
if (translateFn) { |
|||
template = translateFn(template); |
|||
} |
|||
template = createLabelFromDatasource(data.$datasource, template); |
|||
|
|||
let match = /\${([^}]*)}/g.exec(template); |
|||
while (match !== null) { |
|||
const variable = match[0]; |
|||
let label = match[1]; |
|||
let valDec = 2; |
|||
const splitValues = label.split(':'); |
|||
if (splitValues.length > 1) { |
|||
label = splitValues[0]; |
|||
valDec = parseFloat(splitValues[1]); |
|||
} |
|||
|
|||
if (label.startsWith('#')) { |
|||
const keyIndexStr = label.substring(1); |
|||
const n = Math.floor(Number(keyIndexStr)); |
|||
if (String(n) === keyIndexStr && n >= 0) { |
|||
label = data.$datasource.dataKeys[n].label; |
|||
} |
|||
} |
|||
|
|||
const value = data[label] || ''; |
|||
let textValue: string; |
|||
if (isNumber(value)) { |
|||
textValue = padValue(value, valDec); |
|||
} else { |
|||
textValue = value; |
|||
} |
|||
template = template.replace(variable, textValue); |
|||
match = /\${([^}]*)}/g.exec(template); |
|||
} |
|||
|
|||
let actionTags: string; |
|||
let actionText: string; |
|||
let actionName: string; |
|||
let action: string; |
|||
|
|||
match = linkActionRegex.exec(template); |
|||
while (match !== null) { |
|||
[actionTags, actionName, actionText] = match; |
|||
action = createLinkElement(actionName, actionText); |
|||
template = template.replace(actionTags, action); |
|||
match = linkActionRegex.exec(template); |
|||
} |
|||
|
|||
match = buttonActionRegex.exec(template); |
|||
while (match !== null) { |
|||
[actionTags, actionName, actionText] = match; |
|||
action = createButtonElement(actionName, actionText); |
|||
template = template.replace(actionTags, action); |
|||
match = buttonActionRegex.exec(template); |
|||
} |
|||
|
|||
// const compiled = _.template(template);
|
|||
// res = compiled(data);
|
|||
res = template; |
|||
} catch (ex) { |
|||
console.log(ex, template); |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
export function processPattern(template: string, data: { $datasource?: Datasource, [key: string]: any }): Array<ReplaceInfo> { |
|||
const replaceInfo = []; |
|||
try { |
|||
const reg = /\${([^}]*)}/g; |
|||
let match = reg.exec(template); |
|||
while (match !== null) { |
|||
const variableInfo: ReplaceInfo = { |
|||
dataKeyName: '', |
|||
valDec: 2, |
|||
variable: '' |
|||
}; |
|||
const variable = match[0]; |
|||
let label = match[1]; |
|||
let valDec = 2; |
|||
const splitValues = label.split(':'); |
|||
if (splitValues.length > 1) { |
|||
label = splitValues[0]; |
|||
valDec = parseFloat(splitValues[1]); |
|||
} |
|||
|
|||
variableInfo.variable = variable; |
|||
variableInfo.valDec = valDec; |
|||
|
|||
if (label.startsWith('#')) { |
|||
const keyIndexStr = label.substring(1); |
|||
const n = Math.floor(Number(keyIndexStr)); |
|||
if (String(n) === keyIndexStr && n >= 0) { |
|||
variableInfo.dataKeyName = data.$datasource.dataKeys[n].label; |
|||
} |
|||
} else { |
|||
variableInfo.dataKeyName = label; |
|||
} |
|||
replaceInfo.push(variableInfo); |
|||
|
|||
match = reg.exec(template); |
|||
} |
|||
} catch (ex) { |
|||
console.log(ex, template); |
|||
} |
|||
return replaceInfo; |
|||
} |
|||
|
|||
export function fillPattern(markerLabelText: string, replaceInfoLabelMarker: Array<ReplaceInfo>, data: FormattedData) { |
|||
let text = createLabelFromDatasource(data.$datasource, markerLabelText); |
|||
if (replaceInfoLabelMarker) { |
|||
for (const variableInfo of replaceInfoLabelMarker) { |
|||
let txtVal = ''; |
|||
if (variableInfo.dataKeyName && isDefinedAndNotNull(data[variableInfo.dataKeyName])) { |
|||
const varData = data[variableInfo.dataKeyName]; |
|||
if (isNumber(varData)) { |
|||
txtVal = padValue(varData, variableInfo.valDec); |
|||
} else { |
|||
txtVal = varData; |
|||
} |
|||
} |
|||
text = text.replace(variableInfo.variable, txtVal); |
|||
} |
|||
} |
|||
return text; |
|||
} |
|||
|
|||
function prepareProcessPattern(template: string, translateFn?: TranslateFunc): string { |
|||
if (translateFn) { |
|||
template = translateFn(template); |
|||
} |
|||
let actionTags: string; |
|||
let actionText: string; |
|||
let actionName: string; |
|||
let action: string; |
|||
|
|||
let match = linkActionRegex.exec(template); |
|||
while (match !== null) { |
|||
[actionTags, actionName, actionText] = match; |
|||
action = createLinkElement(actionName, actionText); |
|||
template = template.replace(actionTags, action); |
|||
match = linkActionRegex.exec(template); |
|||
} |
|||
|
|||
match = buttonActionRegex.exec(template); |
|||
while (match !== null) { |
|||
[actionTags, actionName, actionText] = match; |
|||
action = createButtonElement(actionName, actionText); |
|||
template = template.replace(actionTags, action); |
|||
match = buttonActionRegex.exec(template); |
|||
} |
|||
return template; |
|||
} |
|||
|
|||
export const parseWithTranslation = { |
|||
|
|||
translateFn: null, |
|||
|
|||
translate(key: string, defaultTranslation?: string): string { |
|||
if (this.translateFn) { |
|||
return this.translateFn(key, defaultTranslation); |
|||
} else { |
|||
throw console.error('Translate not assigned'); |
|||
} |
|||
}, |
|||
parseTemplate(template: string, data: object, forceTranslate = false): string { |
|||
return parseTemplate(forceTranslate ? this.translate(template) : template, data, this.translate.bind(this)); |
|||
}, |
|||
prepareProcessPattern(template: string, forceTranslate = false): string { |
|||
return prepareProcessPattern(forceTranslate ? this.translate(template) : template, this.translate.bind(this)); |
|||
}, |
|||
setTranslate(translateFn: TranslateFunc) { |
|||
this.translateFn = translateFn; |
|||
} |
|||
}; |
|||
|
|||
export function parseData(input: DatasourceData[]): FormattedData[] { |
|||
return _(input).groupBy(el => el?.datasource?.entityName) |
|||
.values().value().map((entityArray, i) => { |
|||
const obj: FormattedData = { |
|||
entityName: entityArray[0]?.datasource?.entityName, |
|||
entityId: entityArray[0]?.datasource?.entityId, |
|||
entityType: entityArray[0]?.datasource?.entityType, |
|||
$datasource: entityArray[0]?.datasource, |
|||
dsIndex: i, |
|||
deviceType: null |
|||
}; |
|||
entityArray.filter(el => el.data.length).forEach(el => { |
|||
const indexDate = el?.data?.length ? el.data.length - 1 : 0; |
|||
obj[el?.dataKey?.label] = el?.data[indexDate][1]; |
|||
obj[el?.dataKey?.label + '|ts'] = el?.data[indexDate][0]; |
|||
if (el?.dataKey?.label === 'type') { |
|||
obj.deviceType = el?.data[indexDate][1]; |
|||
} |
|||
}); |
|||
return obj; |
|||
}); |
|||
} |
|||
|
|||
export function parseArray(input: DatasourceData[]): FormattedData[][] { |
|||
return _(input).groupBy(el => el?.datasource?.entityName) |
|||
.values().value().map((entityArray) => |
|||
entityArray[0].data.map((el, i) => { |
|||
const obj: FormattedData = { |
|||
entityName: entityArray[0]?.datasource?.entityName, |
|||
entityId: entityArray[0]?.datasource?.entityId, |
|||
entityType: entityArray[0]?.datasource?.entityType, |
|||
$datasource: entityArray[0]?.datasource, |
|||
dsIndex: i, |
|||
time: el[0], |
|||
deviceType: null |
|||
}; |
|||
entityArray.filter(e => e.data.length && e.data[i]).forEach(entity => { |
|||
obj[entity?.dataKey?.label] = entity?.data[i][1]; |
|||
obj[entity?.dataKey?.label + '|ts'] = entity?.data[0][0]; |
|||
if (entity?.dataKey?.label === 'type') { |
|||
obj.deviceType = entity?.data[0][1]; |
|||
} |
|||
}); |
|||
return obj; |
|||
}) |
|||
); |
|||
} |
|||
|
|||
export function parseFunction(source: any, params: string[] = ['def']): (...args: any[]) => any { |
|||
let res = null; |
|||
if (source?.length) { |
|||
try { |
|||
res = new Function(...params, source); |
|||
} |
|||
catch (err) { |
|||
res = null; |
|||
} |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
export function safeExecute(func: (...args: any[]) => any, params = []) { |
|||
let res = null; |
|||
if (func && typeof (func) === 'function') { |
|||
try { |
|||
res = func(...params); |
|||
} |
|||
catch (err) { |
|||
console.log('error in external function:', err); |
|||
res = null; |
|||
} |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
export function functionValueCalculator(useFunction: boolean, func: (...args: any[]) => any, params = [], defaultValue: any) { |
|||
let res; |
|||
if (useFunction && isDefined(func) && isFunction(func)) { |
|||
try { |
|||
res = func(...params); |
|||
if (!isDefinedAndNotNull(res) || res === '') { |
|||
res = defaultValue; |
|||
} |
|||
} catch (err) { |
|||
res = defaultValue; |
|||
console.log('error in external function:', err); |
|||
} |
|||
} else { |
|||
res = defaultValue; |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
export function calculateNewPointCoordinate(coordinate: number, imageSize: number): number { |
|||
let pointCoordinate = coordinate / imageSize; |
|||
if (pointCoordinate < 0) { |
|||
pointCoordinate = 0; |
|||
} else if (pointCoordinate > 1) { |
|||
pointCoordinate = 1; |
|||
} |
|||
return pointCoordinate; |
|||
} |
|||
|
|||
export function createLoadingDiv(loadingText: string): JQuery<HTMLElement> { |
|||
return $(` |
|||
<div style=" |
|||
z-index: 12; |
|||
position: absolute; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
flex-direction: column; |
|||
align-content: center; |
|||
align-items: center; |
|||
justify-content: center; |
|||
display: flex; |
|||
background: rgba(255,255,255,0.7); |
|||
font-size: 16px; |
|||
font-family: Roboto; |
|||
font-weight: 400; |
|||
text-transform: uppercase; |
|||
"> |
|||
<span>${loadingText}</span> |
|||
</div> |
|||
`);
|
|||
} |
|||
@ -0,0 +1,327 @@ |
|||
///
|
|||
/// Copyright © 2016-2020 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Ace } from 'ace-builds'; |
|||
import { Observable } from 'rxjs/internal/Observable'; |
|||
import { forkJoin, from, of } from 'rxjs'; |
|||
import { map, mergeMap, tap } from 'rxjs/operators'; |
|||
|
|||
let aceDependenciesLoaded = false; |
|||
let aceModule: any; |
|||
|
|||
export function loadAceDependencies(): Observable<any> { |
|||
if (aceDependenciesLoaded) { |
|||
return of(null); |
|||
} else { |
|||
const aceObservables: Observable<any>[] = []; |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/ext-language_tools'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/ext-searchbox'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/mode-java'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/mode-css'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/mode-json'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/mode-javascript'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/mode-text'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/mode-markdown'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/mode-html'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/snippets/java'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/snippets/css'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/snippets/json'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/snippets/javascript'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/snippets/text'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/snippets/markdown'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/snippets/html'))); |
|||
aceObservables.push(from(import('ace-builds/src-noconflict/theme-github'))); |
|||
return forkJoin(aceObservables).pipe( |
|||
tap(() => { |
|||
aceDependenciesLoaded = true; |
|||
}) |
|||
); |
|||
} |
|||
} |
|||
|
|||
export function getAce(): Observable<any> { |
|||
if (aceModule) { |
|||
return of(aceModule); |
|||
} else { |
|||
return from(import('ace')).pipe( |
|||
mergeMap((module) => { |
|||
return loadAceDependencies().pipe( |
|||
map(() => module) |
|||
); |
|||
}), |
|||
tap((module) => { |
|||
aceModule = module; |
|||
}) |
|||
); |
|||
} |
|||
} |
|||
|
|||
export class Range implements Ace.Range { |
|||
|
|||
public start: Ace.Point; |
|||
public end: Ace.Point; |
|||
|
|||
constructor(startRow: number, startColumn: number, endRow: number, endColumn: number) { |
|||
this.start = { |
|||
row: startRow, |
|||
column: startColumn |
|||
}; |
|||
|
|||
this.end = { |
|||
row: endRow, |
|||
column: endColumn |
|||
}; |
|||
} |
|||
|
|||
static fromPoints(start: Ace.Point, end: Ace.Point): Ace.Range { |
|||
return new Range(start.row, start.column, end.row, end.column); |
|||
} |
|||
|
|||
clipRows(firstRow: number, lastRow: number): Ace.Range { |
|||
let end: Ace.Point; |
|||
let start: Ace.Point; |
|||
if (this.end.row > lastRow) { |
|||
end = {row: lastRow + 1, column: 0}; |
|||
} else if (this.end.row < firstRow) { |
|||
end = {row: firstRow, column: 0}; |
|||
} |
|||
|
|||
if (this.start.row > lastRow) { |
|||
start = {row: lastRow + 1, column: 0}; |
|||
} else if (this.start.row < firstRow) { |
|||
start = {row: firstRow, column: 0}; |
|||
} |
|||
return Range.fromPoints(start || this.start, end || this.end); |
|||
} |
|||
|
|||
clone(): Ace.Range { |
|||
return Range.fromPoints(this.start, this.end); |
|||
} |
|||
|
|||
collapseRows(): Ace.Range { |
|||
if (this.end.column === 0) { |
|||
return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row - 1), 0); |
|||
} else { |
|||
return new Range(this.start.row, 0, this.end.row, 0); |
|||
} |
|||
} |
|||
|
|||
compare(row: number, column: number): number { |
|||
if (!this.isMultiLine()) { |
|||
if (row === this.start.row) { |
|||
return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0); |
|||
} |
|||
} |
|||
|
|||
if (row < this.start.row) { |
|||
return -1; |
|||
} |
|||
|
|||
if (row > this.end.row) { |
|||
return 1; |
|||
} |
|||
|
|||
if (this.start.row === row) { |
|||
return column >= this.start.column ? 0 : -1; |
|||
} |
|||
|
|||
if (this.end.row === row) { |
|||
return column <= this.end.column ? 0 : 1; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
compareEnd(row: number, column: number): number { |
|||
if (this.end.row === row && this.end.column === column) { |
|||
return 1; |
|||
} else { |
|||
return this.compare(row, column); |
|||
} |
|||
} |
|||
|
|||
compareInside(row: number, column: number): number { |
|||
if (this.end.row === row && this.end.column === column) { |
|||
return 1; |
|||
} else if (this.start.row === row && this.start.column === column) { |
|||
return -1; |
|||
} else { |
|||
return this.compare(row, column); |
|||
} |
|||
} |
|||
|
|||
comparePoint(p: Ace.Point): number { |
|||
return this.compare(p.row, p.column); |
|||
} |
|||
|
|||
compareRange(range: Ace.Range): number { |
|||
let cmp: number; |
|||
const end = range.end; |
|||
const start = range.start; |
|||
|
|||
cmp = this.compare(end.row, end.column); |
|||
if (cmp === 1) { |
|||
cmp = this.compare(start.row, start.column); |
|||
if (cmp === 1) { |
|||
return 2; |
|||
} else if (cmp === 0) { |
|||
return 1; |
|||
} else { |
|||
return 0; |
|||
} |
|||
} else if (cmp === -1) { |
|||
return -2; |
|||
} else { |
|||
cmp = this.compare(start.row, start.column); |
|||
if (cmp === -1) { |
|||
return -1; |
|||
} else if (cmp === 1) { |
|||
return 42; |
|||
} else { |
|||
return 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
compareStart(row: number, column: number): number { |
|||
if (this.start.row === row && this.start.column === column) { |
|||
return -1; |
|||
} else { |
|||
return this.compare(row, column); |
|||
} |
|||
} |
|||
|
|||
contains(row: number, column: number): boolean { |
|||
return this.compare(row, column) === 0; |
|||
} |
|||
|
|||
containsRange(range: Ace.Range): boolean { |
|||
return this.comparePoint(range.start) === 0 && this.comparePoint(range.end) === 0; |
|||
} |
|||
|
|||
extend(row: number, column: number): Ace.Range { |
|||
const cmp = this.compare(row, column); |
|||
let end: Ace.Point; |
|||
let start: Ace.Point; |
|||
if (cmp === 0) { |
|||
return this; |
|||
} else if (cmp === -1) { |
|||
start = {row, column}; |
|||
} else { |
|||
end = {row, column}; |
|||
} |
|||
return Range.fromPoints(start || this.start, end || this.end); |
|||
} |
|||
|
|||
inside(row: number, column: number): boolean { |
|||
if (this.compare(row, column) === 0) { |
|||
if (this.isEnd(row, column) || this.isStart(row, column)) { |
|||
return false; |
|||
} else { |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
insideEnd(row: number, column: number): boolean { |
|||
if (this.compare(row, column) === 0) { |
|||
if (this.isStart(row, column)) { |
|||
return false; |
|||
} else { |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
insideStart(row: number, column: number): boolean { |
|||
if (this.compare(row, column) === 0) { |
|||
if (this.isEnd(row, column)) { |
|||
return false; |
|||
} else { |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
intersects(range: Ace.Range): boolean { |
|||
const cmp = this.compareRange(range); |
|||
return (cmp === -1 || cmp === 0 || cmp === 1); |
|||
} |
|||
|
|||
isEmpty(): boolean { |
|||
return (this.start.row === this.end.row && this.start.column === this.end.column); |
|||
} |
|||
|
|||
isEnd(row: number, column: number): boolean { |
|||
return this.end.row === row && this.end.column === column; |
|||
} |
|||
|
|||
isEqual(range: Ace.Range): boolean { |
|||
return this.start.row === range.start.row && |
|||
this.end.row === range.end.row && |
|||
this.start.column === range.start.column && |
|||
this.end.column === range.end.column; |
|||
} |
|||
|
|||
isMultiLine(): boolean { |
|||
return (this.start.row !== this.end.row); |
|||
} |
|||
|
|||
isStart(row: number, column: number): boolean { |
|||
return this.start.row === row && this.start.column === column; |
|||
} |
|||
|
|||
moveBy(row: number, column: number): void { |
|||
this.start.row += row; |
|||
this.start.column += column; |
|||
this.end.row += row; |
|||
this.end.column += column; |
|||
} |
|||
|
|||
setEnd(row: number, column: number): void { |
|||
if (typeof row === 'object') { |
|||
this.end.column = (row as Ace.Point).column; |
|||
this.end.row = (row as Ace.Point).row; |
|||
} else { |
|||
this.end.row = row; |
|||
this.end.column = column; |
|||
} |
|||
} |
|||
|
|||
setStart(row: number, column: number): void { |
|||
if (typeof row === 'object') { |
|||
this.start.column = (row as Ace.Point).column; |
|||
this.start.row = (row as Ace.Point).row; |
|||
} else { |
|||
this.start.row = row; |
|||
this.start.column = column; |
|||
} |
|||
} |
|||
|
|||
toScreenRange(session: Ace.EditSession): Ace.Range { |
|||
const screenPosStart = session.documentToScreenPosition(this.start); |
|||
const screenPosEnd = session.documentToScreenPosition(this.end); |
|||
|
|||
return new Range( |
|||
screenPosStart.row, screenPosStart.column, |
|||
screenPosEnd.row, screenPosEnd.column |
|||
); |
|||
} |
|||
|
|||
} |
|||
Loading…
Reference in new issue