jquery.portal.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /**
  2. * portal - jQuery EasyUI
  3. *
  4. * Licensed under the GPL:
  5. * http://www.gnu.org/licenses/gpl.txt
  6. *
  7. * Copyright 2010-2012 stworthy [ stworthy@gmail.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 setSize(target){
  53. var t = $(target);
  54. var opts = $.data(target, 'portal').options;
  55. if (opts.fit){
  56. var p = t.parent();
  57. opts.width = p.width();
  58. opts.height = p.height();
  59. }
  60. if (!isNaN(opts.width)){
  61. t._outerWidth(opts.width);
  62. } else {
  63. t.width('auto');
  64. }
  65. if (!isNaN(opts.height)){
  66. t._outerHeight(opts.height);
  67. } else {
  68. t.height('auto');
  69. }
  70. var hasScroll = t.find('>table').outerHeight() > t.height();
  71. var width = t.width();
  72. var columnWidths = $.data(target, 'portal').columnWidths;
  73. var leftWidth = 0;
  74. // calculate and set every column size
  75. for(var i=0; i<columnWidths.length; i++){
  76. var p = t.find('div.portal-column:eq('+i+')');
  77. var w = Math.floor(width * columnWidths[i]);
  78. if (i == columnWidths.length - 1){
  79. // w = width - leftWidth - (hasScroll == true ? 28 : 10);
  80. w = width - leftWidth - (hasScroll == true ? 18 : 0);
  81. }
  82. p._outerWidth(w);
  83. leftWidth += p.outerWidth();
  84. // resize every panel of the column
  85. p.find('div.portal-p').panel('resize', {width:p.width()});
  86. }
  87. opts.onResize.call(target, opts.width, opts.height);
  88. }
  89. /**
  90. * set draggable feature for the specified panel
  91. */
  92. function makeDraggable(target, panel){
  93. var spacer;
  94. panel.panel('panel').draggable({
  95. handle:'>div.panel-header>div.panel-title',
  96. proxy:function(source){
  97. var p = $('<div class="portal-proxy">proxy</div>').insertAfter(source);
  98. p.width($(source).width());
  99. p.height($(source).height());
  100. p.html($(source).html());
  101. p.find('div.portal-p').removeClass('portal-p');
  102. return p;
  103. },
  104. onBeforeDrag:function(e){
  105. e.data.startTop = $(this).position().top + $(target).scrollTop();
  106. },
  107. onStartDrag:function(e){
  108. $(this).hide();
  109. spacer = $('<div class="portal-spacer"></div>').insertAfter(this);
  110. setSpacerSize($(this).outerWidth(), $(this).outerHeight());
  111. },
  112. onDrag:function(e){
  113. var p = findPanel(e, this);
  114. if (p){
  115. if (p.pos == 'up'){
  116. spacer.insertBefore(p.target);
  117. } else {
  118. spacer.insertAfter(p.target);
  119. }
  120. setSpacerSize($(p.target).outerWidth());
  121. } else {
  122. var c = findColumn(e);
  123. if (c){
  124. if (c.find('div.portal-spacer').length == 0){
  125. spacer.appendTo(c);
  126. setSize(target);
  127. setSpacerSize(c.width());
  128. }
  129. }
  130. }
  131. },
  132. onStopDrag:function(e){
  133. $(this).css('position', 'static');
  134. $(this).show();
  135. spacer.hide();
  136. $(this).insertAfter(spacer);
  137. spacer.remove();
  138. setSize(target);
  139. panel.panel('move');
  140. var opts = $.data(target, 'portal').options;
  141. opts.onStateChange.call(target);
  142. }
  143. });
  144. /**
  145. * find which panel the cursor is over
  146. */
  147. function findPanel(e, source){
  148. var result = null;
  149. $(target).find('div.portal-p').each(function(){
  150. var pal = $(this).panel('panel');
  151. if (pal[0] != source){
  152. var pos = pal.offset();
  153. if (e.pageX > pos.left && e.pageX < pos.left + pal.outerWidth()
  154. && e.pageY > pos.top && e.pageY < pos.top + pal.outerHeight()){
  155. if (e.pageY > pos.top + pal.outerHeight() / 2){
  156. result = {
  157. target:pal,
  158. pos:'down'
  159. };
  160. } else {
  161. result = {
  162. target:pal,
  163. pos:'up'
  164. }
  165. }
  166. }
  167. }
  168. });
  169. return result;
  170. }
  171. /**
  172. * find which portal column the cursor is over
  173. */
  174. function findColumn(e){
  175. var result = null;
  176. $(target).find('div.portal-column').each(function(){
  177. var pal = $(this);
  178. var pos = pal.offset();
  179. if (e.pageX > pos.left && e.pageX < pos.left + pal.outerWidth()){
  180. result = pal;
  181. }
  182. });
  183. return result;
  184. }
  185. /**
  186. * set the spacer size
  187. */
  188. function setSpacerSize(width, height){
  189. spacer._outerWidth(width);
  190. if (height){
  191. spacer._outerHeight(height);
  192. }
  193. }
  194. }
  195. $.fn.portal = function(options, param){
  196. if (typeof options == 'string'){
  197. return $.fn.portal.methods[options](this, param);
  198. }
  199. options = options || {};
  200. return this.each(function(){
  201. var state = $.data(this, 'portal');
  202. if (state){
  203. $.extend(state.options, options);
  204. } else {
  205. state = $.data(this, 'portal', {
  206. options: $.extend({}, $.fn.portal.defaults, $.fn.portal.parseOptions(this), options),
  207. columnWidths: init(this)
  208. });
  209. }
  210. if (state.options.border){
  211. $(this).removeClass('portal-noborder');
  212. } else {
  213. $(this).addClass('portal-noborder');
  214. }
  215. setSize(this);
  216. });
  217. };
  218. $.fn.portal.methods = {
  219. options: function(jq){
  220. return $.data(jq[0], 'portal').options;
  221. },
  222. resize: function(jq, param){
  223. return jq.each(function(){
  224. if (param){
  225. var opts = $.data(this, 'portal').options;
  226. if (param.width) opts.width = param.width;
  227. if (param.height) opts.height = param.height;
  228. }
  229. setSize(this);
  230. });
  231. },
  232. getPanels: function(jq, columnIndex){
  233. var c = jq; // the panel container
  234. if (columnIndex >= 0){
  235. c = jq.find('div.portal-column:eq(' + columnIndex + ')');
  236. }
  237. var panels = [];
  238. c.find('div.portal-p').each(function(){
  239. panels.push($(this));
  240. });
  241. return panels;
  242. },
  243. add: function(jq, param){ // param: {panel,columnIndex}
  244. return jq.each(function(){
  245. var c = $(this).find('div.portal-column:eq(' + param.columnIndex + ')');
  246. var p = param.panel.addClass('portal-p');
  247. p.panel('panel').addClass('portal-panel').appendTo(c);
  248. makeDraggable(this, p);
  249. p.panel('resize', {width:c.width()});
  250. });
  251. },
  252. remove: function(jq, panel){
  253. return jq.each(function(){
  254. var panels = $(this).portal('getPanels');
  255. for(var i=0; i<panels.length; i++){
  256. var p = panels[i];
  257. if (p[0] == $(panel)[0]){
  258. p.panel('destroy');
  259. }
  260. }
  261. });
  262. },
  263. disableDragging: function(jq, panel){
  264. panel.panel('panel').draggable('disable');
  265. return jq;
  266. },
  267. enableDragging: function(jq, panel){
  268. panel.panel('panel').draggable('enable');
  269. return jq;
  270. }
  271. };
  272. $.fn.portal.parseOptions = function(target){
  273. var t = $(target);
  274. return {
  275. width: (parseInt(target.style.width) || undefined),
  276. height: (parseInt(target.style.height) || undefined),
  277. border: (t.attr('border') ? t.attr('border') == 'true' : undefined),
  278. fit: (t.attr('fit') ? t.attr('fit') == 'true' : undefined)
  279. };
  280. };
  281. $.fn.portal.defaults = {
  282. width:'auto',
  283. height:'auto',
  284. border:true,
  285. fit:false,
  286. onResize:function(width,height){},
  287. onStateChange:function(){}
  288. };
  289. })(jQuery);