import {PlatformEnum} from '../../common/PlatformEnum';
import {Attributes} from '../../common/lang/Attributes';
import {EnumUtil} from '../../common/lang/EnumUtil';
import {Event} from '../../common/lang/Event';
import {Fatal} from '../../common/lang/Fatal';
import {Listeners} from '../../common/lang/Listeners';
import {LoggerUtil} from '../../common/lang/LoggerUtil';
import {StringUtil} from '../../common/lang/StringUtil';
import {Linker} from '../../common/reflect/Linker';
import {Service} from '../../core/Service';
import {EnvironmentService} from '../../core/service/EnvironmentService';
import {BrowserEnum} from '../BrowserEnum';
import {DeviceEnum} from '../DeviceEnum';
import {EventEnum} from '../EventEnum';
import {OrientationEnum} from '../OrientationEnum';
import {SoftwareEnum} from '../SoftwareEnum';
import {ResizeEvent} from '../event/ResizeEvent';
import {BrowserCapability} from './BrowserCapability';
//==========================================================
// 设备控制台。
//==========================================================
export class DeviceService extends Service {
// @attribute
protected _optionSelect = true;
// @attribute
protected _eventResize = new ResizeEvent();
protected _eventVisibility = new Event();
protected _eventOrientation = new Event();
protected _eventUnload = new Event();
// @attribute
protected _agent = null;
protected _capability: BrowserCapability = null;
protected _defineProperties = null;
protected _defineEvents = null;
protected _defineMethods = null;
// @attribute
protected _platformCd = PlatformEnum.Unknown;
protected _deviceCd = DeviceEnum.Unknown;
protected _softwareCd = SoftwareEnum.Unknown;
protected _typeCd = BrowserEnum.Unknown;
protected _orientationCd = OrientationEnum.Horizontal;
protected _supportHtml5 = false;
// @html
protected _hWindow = null;
protected _hDocument = null;
protected _hContainer = null;
// @attribute
protected _requestAnimationFrame = null;
protected _cancelAnimationFrame = null;
// @attribute
protected _cookies = new Attributes();
protected _localStorage = null;
protected _sessionStorage = null;
// 环境控制台
@Linker(EnvironmentService)
protected _environmentConsole: EnvironmentService;
// 监听器集合
public loadListeners = new Listeners();
public loadedListeners = new Listeners();
public unloadListeners = new Listeners();
public resizeListeners = new Listeners();
public visibilityListeners = new Listeners();
public orientationListeners = new Listeners();
public deviceErrorListeners = new Listeners();
//==========================================================
// 构造处理。
//==========================================================
public constructor() {
super();
// 设置属性
this._eventVisibility.code = EventEnum.Visibility;
this._eventOrientation.code = EventEnum.Orientation;
}
//==========================================================
// 获得窗口对象。
//
// @return 窗口对象
//==========================================================
public get htmlWindow() {
return this._hWindow;
}
//==========================================================
// 获得文档对象。
//
// @return 文档对象
//==========================================================
public get htmlDocument() {
return this._hDocument;
}
//==========================================================
// 获得容器对象。
//
// @return 容器对象
//==========================================================
public get htmlContainer() {
return this._hContainer;
}
//==========================================================
// 获得信息。
//
// @return 信息
//==========================================================
public get agent() {
return this._agent;
}
//==========================================================
// 获得浏览器环境信息。
//
// @return 浏览器环境信息
//==========================================================
public get capability(): BrowserCapability {
return this._capability;
}
//==========================================================
// 获得配置选取。
//
// @return 配置选取
//==========================================================
public get optionSelect() {
return this._optionSelect;
}
//==========================================================
// 设置配置选取。
//
// @method
// @param select:Boolean 配置选取
//==========================================================
public set optionSelect(select) {
this._optionSelect = select;
if (this.isBrowser(BrowserEnum.FireFox)) {
this._hContainer.style.MozUserSelect = select ? '' : 'none';
}
}
//===========================================================
// 返回屏幕方向。
//
// @method
// @return 屏幕方向
//===========================================================
public get orientationCd() {
return this._orientationCd;
}
//===========================================================
// 设置屏幕方向。
//
// @method
// @param orientationCd:EOrientation 屏幕方向
//===========================================================
public set setOrientationCd(orientationCd) {
this._orientationCd = orientationCd;
}
//===========================================================
// 判断是否指定浏览器。
//
// @param browserCd:EBrowser 浏览器类型
// @return 是否指定浏览器
//===========================================================
public isBrowser(browserCd) {
return this._typeCd == browserCd;
}
//===========================================================
// 判断是否横屏。
//
// @method
// @return 是否横屏
//===========================================================
public isOrientationHorizontal() {
return this._orientationCd == OrientationEnum.Horizontal;
}
//===========================================================
// 判断是否垂直。
//
// @method
// @return 是否垂直
//===========================================================
public isOrientationVertical() {
return this._orientationCd == OrientationEnum.Vertical;
}
//===========================================================
// 判断是否可见。
//
// @method
// @return 是否可见
//===========================================================
public isVisibility() {
var name = this.definePropertyGet('hidden');
return !window.document[name];
}
//==========================================================
// 获得定义属性集合。
//
// @method
// @return Object 定义属性集合
//==========================================================
public defineProperties() {
return this._defineProperties;
}
//==========================================================
// 获得定义属性。
//
// @method
// @return String 定义属性
//==========================================================
public definePropertyGet(name) {
return this._defineProperties[name];
}
//==========================================================
// 获得定义事件集合。
//
// @method
// @return Object 定义事件集合
//==========================================================
public defineEvents() {
return this._defineEvents;
}
//==========================================================
// 获得定义事件。
//
// @return 定义事件
//==========================================================
public defineEventGet(name) {
return this._defineEvents[name];
}
//==========================================================
// 获得定义函数集合。
//
// @method
// @return Object 定义函数集合
//==========================================================
public defineMethods() {
return this._defineMethods;
}
//==========================================================
// 获得定义函数。
//
// @method
// @return String 定义函数名称
//==========================================================
public defineMethodGet(name) {
return this._defineMethods[name];
}
//==========================================================
// 测试是否支持HTML5规范。
//
// @method
// @return 是否支持
//==========================================================
public supportHtml5() {
return this._supportHtml5;
}
//==========================================================
// 获得事件对象。
//
// @param hEvent 事件
// @return 事件
//==========================================================
public findEvent(hEvent) {
if (!hEvent) {
hEvent = this._hWindow.event;
}
return hEvent;
}
//==========================================================
// 日志输出信息。
//
// @param sender 发送者
// @param event 事件
//==========================================================
public onLogger(sender, event) {
//console.log("\r");
console.log(event.message);
//console.log("\r");
}
//==========================================================
// 关联当前窗口。
//
接管当前窗口对象的各种加载,鼠标,键盘的处理事件。
//
// @param hWindow 窗口对象
//==========================================================
public setup(hWindow: any) {
// 设置属性
var hWindow = this._hWindow = hWindow;
hWindow.__linker = this;
var hDocument = this._hDocument = hWindow.document;
hDocument.__linker = this;
var hContainer = this._hContainer = hDocument.body;
hContainer.__linker = this;
//..........................................................
// 设置日志
LoggerUtil.outputListeners.register(this, this.onLogger);
//..........................................................
var code = this._agent = window.navigator.userAgent.toString();
var agent = code.toLowerCase();
var properties = this._defineProperties = new Object();
var events = this._defineEvents = new Object();
var methods = this._defineMethods = new Object();
var capability = this._capability = new BrowserCapability();
// 判断设备类型
if (agent.indexOf("android") != -1) {
this._typeCd = DeviceEnum.Mobile;
this._softwareCd = SoftwareEnum.Android;
}
// 判断浏览器类型
if (agent.indexOf("chrome") != -1) {
this._typeCd = BrowserEnum.Chrome;
} else if (agent.indexOf("firefox") != -1) {
this._typeCd = BrowserEnum.FireFox;
} else if ((agent.indexOf("msie") != -1) || (agent.indexOf("windows") != -1)) {
this._typeCd = BrowserEnum.Explorer;
} else if ((agent.indexOf("safari") != -1) || (agent.indexOf("applewebkit") != -1)) {
this._typeCd = BrowserEnum.Safari;
} else {
alert('Unknown browser.\n' + agent);
return;
}
// 是否移动或PC模式
var platformCd = PlatformEnum.Mobile;
if (StringUtil.contains(agent, 'android', 'ipad', 'iphone', 'midp', 'rv:1.2.3.4', 'windows ce', 'windows mobile')) {
platformCd = PlatformEnum.Mobile;
// this._environmentConsole.registerValue(EConstant.DeviceType, 'mb');
} else {
platformCd = PlatformEnum.Pc;
// this._environmentConsole.registerValue(EConstant.DeviceType, 'pc');
}
this._platformCd = platformCd;
// RRuntime.setPlatformCd(platformCd);
// 判断浏览器是否需要声音确认
if (StringUtil.contains(agent, 'android 5.1', 'iphone', 'ipad')) {
capability.soundConfirm = true;
}
// 判断浏览器是否支持画面缩放
if (StringUtil.contains(agent, 'mqqbrowser')) {
capability.canvasScale = false;
}
// 注册输出接口
if (this._typeCd == BrowserEnum.Chrome) {
// RLogger.lsnsOutput.register(this, this.onLog);
}
// 输出日志
LoggerUtil.debug(this, 'Parse browser agent. (platform_cd={1}, type_cd={2})', EnumUtil.decode(PlatformEnum, platformCd), EnumUtil.decode(BrowserEnum, this._typeCd));
// 是否支持HTML5
if (hWindow.applicationCache) {
this._supportHtml5 = true;
}
// 检测是否支持声音完成(360浏览器不支持声音完成相应)
var external: any = hWindow.external;
if (external) {
if (external.twGetRunPath) {
if ((agent.indexOf('360chrome') != -1) || (agent.indexOf('360se') != -1)) {
capability.soundFinish = false;
} else {
var runPath = external.twGetRunPath().toLowerCase();
if (runPath.indexOf('360se') != -1) {
capability.soundFinish = false;
}
}
}
}
// 设置浏览器能力
var pixelRatio = hWindow.devicePixelRatio;
if (pixelRatio) {
if (platformCd == PlatformEnum.Mobile) {
// 强制不要超过3倍
capability.pixelRatio = Math.min(pixelRatio, 3);
LoggerUtil.debug(this, 'Parse browser agent. (pixel_ratio={1}, capability_ratio={2})', pixelRatio, capability.pixelRatio);
}
}
if (hWindow.Worker) {
capability.optionProcess = true;
}
if (hWindow.localStorage) {
capability.optionStorage = true;
}
try {
new Blob(["Test"], { 'type': 'text/plain' });
capability.blobCreate = true;
} catch (e) {
LoggerUtil.warn(this, 'Browser blob not support.');
}
// 设置函数
var visibilityChange = null;
if (typeof hDocument.hidden !== "undefined") {
properties['hidden'] = 'hidden';
events['visibilitychange'] = 'visibilitychange';
} else if (typeof hDocument.mozHidden !== "undefined") {
properties['hidden'] = 'mozHidden';
events['visibilitychange'] = 'mozvisibilitychange';
} else if (typeof hDocument.msHidden !== "undefined") {
properties['hidden'] = 'msHidden';
events['visibilitychange'] = 'msvisibilitychange';
} else if (typeof hDocument.webkitHidden !== "undefined") {
properties['hidden'] = 'webkitHidden';
events['visibilitychange'] = 'webkitvisibilitychange';
}
// 计算方向
this.refreshOrientation();
LoggerUtil.debug(this, 'Browser connect. (agent={1})', this._agent);
//..........................................................
// 关联鼠标事件
var visibilitychange = this.defineEventGet('visibilitychange');
if (this.supportHtml5()) {
hDocument.addEventListener(visibilitychange, this.ohVisibility, true);
} else {
hDocument['on' + visibilitychange] = this.ohVisibility;
}
hWindow.onorientationchange = this.ohOrientation;
hContainer.onresize = this.ohResize;
hContainer.onselectstart = this.ohSelect;
hContainer.onunload = this.ohUnload;
// 读取COOKIES
this._cookies.split(hDocument.cookie, '=', ';');
// 检测事件
this._requestAnimationFrame = hWindow.requestAnimationFrame || hWindow.webkitRequestAnimationFrame
|| hWindow.mozRequestAnimationFrame || hWindow.oRequestAnimationFrame || hWindow.msRequestAnimationFrame;
this._cancelAnimationFrame = hWindow.cancelRequestAnimationFrame || hWindow.webkitCancelAnimationFrame
|| hWindow.webkitCancelRequestAnimationFrame || hWindow.mozCancelAnimationFrame
|| hWindow.mozCancelRequestAnimationFrame || hWindow.msCancelAnimationFrame || hWindow.msCancelRequestAnimationFrame;
}
//==========================================================
// 改变大小处理。
//
// @method
// @param event:htmlEvent 事件
//==========================================================
public ohResize(hEvent) {
var linker: DeviceService = (this as any).__linker;
if (!hEvent) {
hEvent = linker._hWindow.event;
}
// 接收事件
var event = linker._eventResize;
event.code = EventEnum.Resize;
event.attachEvent(hEvent);
//LoggerUtil.debug(this, 'Screen resize. (size={1}x{2})', event.width, event.height);
linker.resizeListeners.process(event);
// var h = linker._hDisablePanel;
// if (h) {
// if ('block' == h.style.display) {
// var s = h.style;
// var hd = linker.hDocument;
// s.pixelLeft = 0;
// s.pixelTop = 0
// s.pixelWidth = hd.all ? linker._hContainer.scrollWidth : hd.documentElement.scrollWidth;
// s.pixelHeight = hd.all ? linker._hContainer.scrollHeight : hd.documentElement.scrollHeight;
// }
// }
// // 根据窗口大小,不发送重复事件
// if (linker.oldBodyWidth == linker._hContainer.offsetWidth && linker.oldBodyHeight == linker._hContainer.offsetHeight) {
// return;
// }
// linker.oldBodyWidth = linker._hContainer.offsetWidth;
// linker.oldBodyHeight = linker._hContainer.offsetHeight;
// // 通知所有控件,窗口改变大小
// linker.onResize();
// linker.lsnsResize.process(e);
}
//==========================================================
// 选取处理。
//
// @method
// @param event:htmlEvent 事件
//==========================================================
public ohSelect(event) {
var linker: DeviceService = (this as any).__linker;
return linker._optionSelect;
}
//==========================================================
// 可见性处理。
//
// @param hEvent 事件
//==========================================================
public ohVisibility(hEvent) {
var linker: DeviceService = (this as any).__linker;
// 刷新方向
// var visibility = MO.Window.Browser.isVisibility();
// // 分发消息
// var event = linker._eventVisibility;
// event.visibility = visibility;
// linker.lsnsVisibility.process(event);
// RLogger.debug(linker, 'Window visibility changed. (visibility={1})', visibility);
}
//==========================================================
// 选取处理。
//
// @param hEvent 事件
//==========================================================
public ohOrientation(hEvent) {
var linker: DeviceService = (this as any).__linker;
// 刷新方向
var orientationCd = linker.refreshOrientation();
// 分发消息
var event = linker._eventOrientation;
// event.orientationCd = orientationCd;
linker.orientationListeners.process(event);
LoggerUtil.debug(linker, 'Window orientation changed. (orientation_cd={1})', orientationCd);
}
//==========================================================
// 卸载处理处理。
//
// @param event 事件
//==========================================================
public ohUnload(hEvent) {
var linker: DeviceService = (this as any).__linker;
// 释放处理
var event = linker._eventUnload;
linker.unloadListeners.process(event);
// 释放窗口
linker.dispose();
}
//==========================================================
// 设置标题。
//
// @param value 标题
//==========================================================
public setCaption(value) {
top.document.title = StringUtil.nvl(value);
}
//==========================================================
// 设置状态。
//
// @param value 状态
//==========================================================
public setStatus(value) {
window.status = StringUtil.nvl(value);
}
//==========================================================
// 请求动画回调。
//
// @param callback 回调函数
// @param interval 调用间隔
//==========================================================
public requestAnimationFrame(callback) {
//var method = this._requestAnimationFrame;
var method = null;
if (method) {
method(callback);
return true;
}
return false;
}
//==========================================================
// 取消动画回调。
//
// @param callback 回调函数
//==========================================================
public cancelRequestAnimationFrame(callback) {
//var method = this._cancelAnimationFrame;
var method = null;
if (method) {
method(callback);
return true;
}
return false;
}
//===========================================================
// 判断是否垂直。
//
// @return 是否垂直
//===========================================================
public refreshOrientation() {
var hWindow = this._hWindow;
var orientation = hWindow.orientation;
if (orientation != null) {
if ((orientation == 180) || (orientation == 0)) {
this._orientationCd = OrientationEnum.Vertical;
} else if ((orientation == 90) || (orientation == -90)) {
this._orientationCd = OrientationEnum.Horizontal;
} else {
throw new Fatal(this, 'Unknown orientation mode.');
}
}
return this._orientationCd;
}
//===========================================================
// 参数编码。
//
// @param value 参数
// @return 编码字符串
//===========================================================
public encode(value) {
return this._hWindow.escape(value);
}
//===========================================================
// 参数解码。
//
// @param value 参数
// @return 解码字符串
//===========================================================
public decode(value) {
return this._hWindow.unescape(value);
}
//===========================================================
// URL参数编码。
//
// @param url 网络地址
// @param flag 是否全部
// @return 编码字符串
//===========================================================
public urlEncode(url, flag) {
if (flag) {
return encodeURIComponent(url);
}
return encodeURI(url);
}
//===========================================================
// URL参数解码。
//
// @param url 网络地址
// @param flag 是否全部
// @return 解码字符串
//===========================================================
public urlDecode(url, flag) {
if (flag) {
return decodeURIComponent(url);
}
return decodeURI(url);
}
//==========================================================
// 设置窗口是否全屏。
//
// @param hPanel 页面窗口
// @param flag 标志
//==========================================================
public fullscreen(hPanel, flag) {
if (flag) {
// 进入全屏模式
if (hPanel.requestFullscreen) {
hPanel.requestFullscreen();
} else if (hPanel.mozRequestFullScreen) {
hPanel.mozRequestFullScreen();
} else if (hPanel.webkitRequestFullScreen) {
hPanel.webkitRequestFullScreen();
} else if (hPanel.msRequestFullscreen) {
hPanel.msRequestFullscreen();
}
} else {
// 退出全屏模式
if (hPanel.exitFullscreen) {
hPanel.exitFullscreen();
} else if (hPanel.mozCancelFullScreen) {
hPanel.mozCancelFullScreen();
} else if (hPanel.webkitCancelFullScreen) {
hPanel.webkitCancelFullScreen();
} else if (hPanel.msExitFullscreen) {
hPanel.msExitFullscreen();
}
}
}
//===========================================================
// 下载数据块。
//
// @param fileName 文件名称
// @param text 文本内容
//===========================================================
public static downloadText(fileName, text) {
// var blob = RBlob.fromText(text);
// this.downloadBlob(fileName, blob);
}
//===========================================================
// 下载数据块。
//
// @param fileName 文件名称
// @param blob 数据块
//===========================================================
public static downloadBlob(fileName, blob) {
var link: any = document.createElement('A');
var event: any = document.createEvent("MouseEvents");
event.initEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
link.download = fileName;
link.href = URL.createObjectURL(blob);
link.dispatchEvent(event);
}
//==========================================================
// 释放窗口所有对象。
//==========================================================
public dispose() {
// 设置属性
var hWindow = this._hWindow;
var hDocument = this._hDocument;
var hContainer = this._hContainer;
// // 关联鼠标事件
// //if (MO.Window.Browser.supportHtml5()) {
// hContainer.removeEventListener('mousedown', this.onMouseDown, true);
// hContainer.removeEventListener('mousemove', this.onMouseMove, true);
// hContainer.removeEventListener('mouseup', this.onMouseUp, true);
// hContainer.removeEventListener('mousewheel', this.onMouseWheel, true);
// hContainer.removeEventListener('keydown', this.onKeyDown, true);
// hContainer.removeEventListener('keyup', this.onKeyUp, true);
// hContainer.removeEventListener('keypress', this.onKeyPress, true);
// hWindow.removeEventListener('orientationchange', this.onOrientation);
// //} else {
// hContainer.onmousedown = null;
// hContainer.onmousemove = null;
// hContainer.onmouseup = null;
// hContainer.onmousewheel = null;
// hContainer.onkeydown = null;
// hContainer.onkeyup = null;
// hContainer.onkeypress = null;
// hWindow.onorientationchange = null;
// //}
// hContainer.onresize = null;
// hContainer.onselectstart = null;
// hContainer.onunload = null;
// // @attribute
// this._localStorage = RObject.dispose(this._localStorage);
// this._sessionStorage = RObject.dispose(this._sessionStorage);
// // @attribute
// this._hWindow = null;
// this._hDocument = null;
// this._hContainer = null;
// // @attribute
// this._eventMouse = RObject.dispose(this._eventMouse);
// this._eventKey = RObject.dispose(this._eventKey);
// this._eventResize = RObject.dispose(this._eventResize);
// this._eventOrientation = RObject.dispose(this._eventOrientation);
// this._eventUnload = RObject.dispose(this._eventUnload);
super.dispose();
}
}