123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803 |
- SC.loadPackage({ 'Selection': {
- 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.',
- sharedProperties: {
- 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>' },
- },
- properties: {
- node: { comment: 'My DOM node.' },
- elements: { comment: 'I hold an array of the currently selected elements.' },
- active: { comment: 'Wether a selection is active or not.' },
- 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.'},
- 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.'},
- menuNodeRight: { comment: 'I hold the DOM node containing the right menu node.'},
- menuNodeBottom: { comment: 'I hold the DOM node containing the bottom menu node.'},
- activeWidget: { comment: 'I store either null or the active (selected) widget.'},
- lockWidget: { comment: 'My lockWidget plays a special role, since it appears only on multiple selections and must update its state.'}
- },
- methods: {
- init: {
- comment: 'I init myself.',
- code: function(){
- var node = (new DOMParser()).parseFromString(this.class.get('selectionTools'), 'text/html').body.firstChild;
- this.set({
- node: node,
- menuNodeRight: node.firstChild,
- menuNodeBottom: node.lastChild,
- widgetsRight: [],
- widgetsBottom: [],
- active: false,
- elements: [],
- activeWidget: null
- });
- var generalWidgets = ['WidgetLayerTop', 'WidgetLayerBottom', 'WidgetEditHTML', 'WidgetCopy', 'WidgetDelete'],
- generalWidgetsContainer = this.get('menuNodeRight'),
- widget = null;
- for(var i = 0, l = generalWidgets.length; i < l; i++){
- widget = SC.init(generalWidgets[i], this);
- this.get('widgetsRight').push(widget);
- generalWidgetsContainer.appendChild(widget.get('widgetMenu'));
- }
- this.set({ lockWidget: SC.init('WidgetLock', this) });
-
- }
- },
- updateWidgetMenu: {
- comment: 'I update the menu of widgets according to the current selection.',
- code: function(){
- // Update widget menu to the bottom
- var elements = this.get('elements'),
- elementsWidgetSets = [],
- currentWidgets = [],
- currentWidgetsClasses = null,
- currentWidgetsContainer = this.get('menuNodeBottom'),
- widget = null;
-
- for(var widgetsBottom = this.get('widgetsBottom'), i = 0, l = widgetsBottom.length;
- i < l; i++){
- widgetsBottom[i].set({ isWidgetActive: false });
- currentWidgetsContainer.removeChild(widgetsBottom[i].get('widgetMenu'));
- }
- if(elements.length > 0){
-
- // find intersection of applicable widgets
- for(var i = 0, l = elements.length; i < l; i++){
- elementsWidgetSets.push( elements[i].class.get('applicableWidgets') );
- }
-
- if(elementsWidgetSets.length > 1){
- currentWidgetsClasses = elementsWidgetSets.shift().filter(function(v) {
- return elementsWidgetSets.every(function(a) {
- return a.indexOf(v) !== -1;
- });
- });
- }else{
- currentWidgetsClasses = elementsWidgetSets[0];
- }
- for(var i = 0, l = currentWidgetsClasses.length; i < l; i++){
- widget = SC.init(currentWidgetsClasses[i], this);
- currentWidgets.push(widget);
- currentWidgetsContainer.appendChild(widget.get('widgetMenu'));
- }
- }
- this.set({
- widgetsBottom: currentWidgets,
- activeWidget: null
- });
- // Update widget to the right
- this.do('updateLockGroup');
- // Finally draw red outline when multiple elements are selected
- if(elements.length === 1){
- this.get('node').classList.remove('sg-editing-selection-outline');
- }else{
- this.get('node').classList.add('sg-editing-selection-outline');
- }
- }
- },
- updateLockGroup: {
- comment: 'After adding and removing elements, I check wether I have multiple elements, and if so, if they form a locked group or not.',
- code: function(){
- var myElements = this.get('elements'),
- lockWidget = this.get('lockWidget'),
- menuNodeRight = this.get('menuNodeRight'),
- isGroup = true;
- if(myElements.length > 1){
- // check and add lockWidget
- if(lockWidget.get('widgetMenu').parentNode !== menuNodeRight){
- menuNodeRight.insertBefore(lockWidget.get('widgetMenu'), menuNodeRight.childNodes[0]);
- }
- // check group status of myElements
- for(var i = 0, l = myElements.length; i < l; i++){
- isGroup = isGroup && (myElements[i].get('group') !== null);
- }
- if(isGroup){
- for(var i = 1, l = myElements.length; i < l; i++){
- isGroup = isGroup && (myElements[i].get('group') === myElements[i-1].get('group'))
- }
- }
- lockWidget.set({ locked: isGroup })
- }else if(myElements.length > 0){
- // remove lockWidget
- if(lockWidget.get('widgetMenu').parentNode === menuNodeRight){
- menuNodeRight.removeChild(lockWidget.get('widgetMenu'));
- }
- }
- }
- },
-
- addElement: {
- comment: 'I add anElement to myself.',
- code: function(anElement){
- var elementsToAdd = [ anElement ],
- myElements = this.get('elements'),
- group = anElement.get('group');
- if(group !== null){
- for(var elements = SuperGlue.get('document').get('children'),
- i = 0, l = elements.length; i < l; i++){
- if(elements[i].get('group') === group){
- elementsToAdd.push(elements[i]);
- }
- }
- }
- for(var i = 0, l = elementsToAdd.length; i < l; i++){
- if(myElements.indexOf(elementsToAdd[i]) < 0){
- myElements.push(elementsToAdd[i]);
- }
- }
-
- if(myElements.length === 1){
- myElements[0].get('resizeHandles').set({ selected: true });
- myElements[0].get('resizeHandles').do('showResizeHandles');
- }else{
- for(var i = 0, l = myElements.length; i < l; i++){
- myElements[i].get('resizeHandles').set({ selected: false });
- }
- }
- if(!this.get('active')){
- SuperGlue.get('document').get('editingContainer').appendChild(this.get('node'));
- }
- this.do('updateDimensions');
- this.do('updateWidgetMenu');
-
- }
- },
- removeElement: {
- comment: 'I remove anElement from myself.',
- code: function(anElement){
- var myElements = this.get('elements'),
- elementsToRemove = [ anElement ],
- group = anElement.get('group');
- if(group !== null){
- for(var i = 0, l = myElements.length; i < l; i++){
- if(myElements[i].get('group') === group){
- elementsToRemove.push(myElements[i]);
- }
- }
- }
- for(var i = 0, l = elementsToRemove.length; i < l; i++){
- var elementIndex = myElements.indexOf(elementsToRemove[i]);
- if(elementIndex >= 0){
- myElements.splice(elementIndex, 1);
- elementsToRemove[i].get('resizeHandles').set({ selected: false, mouseOnElement: false });
- elementsToRemove[i].get('resizeHandles').do('hideResizeHandles', true);
- }
- }
-
-
- if(myElements.length === 0){
- SuperGlue.get('document').get('editingContainer').removeChild(this.get('node'));
- this.set({ active: false });
- }else{
- if(myElements.length === 1){
- myElements[0].get('resizeHandles').set({ selected: true });
- myElements[0].get('resizeHandles').do('showResizeHandles');
- }else{
- for(var i = 0, l = myElements.length; i < l; i++){
- myElements[i].get('resizeHandles').set({ selected: false });
- }
- }
- this.do('updateDimensions');
- this.do('updateWidgetMenu');
- }
- }
- },
- toggleSelectionFor: {
- comment: 'I check wether anElement belongs to me already, and then add or remove it.',
- code: function(anElement){
- if(this.get('elements').indexOf(anElement) > -1){
- this.do('removeElement', anElement);
- }else{
- this.do('addElement', anElement);
- }
- }
- },
- clearAll: {
- comment: 'I remove all my Elements.',
- code: function(){
- var elements = this.get('elements');
- for(var i = 0, l = elements.length; i < l; i++){
- elements[i].get('resizeHandles').set({ selected: false, mouseOnElement: false });
- elements[i].get('resizeHandles').do('hideResizeHandles', true)
- }
- var widgetsBottom = this.get('widgetsBottom');
- for(var i = 0, l = widgetsBottom.length; i < l; i++){
- widgetsBottom[i].set({ isWidgetActive: false });
- }
- var editingContainer = SuperGlue.get('document').get('editingContainer');
- if(this.get('node').parentNode === editingContainer){
- editingContainer.removeChild(this.get('node'));
- }
- this.set({
- elements: [],
- active: false
- });
-
- }
- },
- isEmpty: {
- comment: 'Am I empty?',
- code: function(){
- return this.get('elements').length === 0
- }
- },
- calculateDimensions: {
- comment: 'I return the overall dimension to fit in all my Elements in the form [top, left, width, height].',
- code: function(){
- if(this.do('isEmpty')){ return []; }
-
- var myElements = this.get('elements'),
- top = myElements[0].get('top'),
- left = myElements[0].get('left'),
- width = 0,
- height = 0,
- l = myElements.length;
- for(var i = 0; i < l; i++){
- top = myElements[i].get('top') < top ? myElements[i].get('top') : top;
- left = myElements[i].get('left') < left ? myElements[i].get('left') : left;
- width = (myElements[i].get('width') + myElements[i].get('left')) < width
- ? width
- : (myElements[i].get('width') + myElements[i].get('left'));
- height = (myElements[i].get('height') + myElements[i].get('top')) < height
- ? height
- : (myElements[i].get('height') + myElements[i].get('top'));
- }
- width -= left;
- height -= top;
-
- return [top, left, width, height];
- }
- },
- updateDimensions: {
- comment: 'I update the overall dimension of my DOM node to fit in all my Elements.',
- code: function(){
- if(this.do('isEmpty')){ return; }
-
- var nodeStyle = this.get('node').style,
- dimensions = this.do('calculateDimensions'),
- top = dimensions[0],
- left = dimensions[1],
- width = dimensions[2],
- height = dimensions[3];
-
- nodeStyle.top = top + 'px';
- nodeStyle.left = left + 'px';
- nodeStyle.width = width + 'px';
- nodeStyle.height = height + 'px';
- }
- },
- registerForSelection: {
- comment: 'I prepare an Element to be selectable. Used by Element>>init.',
- code: function(anElement){
- var self = this,
- myNode = this.get('node'),
- thisElement = anElement,
- elementNode = anElement.get('node'),
- elements = [],
-
- infiniteSpace = true,
- pageWidth = 0,
- virtualTop = 0,
- virtualLeft = 0,
- virtualWidth = 0,
- virtualHeight = 0,
- elementsOffsetsX = null,
- elementsOffsetsY = null,
- targetNotInSelection,
- isGroup,
- group,
- startX = 0,
- startY = 0,
- clickPrecisionXleft = 0,
- clickPrecisionXright = 0,
- clickPrecisionYtop = 0,
- clickPrecisionYbottom = 0,
- withinClickPrecision = true,
- widthMarkersVisible,
- gridVisible,
- onMouseDown = function(evt){
- if(evt.button !== 0) return;
- if(evt.shiftKey || evt.ctrlKey){
- document.addEventListener('mouseup', onMouseUpWithModifier, true);
- SuperGlue.get('document').set({ interactionInProgress: true });
- // UNDO
- }else{
- startX = evt.pageX;
- startY = evt.pageY;
-
- clickPrecisionXleft = startX - 6;
- clickPrecisionXright = startX + 6;
- clickPrecisionYtop = startY - 6;
- clickPrecisionYbottom = startY + 6;
- withinClickPrecision = true;
- isGroup = false;
- infiniteSpace = ! SuperGlue.get('document').get('layout').centered;
- pageWidth = SuperGlue.get('document').get('layout').width;
- if(SuperGlue.get('document').get('grid').get('active')){
- var gridSize = SuperGlue.get('document').get('grid').get('gridSize');
- pageWidth = Math.floor(pageWidth / gridSize) * gridSize;
- }
- elements = self.get('elements');
-
- if(elements.length !== 0){
- targetNotInSelection = true;
- for(var i = 0, l = elements.length; i < l; i++){
- if(elements[i].get('node') === thisElement.get('node')){
- targetNotInSelection = false;
- break;
- }
- }
- if(targetNotInSelection){
- self.do('clearAll');
- elements = self.get('elements');
- }
- }else{
- targetNotInSelection = elements.indexOf(thisElement) < 0;
- }
- if(elements.length === 0){
- group = thisElement.get('group');
- if(group !== null){
- isGroup = true;
- for(var allElements = SuperGlue.get('document').get('children'),
- i = 0, l = allElements.length; i < l; i++){
- if(allElements[i].get('group') === group){
- elements.push(allElements[i]);
- }
- }
-
- }
- }
- if(elements.length === 0){
- virtualTop = anElement.get('top');
- virtualLeft = anElement.get('left');
- virtualWidth = anElement.get('width');
- virtualHeight = anElement.get('height');
- }else{
- var dimensions = self.do('calculateDimensions');
- virtualTop = dimensions[0];
- virtualLeft = dimensions[1];
- virtualWidth = dimensions[2];
- virtualHeight = dimensions[3];
- elementsOffsetsX = [];
- elementsOffsetsY = [];
- for(var i = 0, l = elements.length; i < l; i++){
- elementsOffsetsX.push( elements[i].get('left') - virtualLeft );
- elementsOffsetsY.push( elements[i].get('top') - virtualTop );
- }
- }
-
- document.addEventListener('mousemove', onMouseMove, true);
- document.addEventListener('mouseup', onMouseUp, true);
- SuperGlue.get('document').set({ interactionInProgress: true });
- // UNDO
- }
- evt.stopPropagation();
- evt.preventDefault();
- },
- onMouseUpWithModifier = function(evt){
- self.do('toggleSelectionFor', thisElement);
- document.removeEventListener('mouseup', onMouseUpWithModifier, true);
- SuperGlue.get('document').set({ interactionInProgress: false });
-
- // UNDO
-
- evt.stopPropagation();
- evt.preventDefault();
- },
- onMouseUp = function(evt){
- document.removeEventListener('mousemove', onMouseMove, true);
- document.removeEventListener('mouseup', onMouseUp, true);
-
- var myDocument = SuperGlue.get('document');
- myDocument.set({ interactionInProgress: false });
- myDocument.do('afterLayoutHasChanged');
- if(withinClickPrecision){
-
- if( !targetNotInSelection
- && thisElement.class() === 'TextElement'
- ){
- thisElement.do('activateTextEditor');
- }else{
-
- self.do('clearAll');
- self.do('addElement', thisElement);
- }
-
- }else{
- (function(elements, thisElement){
- var savedDimensions = []
- if(elements.length === 0){
- savedDimensions.push({
- top: thisElement.get('top'),
- left: thisElement.get('left'),
- width: thisElement.get('width'),
- height: thisElement.get('height')
- })
- }else{
- for(var i = 0, l = elements.length; i < l; i++){
- savedDimensions.push({
- top: elements[i].get('top'),
- left: elements[i].get('left'),
- width: elements[i].get('width'),
- height: elements[i].get('height')
- })
- }
- }
- SuperGlue.get('history').do('actionHasSucceeded', function(){
- if(elements.length === 0){
- thisElement.set({
- top: savedDimensions[0].top,
- left: savedDimensions[0].left,
- width: savedDimensions[0].width,
- height: savedDimensions[0].height
- })
- }else{
- for(var i = 0, l = elements.length; i < l; i++){
- elements[i].set({
- top: savedDimensions[i].top,
- left: savedDimensions[i].left,
- width: savedDimensions[i].width,
- height: savedDimensions[i].height
- })
- }
- }
- })
- }).call(this, elements, thisElement)
- SuperGlue.get('document').get('widthMarkers').set({ visible: widthMarkersVisible });
- SuperGlue.get('document').get('grid').set({ visible: gridVisible });
- if(isGroup){
- self.do('clearAll');
- }
- }
- // UNDO
-
- evt.stopPropagation();
- evt.preventDefault();
- },
- onMouseMove = function(evt){
- var diffX = evt.pageX - startX,
- diffY = evt.pageY - startY;
-
- if( withinClickPrecision &&
- ( evt.pageX < clickPrecisionXleft
- || evt.pageX > clickPrecisionXright
- || evt.pageY < clickPrecisionYtop
- || evt.pageY > clickPrecisionYbottom )
- ){
- var widthMarkers = SuperGlue.get('document').get('widthMarkers'),
- grid = SuperGlue.get('document').get('grid');
- widthMarkersVisible = widthMarkers.get('visible');
- gridVisible = grid.get('visible');
- widthMarkers.set({ visible: true });
- grid.set({ visible: true });
- (function(elements, thisElement){
- var savedDimensions = []
- if(elements.length === 0){
- savedDimensions.push({
- top: thisElement.get('top'),
- left: thisElement.get('left'),
- width: thisElement.get('width'),
- height: thisElement.get('height')
- })
- }else{
- for(var i = 0, l = elements.length; i < l; i++){
- savedDimensions.push({
- top: elements[i].get('top'),
- left: elements[i].get('left'),
- width: elements[i].get('width'),
- height: elements[i].get('height')
- })
- }
- }
- SuperGlue.get('history').do('actionHasStarted', function(){
- if(elements.length === 0){
- thisElement.set({
- top: savedDimensions[0].top,
- left: savedDimensions[0].left,
- width: savedDimensions[0].width,
- height: savedDimensions[0].height
- })
- }else{
- for(var i = 0, l = elements.length; i < l; i++){
- elements[i].set({
- top: savedDimensions[i].top,
- left: savedDimensions[i].left,
- width: savedDimensions[i].width,
- height: savedDimensions[i].height
- })
- }
- }
- })
- }).call(this, elements, thisElement)
- withinClickPrecision = false;
- }
- if(!withinClickPrecision){
- virtualTop += diffY;
- virtualLeft += diffX;
- if(elements.length === 0){
- if(virtualTop > 0){
- thisElement.set({ top: virtualTop });
- }else{
- thisElement.set({ top: 0 });
- }
- if(virtualLeft > 0){
- if(infiniteSpace || (virtualLeft + virtualWidth < pageWidth) ){
- thisElement.set({ left: virtualLeft });
- }else{
- thisElement.set({ left: (pageWidth - virtualWidth) });
- }
- }else{
- thisElement.set({ left: 0 });
- }
-
- }else{
- if(virtualTop > 0){
- for(var i = 0, l = elements.length; i < l; i++){
- elements[i].set({
- top: elementsOffsetsY[i] + virtualTop
- });
- }
- self.do('updateDimensions');
- }else{
- myNode.style.top = '0px';
- for(var i = 0, l = elements.length; i < l; i++){
- elements[i].set({
- top: elementsOffsetsY[i]
- });
- }
- }
- if(virtualLeft > 0){
- if(infiniteSpace || (virtualLeft + virtualWidth < pageWidth) ){
- for(var i = 0, l = elements.length; i < l; i++){
- elements[i].set({
- left: elementsOffsetsX[i] + virtualLeft
- });
- }
- self.do('updateDimensions');
- }else{
- myNode.style.left = (pageWidth - virtualWidth) + 'px';
- for(var i = 0, l = elements.length; i < l; i++){
- elements[i].set({
- left: elementsOffsetsX[i] + (pageWidth - virtualWidth)
- });
- }
- }
- }else{
- myNode.style.left = '0px';
- for(var i = 0, l = elements.length; i < l; i++){
- elements[i].set({
- left: elementsOffsetsX[i]
- });
- }
- }
-
- }
- startX = evt.pageX;
- startY = evt.pageY;
-
- }
-
- evt.stopPropagation();
- evt.preventDefault();
- };
- elementNode.addEventListener('mousedown', onMouseDown, false);
- }
- }
- }
- }});
|