flexible-admin.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. (function ($) {
  2. Drupal.flexible = Drupal.flexible || {};
  3. Drupal.flexible.splitters = [];
  4. /**
  5. * Fix the height of all splitters to be the same as the items they are
  6. * splitting.
  7. */
  8. Drupal.flexible.fixHeight = function() {
  9. for (i in Drupal.flexible.splitters) {
  10. Drupal.flexible.splitters[i].fixHeight();
  11. }
  12. }
  13. Drupal.behaviors.flexibleAdmin = {
  14. attach: function(context) {
  15. // Show/hide layout manager button
  16. $('#panels-flexible-toggle-layout:not(.panels-flexible-processed)', context)
  17. .addClass('panels-flexible-processed')
  18. .click(function() {
  19. $('.panel-flexible-admin')
  20. .toggleClass('panel-flexible-no-edit-layout')
  21. .toggleClass('panel-flexible-edit-layout');
  22. if ($('.panel-flexible-admin').hasClass('panel-flexible-edit-layout')) {
  23. $(this).val(Drupal.t('Hide layout designer'));
  24. Drupal.flexible.fixHeight();
  25. }
  26. else {
  27. $(this).val(Drupal.t('Show layout designer'));
  28. }
  29. return false;
  30. });
  31. // Window splitter behavior.
  32. $('div.panels-flexible-splitter:not(.panels-splitter-processed)')
  33. .addClass('panels-splitter-processed')
  34. .each(function() {
  35. Drupal.flexible.splitters.push(new Drupal.flexible.splitter($(this)));
  36. });
  37. Drupal.flexible.fixHeight();
  38. }
  39. };
  40. Drupal.flexible.splitter = function($splitter) {
  41. var splitter = this;
  42. this.fixHeight = function() {
  43. // Set the splitter height to the shorter of the two:
  44. $splitter.height(Math.max(this.left.outerHeight(), this.right.outerHeight()));
  45. }
  46. function splitterStart(event) {
  47. // Bind motion events.
  48. $(document)
  49. .bind("mousemove", splitterMove)
  50. .bind("mouseup", splitterEnd);
  51. // Calculate some data about our split regions:
  52. splitter.getSizes();
  53. // The X coordinate where we clicked.
  54. splitter.startX = event.pageX;
  55. // The current sizes of the left/right panes.
  56. splitter.currentLeft = parseFloat(splitter.left_width) * parseFloat(splitter.left_scale);
  57. splitter.currentRight = parseFloat(splitter.right_width) * parseFloat(splitter.right_scale);
  58. // The starting sizes of the left right panes.
  59. splitter.startLeft = splitter.currentLeft;
  60. splitter.startRight = splitter.currentRight;
  61. if (splitter.left_width_type == splitter.right_width_type) {
  62. // If they're the same type, add the two together so we know how
  63. // much space we have for splitting.
  64. splitter.max = splitter.startLeft + splitter.startRight;
  65. // calculate unit size and min/max width.
  66. if (splitter.left_width_type == '%') {
  67. splitter.left_total = splitter.left.width() / (splitter.left_width / 100);
  68. // One pixel is equivalent to what percentage of the total?
  69. splitter.left_unit = (1 / splitter.left_total) * 100;
  70. splitter.left_min = 5; // minimum % we'll use.
  71. }
  72. else {
  73. splitter.left_unit = 1;
  74. splitter.left_min = 25; // minimum pixels we'll use.
  75. }
  76. if (splitter.right_width_type == '%') {
  77. splitter.right_total = splitter.right.width() / (splitter.right_width / 100);
  78. // One pixel is equivalent to what percentage of the total?
  79. splitter.right_unit = (1 / splitter.right_total) * 100;
  80. splitter.right_min = 5; // minimum % we'll use.
  81. }
  82. else {
  83. splitter.right_unit = 1;
  84. splitter.right_min = 25; // minimum pixels we'll use.
  85. }
  86. }
  87. else {
  88. // Figure out the parent blob's width and set the max to that
  89. splitter.parent = $splitter.parent().parent();
  90. if (splitter.left_width_type != 'px') {
  91. // Only the 'px' side can resize.
  92. splitter.left_unit = 0;
  93. splitter.right_unit = 1;
  94. splitter.right_min = 25;
  95. splitter.right_padding = parseInt(splitter.parent.css('padding-right'));
  96. splitter.right_parent = parseInt(splitter.right.parent().css('margin-right'));
  97. splitter.max = splitter.right.width() + splitter.left.parent().width() -
  98. (splitter.left.siblings(':not(.panels-flexible-splitter)').length * 25) - 25;
  99. }
  100. else {
  101. splitter.right_unit = 0;
  102. splitter.left_unit = 1;
  103. splitter.left_min = 25;
  104. splitter.left_padding = parseInt(splitter.parent.css('padding-left'));
  105. splitter.left_parent = parseInt(splitter.left.parent().css('margin-left'));
  106. if (splitter.right_id) {
  107. splitter.max = splitter.left.width() + splitter.right.parent().width() -
  108. (splitter.right.siblings(':not(.panels-flexible-splitter)').length * 25) - 25;
  109. }
  110. else {
  111. var subtract = 0;
  112. splitter.left.siblings(':not(.panels-flexible-splitter)').each(function() { subtract += $(this).width()});
  113. splitter.max = splitter.left.parent().width() - subtract;
  114. }
  115. }
  116. }
  117. var offset = $(splitter.splitter).offset();
  118. // Create boxes to display widths left and right of the mouse pointer.
  119. // Create left box only if left box is mobile.
  120. if (splitter.left_unit) {
  121. splitter.left_box = $('<div class="flexible-splitter-hover-box">&nbsp;</div>');
  122. $('body').append(splitter.left_box);
  123. splitter.left_box.css('top', offset.top);
  124. splitter.left_box.css('left', event.pageX - 65);
  125. if (splitter.left_width_type == '%') {
  126. var left = splitter.currentLeft / splitter.left_scale;
  127. splitter.left_box.html(left.toFixed(2) + splitter.left_width_type);
  128. }
  129. else {
  130. // make sure pixel values are always whole integers.
  131. splitter.currentLeft = parseInt(splitter.currentLeft);
  132. splitter.left_box.html(splitter.currentLeft + splitter.left_width_type);
  133. }
  134. }
  135. // Create the right box if the right side is mobile.
  136. if (splitter.right_unit) {
  137. splitter.right_box = $('<div class="flexible-splitter-hover-box"></div>');
  138. $('body').append(splitter.right_box);
  139. splitter.right_box.css('top', offset.top);
  140. splitter.right_box.css('left', event.pageX + 5);
  141. if (splitter.right_width_type == '%') {
  142. var right = splitter.currentRight / splitter.right_scale;
  143. splitter.right_box.html(right.toFixed(2) + splitter.right_width_type);
  144. }
  145. else {
  146. // make sure pixel values are always whole integers.
  147. splitter.currentRight = parseInt(splitter.currentRight);
  148. splitter.right_box.html(splitter.currentRight + splitter.right_width_type);
  149. }
  150. }
  151. return false;
  152. };
  153. function splitterMove(event) {
  154. var diff = splitter.startX - event.pageX;
  155. var moved = 0;
  156. if (event.keyCode == 37) diff = 10;
  157. if (event.keyCode == 39) diff = -10;
  158. // Bah, javascript has no logical xor operator
  159. if ((splitter.left_unit && !splitter.right_unit) ||
  160. (!splitter.left_unit && splitter.right_unit)) {
  161. // This happens when one side is fixed and the other side is fluid. The
  162. // fixed side actually adjusts while the fluid side does not. However,
  163. // in order to move the fluid side we have to adjust the padding
  164. // on our parent object.
  165. if (splitter.left_unit) {
  166. // Only the left box is allowed to move.
  167. splitter.currentLeft = splitter.startLeft - diff;
  168. if (splitter.currentLeft < splitter.left_min) {
  169. splitter.currentLeft = splitter.left_min;
  170. }
  171. if (splitter.currentLeft > splitter.max) {
  172. splitter.currentLeft = splitter.max;
  173. }
  174. // If the shift key is pressed, go with 1% or 10px boundaries.
  175. if (event.shiftKey) {
  176. splitter.currentLeft = parseInt(splitter.currentLeft / 10) * 10;
  177. }
  178. moved = (splitter.startLeft - splitter.currentLeft);
  179. }
  180. else {
  181. // Only the left box is allowed to move.
  182. splitter.currentRight = splitter.startRight + diff;
  183. if (splitter.currentRight < splitter.right_min) {
  184. splitter.currentRight = splitter.right_min;
  185. }
  186. if (splitter.currentRight > splitter.max) {
  187. splitter.currentRight = splitter.max;
  188. }
  189. // If the shift key is pressed, go with 1% or 10px boundaries.
  190. if (event.shiftKey) {
  191. splitter.currentRight = parseInt(splitter.currentRight / 10) * 10;
  192. }
  193. moved = (splitter.currentRight - splitter.startRight);
  194. }
  195. }
  196. else {
  197. // If they are both the same type, do this..
  198. // Adjust the left side by the amount we moved.
  199. var left = -1 * diff * splitter.left_unit;
  200. splitter.currentLeft = splitter.startLeft + left;
  201. if (splitter.currentLeft < splitter.left_min) {
  202. splitter.currentLeft = splitter.left_min;
  203. }
  204. if (splitter.currentLeft > splitter.max - splitter.right_min) {
  205. splitter.currentLeft = splitter.max - splitter.right_min;
  206. }
  207. // If the shift key is pressed, go with 1% or 10px boundaries.
  208. if (event.shiftKey) {
  209. if (splitter.left_width_type == '%') {
  210. splitter.currentLeft = parseInt(splitter.currentLeft / splitter.left_scale) * splitter.left_scale;
  211. }
  212. else {
  213. splitter.currentLeft = parseInt(splitter.currentLeft / 10) * 10;
  214. }
  215. }
  216. // Now automatically make the right side to be the other half.
  217. splitter.currentRight = splitter.max - splitter.currentLeft;
  218. // recalculate how far we've moved into pixels so we can adjust our visible
  219. // boxes.
  220. moved = (splitter.startLeft - splitter.currentLeft) / splitter.left_unit;
  221. }
  222. if (splitter.left_unit) {
  223. splitter.left_box.css('left', splitter.startX - 65 - moved);
  224. if (splitter.left_width_type == '%') {
  225. var left = splitter.currentLeft / splitter.left_scale;
  226. splitter.left_box.html(left.toFixed(2) + splitter.left_width_type);
  227. }
  228. else {
  229. splitter.left_box.html(parseInt(splitter.currentLeft) + splitter.left_width_type);
  230. }
  231. // Finally actually move the left side
  232. splitter.left.css('width', splitter.currentLeft + splitter.left_width_type);
  233. }
  234. else {
  235. // if not moving the left side, adjust the parent padding instead.
  236. splitter.parent.css('padding-right', (splitter.right_padding + moved) + 'px');
  237. splitter.right.parent().css('margin-right', (splitter.right_parent - moved) + 'px');
  238. }
  239. if (splitter.right_unit) {
  240. splitter.right_box.css('left', splitter.startX + 5 - moved);
  241. if (splitter.right_width_type == '%') {
  242. var right = splitter.currentRight / splitter.right_scale;
  243. splitter.right_box.html(right.toFixed(2) + splitter.right_width_type);
  244. }
  245. else {
  246. splitter.right_box.html(parseInt(splitter.currentRight) + splitter.right_width_type);
  247. }
  248. // Finally actually move the right side
  249. splitter.right.css('width', splitter.currentRight + splitter.right_width_type);
  250. }
  251. else {
  252. // if not moving the right side, adjust the parent padding instead.
  253. splitter.parent.css('padding-left', (splitter.left_padding - moved) + 'px');
  254. splitter.left.parent().css('margin-left', (splitter.left_parent + moved) + 'px');
  255. }
  256. return false;
  257. };
  258. function splitterKeyPress(event) {
  259. splitterStart(event);
  260. splitterMove(event);
  261. splitterEnd(event);
  262. };
  263. function splitterEnd(event) {
  264. if (splitter.left_unit) {
  265. splitter.left_box.remove();
  266. }
  267. if (splitter.right_unit) {
  268. splitter.right_box.remove();
  269. }
  270. splitter.left.css("-webkit-user-select", "text"); // let Safari select text again
  271. splitter.right.css("-webkit-user-select", "text"); // let Safari select text again
  272. if (splitter.left_unit) {
  273. splitter.left_width = splitter.currentLeft / parseFloat(splitter.left_scale);
  274. }
  275. if (splitter.right_unit) {
  276. splitter.right_width = splitter.currentRight / parseFloat(splitter.right_scale);
  277. }
  278. splitter.putSizes();
  279. Drupal.flexible.fixHeight();
  280. $(document)
  281. .unbind("mousemove", splitterMove)
  282. .unbind("mouseup", splitterEnd);
  283. // Store the data on the server.
  284. Drupal.ajax['flexible-splitter-ajax'].options.data = {
  285. 'left': splitter.left_id,
  286. 'left_width': splitter.left_width,
  287. 'right': splitter.right_id,
  288. 'right_width': splitter.right_width
  289. };
  290. $('.panel-flexible-edit-layout').trigger('UpdateFlexibleSplitter');
  291. };
  292. this.getSizes = function() {
  293. splitter.left_width = $splitter.children('.panels-flexible-splitter-left-width').html();
  294. splitter.left_scale = $splitter.children('.panels-flexible-splitter-left-scale').html();
  295. splitter.left_width_type = $splitter.children('.panels-flexible-splitter-left-width-type').html();
  296. splitter.right_width = $splitter.children('.panels-flexible-splitter-right-width').html();
  297. splitter.right_scale = $splitter.children('.panels-flexible-splitter-right-scale').html();
  298. splitter.right_width_type = $splitter.children('.panels-flexible-splitter-right-width-type').html();
  299. };
  300. this.putSizes = function() {
  301. $(splitter.left_class + '-width').html(splitter.left_width);
  302. if (splitter.left_class != splitter.right_class) {
  303. $(splitter.right_class + '-width').html(splitter.right_width);
  304. }
  305. }
  306. splitter.splitter = $splitter;
  307. splitter.left_class = $splitter.children('.panels-flexible-splitter-left').html();
  308. splitter.left_id = $splitter.children('.panels-flexible-splitter-left-id').html();
  309. splitter.left = $(splitter.left_class);
  310. splitter.right_class = $splitter.children('.panels-flexible-splitter-right').html();
  311. splitter.right_id = $splitter.children('.panels-flexible-splitter-right-id').html();
  312. splitter.right = $(splitter.right_class);
  313. $splitter
  314. .bind("mousedown", splitterStart)
  315. .bind("keydown", splitterKeyPress);
  316. };
  317. $(function() {
  318. /**
  319. * Provide an AJAX response command to allow the server to request
  320. * height fixing.
  321. */
  322. Drupal.ajax.prototype.commands.flexible_fix_height = function(ajax, command, status) {
  323. Drupal.flexible.fixHeight();
  324. };
  325. /**
  326. * Provide an AJAX response command to allow the server to change width on existing splitters.
  327. */
  328. Drupal.ajax.prototype.commands.flexible_set_width = function(ajax, command, status) {
  329. $(command.selector).html(command.width);
  330. };
  331. /**
  332. * Provide an AJAX response command to fix the first/last bits of a
  333. * group.
  334. */
  335. Drupal.ajax.prototype.commands.flexible_fix_firstlast = function(ajax, data, status) {
  336. $(data.selector + ' > div > .' + data.base)
  337. .removeClass(data.base + '-first')
  338. .removeClass(data.base + '-last');
  339. $(data.selector + ' > div > .' + data.base + ':first')
  340. .addClass(data.base + '-first');
  341. $(data.selector + ' > div > .' + data.base + ':last')
  342. .addClass(data.base + '-last');
  343. };
  344. // Create a generic ajax callback for use with the splitters which
  345. // background AJAX to store their data.
  346. var element_settings = {
  347. url: Drupal.settings.flexible.resize,
  348. event: 'UpdateFlexibleSplitter',
  349. keypress: false,
  350. // No throbber at all.
  351. progress: { 'type': 'none' }
  352. };
  353. Drupal.ajax['flexible-splitter-ajax'] = new Drupal.ajax('flexible-splitter-ajax', $('.panel-flexible-admin').get(0), element_settings);
  354. // Prevent ajax goo from doing odd things to our layout.
  355. Drupal.ajax['flexible-splitter-ajax'].beforeSend = function() { };
  356. Drupal.ajax['flexible-splitter-ajax'].beforeSerialize = function() { };
  357. });
  358. })(jQuery);