Selection.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. SC.loadPackage({ 'Selection': {
  2. comment: 'I represent the selection of the editing tool, holding one or more Elements. I selection can move its Elements, it shows the Widgets, that apply to all of the Elements in the current selection, and it can start the content editing mode of one of its Elements.',
  3. sharedProperties: {
  4. selectionTools: { initValue: '<div class="sg-editing-selection"><div class="sg-editing-selection-widget-menu-right"></div><div class="sg-editing-selection-widget-menu-bottom"></div></div>' },
  5. },
  6. properties: {
  7. node: { comment: 'My DOM node.' },
  8. elements: { comment: 'I hold an array of the currently selected elements.' },
  9. active: { comment: 'Wether a selection is active or not.' },
  10. widgetsRight: { comment: 'I hold an array of the standard widgets, which are applicable to all elements, and which are shown on the right side of the selection.'},
  11. widgetsBottom: { comment: 'I hold an array of the widgets, which are applicable to the elements in the current selection, and which are shown on the bottom of the selection.'},
  12. menuNodeRight: { comment: 'I hold the DOM node containing the right menu node.'},
  13. menuNodeBottom: { comment: 'I hold the DOM node containing the bottom menu node.'},
  14. activeWidget: { comment: 'I store either null or the active (selected) widget.'},
  15. lockWidget: { comment: 'My lockWidget plays a special role, since it appears only on multiple selections and must update its state.'}
  16. },
  17. methods: {
  18. init: {
  19. comment: 'I init myself.',
  20. code: function(){
  21. var node = (new DOMParser()).parseFromString(this.class.get('selectionTools'), 'text/html').body.firstChild;
  22. this.set({
  23. node: node,
  24. menuNodeRight: node.firstChild,
  25. menuNodeBottom: node.lastChild,
  26. widgetsRight: [],
  27. widgetsBottom: [],
  28. active: false,
  29. elements: [],
  30. activeWidget: null
  31. });
  32. var generalWidgets = ['WidgetLayerTop', 'WidgetLayerBottom', 'WidgetCopy', 'WidgetDelete', 'WidgetEditHTML'],
  33. generalWidgetsContainer = this.get('menuNodeRight'),
  34. widget = null;
  35. for(var i = 0, l = generalWidgets.length; i < l; i++){
  36. widget = SC.init(generalWidgets[i], this);
  37. this.get('widgetsRight').push(widget);
  38. generalWidgetsContainer.appendChild(widget.get('widgetMenu'));
  39. }
  40. this.set({ lockWidget: SC.init('WidgetLock', this) });
  41. }
  42. },
  43. updateWidgetMenu: {
  44. comment: 'I update the menu of widgets according to the current selection.',
  45. code: function(){
  46. // Update widget menu to the right
  47. for(var widgetsRight = this.get('widgetsRight'), i = 0, l = widgetsRight.length;
  48. i < l; i++){
  49. widgetsRight[i].set({ isWidgetActive: false });
  50. }
  51. // Update widget menu to the bottom
  52. var elements = this.get('elements'),
  53. elementsWidgetSets = [],
  54. currentWidgets = [],
  55. currentWidgetsClasses = null,
  56. currentWidgetsContainer = this.get('menuNodeBottom'),
  57. widget = null;
  58. for(var widgetsBottom = this.get('widgetsBottom'), i = 0, l = widgetsBottom.length;
  59. i < l; i++){
  60. widgetsBottom[i].set({ isWidgetActive: false });
  61. currentWidgetsContainer.removeChild(widgetsBottom[i].get('widgetMenu'));
  62. }
  63. if(elements.length > 0){
  64. // find intersection of applicable widgets
  65. for(var i = 0, l = elements.length; i < l; i++){
  66. elementsWidgetSets.push( elements[i].class.get('applicableWidgets') );
  67. }
  68. if(elementsWidgetSets.length > 1){
  69. currentWidgetsClasses = elementsWidgetSets.shift().filter(function(v) {
  70. return elementsWidgetSets.every(function(a) {
  71. return a.indexOf(v) !== -1;
  72. });
  73. });
  74. }else{
  75. currentWidgetsClasses = elementsWidgetSets[0];
  76. }
  77. for(var i = 0, l = currentWidgetsClasses.length; i < l; i++){
  78. widget = SC.init(currentWidgetsClasses[i], this);
  79. currentWidgets.push(widget);
  80. currentWidgetsContainer.appendChild(widget.get('widgetMenu'));
  81. }
  82. }
  83. this.set({
  84. widgetsBottom: currentWidgets,
  85. activeWidget: null
  86. });
  87. // Update widget to the right
  88. this.do('updateLockGroup');
  89. // Finally draw red outline when multiple elements are selected
  90. if(elements.length === 1){
  91. this.get('node').classList.remove('sg-editing-selection-outline');
  92. }else{
  93. this.get('node').classList.add('sg-editing-selection-outline');
  94. }
  95. }
  96. },
  97. updateLockGroup: {
  98. comment: 'After adding and removing elements, I check wether I have multiple elements, and if so, if they form a locked group or not.',
  99. code: function(){
  100. var myElements = this.get('elements'),
  101. lockWidget = this.get('lockWidget'),
  102. menuNodeRight = this.get('menuNodeRight'),
  103. isGroup = true;
  104. if(myElements.length > 1){
  105. // check and add lockWidget
  106. if(lockWidget.get('widgetMenu').parentNode !== menuNodeRight){
  107. menuNodeRight.insertBefore(lockWidget.get('widgetMenu'), menuNodeRight.childNodes[0]);
  108. }
  109. // check group status of myElements
  110. for(var i = 0, l = myElements.length; i < l; i++){
  111. isGroup = isGroup && (myElements[i].get('group') !== null);
  112. }
  113. if(isGroup){
  114. for(var i = 1, l = myElements.length; i < l; i++){
  115. isGroup = isGroup && (myElements[i].get('group') === myElements[i-1].get('group'))
  116. }
  117. }
  118. lockWidget.set({ locked: isGroup })
  119. }else if(myElements.length > 0){
  120. // remove lockWidget
  121. if(lockWidget.get('widgetMenu').parentNode === menuNodeRight){
  122. menuNodeRight.removeChild(lockWidget.get('widgetMenu'));
  123. }
  124. }
  125. }
  126. },
  127. callWidgetAction: {
  128. comment: 'I call a widget object\'s action',
  129. code: function(config){
  130. if(this.do('isEmpty')){
  131. return;
  132. }
  133. var widget = (function(){
  134. var widgetsRight = this.get('widgetsRight'),
  135. widgetsBottom = this.get('widgetsBottom');
  136. for(var i = 0, l = widgetsRight.length; i < l; i++){
  137. if(widgetsRight[i].class() === config.widget){
  138. return widgetsRight[i];
  139. }
  140. }
  141. for(var i = 0, l = widgetsBottom.length; i < l; i++){
  142. if(widgetsBottom[i].class() === config.widget){
  143. return widgetsBottom[i];
  144. }
  145. }
  146. if('WidgetLock' === config.widget){
  147. return this.get('lockWidget');
  148. }
  149. }).call(this);
  150. if(!widget){
  151. return;
  152. }
  153. widget.do('action', config.modifier)
  154. }
  155. },
  156. addElement: {
  157. comment: 'I add anElement to myself.',
  158. code: function(anElement){
  159. var elementsToAdd = [ anElement ],
  160. myElements = this.get('elements'),
  161. group = anElement.get('group');
  162. if(group !== null){
  163. for(var elements = SuperGlue.get('document').get('children'),
  164. i = 0, l = elements.length; i < l; i++){
  165. if(elements[i].get('group') === group){
  166. elementsToAdd.push(elements[i]);
  167. }
  168. }
  169. }
  170. for(var i = 0, l = elementsToAdd.length; i < l; i++){
  171. if(myElements.indexOf(elementsToAdd[i]) < 0){
  172. myElements.push(elementsToAdd[i]);
  173. }
  174. }
  175. if(myElements.length === 1){
  176. myElements[0].get('resizeHandles').set({ selected: true });
  177. myElements[0].get('resizeHandles').do('showResizeHandles');
  178. }else{
  179. for(var i = 0, l = myElements.length; i < l; i++){
  180. myElements[i].get('resizeHandles').set({ selected: false });
  181. }
  182. }
  183. if(!this.get('active')){
  184. SuperGlue.get('document').get('editingContainer').appendChild(this.get('node'));
  185. }
  186. this.do('updateDimensions');
  187. this.do('updateWidgetMenu');
  188. }
  189. },
  190. removeElement: {
  191. comment: 'I remove anElement from myself.',
  192. code: function(anElement){
  193. var myElements = this.get('elements'),
  194. elementsToRemove = [ anElement ],
  195. group = anElement.get('group');
  196. if(group !== null){
  197. for(var i = 0, l = myElements.length; i < l; i++){
  198. if(myElements[i].get('group') === group){
  199. elementsToRemove.push(myElements[i]);
  200. }
  201. }
  202. }
  203. for(var i = 0, l = elementsToRemove.length; i < l; i++){
  204. var elementIndex = myElements.indexOf(elementsToRemove[i]);
  205. if(elementIndex >= 0){
  206. myElements.splice(elementIndex, 1);
  207. elementsToRemove[i].get('resizeHandles').set({ selected: false, mouseOnElement: false });
  208. elementsToRemove[i].get('resizeHandles').do('hideResizeHandles', true);
  209. }
  210. }
  211. if(myElements.length === 0){
  212. SuperGlue.get('document').get('editingContainer').removeChild(this.get('node'));
  213. this.set({ active: false });
  214. }else{
  215. if(myElements.length === 1){
  216. myElements[0].get('resizeHandles').set({ selected: true });
  217. myElements[0].get('resizeHandles').do('showResizeHandles');
  218. }else{
  219. for(var i = 0, l = myElements.length; i < l; i++){
  220. myElements[i].get('resizeHandles').set({ selected: false });
  221. }
  222. }
  223. this.do('updateDimensions');
  224. this.do('updateWidgetMenu');
  225. }
  226. }
  227. },
  228. toggleSelectionFor: {
  229. comment: 'I check wether anElement belongs to me already, and then add or remove it.',
  230. code: function(anElement){
  231. if(this.get('elements').indexOf(anElement) > -1){
  232. this.do('removeElement', anElement);
  233. }else{
  234. this.do('addElement', anElement);
  235. }
  236. }
  237. },
  238. clearAll: {
  239. comment: 'I remove all my Elements.',
  240. code: function(){
  241. var elements = this.get('elements');
  242. for(var i = 0, l = elements.length; i < l; i++){
  243. elements[i].get('resizeHandles').set({ selected: false, mouseOnElement: false });
  244. elements[i].get('resizeHandles').do('hideResizeHandles', true)
  245. }
  246. var widgetsBottom = this.get('widgetsBottom');
  247. for(var i = 0, l = widgetsBottom.length; i < l; i++){
  248. widgetsBottom[i].set({ isWidgetActive: false });
  249. }
  250. var editingContainer = SuperGlue.get('document').get('editingContainer');
  251. if(this.get('node').parentNode === editingContainer){
  252. editingContainer.removeChild(this.get('node'));
  253. }
  254. this.set({
  255. elements: [],
  256. active: false
  257. });
  258. }
  259. },
  260. isEmpty: {
  261. comment: 'Am I empty?',
  262. code: function(){
  263. return this.get('elements').length === 0
  264. }
  265. },
  266. calculateDimensions: {
  267. comment: 'I return the overall dimension to fit in all my Elements in the form [top, left, width, height].',
  268. code: function(){
  269. if(this.do('isEmpty')){ return []; }
  270. var myElements = this.get('elements'),
  271. top = myElements[0].get('top'),
  272. left = myElements[0].get('left'),
  273. width = 0,
  274. height = 0,
  275. l = myElements.length;
  276. for(var i = 0; i < l; i++){
  277. top = myElements[i].get('top') < top ? myElements[i].get('top') : top;
  278. left = myElements[i].get('left') < left ? myElements[i].get('left') : left;
  279. width = (myElements[i].get('width') + myElements[i].get('left')) < width
  280. ? width
  281. : (myElements[i].get('width') + myElements[i].get('left'));
  282. height = (myElements[i].get('height') + myElements[i].get('top')) < height
  283. ? height
  284. : (myElements[i].get('height') + myElements[i].get('top'));
  285. }
  286. width -= left;
  287. height -= top;
  288. return [top, left, width, height];
  289. }
  290. },
  291. updateDimensions: {
  292. comment: 'I update the overall dimension of my DOM node to fit in all my Elements.',
  293. code: function(){
  294. if(this.do('isEmpty')){ return; }
  295. var nodeStyle = this.get('node').style,
  296. dimensions = this.do('calculateDimensions'),
  297. top = dimensions[0],
  298. left = dimensions[1],
  299. width = dimensions[2],
  300. height = dimensions[3];
  301. nodeStyle.top = top + 'px';
  302. nodeStyle.left = left + 'px';
  303. nodeStyle.width = width + 'px';
  304. nodeStyle.height = height + 'px';
  305. }
  306. },
  307. registerForSelection: {
  308. comment: 'I prepare an Element to be selectable. Used by Element>>init.',
  309. code: function(anElement){
  310. var self = this,
  311. myNode = this.get('node'),
  312. thisElement = anElement,
  313. elementNode = anElement.get('node'),
  314. elements = [],
  315. infiniteSpace = true,
  316. pageWidth = 0,
  317. virtualTop = 0,
  318. virtualLeft = 0,
  319. virtualWidth = 0,
  320. virtualHeight = 0,
  321. elementsOffsetsX = null,
  322. elementsOffsetsY = null,
  323. targetNotInSelection,
  324. isGroup,
  325. group,
  326. startX = 0,
  327. startY = 0,
  328. clickPrecisionXleft = 0,
  329. clickPrecisionXright = 0,
  330. clickPrecisionYtop = 0,
  331. clickPrecisionYbottom = 0,
  332. withinClickPrecision = true,
  333. widthMarkersVisible,
  334. gridVisible,
  335. onMouseDown = function(evt){
  336. if(evt.button !== 0) return;
  337. if(evt.shiftKey || evt.ctrlKey){
  338. document.addEventListener('mouseup', onMouseUpWithModifier, true);
  339. SuperGlue.get('document').set({ interactionInProgress: true });
  340. // UNDO
  341. }else{
  342. startX = evt.pageX;
  343. startY = evt.pageY;
  344. clickPrecisionXleft = startX - 6;
  345. clickPrecisionXright = startX + 6;
  346. clickPrecisionYtop = startY - 6;
  347. clickPrecisionYbottom = startY + 6;
  348. withinClickPrecision = true;
  349. isGroup = false;
  350. infiniteSpace = ! SuperGlue.get('document').get('layout').centered;
  351. pageWidth = SuperGlue.get('document').get('layout').width;
  352. if(SuperGlue.get('document').get('grid').get('active')){
  353. var gridSize = SuperGlue.get('document').get('grid').get('gridSize');
  354. pageWidth = Math.floor(pageWidth / gridSize) * gridSize;
  355. }
  356. elements = self.get('elements');
  357. if(elements.length !== 0){
  358. targetNotInSelection = true;
  359. for(var i = 0, l = elements.length; i < l; i++){
  360. if(elements[i].get('node') === thisElement.get('node')){
  361. targetNotInSelection = false;
  362. break;
  363. }
  364. }
  365. if(targetNotInSelection){
  366. self.do('clearAll');
  367. elements = self.get('elements');
  368. }
  369. }else{
  370. targetNotInSelection = elements.indexOf(thisElement) < 0;
  371. }
  372. if(elements.length === 0){
  373. group = thisElement.get('group');
  374. if(group !== null){
  375. isGroup = true;
  376. for(var allElements = SuperGlue.get('document').get('children'),
  377. i = 0, l = allElements.length; i < l; i++){
  378. if(allElements[i].get('group') === group){
  379. elements.push(allElements[i]);
  380. }
  381. }
  382. }
  383. }
  384. if(elements.length === 0){
  385. virtualTop = anElement.get('top');
  386. virtualLeft = anElement.get('left');
  387. virtualWidth = anElement.get('width');
  388. virtualHeight = anElement.get('height');
  389. }else{
  390. var dimensions = self.do('calculateDimensions');
  391. virtualTop = dimensions[0];
  392. virtualLeft = dimensions[1];
  393. virtualWidth = dimensions[2];
  394. virtualHeight = dimensions[3];
  395. elementsOffsetsX = [];
  396. elementsOffsetsY = [];
  397. for(var i = 0, l = elements.length; i < l; i++){
  398. elementsOffsetsX.push( elements[i].get('left') - virtualLeft );
  399. elementsOffsetsY.push( elements[i].get('top') - virtualTop );
  400. }
  401. }
  402. document.addEventListener('mousemove', onMouseMove, true);
  403. document.addEventListener('mouseup', onMouseUp, true);
  404. SuperGlue.get('document').set({ interactionInProgress: true });
  405. // UNDO
  406. }
  407. evt.stopPropagation();
  408. evt.preventDefault();
  409. },
  410. onMouseUpWithModifier = function(evt){
  411. self.do('toggleSelectionFor', thisElement);
  412. document.removeEventListener('mouseup', onMouseUpWithModifier, true);
  413. SuperGlue.get('document').set({ interactionInProgress: false });
  414. // UNDO
  415. evt.stopPropagation();
  416. evt.preventDefault();
  417. },
  418. onMouseUp = function(evt){
  419. document.removeEventListener('mousemove', onMouseMove, true);
  420. document.removeEventListener('mouseup', onMouseUp, true);
  421. var myDocument = SuperGlue.get('document');
  422. myDocument.set({ interactionInProgress: false });
  423. myDocument.do('afterLayoutHasChanged');
  424. if(withinClickPrecision){
  425. if( !targetNotInSelection
  426. && thisElement.class() === 'TextElement'
  427. ){
  428. thisElement.do('activateTextEditor');
  429. }else{
  430. self.do('clearAll');
  431. self.do('addElement', thisElement);
  432. }
  433. }else{
  434. (function(elements, thisElement){
  435. var savedDimensions = []
  436. if(elements.length === 0){
  437. savedDimensions.push({
  438. top: thisElement.get('top'),
  439. left: thisElement.get('left'),
  440. width: thisElement.get('width'),
  441. height: thisElement.get('height')
  442. })
  443. }else{
  444. for(var i = 0, l = elements.length; i < l; i++){
  445. savedDimensions.push({
  446. top: elements[i].get('top'),
  447. left: elements[i].get('left'),
  448. width: elements[i].get('width'),
  449. height: elements[i].get('height')
  450. })
  451. }
  452. }
  453. SuperGlue.get('history').do('actionHasSucceeded', function(){
  454. if(elements.length === 0){
  455. thisElement.set({
  456. top: savedDimensions[0].top,
  457. left: savedDimensions[0].left,
  458. width: savedDimensions[0].width,
  459. height: savedDimensions[0].height
  460. })
  461. }else{
  462. for(var i = 0, l = elements.length; i < l; i++){
  463. elements[i].set({
  464. top: savedDimensions[i].top,
  465. left: savedDimensions[i].left,
  466. width: savedDimensions[i].width,
  467. height: savedDimensions[i].height
  468. })
  469. }
  470. }
  471. })
  472. }).call(this, elements, thisElement)
  473. SuperGlue.get('document').get('widthMarkers').set({ visible: widthMarkersVisible });
  474. SuperGlue.get('document').get('grid').set({ visible: gridVisible });
  475. if(isGroup){
  476. self.do('clearAll');
  477. }
  478. }
  479. // UNDO
  480. evt.stopPropagation();
  481. evt.preventDefault();
  482. },
  483. onMouseMove = function(evt){
  484. var diffX = evt.pageX - startX,
  485. diffY = evt.pageY - startY;
  486. if( withinClickPrecision &&
  487. ( evt.pageX < clickPrecisionXleft
  488. || evt.pageX > clickPrecisionXright
  489. || evt.pageY < clickPrecisionYtop
  490. || evt.pageY > clickPrecisionYbottom )
  491. ){
  492. var widthMarkers = SuperGlue.get('document').get('widthMarkers'),
  493. grid = SuperGlue.get('document').get('grid');
  494. widthMarkersVisible = widthMarkers.get('visible');
  495. gridVisible = grid.get('visible');
  496. widthMarkers.set({ visible: true });
  497. grid.set({ visible: true });
  498. (function(elements, thisElement){
  499. var savedDimensions = []
  500. if(elements.length === 0){
  501. savedDimensions.push({
  502. top: thisElement.get('top'),
  503. left: thisElement.get('left'),
  504. width: thisElement.get('width'),
  505. height: thisElement.get('height')
  506. })
  507. }else{
  508. for(var i = 0, l = elements.length; i < l; i++){
  509. savedDimensions.push({
  510. top: elements[i].get('top'),
  511. left: elements[i].get('left'),
  512. width: elements[i].get('width'),
  513. height: elements[i].get('height')
  514. })
  515. }
  516. }
  517. SuperGlue.get('history').do('actionHasStarted', function(){
  518. if(elements.length === 0){
  519. thisElement.set({
  520. top: savedDimensions[0].top,
  521. left: savedDimensions[0].left,
  522. width: savedDimensions[0].width,
  523. height: savedDimensions[0].height
  524. })
  525. }else{
  526. for(var i = 0, l = elements.length; i < l; i++){
  527. elements[i].set({
  528. top: savedDimensions[i].top,
  529. left: savedDimensions[i].left,
  530. width: savedDimensions[i].width,
  531. height: savedDimensions[i].height
  532. })
  533. }
  534. }
  535. })
  536. }).call(this, elements, thisElement)
  537. withinClickPrecision = false;
  538. }
  539. if(!withinClickPrecision){
  540. virtualTop += diffY;
  541. virtualLeft += diffX;
  542. if(elements.length === 0){
  543. if(virtualTop > 0){
  544. thisElement.set({ top: virtualTop });
  545. }else{
  546. thisElement.set({ top: 0 });
  547. }
  548. if(virtualLeft > 0){
  549. if(infiniteSpace || (virtualLeft + virtualWidth < pageWidth) ){
  550. thisElement.set({ left: virtualLeft });
  551. }else{
  552. thisElement.set({ left: (pageWidth - virtualWidth) });
  553. }
  554. }else{
  555. thisElement.set({ left: 0 });
  556. }
  557. }else{
  558. if(virtualTop > 0){
  559. for(var i = 0, l = elements.length; i < l; i++){
  560. elements[i].set({
  561. top: elementsOffsetsY[i] + virtualTop
  562. });
  563. }
  564. self.do('updateDimensions');
  565. }else{
  566. myNode.style.top = '0px';
  567. for(var i = 0, l = elements.length; i < l; i++){
  568. elements[i].set({
  569. top: elementsOffsetsY[i]
  570. });
  571. }
  572. }
  573. if(virtualLeft > 0){
  574. if(infiniteSpace || (virtualLeft + virtualWidth < pageWidth) ){
  575. for(var i = 0, l = elements.length; i < l; i++){
  576. elements[i].set({
  577. left: elementsOffsetsX[i] + virtualLeft
  578. });
  579. }
  580. self.do('updateDimensions');
  581. }else{
  582. myNode.style.left = (pageWidth - virtualWidth) + 'px';
  583. for(var i = 0, l = elements.length; i < l; i++){
  584. elements[i].set({
  585. left: elementsOffsetsX[i] + (pageWidth - virtualWidth)
  586. });
  587. }
  588. }
  589. }else{
  590. myNode.style.left = '0px';
  591. for(var i = 0, l = elements.length; i < l; i++){
  592. elements[i].set({
  593. left: elementsOffsetsX[i]
  594. });
  595. }
  596. }
  597. }
  598. startX = evt.pageX;
  599. startY = evt.pageY;
  600. }
  601. evt.stopPropagation();
  602. evt.preventDefault();
  603. };
  604. elementNode.addEventListener('mousedown', onMouseDown, false);
  605. }
  606. }
  607. }
  608. }});