jodit
Version:
Jodit is awesome and usefully wysiwyg editor with filebrowser
277 lines (232 loc) • 7.49 kB
text/typescript
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Licensed under GNU General Public License version 2 or later or a commercial license or MIT;
* For GPL see LICENSE-GPL.txt in the project root for license information.
* For MIT see LICENSE-MIT.txt in the project root for license information.
* For commercial licenses see https://xdsoft.net/jodit/commercial/
* Copyright (c) 2013-2019 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { Config } from '../Config';
import { IDictionary } from '../types';
import { IViewBased } from '../types/view';
import { each, extend } from './helpers/';
/**
* @property {object} defaultAjaxOptions A set of key/value pairs that configure the Ajax request. All settings
* are optional
* @property {object} defaultAjaxOptions.headers An object of additional header key/value pairs toWYSIWYG send along
* with requests using the XMLHttpRequest transport. Uses in {@link FileBrowser|FileBrowser}
* and {@link Uploader|Uploader}
* @property {string} defaultAjaxOptions.dataType='json' json or text The type of data that you're expecting back
* from the server. if `json` the return value passes through the `JSON.parse`
* @property {string} defaultAjaxOptions.method='GET' The HTTP method toWYSIWYG use for the request
* (e.g. "POST", "GET", "PUT")
* @property {string} defaultAjaxOptions.url='' A string containing the URL toWYSIWYG which the request is sent.
* @property {string} defaultAjaxOptions.async=true By default, all requests are sent asynchronously (i.e. this is
* set toWYSIWYG true by default). If you need synchronous requests, set this option toWYSIWYG false
* @property {object|string} defaultAjaxOptions.data=null Data toWYSIWYG be sent toWYSIWYG the server.
* It is converted toWYSIWYG a query string, if not already a string. It's appended toWYSIWYG the url for GET-requests.
* @property {string} defaultAjaxOptions.contentType='application/x-www-form-urlencoded; charset=UTF-8'
* When sending data toWYSIWYG the server, use this content type. Default is "application/x-www-form-urlencoded;
* charset=UTF-8", which is fine for most cases
* @property {boolean} defaultAjaxOptions.withCredentials=false
* Enable or disable Access-Control-Allow-Credentials client side. Useful for cross domain requests
* @property {function} defaultAjaxOptions.error=function () {} A function toWYSIWYG be called if the request fails
* @property {function} defaultAjaxOptions.success=function (resp) {} A function toWYSIWYG be called if the
* request succeeds
* @property {function} defaultAjaxOptions.xhr=function () { return new XMLHttpRequest(); } Callback for creating
* the XMLHttpRequest object.
*/
declare const XDomainRequest: any;
export interface AjaxOptions {
dataType?: string;
method?: string;
url?: string;
data:
| IDictionary<string>
| null
| FormData
| string
| IDictionary<string | IDictionary<any>>;
contentType?: string | false;
headers?: IDictionary<string> | null;
withCredentials?: boolean;
queryBuild?: (
this: Ajax,
obj: string | IDictionary<string | object> | FormData,
prefix?: string
) => string | FormData;
xhr?: () => XMLHttpRequest;
}
declare module '../Config' {
interface Config {
defaultAjaxOptions: AjaxOptions;
}
}
Config.prototype.defaultAjaxOptions = {
dataType: 'json',
method: 'GET',
url: '',
data: null,
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
headers: {
'X-REQUESTED-WITH': 'XMLHttpRequest' // compatible with jQuery
},
withCredentials: false,
xhr(): XMLHttpRequest {
const XHR =
typeof XDomainRequest === 'undefined'
? XMLHttpRequest
: XDomainRequest;
return new XHR();
}
} as AjaxOptions;
export class Ajax {
private readonly xhr: XMLHttpRequest;
private success_response_codes = [200, 201, 202];
private __buildParams(
obj: string | IDictionary<string | object> | FormData,
prefix?: string
): string | FormData {
if (
this.options.queryBuild &&
typeof this.options.queryBuild === 'function'
) {
return this.options.queryBuild.call(this, obj, prefix);
}
if (
typeof obj === 'string' ||
((this.jodit.ownerWindow as any).FormData &&
obj instanceof (this.jodit.ownerWindow as any).FormData)
) {
return obj as string | FormData;
}
const str: string[] = [];
let p: string, k: string, v: any;
for (p in obj) {
if (obj.hasOwnProperty(p)) {
k = prefix ? prefix + '[' + p + ']' : p;
v = (obj as IDictionary<string>)[p];
str.push(
typeof v === 'object'
? (this.__buildParams(v, k) as string)
: encodeURIComponent(k) +
'=' +
encodeURIComponent(v as string)
);
}
}
return str.join('&');
}
public status: number;
public response: string;
public options: AjaxOptions;
public jodit: IViewBased;
public abort(): Ajax {
try {
this.xhr.abort();
} catch {}
return this;
}
send(): Promise<any> {
return new Promise(
(
resolve: (this: XMLHttpRequest, resp: object) => any,
reject: (error: Error) => any
) => {
const __parse = (resp: string): object => {
let result: object | null = null;
if (this.options.dataType === 'json') {
result = JSON.parse(resp);
}
if (!result) {
throw new Error('No JSON format');
}
return result;
};
this.xhr.onabort = () => {
reject(new Error(this.xhr.statusText));
};
this.xhr.onerror = () => {
reject(new Error(this.xhr.statusText));
};
this.xhr.ontimeout = () => {
reject(new Error(this.xhr.statusText));
};
this.xhr.onload = () => {
this.response = this.xhr.responseText;
this.status = this.xhr.status;
resolve.call(this.xhr, __parse(this.response) || {});
};
this.xhr.onreadystatechange = () => {
if (this.xhr.readyState === XMLHttpRequest.DONE) {
const resp = this.xhr.responseText;
this.response = resp;
this.status = this.xhr.status;
if (
this.success_response_codes.indexOf(
this.xhr.status
) > -1
) {
resolve.call(this.xhr, __parse(resp));
} else {
reject.call(
this.xhr,
new Error(
this.xhr.statusText ||
this.jodit.i18n('Connection error!')
)
);
}
}
};
this.xhr.withCredentials =
this.options.withCredentials || false;
if (this.options.url) {
this.xhr.open(
this.options.method || 'get',
this.options.url,
true
);
} else {
throw new Error('Need URL for AJAX request');
}
if (this.options.contentType && this.xhr.setRequestHeader) {
this.xhr.setRequestHeader(
'Content-type',
this.options.contentType
);
}
if (this.options.headers && this.xhr.setRequestHeader) {
each(this.options.headers, (key: string, value: string) => {
this.xhr.setRequestHeader(key, value);
});
}
// IE
setTimeout(() => {
this.xhr.send(
this.options.data
? this.__buildParams(this.options.data)
: undefined
);
}, 0);
}
);
}
constructor(editor: IViewBased, options: AjaxOptions) {
this.jodit = editor;
this.options = extend(
true,
{},
Config.prototype.defaultAjaxOptions,
options
) as AjaxOptions;
if (this.options.xhr) {
this.xhr = this.options.xhr();
}
editor &&
editor.events &&
editor.events.on('beforeDestruct', () => {
this.abort();
});
}
}