UNPKG

nyx_server

Version:

Node内容发布

628 lines (544 loc) 20.4 kB
(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));