nyx_server
Version:
Node内容发布
628 lines (544 loc) • 20.4 kB
JavaScript
(function ($, lib) {
"use strict";
var win = window;
var doc = document;
var index = 0;
var defaultConfig = {
width: 800, // 窗口宽度
height: 600, // 窗口高度“带头部”
title: '', // 窗口标题
position: "center", // 窗口位置,居中就用center,非居中可以用{top: 100, left: 200}
canDrag: true, // 是否可以拖动,
isMaximize: true, // 是否可以最大化,
isMinimize: true, // 是否可以最小化,
isClose: true,
isHead: true, // 是否要头部
isFoot: false,
buttons: [],
useMask: true, // 是否启用蒙板,
content: '', // 窗体内部主要内容,html字符串,如果需要加入iframe,则使用url
marginLeft: 50, // 右侧留出空间,默认50
cls: '', // 外围自定义class
beforeClose: function () { // 关闭窗口前调用的函数,后期会根据postmessage的机制进行修改
return true;
},
initHandle: function () {
}
};
var dialogEvent = new topic.Events();
var Dialog = function (option) {
this.init(option);
};
Dialog.prototype = {
init: function (option) {
this.initParam(option);
this.render();
this.initEvent();
},
initParam: function (option) {
this.config = lib.extend(defaultConfig, option);
if (this.config.isHead === false) {
this.config.isMaximize = false;
this.config.isMinimize = false;
this.config.isClose = false;
}
// 全局状态
this.isFull = false;
// 拖动状态
this.isDrag = false;
// 设置一个弹出框的索引号,可以做一些弹出框的区别的事情。
this.dialogIndex = index++;
// 是否设置了居中,此状态在拖动一次以后会变成false
this.isCenter = this.config.position === "center";
// 记录鼠标位置坐标
this.mousePosition = undefined;
// 记录计算过后的窗口的左上角坐标位置
this.current = {x: 'notBegin', y: 'notBegin'};
// 获取浏览器窗口的大小,进行缓存
this.setWindowRect();
},
// 对组件相关dom节点进行渲染定位和显示动画。
render: function () {
this.createHtml();
this.positionIt();
this.renderToBody();
this.maskRender();
this.scaleUp();
this.previewDialog();
if (typeof this.config.initHandle === 'function') {
this.config.initHandle(this.contentBox);
}
dialogEvent.trigger('open');
},
createHtml: function () {
var createButton = function (items) {
return items.reduce(function(s, item){
return s + '<nyx-div action="' + item.value + '" class="t-dialog-button">' + item.desc + '</nyx-div>';
}, '');
};
var config = this.config;
var maxHtml = config.isMaximize ?
'<nyx-span class="icon-full" data-topicSystem="true" title="最大化窗口"><nyx-em>最大化</nyx-em></nyx-span>' : '';
var minHtml = config.isMinimize ?
'<nyx-span class="icon-min" data-topicSystem="true" title="最小化窗口"><nyx-em>最小化</nyx-em></nyx-span>' : '';
var closeHtml = config.isClose ?
'<nyx-span class="icon-close" data-topicSystem="true" title="关闭窗口"><nyx-em>关闭</nyx-em></nyx-span>' : '';
var content = config.url ? '<iframe src="' + config.url +
'" class="form-iframe" data-topicSystem="true" frameborder="0"></iframe>' :
config.content;
var headHtml = config.isHead ? '<nyx-header data-topicSystem="true">' +
'<nyx-nav data-topicSystem="true">' +
minHtml + maxHtml + closeHtml +
'</nyx-nav>' +
'<nyx-h1 data-topicSystem="true"><nyx-span class="titleBox" data-topicSystem="true">' + config.title + '</nyx-span>' +
'<nyx-em data-topicSystnyx-em="true" class="userBox"></nyx-em></nyx-h1>' +
'</nyx-header>' : '';
var footHtml = config.isFoot ? '<nyx-footer>' + createButton(config.buttons) + '</nyx-footer>' : '';
this.contain = $('<nyx-section class="t-dialog ' + config.cls + '" data-topicSystem="true" style="width: ' +
config.width + 'px; height: ' + config.height + 'px;" >' +
'<nyx-div class="t-dialog-inner" data-topicSystem="true">' +
headHtml +
'<nyx-article data-topicSystem="true">' +
'<nyx-div class="t-content" data-topicSystem="true">' + content + '</nyx-div>' +
'<nyx-div class="iframe-overflow" data-topicSystem="true"></nyx-div>' +
'</nyx-article>' +
footHtml +
'</nyx-div>' +
'</nyx-section>');
this.regElements();
},
regElements: function () {
var config = this.config;
if (config.isMaximize) {
this.fullBtn = this.contain.find('.icon-full');
}
if (config.isMinimize) {
this.minBtn = this.contain.find('.icon-min');
}
if (config.isClose) {
this.closeBtn = this.contain.find('.icon-close');
}
if (config.isHead) {
this.header = this.contain.find('nyx-header');
}
this.contentBox = this.contain.find('.t-content');
this.overflow = this.contain.find('.iframe-overflow');
if (config.url) {
this.iframe = this.contain.find('iframe');
}
},
getContentBox: function () {
return this.contentBox;
},
positionIt: function () {
var config = this.config;
if (config.position === "center") {
this.setCenterPosition();
} else {
config.top = config.position.top;
config.left = config.position.left;
}
this.contain.css({
top: config.top + 'px',
left: config.left + 'px'
});
},
setCenterPosition: function () {
var config = this.config;
var position = this.calCenterPosition();
config.top = position.top;
config.left = position.left;
},
// 计算窗口居中时的top和left位置
calCenterPosition: function () {
var config = this.config;
var position = {
top: 0,
left: 0
};
var windowHeight = this.windowHeight;
var windowWidth = this.windowWidth;
if (config.height < windowHeight) {
position.top = (windowHeight - config.height) / 2;
}
if (config.width < windowWidth) {
position.left = (windowWidth - config.width) / 2;
}
return position;
},
renderToBody: function () {
$(document.body).append(this.contain);
},
maskRender: function () {
if (this.config.useMask) {
this.mask = $('<nyx-div class="t-dialog-mask" data-topicSystem="true"></nyx-div>');
$(doc.body).append(this.mask);
}
},
initEvent: function () {
var config = this.config;
var _this = this;
if (config.isClose) {
this.closeBtn.on('click', function () {
_this.closeIt();
return false;
});
}
if (config.isMaximize) {
this.fullBtn.on('click', function () {
if (_this.isFull) {
_this.maxRestore();
} else {
_this.maximize();
}
return false;
});
}
if (config.isMinimize) {
this.minBtn.on('click', function () {
if (_this.isMin) {
_this.minRestore();
} else {
_this.minimize();
}
return false;
});
}
if (config.canDrag && config.isHead) {
this.header.find("nyx-nav nyx-span").on("mousedown", function () {
return false;
});
this.header.on('mousedown', function (e) {
$(doc.body).addClass('noselect');
var x = e.pageX;
var y = e.pageY;
_this.beginMove(x, y);
});
// 这里加上.dialog是为了以后关闭窗口时,方便卸载掉相关的事件。
// 因为这些注册到window和body上的事件,不会跟随dom的清楚而被清除掉,需要手动清除。
$(win).on('resize.dialog' + this.dialogIndex, function () {
_this.resizeIt();
});
$(doc.body).on('mousemove.dialog' + this.dialogIndex, function (e) {
var x = e.pageX;
var y = e.pageY;
_this.moveTo(x, y);
});
$(doc.body).on('mouseup.dialog' + this.dialogIndex, function (e) {
$(doc.body).removeClass('noselect');
var x = e.pageX;
var y = e.pageY;
_this.moveEnd(x, y);
});
}
this.contain.on('click', '[action]', function () {
var action = $(this).attr('action');
var frame = _this.iframe[0];
var context = _this.config.context;
var dataPromise = frame.contentWindow.getData();
Promise.resolve(dataPromise).then(context[action].bind(context)).catch(function(e){
console.log(e);
});
// dataPromise.then(context[action].bind(context)).catch(function (e) {
// console.log(e);
// });
});
if (config.useMask) {
this.mask.on('click', function () {
if (_this.isMin) {
_this.minRestore();
}
});
}
this.contain.on('click', function () {
if (_this.isMin) {
_this.minRestore();
}
});
if($('#preDiv') != null){
$('#preDiv').on('click',function(){
$('#preDiv').hide();
_this.contain.show();
_this.minRestore();
})
}
},
show: function () {
this.contain.fadeIn();
},
hide: function () {
this.contain.fadeOut();
},
closeIt: function () {
if (this.config.beforeClose()) {
this.destroy();
}
},
// 最大化
maximize: function () {
this.contain.animate({
top: '0px',
left: '0px',
width: this.windowWidth + 'px',
height: this.windowHeight + 'px'
});
this.isFull = true;
this.fullBtn.addClass('active');
this.fullBtn.attr('title', '恢复窗口');
},
// 最大化恢复
// 取出设置中保存的数值进行恢复。
maxRestore: function () {
var config = this.config;
this.contain.css({
top: config.top + 'px',
left: config.left + 'px',
width: config.width + 'px',
height: config.height + 'px'
});
this.isFull = false;
this.fullBtn.removeClass('active');
this.fullBtn.attr('title', '最大化窗口');
},
// 最小化,实现方法就是,添加上样式,将不需要显示的部分隐藏掉
minimize: function () {
this.contain.addClass('mini');
this.minBtn.addClass('active');
this.isMin = true;
this.minBtn.attr('title', '恢复窗口');
this.mask.addClass('active');
},
// 最小化恢复,移除样式和状态。
minRestore: function () {
this.contain.removeClass('mini');
this.minBtn.removeClass('active');
this.isMin = false;
this.minBtn.attr('title', '最小化窗口');
this.mask.removeClass('active');
},
//设置预览最小化窗口
previewDialog:function(){
var preDiv = $('<nyx-div id="preDiv" style="display:none;width: 800px;height: 31px; background-color: #393f4f; z-index: 2147483640;color: #fff;font-size: 14px;text-align: center;line-height: 31px;font-weight: bold"></nyx-div>');
$(document.body).append(preDiv);
var preDivObj = $('#preDiv');
preDivObj.attr('title', '预览最小化窗口');
var config = this.config;
preDivObj.css({
position: 'fixed',
top: config.top + 'px',
left: config.left + 'px',
//opacity: '0.7',
borderRadius: '4px 4px 3px 3px',
cursor: 'pointer'
});
},
//预览最小化窗口
preview:function(){
this.minimize();
this.contain.hide();
$('#preDiv').text(this.config.title+" (点击恢复编辑窗口)");
//
$('#preDiv').css({display:""});
this.mask.remove();
},
changeTitle: function (newTitle) {
if (this.config.isHead) {
this.header.find('nyx-h1 nyx-span').html(newTitle);
}
},
// 在窗口大小改变时,对弹窗大小进行调整,
// 分为最大化状态调整和非最大化状态
// 非最大化状态又分为居中和非居中的情况
resizeIt: function () {
if (this.isFull) {
this.setContainFull();
}
// 如果是有居中状态的话,需要调整弹出框左上角的坐标
// 并且在非最大化的情况下,对top和left进行重新设置
if (this.isCenter) {
this.setCenterPosition();
if (!this.isFull) {
this.contain.css({
top: this.config.top + 'px',
left: this.config.left + 'px'
});
}
}
this.setWindowRect();
},
setContainFull: function () {
this.contain.css({
width: this.calFullWidth() + 'px',
height: this.calFullHeight() + 'px'
});
},
// 外部调用的方法,用来改变弹出框的大小
resizeSize: function (width, height) {
// 对传参形式进行转换,现在好像还没使用。
if (typeof width === 'object') {
height = width.height;
width = width.width;
}
// 下面一堆是用来判断弹出框大小变化以后,top和left的位置,
// 这里主要处理了让弹出框保持在窗口内。
var config = this.config;
// top 和 left位置的修正是基于弹出框的中心点进行扩大和缩小的。
var top = config.top + (config.height - height) / 2;
var left = config.left + (config.width - width) / 2;
// 下面这段是用来做缩放溢出窗口的位置修正。
top = top <= 0 ?
0 : top + height <= this.windowHeight ?
top: this.windowHeight - height;
left = left <= 0 ?
0 : left + width + this.config.marginLeft <= this.windowWidth ?
left : this.windowWidth - width - this.config.marginLeft;
top = top > 0 ? top : 0;
left = left > 0 ? left : 0;
// 将调整完成后的值放到设置中,因为其他操作也需要基于这些值。
config.top = top;
config.left = left;
config.width = width;
config.height = height;
this.contain.css({
top: top + 'px',
left: left + 'px',
width: width + 'px',
height: height + 'px'
});
// 全屏状态的处理,退出全屏状态。最小化的处理没做,现在没有业务场景需要。
if (this.isFull) {
this.isFull = false;
this.fullBtn.removeClass('active');
}
},
setWindowRect: function () {
this.windowWidth = this.calFullWidth();
this.windowHeight = this.calFullHeight();
},
calFullWidth: function () {
return $(win).width() - this.config.marginLeft;
},
calFullHeight: function () {
return $(win).height();
},
// 拖动窗口的思路是,鼠标在需要拖动的dom节点上按下,记住鼠标位置
// 在拖动时一直计算当前鼠标位置跟按下位置之间,并根据此位置计算弹出框左上角坐标位置
// 鼠标按键放开后,将位置设置为notbegin,停止移动窗口
// 这里做了一个对拖动性能优化的事情,在对窗口做移动的时候,使用的是定时器,
// 每66毫秒调用一次移动函数,这样不会因为拖动速度太快,导致移动的时候响应变慢。
beginMove: function (x, y) {
var _this = this;
if (this.isFull || this.isMin) {
return;
}
this.contain.removeClass('anim');
this.isDrag = true;
this.mousePosition = {x: x, y: y};
this.moverTimer = setInterval(function () {
_this.moveIt();
}, 67);
// 显示对iframe的遮罩,放置鼠标滑到iframe中,导致移动失效。
this.overflow.show();
},
moveIt: function () {
if (this.current.x === "notBegin" && this.current.y === "notBegin") {
return;
}
// 获取当前位置,并赋给弹出框样式。
this.contain.css({
top: this.current.y + 'px',
left: this.current.x + 'px'
});
},
// 根据鼠标位置,计算弹出框左上角的坐标值,这里需要限制弹出框在窗口内部移动,不能移出窗口。
moveTo: function (x, y) {
if (this.isDrag === false) {
return;
}
var config = this.config;
x = x - this.mousePosition.x;
y = y - this.mousePosition.y;
// 对左右边界的判断
if (x + config.left > 0 && x + config.left + config.width < this.windowWidth) {
this.current.x = this.config.left + x;
} else if (x + config.left <= 0) {
this.current.x = 0;
} else {
this.current.x = this.windowWidth - config.width;
}
// 对上下边界的判断
if (y + config.top > 0 && y + config.top + config.height < this.windowHeight) {
this.current.y = this.config.top + y;
} else if (y + config.top <= 0) {
this.current.y = 0;
} else {
this.current.y = this.windowHeight - config.height;
}
},
// 移动结束,要做以下的事情
// 1. 清除定时器
// 2. 设置一批状态,包括弹出框top left位置
// 是否在拖动,一旦拖动,则将居中状态改为false
// 将iframe遮罩层隐藏
// 设置current.x y为notBegin,如果x y为此值,则会不对弹出框进行移动
moveEnd: function () {
var config = this.config;
clearInterval(this.moverTimer);
if (this.isDrag === false) {
return;
}
if (this.current.y !== 'notBegin') {
config.top = this.current.y;
}
if (this.current.x !== 'notBegin') {
config.left = this.current.x;
}
this.isDrag = false;
this.isCenter = false;
this.current.x = 'notBegin';
this.current.y = 'notBegin';
this.contain.addClass('anim');
this.overflow.hide();
},
// 销毁弹出框
destroy: function () {
this.contain.remove();
if (this.config.useMask) {
this.mask.remove();
}
// 这里要将绑定在window和body上的事件清除掉
$(win).off('.dialog' + this.dialogIndex);
$(doc.body).off('.dialog' + this.dialogIndex);
dialogEvent.trigger('destroy');
},
// 对窗口进行缩放
scaleUp: function () {
var _this = this;
var config = this.config;
var rely = config.rely;
var relyPosition;
// 现在依赖的缩放动画,移动轨迹比较怪异,暂时没有应用。
if (this.config.rely) {
relyPosition = rely.offset();
this.contain.css({
'-webkit-transform': 'scale(' + rely.width() / config.width + ', ' + rely.height() / config.height + ')',
'top': relyPosition.top - ((config.height - rely.height()) / 2) + 'px',
'left': relyPosition.left - ((config.width - rely.width()) / 2) + 'px'
});
} else {
this.contain.css('-webkit-transform', 'scale(0.3, 0.3)');
}
// 这里做动画效果时,需要用setTimeout做一个延迟处理。
setTimeout(function () {
_this.contain.addClass('anim');
_this.contain.css({
'-webkit-transform': 'scale(1, 1)',
'top': config.top,
'left': config.left
});
}, 33);
}
};
lib.ns('topic.module').Dialog = Dialog;
lib.ns('topic').dialogEvent = dialogEvent;
}(topicJquery, topic.utils));