Michael Schwartz
Michael Schwartz

Reputation: 8425

JQuery Toggle Drag, Drop & Contenteditable

http://codepen.io/mikethedj4/pen/gCsih
http://jsfiddle.net/ba5Ld/3/

I'm working on a basic experimental html designer (all you do is draw divs/rectangles and resize them nothing to fancy)

I'm using ThreeDubMedia's drag plugin to accomplish the the drag and resize events.

I know using global variables is bad practice, but I couldn't figureout how to accomplish this type of effect without them.

Anyway I ran into two problems: first is divs are still draggable when select tool is inactive (which moveable is set to false in which I assume it shouldn't be dragging), two when I pick the edit tool when the mouse is down on a div it sets the contenteditable property to true, however it's not working. When I took a look in the google developer tools it shows that the property is added and active but it's not working.

Any help is greatly appreciated.

    $('.start').click(function() {
      moveable = 1;
      drawable = false;
      editable = false;
      removeable = false;
      $('.draw, .nodraw').removeClass('d-active e-active noselect active inactive r-active');
      $(this).addClass('active noselect s-active');
      if ($('.s-active').is(':visible')) {
        if(moveable) {
          $('#drawingArea *').addClass('moveable');

          $('.moveable').drag("start",function( ev, dd ){
            dd.attr = $( ev.target ).prop("className");
            dd.width = $( this ).width();
            dd.height = $( this ).height();
          })
          .drag(function( ev, dd ){
            var props = {};
            if ( dd.attr.indexOf("E") > -1 ){
              props.width = Math.max( 32, dd.width + dd.deltaX );
            }
            if ( dd.attr.indexOf("S") > -1 ){
              props.height = Math.max( 32, dd.height + dd.deltaY );
            }
            if ( dd.attr.indexOf("W") > -1 ){
              props.width = Math.max( 32, dd.width - dd.deltaX );
              props.left = dd.originalX + dd.width - props.width;
            }
            if ( dd.attr.indexOf("N") > -1 ){
              props.height = Math.max( 32, dd.height - dd.deltaY );
              props.top = dd.originalY + dd.height - props.height;
            }
            if ( dd.attr.indexOf("editable") > -1 ){
              props.top = dd.offsetY;
              props.left = dd.offsetX;
            }
            $( this ).css( props );
          }, {relative:true});

          $('#drawingArea *').on('mousedown touchstart', function() {
            if(moveable) {
              $('#drawingArea *').removeClass('editable');
              $('.handle, .NN, .NE, .EE, .SE, .SS, .SW, .WW, .NW').remove();
              $(this).addClass('editable').append('<div class="handle NE"></div> <div class="handle NN"></div> <div class="handle NW"></div> <div class="handle WW"></div> <div class="handle EE"></div> <div class="handle SW"></div> <div class="handle SS"></div> <div class="handle SE"></div>');
              $('#drawingArea').on('mousemove touchmove', function(e) {
                e.preventDefault();
              });
            }
          });
        }
      } else {
        moveable = false;
        $('.handle, .NN, .NE, .EE, .SE, .SS, .SW, .WW, .NW').remove();
        return false;
      }
    });

Upvotes: 0

Views: 339

Answers (1)

Paul Rumkin
Paul Rumkin

Reputation: 6883

Closures are created to do this for you:

var a = 1;
(function(){ // Function call creates new scope every time.
    var a = 2;
    // JS look up current scope, then parent to search correct `a` variable
    a = a + 1;
    console.log(a) // -> 3. 
})();

console.log(a) //-> 1, use local scope

One more example

var b = 1;
(function(){       // Function call nests new scope
    console.log(b) // -> 1. Use 'b' from parent scope
    b++;           // -> 2. Increase `b` from parent scope
    var b = 1;     // -> 1. Define b in local scope
    console.log(b) // -> 1. This `b` from local scope
})();

console.log(b)     // -> 2. Search in local scope only

Each function searching for local scope then parent and so on. Now you can wrap all of your HTMLNodes into closures. Example:

$('.start') // -> two or more nodes
    .each(function(i, node){
        // Bind variables in function scope
        var moveable, drawable, editable, removable; 
        $(node).click(function(){
            // If you click twice you will get 'undefined' and 1 respectively.
            console.log(moveable);
            moveable = 1;
            // Do all other useful stuff
        });

It is the only answer to your question. But it is not the best or event approperiate solution (you can use jQuery's data method to save state of each node). Let me explain. String and Array are globals, so global variables aren't bad. It's bad practice to use them to save the states.

Upvotes: 1

Related Questions