HLayout.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. (function(window) {
  2. function startHLayout() {
  3. var md
  4. var grabEl
  5. var sectionResizeEl
  6. // Global mouse update
  7. document.addEventListener("mousemove", function(e) {
  8. if (md === undefined) md = {x: e.clientX, y: e.clientY}
  9. md.deltaX = e.clientX - md.x
  10. md.deltaY = e.clientY - md.y
  11. md.x = e.clientX
  12. md.y = e.clientY
  13. })
  14. // Handle dragstart
  15. document.addEventListener("mousedown", function(e) {
  16. // Check for section resize
  17. if (e.target.matches("section")) {
  18. e.preventDefault()
  19. e.stopPropagation()
  20. sectionResizeEl = e.target
  21. sectionResizeEl.classList.add("resizing")
  22. return
  23. }
  24. // Check if element is our
  25. if (!e.target.matches(".hpane > header")) {
  26. return
  27. }
  28. e.preventDefault()
  29. e.stopPropagation()
  30. grabEl = e.target.parentElement
  31. var parent = grabEl.parentElement
  32. var elDim = grabEl.getBoundingClientRect()
  33. document.body.appendChild(grabEl)
  34. grabEl.classList.add("detached", "moving")
  35. grabEl.style.width = elDim.width + "px"
  36. grabEl.style.height = elDim.height + "px"
  37. // Add discover to other panes
  38. // $('.hpane:not(.detached)').addClass("discover");
  39. // All childs to pointer event none
  40. if (parent.matches("section")) {
  41. var child = parent.querySelector(".hpane, section") // hpane or section
  42. child.removeAttribute("style")
  43. child.style["flex-basis"] = parent.style["flex-basis"]
  44. parent.parentElement.insertBefore(child, parent)
  45. parent.parentElement.removeChild(parent)
  46. }
  47. })
  48. // Handle drag
  49. document.addEventListener("mousemove", function(e) {
  50. if (sectionResizeEl != null) {
  51. var firstEl = sectionResizeEl.children[0]
  52. var secondEl = sectionResizeEl.children[1]
  53. // Default vertical
  54. var tDim = "offsetWidth"
  55. var tDelta = "deltaX"
  56. if (sectionResizeEl.matches(".horizontal")) {
  57. tDim = "offsetHeight"
  58. tDelta = "deltaY"
  59. }
  60. var parentValue = sectionResizeEl[tDim]
  61. var firstNewDim = (firstEl[tDim] + md[tDelta]) / parentValue * 100
  62. var secondNewDim = (secondEl[tDim] - md[tDelta]) / parentValue * 100
  63. firstEl.style["flex-basis"] = firstNewDim + "%"
  64. secondEl.style["flex-basis"] = secondNewDim + "%"
  65. return
  66. }
  67. // console.log("Drag:",e)
  68. // if (!e.target.matches(".hpane > header")) { // we only deal with header
  69. // return
  70. // }
  71. if (grabEl === undefined) return
  72. // Get Absolute position somehow
  73. // var pos = $grab.position();
  74. var elDim = grabEl.getBoundingClientRect()
  75. // var nx = elDim.left + md.deltaX
  76. // var ny = elDim.top + md.deltaY
  77. var offX = elDim.width / 2
  78. var offY = 0
  79. grabEl.style.left = e.clientX - offX + "px"
  80. grabEl.style.top = e.clientY - offY + "px"
  81. var targetEl = e.target
  82. // if(!targetEl.matches(".hpane")) {
  83. for (;targetEl !== null && !targetEl.matches(".hpane"); targetEl = targetEl.parentElement); // find Parent ".hpane"
  84. if (targetEl != null && targetEl.matches(".hpane:not(.preview)")) {
  85. // check attachment
  86. var placement = checkAttach(targetEl, e)
  87. if (placement !== 0) {
  88. previewPanel(grabEl, targetEl, placement)
  89. } else {
  90. removePreviews()
  91. }
  92. } else {
  93. removePreviews()
  94. }
  95. })
  96. document.addEventListener("mouseup", function(e) {
  97. if (sectionResizeEl) {
  98. sectionResizeEl.classList.remove("resizing")
  99. sectionResizeEl = null
  100. return
  101. }
  102. // Drag
  103. if (grabEl === undefined) return
  104. removePreviews()
  105. grabEl.classList.remove("moving")
  106. var targetEl = e.target
  107. for (;targetEl !== null && !targetEl.matches(".hpane"); targetEl = targetEl.parentElement); // find Parent ".hpane"
  108. if (targetEl !== null) {
  109. var placement = checkAttach(targetEl, e)
  110. if (placement !== 0) {
  111. grabEl.classList.remove("detached")
  112. grabEl.removeAttribute("style")
  113. attachPanel(grabEl, targetEl, placement)
  114. }
  115. }
  116. grabEl = undefined
  117. })
  118. }
  119. function attachPanel(grabEl, targetEl, placement) {
  120. if (!placement) {
  121. return
  122. }
  123. var type
  124. if ((placement % 2) === 1)type = "horizontal" // else
  125. if ((placement % 2) === 0)type = "vertical"
  126. var parentEl = targetEl.parentElement
  127. var sectionEl
  128. var sibEl = targetEl // it will be new sibling
  129. var newSectionEl = document.createElement("section")
  130. newSectionEl.classList.add(type)
  131. newSectionEl.style["flex-basis"] = targetEl.style["flex-basis"]
  132. if (sibEl.nextElementSibling !== null && sibEl.nextElementSibling.matches("section, .hpane")) {
  133. parentEl.insertBefore(newSectionEl, parentEl.children[0])
  134. } else {
  135. parentEl.appendChild(newSectionEl)
  136. }
  137. // parentEl.removeChild(sibEl)
  138. grabEl.style["flex-basis"] = "33%"
  139. sibEl.style["flex-basis"] = "66%"
  140. if (placement < 3) {
  141. newSectionEl.appendChild(grabEl)
  142. newSectionEl.appendChild(sibEl) // will this work?
  143. // $section.append(what);
  144. // $section.append("<div class='splitter'></div>");
  145. // $section.append($sib);
  146. } else {
  147. newSectionEl.appendChild(sibEl)
  148. newSectionEl.appendChild(grabEl) // will this work?
  149. // $section.append($sib);
  150. // $section.append("<div class='splitter'></div>");
  151. // $section.append(what);
  152. }
  153. }
  154. function removePreviews() {
  155. var previewEls = document.querySelectorAll(".attach-preview")
  156. if (previewEls === null) { // not sure if it is needed
  157. return
  158. }
  159. for (var i = previewEls.length; i--; i >= 0) {
  160. previewEls[i].style.display = "none"
  161. }
  162. }
  163. function checkAttach(targetEl, e) {
  164. var targetDim = targetEl.getBoundingClientRect()
  165. var tW = targetDim.width / 3
  166. var tH = targetDim.height / 3
  167. var rPos = {x: e.pageX - targetDim.left, y: e.pageY - targetDim.top}
  168. // Calc dists and check the closest one
  169. // Counter clock wise 1 TOP 2 RIGHT 3 BOTTOM 4 LEFT
  170. if (rPos.x > tW && rPos.x < targetDim.width - tW && rPos.y < tH) { // 1 Top
  171. return 1
  172. } else if (rPos.x > tW && rPos.x < targetDim.width - tW && rPos.y > targetDim.height - tH) { // 3 Bottom
  173. return 3
  174. } else if (rPos.x < tW) { // 2 Left
  175. return 2
  176. } else if (rPos.x > targetDim.width - tW) { // 4 Right
  177. return 4
  178. }
  179. return 0
  180. }
  181. function previewPanel(grabEl, targetEl, placement) {
  182. var previewEl = document.querySelector(".attach-preview")
  183. if (previewEl === undefined || previewEl === null) {
  184. previewEl = document.createElement("div")
  185. previewEl.setAttribute("class", "attach-preview")
  186. previewEl.setAttribute("style", "display:none;position:fixed")
  187. document.body.appendChild(previewEl)
  188. }
  189. previewEl.style.display = "block" // Show element
  190. var targetDim = targetEl.getBoundingClientRect()
  191. if ((placement % 2) === 1) { // Odd is top or bottom
  192. previewEl.style.height = (targetDim.height / 3) + "px"
  193. previewEl.style.width = targetDim.width + "px"
  194. previewEl.style.left = targetDim.left + "px"
  195. if (placement === 1) {
  196. previewEl.style.top = targetDim.top + "px"
  197. } else {
  198. previewEl.style.top = (targetDim.top + targetDim.height - (targetDim.height / 3)) + "px"
  199. }
  200. } else if ((placement % 2) === 0) {
  201. previewEl.style.height = targetDim.height + "px"
  202. previewEl.style.width = (targetDim.width / 3) + "px"
  203. previewEl.style.top = targetDim.top + "px"
  204. if (placement === 2) {
  205. previewEl.style.left = targetDim.left + "px"
  206. } else {
  207. previewEl.style.left = (targetDim.left + targetDim.width - (targetDim.width / 3)) + "px"
  208. }
  209. }
  210. }
  211. window.onload = startHLayout
  212. })(window)
  213. /*
  214. var md
  215. function startHLayoutEvents() {
  216. document.addEventListener("mousemove", function(e) {
  217. if (md === undefined) md = {x: e.clientX, y: e.clientY}
  218. md.deltaX = e.clientX - md.x
  219. md.deltaY = e.clientY - md.y
  220. md.x = e.clientX
  221. md.y = e.clientY
  222. })
  223. // Global mouse event;
  224. var $grab = undefined;
  225. // Start drag
  226. $(document).on('mousedown','.hpane > header',function(e){
  227. if(e.which != 1) return;
  228. if(!$(e.target).is(".hpane > header")) return;
  229. e.preventDefault();
  230. e.stopPropagation();
  231. $grab = $(this).parent();
  232. $parent = $grab.parent();
  233. var next = $grab.next();
  234. var origW = $grab.width();
  235. var origH = $grab.height();
  236. // Check if we are root?
  237. var dim = {w: $grab.width(), h: $grab.height()};
  238. var pos = $grab.position();
  239. $($grab).detach().appendTo('body').addClass("detached").addClass("moving").css({width:dim.w,height:dim.h});
  240. $('.hpane:not(.detached)').addClass("discover");
  241. // All childs to pointer event none
  242. if($parent.is('section')) {
  243. // We aren't
  244. $child = $parent.children('.hpane, section');
  245. $child.attr('style','');
  246. $child.css('flex-basis',$parent.css('flex-basis'));
  247. $child.detach();
  248. $parent.replaceWith($child);
  249. }
  250. })
  251. var $sectionResize = null;
  252. $(document).on('mousedown','section',function(e) {
  253. var $target = $(e.target);
  254. if(!$target.is("section"))return;
  255. e.preventDefault();
  256. $sectionResize = $target;
  257. $sectionResize.addClass("resizing");
  258. });
  259. $(document).on('mousemove',function(e) {
  260. if($sectionResize == null) return;
  261. var $first = $sectionResize.children(':nth-child(1)');
  262. var $second = $sectionResize.children(':nth-child(2)');
  263. var common;
  264. var common2;
  265. if( $sectionResize.is(".horizontal")) {common = "height",common2 = "deltaY"};
  266. if( $sectionResize.is(".vertical")) {common = "width", common2 = "deltaX"};
  267. var parentValue = $sectionResize[common]();
  268. var hFirst = $first[common]();
  269. var hSec = $second[common]();
  270. var newVal1 = (hFirst + md[common2]) / parentValue * 100;
  271. var newVal2 = (hSec -md[common2]) / parentValue * 100;
  272. $first.css('flex-basis',newVal1 + "%");
  273. $second.css('flex-basis',newVal2 + "%");
  274. });
  275. $(document).on('mouseup',function(e) {
  276. if($sectionResize) {
  277. $sectionResize.removeClass("resizing");
  278. }
  279. $sectionResize = null;
  280. });
  281. $(document).on('mousemove',function(e) {
  282. if($grab == undefined) return;
  283. var pos = $grab.position();
  284. var nx = pos.left + md.deltaX;
  285. var ny = pos.top + md.deltaY;
  286. var offX = $grab.width() / 2;
  287. var offY = 0;
  288. $grab.css({left: e.clientX - offX, top: e.clientY -offY});
  289. // Check target
  290. var $target = $(e.target);
  291. if(!$target.is(".hpane")) {
  292. $target = $target.parents(".hpane");
  293. }
  294. if($target.is(".hpane:not(.preview)")){
  295. var placement = checkAttach($target,e);
  296. if(placement != 0 ) {
  297. previewPanel($grab,$target,placement);
  298. } else {
  299. removePreviews();
  300. }
  301. } else {
  302. removePreviews();
  303. }
  304. });
  305. $(document).on('mouseup',function(e) {
  306. if($grab == undefined) return;
  307. removePreviews();
  308. $grab.removeClass("moving");
  309. $('.hpane').removeClass("discover");
  310. $target = $(e.target);
  311. if(!$target.is(".hpane")) $target = $target.parents('.hpane');
  312. if($target.is(".hpane")){
  313. var placement = checkAttach($target,e);
  314. if(placement != 0 ) {
  315. $grab.removeClass("detached");
  316. $grab.attr('style','');
  317. attachPanel($grab,$target,placement);
  318. }
  319. }
  320. $grab = undefined;
  321. return;
  322. });
  323. }
  324. function recalcFlex() {
  325. $('section.horizontal > section, section.horizontal > .hpane').each(function() {
  326. var parentH = $(this).parent().height();
  327. var curH = $(this).height();
  328. var flex = 100 * curH / parentH;
  329. $(this).css({'flex-basis':flex + "%"});
  330. });
  331. $('section.vertical > section, section.vertical > .hpane').each(function() {
  332. var parentW = $(this).parent().width();
  333. var curW = $(this).width();
  334. var flex = 100 * curW / parentW;
  335. $(this).css({'flex-basis':flex + "%"});
  336. });
  337. }
  338. recalcFlex();
  339. function checkAttach($target,e) {
  340. var tW = $target.width()/3;
  341. var tH = $target.height()/3;
  342. var targetPos = $target.offset();
  343. var dim = { w: $target.width(), h: $target.height()};
  344. var rPos = { x: e.pageX - targetPos.left, y: e.pageY - targetPos.top};
  345. //Calc dists and check the closest one
  346. if(rPos.x > tW && rPos.x < dim.w - tW && rPos.y < tH) { // 1 Top
  347. return 1;
  348. } else if(rPos.x > tW && rPos.x < dim.w - tW && rPos.y > dim.h - tH){ // 3 Bottom
  349. return 3;
  350. } else if(rPos.x < tW) { // 2 Left
  351. return 2;
  352. } else if( rPos.x > dim.w - tW){ // 4 Right
  353. return 4;
  354. }
  355. return 0;
  356. }
  357. function removePreviews() {
  358. $('.attach-preview').hide();
  359. }
  360. function previewPanel($grab,$target,attach) {
  361. $previewDiv = $(".attach-preview");
  362. if($previewDiv.length == 0 ) {
  363. $previewDiv = $('<div class="attach-preview" style="display:none;position:fixed"></div>').appendTo('body');
  364. }
  365. $previewDiv.show();
  366. var dim = {w:$target.width(),h:$target.height()};
  367. var pos = $target.offset();
  368. if((attach % 2) == 1) {
  369. $previewDiv.css('height',dim.h/3);
  370. $previewDiv.css("width",dim.w);
  371. $previewDiv.css("left",pos.left);
  372. if(attach == 1) {
  373. $previewDiv.css('top',pos.top);
  374. } else {
  375. $previewDiv.css('top',pos.top + dim.h - dim.h/3);
  376. }
  377. } else if((attach % 2) == 0) {
  378. $previewDiv.css("height",dim.h);
  379. $previewDiv.css('width',dim.w/3);
  380. $previewDiv.css("top",pos.top);
  381. if(attach == 2) {
  382. $previewDiv.css('left',pos.left);
  383. } else {
  384. $previewDiv.css('left',pos.left + dim.w - dim.w/3);
  385. }
  386. }
  387. }
  388. function attachPanel(what,target, attach) {
  389. if(attach){
  390. var type
  391. if((attach % 2) == 1)type = "horizontal";
  392. if((attach % 2) == 0)type = "vertical";
  393. $target = $(target);
  394. $parent = $(target).parent();
  395. $sib = $(target);
  396. if($sib.next().is("section, .hpane,.splitter")) {
  397. $section = $("<section class='" + type +"' style='flex-basis:" + $target.css('flex-basis') + "'></section>").prependTo($parent);
  398. } else {
  399. $section = $("<section class='" + type + "' style='flex-basis:" + $target.css('flex-basis') +" '></section>").appendTo($parent);
  400. }
  401. $sib.detach();
  402. what.css('flex-basis','33%');
  403. $sib.css('flex-basis','66%');
  404. if(attach < 3) {
  405. $section.append(what);
  406. //$section.append("<div class='splitter'></div>");
  407. $section.append($sib);
  408. } else {
  409. $section.append($sib);
  410. //$section.append("<div class='splitter'></div>");
  411. $section.append(what);
  412. }
  413. }
  414. }
  415. $(function() {
  416. startHLayoutEvents();
  417. });*/