In the below image (from chrome performance profiling tab for a API call), what is resource loading which costs 719 ms ?
If I visit the network tab, for the same API call, I see only 10.05 seconds.
What is resource loading mean here ? Is there any specific activity the browser does after receiving the data ?
As #wOxxOM stated, buildNetworkRequestDetails is being called from Source Code
From the statement by #Sanju singh :
that statement doesn't tell anything, why it is taking that much time to make the resource available?
I think its necessary to break down exactly what is happening..
Summary:
Activity Browser and Network Activity are using different algorithms for calculating completion. Network Activity is calculating the response times from the request and Activity Browser is calculating the response time + time it took to add it into the WebInspector tracer.
Looking at
/**
* #param {!TimelineModel.TimelineModel.NetworkRequest} request
* #param {!TimelineModel.TimelineModel.TimelineModelImpl} model
* #param {!Components.Linkifier.Linkifier} linkifier
* #return {!Promise<!DocumentFragment>}
*/
static async buildNetworkRequestDetails(request, model, linkifier) {
const target = model.targetByEvent(request.children[0]);
const contentHelper = new TimelineDetailsContentHelper(target, linkifier);
const category = TimelineUIUtils.networkRequestCategory(request);
const color = TimelineUIUtils.networkCategoryColor(category);
contentHelper.addSection(ls`Network request`, color);
if (request.url) {
contentHelper.appendElementRow(ls`URL`, Components.Linkifier.Linkifier.linkifyURL(request.url));
}
// The time from queueing the request until resource processing is finished.
const fullDuration = request.endTime - (request.getStartTime() || -Infinity);
if (isFinite(fullDuration)) {
let textRow = Number.millisToString(fullDuration, true);
// The time from queueing the request until the download is finished. This
// corresponds to the total time reported for the request in the network tab.
const networkDuration = request.finishTime - request.getStartTime();
// The time it takes to make the resource available to the renderer process.
const processingDuration = request.endTime - request.finishTime;
if (isFinite(networkDuration) && isFinite(processingDuration)) {
const networkDurationStr = Number.millisToString(networkDuration, true);
const processingDurationStr = Number.millisToString(processingDuration, true);
const cacheOrNetworkLabel = request.cached() ? ls`load from cache` : ls`network transfer`;
textRow += ls` (${networkDurationStr} ${cacheOrNetworkLabel} + ${processingDurationStr} resource loading)`;
}
contentHelper.appendTextRow(ls`Duration`, textRow);
}
if (request.requestMethod) {
contentHelper.appendTextRow(ls`Request Method`, request.requestMethod);
}
if (typeof request.priority === 'string') {
const priority = PerfUI.NetworkPriorities.uiLabelForNetworkPriority(
/** #type {!Protocol.Network.ResourcePriority} */ (request.priority));
contentHelper.appendTextRow(ls`Priority`, priority);
}
if (request.mimeType) {
contentHelper.appendTextRow(ls`Mime Type`, request.mimeType);
}
let lengthText = '';
if (request.memoryCached()) {
lengthText += ls` (from memory cache)`;
} else if (request.cached()) {
lengthText += ls` (from cache)`;
} else if (request.timing && request.timing.pushStart) {
lengthText += ls` (from push)`;
}
if (request.fromServiceWorker) {
lengthText += ls` (from service worker)`;
}
if (request.encodedDataLength || !lengthText) {
lengthText = `${Number.bytesToString(request.encodedDataLength)}${lengthText}`;
}
contentHelper.appendTextRow(ls`Encoded Data`, lengthText);
if (request.decodedBodyLength) {
contentHelper.appendTextRow(ls`Decoded Body`, Number.bytesToString(request.decodedBodyLength));
}
const title = ls`Initiator`;
const sendRequest = request.children[0];
const topFrame = TimelineModel.TimelineModel.TimelineData.forEvent(sendRequest).topFrame();
if (topFrame) {
const link = linkifier.maybeLinkifyConsoleCallFrame(target, topFrame, {tabStop: true});
if (link) {
contentHelper.appendElementRow(title, link);
}
} else {
const initiator = TimelineModel.TimelineModel.TimelineData.forEvent(sendRequest).initiator();
if (initiator) {
const initiatorURL = TimelineModel.TimelineModel.TimelineData.forEvent(initiator).url;
if (initiatorURL) {
const link = linkifier.maybeLinkifyScriptLocation(target, null, initiatorURL, 0, {tabStop: true});
if (link) {
contentHelper.appendElementRow(title, link);
}
}
}
}
if (!request.previewElement && request.url && target) {
request.previewElement = await Components.ImagePreview.ImagePreview.build(
target, request.url, false,
{imageAltText: Components.ImagePreview.ImagePreview.defaultAltTextForImageURL(request.url)});
}
if (request.previewElement) {
contentHelper.appendElementRow(ls`Preview`, request.previewElement);
}
return contentHelper.fragment;
}
We can easily see that the request parameter is of type
`TimelineModel.TimelineModel.NetworkRequest`
NetWorkRequest has the following code:
_didStopRecordingTraceEvents: function()
{
var metadataEvents = this._processMetadataEvents();
this._injectCpuProfileEvents(metadataEvents);
this._tracingModel.tracingComplete();
this._resetProcessingState();
var startTime = 0;
for (var i = 0, length = metadataEvents.page.length; i < length; i++) {
var metaEvent = metadataEvents.page[i];
var process = metaEvent.thread.process();
var endTime = i + 1 < length ? metadataEvents.page[i + 1].startTime : Infinity;
this._currentPage = metaEvent.args["data"] && metaEvent.args["data"]["page"];
for (var thread of process.sortedThreads()) {
if (thread.name() === WebInspector.TimelineModel.WorkerThreadName && !metadataEvents.workers.some(function(e) { return e.args["data"]["workerThreadId"] === thread.id(); }))
continue;
this._processThreadEvents(startTime, endTime, metaEvent.thread, thread);
}
startTime = endTime;
}
this._inspectedTargetEvents.sort(WebInspector.TracingModel.Event.compareStartTime);
this._cpuProfiles = null;
this._buildTimelineRecords();
this._buildGPUTasks();
this._insertFirstPaintEvent();
this._resetProcessingState();
this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordingStopped);
},
We can see that endTime is being calculated from:
metaEvent.thread.process()
We can see that metaEvent.page is being set by:
_processMetadataEvents: function()
{
var metadataEvents = this._tracingModel.devToolsMetadataEvents();
var pageDevToolsMetadataEvents = [];
var workersDevToolsMetadataEvents = [];
for (var event of metadataEvents) {
if (event.name === WebInspector.TimelineModel.DevToolsMetadataEvent.TracingStartedInPage)
pageDevToolsMetadataEvents.push(event);
else if (event.name === WebInspector.TimelineModel.DevToolsMetadataEvent.TracingSessionIdForWorker)
workersDevToolsMetadataEvents.push(event);
}
if (!pageDevToolsMetadataEvents.length) {
// The trace is probably coming not from DevTools. Make a mock Metadata event.
var pageMetaEvent = this._loadedFromFile ? this._makeMockPageMetadataEvent() : null;
if (!pageMetaEvent) {
console.error(WebInspector.TimelineModel.DevToolsMetadataEvent.TracingStartedInPage + " event not found.");
return {page: [], workers: []};
}
pageDevToolsMetadataEvents.push(pageMetaEvent);
}
var sessionId = pageDevToolsMetadataEvents[0].args["sessionId"] || pageDevToolsMetadataEvents[0].args["data"]["sessionId"];
this._sessionId = sessionId;
var mismatchingIds = new Set();
/**
* #param {!WebInspector.TracingModel.Event} event
* #return {boolean}
*/
function checkSessionId(event)
{
var args = event.args;
// FIXME: put sessionId into args["data"] for TracingStartedInPage event.
if (args["data"])
args = args["data"];
var id = args["sessionId"];
if (id === sessionId)
return true;
mismatchingIds.add(id);
return false;
}
var result = {
page: pageDevToolsMetadataEvents.filter(checkSessionId).sort(WebInspector.TracingModel.Event.compareStartTime),
workers: workersDevToolsMetadataEvents.filter(checkSessionId).sort(WebInspector.TracingModel.Event.compareStartTime)
};
if (mismatchingIds.size)
WebInspector.console.error("Timeline recording was started in more than one page simultaneously. Session id mismatch: " + this._sessionId + " and " + mismatchingIds.valuesArray() + ".");
return result;
}
It's a beginner question so don't be to hard to me.
Example:
A,B,C,D, ..
I need to convert this string to the following output in VSCode
enum id name
{
value(0; A) { Caption = 'A'; }
value(1; B) { Caption = 'B'; }
value(2; C) { Caption = 'C'; }
value(3; D) { Caption = 'D'; }
}
I can read the selection and split it into separate tokens.
But I'm stuck when it comes to writing it back to my line.
My Code:
'use strict';
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
//import * as vscode from 'vscode';
import { window, commands, Disposable, ExtensionContext, StatusBarAlignment, StatusBarItem, TextDocument, TextEditor, ViewColumn, workspace, TextLine, TextEdit, Uri, Position } from 'vscode';
import { stringify } from 'querystring';
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: ExtensionContext) {
console.log('"Cg Helper" is now active!');
let cgHelper = new CgALHelper;
let disp = commands.registerCommand('extension.convertSelection2Enum', () =>{
cgHelper.convertSelection2Enum(window.activeTextEditor);
})
context.subscriptions.push(disp);
}
// this method is called when your extension is deactivated
export function deactivate() {
}
class CgALHelper
{
public convertSelection2Enum(editor: TextEditor)
{
this.convertTextLine2Enum(editor);
}
public convertInputText2Enum()
{
}
private convertTextLine2Enum(editor: TextEditor)
{
let line = editor.document.lineAt(editor.selection.active.line);
if (line != null && line.text != null)
{
window.showInformationMessage(line.text);
let tokens = line.text.split(',');
if (tokens[0] != null && tokens[0] != '' && tokens.length != 0 )
{
tokens.forEach(tok => {
// I'm stuck here !
});
} else
window.showErrorMessage('nothing to convert');
} else
window.showErrorMessage('Nothing to convert');
}
}
You want to construct a SnippetString. Snippet strings can be constructed incrementally:
const snippet = new vscode.SnippetString();
snippet.appendText('enum id name {');
tokens.forEach(tok => {
snippet.appendText(` value(0; ${tok}) { Caption = '${tok}'; }`)
});
snippet.appendText('}');
Then apply the snippet to the editor using TextEditor.insertSnippet:
editor.insertSnippet(snippet);
I am trying to draw an ellipse on a map made using react-leaflet, which has built-in support for circles and rectangles.
To achieve this, I am using code to produce an ellipse in (non-react) leaflet from here, that I have adapted and pasted below:
import * as L from 'leaflet';
L.SVG.include ({
_updateEllipse: function (layer) {
var // c = layer._point,
rx = layer._radiusX,
ry = layer._radiusY,
phi = layer._tiltDeg,
endPoint = layer._endPointParams;
var d = 'M' + endPoint.x0 + ',' + endPoint.y0 +
'A' + rx + ',' + ry + ',' + phi + ',' +
endPoint.largeArc + ',' + endPoint.sweep + ',' +
endPoint.x1 + ',' + endPoint.y1 + ' z';
this._setPath(layer, d);
}
});
L.Canvas.include ({
_updateEllipse: function (layer) {
if (layer._empty()) { return; }
var p = layer._point,
ctx = this._ctx,
r = layer._radiusX,
s = (layer._radiusY || r) / r;
this._drawnLayers[layer._leaflet_id] = layer;
ctx.save();
ctx.translate(p.x, p.y);
if (layer._tilt !== 0) {
ctx.rotate( layer._tilt );
}
if (s !== 1) {
ctx.scale(1, s);
}
ctx.beginPath();
ctx.arc(0, 0, r, 0, Math.PI * 2);
ctx.restore();
this._fillStroke(ctx, layer);
},
});
L.Ellipse = L.Path.extend({
options: {
fill: true,
startAngle: 0,
endAngle: 359.9
},
initialize: function (latlng, radii, tilt, options) {
L.setOptions(this, options);
this._latlng = L.latLng(latlng);
if (tilt) {
this._tiltDeg = tilt;
} else {
this._tiltDeg = 0;
}
if (radii) {
this._mRadiusX = radii[0];
this._mRadiusY = radii[1];
}
},
setRadius: function (radii) {
this._mRadiusX = radii[0];
this._mRadiusY = radii[1];
return this.redraw();
},
getRadius: function () {
return new L.point(this._mRadiusX, this._mRadiusY);
},
setTilt: function (tilt) {
this._tiltDeg = tilt;
return this.redraw();
},
getBounds: function () {
// TODO respect tilt (bounds are too big)
var lngRadius = this._getLngRadius(),
latRadius = this._getLatRadius(),
latlng = this._latlng;
return new L.LatLngBounds(
[latlng.lat - latRadius, latlng.lng - lngRadius],
[latlng.lat + latRadius, latlng.lng + lngRadius]);
},
// #method setLatLng(latLng: LatLng): this
// Sets the position of a circle marker to a new location.
setLatLng: function (latlng) {
this._latlng = L.latLng(latlng);
this.redraw();
return this.fire('move', {latlng: this._latlng});
},
// #method getLatLng(): LatLng
// Returns the current geographical position of the circle marker
getLatLng: function () {
return this._latlng;
},
setStyle: L.Path.prototype.setStyle,
_project: function () {
var lngRadius = this._getLngRadius(),
latRadius = this._getLatRadius(),
latlng = this._latlng,
pointLeft = this._map.latLngToLayerPoint([latlng.lat, latlng.lng - lngRadius]),
pointBelow = this._map.latLngToLayerPoint([latlng.lat - latRadius, latlng.lng]);
this._point = this._map.latLngToLayerPoint(latlng);
this._radiusX = Math.max(this._point.x - pointLeft.x, 1);
this._radiusY = Math.max(pointBelow.y - this._point.y, 1);
this._tilt = Math.PI * this._tiltDeg / 180;
this._endPointParams = this._centerPointToEndPoint();
this._updateBounds();
},
_updateBounds: function () {
// http://math.stackexchange.com/questions/91132/how-to-get-the-limits-of-rotated-ellipse
var sin = Math.sin(this._tilt);
var cos = Math.cos(this._tilt);
var sinSquare = sin * sin;
var cosSquare = cos * cos;
var aSquare = this._radiusX * this._radiusX;
var bSquare = this._radiusY * this._radiusY;
var halfWidth = Math.sqrt(aSquare*cosSquare+bSquare*sinSquare);
var halfHeight = Math.sqrt(aSquare*sinSquare+bSquare*cosSquare);
var w = this._clickTolerance();
var p = [halfWidth + w, halfHeight + w];
this._pxBounds = new L.Bounds(this._point.subtract(p), this._point.add(p));
},
_update: function () {
if (this._map) {
this._updatePath();
}
},
_updatePath: function () {
this._renderer._updateEllipse(this);
},
_getLatRadius: function () {
return (this._mRadiusY / 40075017) * 360;
},
_getLngRadius: function () {
return ((this._mRadiusX / 40075017) * 360) / Math.cos((Math.PI / 180) * this._latlng.lat);
},
_centerPointToEndPoint: function () {
// Convert between center point parameterization of an ellipse
// too SVG's end-point and sweep parameters. This is an
// adaptation of the perl code found here:
// http://commons.oreilly.com/wiki/index.php/SVG_Essentials/Paths
var c = this._point,
rx = this._radiusX,
ry = this._radiusY,
theta2 = (this.options.startAngle + this.options.endAngle) * (Math.PI / 180),
theta1 = this.options.startAngle * (Math.PI / 180),
delta = this.options.endAngle,
phi = this._tiltDeg * (Math.PI / 180);
// Determine start and end-point coordinates
var x0 = c.x + Math.cos(phi) * rx * Math.cos(theta1) +
Math.sin(-phi) * ry * Math.sin(theta1);
var y0 = c.y + Math.sin(phi) * rx * Math.cos(theta1) +
Math.cos(phi) * ry * Math.sin(theta1);
var x1 = c.x + Math.cos(phi) * rx * Math.cos(theta2) +
Math.sin(-phi) * ry * Math.sin(theta2);
var y1 = c.y + Math.sin(phi) * rx * Math.cos(theta2) +
Math.cos(phi) * ry * Math.sin(theta2);
var largeArc = (delta > 180) ? 1 : 0;
var sweep = (delta > 0) ? 1 : 0;
return {'x0': x0, 'y0': y0, 'tilt': phi, 'largeArc': largeArc,
'sweep': sweep, 'x1': x1, 'y1': y1};
},
_empty: function () {
return this._radiusX && this._radiusY && !this._renderer._bounds.intersects(this._pxBounds);
},
_containsPoint : function (p) {
// http://stackoverflow.com/questions/7946187/point-and-ellipse-rotated-position-test-algorithm
var sin = Math.sin(this._tilt);
var cos = Math.cos(this._tilt);
var dx = p.x - this._point.x;
var dy = p.y - this._point.y;
var sumA = cos * dx + sin * dy;
var sumB = sin * dx - cos * dy;
return sumA * sumA / (this._radiusX * this._radiusX) + sumB * sumB / (this._radiusY * this._radiusY) <= 1;
}
});
export const lellipse = function (latlng, radii, tilt, options) {
return new L.Ellipse(latlng, radii, tilt, options);
};
To create an ellipse to use with react-leaflet, I followed the example of Circle in react-leaflet to produce the following Ellipse component:
import PropTypes from 'prop-types'
import { lellipse as LeafletEllipse } from '../l.ellipse';
import Path from './Path'
import children from './propTypes/children'
import latlng from './propTypes/latlng'
import type { LatLng, MapLayerProps, PathOptions } from './types'
type LeafletElement = LeafletEllipse
type Props = {
center: LatLng,
mSemiMajorAxis: number,
mSemiMinorAxis: number,
degreeTiltFromWest: number,
} & MapLayerProps &
PathOptions &
Object
export default class Ellipse extends Path<LeafletElement, Props> {
static propTypes = {
center: latlng.isRequired,
mSemiMajorAxis: PropTypes.number.isRequired,
mSemiMinorAxis: PropTypes.number.isRequired,
degreeTiltFromWest: PropTypes.number.isRequired,
children: children,
}
createLeafletElement(props: Props): LeafletElement {
const { center, mSemiMajorAxis, mSemiMinorAxis, degreeTiltFromWest, ...options } = props
return new LeafletEllipse(center, [mSemiMajorAxis, mSemiMinorAxis], this.getOptions(options))
}
updateLeafletElement(fromProps: Props, toProps: Props) {
if (toProps.center !== fromProps.center) {
this.leafletElement.setLatLng(toProps.center);
}
if (toProps.degreeTiltFromWest !== fromProps.degreeTiltFromWest) {
this.leafletElement.setTilt(toProps.degreeTiltFromWest);
}
if (toProps.mSemiMinorAxis !== fromProps.mSemiMinorAxis || toProps.mSemiMajorAxis !== fromProps.mSemiMajorAxis) {
this.leafletElement.setRadius([toProps.mSemiMajorAxis, toProps.mSemiMinorAxis]);
}
}
}
The problem with the code is that it does not render an ellipse and it does not throw any errors. Could someone suggest how to render an ellipse with react-leaflet? Thanks.
Your createLeafletElement function is missing the tilt parameter. It should be:
createLeafletElement(props) {
const { center, mSemiMajorAxis, mSemiMinorAxis, degreeTiltFromWest, ...options } = props
return new LeafletEllipse(center, [mSemiMajorAxis, mSemiMinorAxis], degreeTiltFromWest, this.getOptions(options))
}
See below for the complete file (in ES6 rather than in typescript, as I find it clearer).
import React, { PropTypes } from 'react';
import { lellipse as LeafletEllipse } from './l.ellipse';
import { Path, withLeaflet } from 'react-leaflet';
class Ellipse extends Path {
static propTypes = {
center: PropTypes.arrayOf(PropTypes.number).isRequired,
mSemiMajorAxis: PropTypes.number.isRequired,
mSemiMinorAxis: PropTypes.number.isRequired,
degreeTiltFromWest: PropTypes.number.isRequired
}
createLeafletElement(props) {
const { center, mSemiMajorAxis, mSemiMinorAxis, degreeTiltFromWest, ...options } = props
return new LeafletEllipse(center, [mSemiMajorAxis, mSemiMinorAxis], degreeTiltFromWest, this.getOptions(options))
}
updateLeafletElement(fromProps, toProps) {
if (toProps.center !== fromProps.center) {
this.leafletElement.setLatLng(toProps.center);
}
if (toProps.degreeTiltFromWest !== fromProps.degreeTiltFromWest) {
this.leafletElement.setTilt(toProps.degreeTiltFromWest);
}
if (toProps.mSemiMinorAxis !== fromProps.mSemiMinorAxis || toProps.mSemiMajorAxis !== fromProps.mSemiMajorAxis) {
this.leafletElement.setRadius([toProps.mSemiMajorAxis, toProps.mSemiMinorAxis]);
}
}
}
export default class withLeaflet(Ellipse);
I am trying create ReactLeafletArc Plugin with animation this is the code
if (!L) {
throw "Leaflet.js not included";
} else if (!arc || !arc.GreatCircle) {
throw "arc.js not included";
} else {
L.Polyline.Arc = function (from, to, options) {
from = L.latLng(from);
to = L.latLng(to);
var vertices = 10;
var arcOptions = {};
if (options) {
if (options.offset) {
arcOptions.offset = options.offset;
delete options.offset;
}
if (options.vertices) {
vertices = options.vertices;
delete options.vertices;
}
}
var generator = new arc.GreatCircle({ x: from.lng, y: from.lat }, { x: to.lng, y: to.lat });
var line = generator.Arc(vertices, arcOptions);
var latLngs = [];
var newLine = L.polyline(line.geometries[0].coords.map(function (c) {
return c.reverse();
}), options);
var totalLength = newLine._path.getTotalLength() * 4;
newLine._path.classList.add('path-start');
newLine._path.style.strokeDashoffset = totalLength;
newLine._path.style.strokeDasharray = totalLength;
setTimeout((function (path) {
return function () {
path.style.strokeDashoffset = 0;
};
})(newLine._path), 200);
return newLine;
};
}
I get error
Uncaught TypeError: Cannot read property 'getTotalLength' of undefined
with console.log(newLine) i can see that there is not _path.
NewClass
_bounds:L.LatLngBounds
_initHooksCalled:true
_latlngs:Array[100]
options:Object
__proto__:NewClass
But if i comment the part
var totalLength = newLine._path.getTotalLength() * 4;
newLine._path.classList.add('path-start');
newLine._path.style.strokeDashoffset = totalLength;
newLine._path.style.strokeDasharray = totalLength;
setTimeout((function (path) {
return function () {
path.style.strokeDashoffset = 0;
};
})(newLine._path), 200);
The line is created without animation and with console.log(newLine) i get this
NewClass
_bounds:L.LatLngBounds
_initHooksCalled:true
_latlngs:Array[100]
_leaflet_id:122
_map:NewClass
_mapToAdd:NewClass
_parts:Array[1]
_path:path
_pxBounds:L.Bounds
_renderer:NewClass
_rings:Array[1]
_zoomAnimated:true
options:Object
__proto__:NewClass
Any suggestion?
How can a xtext editor translate (for example) -> to the latex symbol \rightarrow?
Have a look at the nice feature of autoedit
public class MyDslDefaultAutoEditStrategyProvider extends DefaultAutoEditStrategyProvider {
#Inject
protected Provider<ShortCutEditStrategy> shortCut;
#Override
protected void configureStringLiteral(IEditStrategyAcceptor acceptor) {
acceptor.accept(shortCut.get().configure("->", "\\rightarrow"), IDocument.DEFAULT_CONTENT_TYPE);
}
}
and dont forget the binding
override Class<? extends AbstractEditStrategyProvider> bindAbstractEditStrategyProvider() {
MyDslDefaultAutoEditStrategyProvider
}
It's quite easy using JavaScript. This simple script should help:
replaceText('->', '\rightarrow');
var replaceText = function (search, replaceWith) {
var area = document.getElementById("area");
var getCount = function (str, search) {
return str.split(search).length - 1;
};
if (area.value.indexOf(search) >= 0) {
var start = area.selectionStart;
var end = area.selectionEnd;
var textBefore = area.value.substr(0, end);
var lengthDiff = (replaceWith.length - search.length) * getCount(textBefore, search);
area.value = area.value.replace(search, replaceWith);
area.selectionStart = start + lengthDiff;
area.selectionEnd = end + lengthDiff;
}
};
This full text can be easily adapted for your use- here's a full example.
<textarea id="area"></textarea>
<script>
function keyDownTextField() {
replaceText('->', '\u2192');
}
var replaceText = function (search, replaceWith) {
var area = document.getElementById("area");
var getCount = function (str, search) {
return str.split(search).length - 1;
};
if (area.value.indexOf(search) >= 0) {
var start = area.selectionStart;
var end = area.selectionEnd;
var textBefore = area.value.substr(0, end);
var lengthDiff = (replaceWith.length - search.length) * getCount(textBefore, search);
area.value = area.value.replace(search, replaceWith);
area.selectionStart = start + lengthDiff;
area.selectionEnd = end + lengthDiff;
}
};
document.addEventListener("keydown", keyDownTextField, false);
</script>