jquery.portal.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /**
  2. * portal - jQuery EasyUI
  3. *
  4. * Licensed under the GPL:
  5. * http://www.gnu.org/licenses/gpl.txt
  6. *
  7. * Copyright 2010-2012 www.jeasyui.com
  8. *
  9. * Dependencies:
  10. * draggable
  11. * panel
  12. *
  13. */
  14. (function($){
  15. /**
  16. * initialize the portal
  17. */
  18. function init(target){
  19. $(target).addClass('portal');
  20. var table = $('<table border="0" cellspacing="0" cellpadding="0"><tr></tr></table>').appendTo(target);
  21. var tr = table.find('tr');
  22. var columnWidths = [];
  23. var totalWidth = 0;
  24. $(target).children('div:first').addClass('portal-column-left');
  25. $(target).children('div:last').addClass('portal-column-right');
  26. $(target).find('>div').each(function(){ // each column panel
  27. var column = $(this);
  28. totalWidth += column.outerWidth();
  29. columnWidths.push(column.outerWidth());
  30. var td = $('<td class="portal-column-td"></td>').appendTo(tr)
  31. column.addClass('portal-column').appendTo(td);
  32. column.find('>div').each(function(){ // each portal panel
  33. var p = $(this).addClass('portal-p').panel({
  34. doSize:false,
  35. cls:'portal-panel'
  36. });
  37. makeDraggable(target, p);
  38. });
  39. });
  40. for(var i=0; i<columnWidths.length; i++){
  41. columnWidths[i] /= totalWidth;
  42. }
  43. $(target).bind('_resize', function(){
  44. var opts = $.data(target, 'portal').options;
  45. if (opts.fit == true){
  46. setSize(target);
  47. }
  48. return false;
  49. });
  50. return columnWidths;
  51. }
  52. function initCss(){
  53. if (!$('#easyui-portal-style').length){
  54. $('head').append(
  55. '<style id="easyui-portal-style">' +
  56. '.portal{padding:0;margin:0;overflow:auto;border:1px solid #99bbe8;}' +
  57. '.portal-noborder{border:0;}' +
  58. '.portal .portal-panel{margin-bottom:10px;}' +
  59. '.portal-column-td{vertical-align:top;}' +
  60. '.portal-column{padding:10px 0 10px 10px;overflow:hidden;}' +
  61. '.portal-column-left{padding-left:10px;}' +
  62. '.portal-column-right{padding-right:10px;}' +
  63. '.portal-proxy{opacity:0.6;filter:alpha(opacity=60);}' +
  64. '.portal-spacer{border:3px dashed #eee;margin-bottom:10px;}' +
  65. '</style>'
  66. );
  67. }
  68. }
  69. function setSize(target){
  70. var t = $(target);
  71. var opts = $.data(target, 'portal').options;
  72. if (opts.fit){
  73. var p = t.parent();
  74. opts.width = p.width();
  75. opts.height = p.height();
  76. }
  77. if (!isNaN(opts.width)){
  78. t._outerWidth(opts.width);
  79. } else {
  80. t.width('auto');
  81. }
  82. if (!isNaN(opts.height)){
  83. t._outerHeight(opts.height);
  84. } else {
  85. t.height('auto');
  86. }
  87. var hasScroll = t.find('>table').outerHeight() > t.height();
  88. var width = t.width();
  89. var columnWidths = $.data(target, 'portal').columnWidths;
  90. var leftWidth = 0;
  91. // calculate and set every column size
  92. for(var i=0; i<columnWidths.length; i++){
  93. var p = t.find('div.portal-column:eq('+i+')');
  94. var w = Math.floor(width * columnWidths[i]);
  95. if (i == columnWidths.length - 1){
  96. // w = width - leftWidth - (hasScroll == true ? 28 : 10);
  97. w = width - leftWidth - (hasScroll == true ? 18 : 0);
  98. }
  99. p._outerWidth(w);
  100. leftWidth += p.outerWidth();
  101. // resize every panel of the column
  102. p.find('div.portal-p').panel('resize', {width:p.width()});
  103. }
  104. opts.onResize.call(target, opts.width, opts.height);
  105. }
  106. /**
  107. * set draggable feature for the specified panel
  108. */
  109. function makeDraggable(target, panel){
  110. var spacer;
  111. panel.panel('panel').draggable({
  112. handle:'>div.panel-header>div.panel-title',
  113. proxy:function(source){
  114. var p = $('<div class="portal-proxy">proxy</div>').insertAfter(source);
  115. p.width($(source).width());
  116. p.height($(source).height());
  117. p.html($(source).html());
  118. p.find('div.portal-p').removeClass('portal-p');
  119. return p;
  120. },
  121. onBeforeDrag:function(e){
  122. e.data.startTop = $(this).position().top + $(target).scrollTop();
  123. },
  124. onStartDrag:function(e){
  125. $(this).hide();
  126. spacer = $('<div class="portal-spacer"></div>').insertAfter(this);
  127. setSpacerSize($(this).outerWidth(), $(this).outerHeight());
  128. },
  129. onDrag:function(e){
  130. var p = findPanel(e, this);
  131. if (p){
  132. if (p.pos == 'up'){
  133. spacer.insertBefore(p.target);
  134. } else {
  135. spacer.insertAfter(p.target);
  136. }
  137. setSpacerSize($(p.target).outerWidth());
  138. } else {
  139. var c = findColumn(e);
  140. if (c){
  141. if (c.find('div.portal-spacer').length == 0){
  142. spacer.appendTo(c);
  143. setSize(target);
  144. setSpacerSize(c.width());
  145. }
  146. }
  147. }
  148. },
  149. onStopDrag:function(e){
  150. $(this).css('position', 'static');
  151. $(this).show();
  152. spacer.hide();
  153. $(this).insertAfter(spacer);
  154. spacer.remove();
  155. setSize(target);
  156. panel.panel('move');
  157. var opts = $.data(target, 'portal').options;
  158. opts.onStateChange.call(target, panel);
  159. }
  160. });
  161. /**
  162. * find which panel the cursor is over
  163. */
  164. function findPanel(e, source){
  165. var result = null;
  166. $(target).find('div.portal-p').each(function(){
  167. var pal = $(this).panel('panel');
  168. if (pal[0] != source){
  169. var pos = pal.offset();
  170. if (e.pageX > pos.left && e.pageX < pos.left + pal.outerWidth()
  171. && e.pageY > pos.top && e.pageY < pos.top + pal.outerHeight()){
  172. if (e.pageY > pos.top + pal.outerHeight() / 2){
  173. result = {
  174. target:pal,
  175. pos:'down'
  176. };
  177. } else {
  178. result = {
  179. target:pal,
  180. pos:'up'
  181. }
  182. }
  183. }
  184. }
  185. });
  186. return result;
  187. }
  188. /**
  189. * find which portal column the cursor is over
  190. */
  191. function findColumn(e){
  192. var result = null;
  193. $(target).find('div.portal-column').each(function(){
  194. var pal = $(this);
  195. var pos = pal.offset();
  196. if (e.pageX > pos.left && e.pageX < pos.left + pal.outerWidth()){
  197. result = pal;
  198. }
  199. });
  200. return result;
  201. }
  202. /**
  203. * set the spacer size
  204. */
  205. function setSpacerSize(width, height){
  206. spacer._outerWidth(width);
  207. if (height){
  208. spacer._outerHeight(height);
  209. }
  210. }
  211. }
  212. $.fn.portal = function(options, param){
  213. if (typeof options == 'string'){
  214. return $.fn.portal.methods[options](this, param);
  215. }
  216. options = options || {};
  217. return this.each(function(){
  218. var state = $.data(this, 'portal');
  219. if (state){
  220. $.extend(state.options, options);
  221. } else {
  222. state = $.data(this, 'portal', {
  223. options: $.extend({}, $.fn.portal.defaults, $.fn.portal.parseOptions(this), options),
  224. columnWidths: init(this)
  225. });
  226. }
  227. if (state.options.border){
  228. $(this).removeClass('portal-noborder');
  229. } else {
  230. $(this).addClass('portal-noborder');
  231. }
  232. initCss();
  233. setSize(this);
  234. });
  235. };
  236. $.fn.portal.methods = {
  237. options: function(jq){
  238. return $.data(jq[0], 'portal').options;
  239. },
  240. resize: function(jq, param){
  241. return jq.each(function(){
  242. if (param){
  243. var opts = $.data(this, 'portal').options;
  244. if (param.width) opts.width = param.width;
  245. if (param.height) opts.height = param.height;
  246. }
  247. setSize(this);
  248. });
  249. },
  250. getPanels: function(jq, columnIndex){
  251. var c = jq; // the panel container
  252. if (columnIndex >= 0){
  253. c = jq.find('div.portal-column:eq(' + columnIndex + ')');
  254. }
  255. var panels = [];
  256. c.find('div.portal-p').each(function(){
  257. panels.push($(this));
  258. });
  259. return panels;
  260. },
  261. add: function(jq, param){ // param: {panel,columnIndex}
  262. return jq.each(function(){
  263. var c = $(this).find('div.portal-column:eq(' + param.columnIndex + ')');
  264. var p = param.panel.addClass('portal-p');
  265. p.panel('panel').addClass('portal-panel').appendTo(c);
  266. makeDraggable(this, p);
  267. p.panel('resize', {width:c.width()});
  268. });
  269. },
  270. remove: function(jq, panel){
  271. return jq.each(function(){
  272. var panels = $(this).portal('getPanels');
  273. for(var i=0; i<panels.length; i++){
  274. var p = panels[i];
  275. if (p[0] == $(panel)[0]){
  276. p.panel('destroy');
  277. }
  278. }
  279. });
  280. },
  281. disableDragging: function(jq, panel){
  282. panel.panel('panel').draggable('disable');
  283. return jq;
  284. },
  285. enableDragging: function(jq, panel){
  286. panel.panel('panel').draggable('enable');
  287. return jq;
  288. }
  289. };
  290. $.fn.portal.parseOptions = function(target){
  291. var t = $(target);
  292. return {
  293. width: (parseInt(target.style.width) || undefined),
  294. height: (parseInt(target.style.height) || undefined),
  295. border: (t.attr('border') ? t.attr('border') == 'true' : undefined),
  296. fit: (t.attr('fit') ? t.attr('fit') == 'true' : undefined)
  297. };
  298. };
  299. $.fn.portal.defaults = {
  300. width:'auto',
  301. height:'auto',
  302. border:true,
  303. fit:false,
  304. onResize:function(width,height){},
  305. onStateChange:function(panel){}
  306. };
  307. })(jQuery);