<commit_before>'use strict';
const app = require('app');
const BrowserWindow = require('browser-window');

// report crashes to the Electron project
// require('crash-reporter').start();

// adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')();

// prevent window being GC'd
let mainWindow;

function createMainWindow() {
  const win = new BrowserWindow({
    width: 600,
    height: 400,
    resizable: true,
    transparent: true,
    frame: true,
    "always-on-top": true,
  });
  // win.maximize();

  win.loadUrl(`file://${__dirname}/renderer/index.html`);
  win.on('closed', onClosed);

  return win;
}

function onClosed() {
  // deref the window
  // for multiple windows store them in an array
  mainWindow = null;
}

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate-with-no-open-windows', function () {
  if (!mainWindow) {
    mainWindow = createMainWindow();
  }
});

app.on('ready', function () {
  mainWindow = createMainWindow();
});
<commit_msg>Minor changes<commit_after>'use strict';
const app = require('app');
const BrowserWindow = require('browser-window');

// report crashes to the Electron project
// require('crash-reporter').start();

// adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')();

// prevent window being GC'd
let mainWindow;

function createMainWindow() {
  const win = new BrowserWindow({
    width: 600,
    height: 400,
    resizable: true,
    transparent: true,
    frame: true,
    // 'title-bar-style': 'hidden',
    'always-on-top': true
  });
  // win.maximize();

  win.loadUrl(`file://${__dirname}/renderer/index.html`);
  win.on('closed', onClosed);

  return win;
}

function onClosed() {
  // deref the window
  // for multiple windows store them in an array
  mainWindow = null;
}

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate-with-no-open-windows', function () {
  if (!mainWindow) {
    mainWindow = createMainWindow();
  }
});

app.on('ready', function () {
  mainWindow = createMainWindow();
});
<|endoftext|>


<commit_before>/**
 * Taking care of events
 *  - Simulating 'change' event on contentEditable element
 *  - Handling drag & drop logic
 *  - Catch paste events
 *  - Dispatch proprietary newword:composer event
 *  - Keyboard shortcuts
 */
(function(wysihtml5) {
  var dom       = wysihtml5.dom,
      browser   = wysihtml5.browser,
      /**
       * Map keyCodes to query commands
       */
      shortcuts = {
        "66": "bold",     // B
        "73": "italic",   // I
        "85": "underline" // U
      };

  var deleteAroundEditable = function(selection, uneditable, element) {
    // merge node with previous node from uneditable
    var prevNode = selection.getPreviousNode(uneditable, true),
        curNode = selection.getSelectedNode();

    if (curNode.nodeType !== 1 && curNode.parentNode !== element) { curNode = curNode.parentNode; }
    if (prevNode) {
      if (curNode.nodeType == 1) {
        var first = curNode.firstChild;

        if (prevNode.nodeType == 1) {
          while (curNode.firstChild) {
            prevNode.appendChild(curNode.firstChild);
          }
        } else {
          while (curNode.firstChild) {
            uneditable.parentNode.insertBefore(curNode.firstChild, uneditable);
          }
        }
        if (curNode.parentNode) {
          curNode.parentNode.removeChild(curNode);
        }
        selection.setBefore(first);
      } else {
        if (prevNode.nodeType == 1) {
          prevNode.appendChild(curNode);
        } else {
          uneditable.parentNode.insertBefore(curNode, uneditable);
        }
        selection.setBefore(curNode);
      }
    }
  };

  var handleDeleteKeyPress = function(selection, element) {
    if (selection.isCollapsed()) {
      if (selection.caretIsInTheBeginnig()) {
        event.preventDefault();
      } else {
        var beforeUneditable = selection.caretIsBeforeUneditable();

        // Do a special delete if caret would delete uneditable
        if (beforeUneditable) {
          event.preventDefault();
          deleteAroundEditable(selection, beforeUneditable, element);
        }
      }
    } else if (selection.containsUneditable()) {
      event.preventDefault();
      selection.deleteContents();
    }
  };

  var tryToPushLiLevel = function(selection) {
    var prevLi;
    selection.executeAndRestoreRangy(function() {
      var selNode = selection.getSelectedNode(),
          liNode = (selNode.nodeName && selNode.nodeName === 'LI') ? selNode : selNode.parentNode,
          listTag, list;

      if (liNode.getAttribute('class') === "rangySelectionBoundary") {
        liNode = liNode.parentNode;
      }

      if (liNode.nodeName === 'LI') {
        listTag = (liNode.parentNode.nodeName === 'OL') ? 'OL' : 'UL';
        list = selNode.ownerDocument.createElement(listTag);
        prevLi = wysihtml5.dom.getPreviousElement(liNode);

        if (prevLi) {
          list.appendChild(liNode);
          prevLi.appendChild(list);
        }
      }

    });
    return (prevLi) ? true : false;
  };

  var handleTabKeyDown = function(composer, element) {
    if (!composer.selection.isCollapsed()) {
      composer.selection.deleteContents();
    } else if (composer.selection.caretIsInTheBeginnig('LI')) {
      if (tryToPushLiLevel(composer.selection)) return;
    }

    // Is   close enough to tab. Could not find enough counter arguments for now.
    composer.commands.exec("insertHTML", " ");
  };

  wysihtml5.views.Composer.prototype.observe = function() {
    var that                = this,
        state               = this.getValue(),
        container           = (this.sandbox.getIframe) ? this.sandbox.getIframe() : this.sandbox.getContentEditable(),
        element             = this.element,
        focusBlurElement    = (browser.supportsEventsInIframeCorrectly() || this.sandbox.getContentEditable) ? element : this.sandbox.getWindow(),
        pasteEvents         = ["drop", "paste"],
        interactionEvents   = ["drop", "paste", "mouseup", "focus", "keyup"];

    // --------- destroy:composer event ---------
    dom.observe(container, "DOMNodeRemoved", function() {
      clearInterval(domNodeRemovedInterval);
      that.parent.fire("destroy:composer");
    });

    // DOMNodeRemoved event is not supported in IE 8
    if (!browser.supportsMutationEvents()) {
        var domNodeRemovedInterval = setInterval(function() {
          if (!dom.contains(document.documentElement, container)) {
            clearInterval(domNodeRemovedInterval);
            that.parent.fire("destroy:composer");
          }
        }, 250);
    }

    // --------- User interaction tracking --

    dom.observe(focusBlurElement, interactionEvents, function() {
      setTimeout(function() {
        that.parent.fire("interaction").fire("interaction:composer");
      }, 0);
    });

    if (this.config.handleTables) {
      if(this.doc.execCommand && wysihtml5.browser.supportsCommand(this.doc, "enableObjectResizing") && wysihtml5.browser.supportsCommand(this.doc, "enableInlineTableEditing")) {
        setTimeout(function() {
          that.doc.execCommand("enableObjectResizing", false, "false");
          that.doc.execCommand("enableInlineTableEditing", false, "false");
        }, 0);
      }
      this.tableSelection = wysihtml5.quirks.tableCellsSelection(element, that.parent);
    }

    // --------- Focus & blur logic ---------
    dom.observe(focusBlurElement, "focus", function() {
      that.parent.fire("focus").fire("focus:composer");

      // Delay storing of state until all focus handler are fired
      // especially the one which resets the placeholder
      setTimeout(function() { state = that.getValue(); }, 0);
    });

    dom.observe(focusBlurElement, "blur", function() {
      if (state !== that.getValue()) {
        that.parent.fire("change").fire("change:composer");
      }
      that.parent.fire("blur").fire("blur:composer");
    });

    // --------- Drag & Drop logic ---------
    dom.observe(element, "dragenter", function() {
      that.parent.fire("unset_placeholder");
    });

    dom.observe(element, pasteEvents, function() {
      setTimeout(function() {
        that.parent.fire("paste").fire("paste:composer");
      }, 0);
    });

    // --------- neword event ---------
    dom.observe(element, "keyup", function(event) {
      var keyCode = event.keyCode;
      if (keyCode === wysihtml5.SPACE_KEY || keyCode === wysihtml5.ENTER_KEY) {
        that.parent.fire("newword:composer");
      }
    });

    this.parent.on("paste:composer", function() {
      setTimeout(function() { that.parent.fire("newword:composer"); }, 0);
    });

    // --------- Make sure that images are selected when clicking on them ---------
    if (!browser.canSelectImagesInContentEditable()) {
      dom.observe(element, "mousedown", function(event) {
        var target = event.target;
        var allImages = element.querySelectorAll('img'),
            notMyImages = element.querySelectorAll('.' + that.config.uneditableContainerClassname + ' img'),
            myImages = wysihtml5.lang.array(allImages).without(notMyImages);

        if (target.nodeName === "IMG" && wysihtml5.lang.array(myImages).contains(target)) {
          that.selection.selectNode(target);
        }
      });
    }

    if (!browser.canSelectImagesInContentEditable()) {
        dom.observe(element, "drop", function(event) {
            // TODO: if I knew how to get dropped elements list from event I could limit it to only IMG element case
            setTimeout(function() {
                that.selection.getSelection().removeAllRanges();
            }, 0);
        });
    }

    if (browser.hasHistoryIssue() && browser.supportsSelectionModify()) {
      dom.observe(element, "keydown", function(event) {
        if (!event.metaKey && !event.ctrlKey) {
          return;
        }

        var keyCode   = event.keyCode,
            win       = element.ownerDocument.defaultView,
            selection = win.getSelection();

        if (keyCode === 37 || keyCode === 39) {
          if (keyCode === 37) {
            selection.modify("extend", "left", "lineboundary");
            if (!event.shiftKey) {
              selection.collapseToStart();
            }
          }
          if (keyCode === 39) {
            selection.modify("extend", "right", "lineboundary");
            if (!event.shiftKey) {
              selection.collapseToEnd();
            }
          }
          event.preventDefault();
        }
      });
    }

    // --------- Shortcut logic ---------
    dom.observe(element, "keydown", function(event) {
      var keyCode  = event.keyCode,
          command  = shortcuts[keyCode];
      if ((event.ctrlKey || event.metaKey) && !event.altKey && command) {
        that.commands.exec(command);
        event.preventDefault();
      }
      if (keyCode === 8) {
        // delete key
        handleDeleteKeyPress(that.selection, element);
      } else if (keyCode === 9) {
        event.preventDefault();
        handleTabKeyDown(that, element);
      }
    });

    // --------- Make sure that when pressing backspace/delete on selected images deletes the image and it's anchor ---------
    dom.observe(element, "keydown", function(event) {
      var target  = that.selection.getSelectedNode(true),
          keyCode = event.keyCode,
          parent;
      if (target && target.nodeName === "IMG" && (keyCode === wysihtml5.BACKSPACE_KEY || keyCode === wysihtml5.DELETE_KEY)) { // 8 => backspace, 46 => delete
        parent = target.parentNode;
        // delete the <img>
        parent.removeChild(target);
        // and it's parent <a> too if it hasn't got any other child nodes
        if (parent.nodeName === "A" && !parent.firstChild) {
          parent.parentNode.removeChild(parent);
        }

        setTimeout(function() { wysihtml5.quirks.redraw(element); }, 0);
        event.preventDefault();
      }
    });

    // --------- IE 8+9 focus the editor when the iframe is clicked (without actually firing the 'focus' event on the <body>) ---------
    if (!this.config.contentEditableMode && browser.hasIframeFocusIssue()) {
      dom.observe(container, "focus", function() {
        setTimeout(function() {
          if (that.doc.querySelector(":focus") !== that.element) {
            that.focus();
          }
        }, 0);
      });

      dom.observe(this.element, "blur", function() {
        setTimeout(function() {
          that.selection.getSelection().removeAllRanges();
        }, 0);
      });
    }

    // --------- Show url in tooltip when hovering links or images ---------
    var titlePrefixes = {
      IMG: "Image: ",
      A:   "Link: "
    };

    dom.observe(element, "mouseover", function(event) {
      var target   = event.target,
          nodeName = target.nodeName,
          title;
      if (nodeName !== "A" && nodeName !== "IMG") {
        return;
      }
      var hasTitle = target.hasAttribute("title");
      if(!hasTitle){
        title = titlePrefixes[nodeName] + (target.getAttribute("href") || target.getAttribute("src"));
        target.setAttribute("title", title);
      }
    });
  };
})(wysihtml5);
<commit_msg>Add event parameter to handleDeleteKeyPress<commit_after>/**
 * Taking care of events
 *  - Simulating 'change' event on contentEditable element
 *  - Handling drag & drop logic
 *  - Catch paste events
 *  - Dispatch proprietary newword:composer event
 *  - Keyboard shortcuts
 */
(function(wysihtml5) {
  var dom       = wysihtml5.dom,
      browser   = wysihtml5.browser,
      /**
       * Map keyCodes to query commands
       */
      shortcuts = {
        "66": "bold",     // B
        "73": "italic",   // I
        "85": "underline" // U
      };

  var deleteAroundEditable = function(selection, uneditable, element) {
    // merge node with previous node from uneditable
    var prevNode = selection.getPreviousNode(uneditable, true),
        curNode = selection.getSelectedNode();

    if (curNode.nodeType !== 1 && curNode.parentNode !== element) { curNode = curNode.parentNode; }
    if (prevNode) {
      if (curNode.nodeType == 1) {
        var first = curNode.firstChild;

        if (prevNode.nodeType == 1) {
          while (curNode.firstChild) {
            prevNode.appendChild(curNode.firstChild);
          }
        } else {
          while (curNode.firstChild) {
            uneditable.parentNode.insertBefore(curNode.firstChild, uneditable);
          }
        }
        if (curNode.parentNode) {
          curNode.parentNode.removeChild(curNode);
        }
        selection.setBefore(first);
      } else {
        if (prevNode.nodeType == 1) {
          prevNode.appendChild(curNode);
        } else {
          uneditable.parentNode.insertBefore(curNode, uneditable);
        }
        selection.setBefore(curNode);
      }
    }
  };

  var handleDeleteKeyPress = function(event, selection, element) {
    if (selection.isCollapsed()) {
      if (selection.caretIsInTheBeginnig()) {
        event.preventDefault();
      } else {
        var beforeUneditable = selection.caretIsBeforeUneditable();

        // Do a special delete if caret would delete uneditable
        if (beforeUneditable) {
          event.preventDefault();
          deleteAroundEditable(selection, beforeUneditable, element);
        }
      }
    } else if (selection.containsUneditable()) {
      event.preventDefault();
      selection.deleteContents();
    }
  };

  var tryToPushLiLevel = function(selection) {
    var prevLi;
    selection.executeAndRestoreRangy(function() {
      var selNode = selection.getSelectedNode(),
          liNode = (selNode.nodeName && selNode.nodeName === 'LI') ? selNode : selNode.parentNode,
          listTag, list;

      if (liNode.getAttribute('class') === "rangySelectionBoundary") {
        liNode = liNode.parentNode;
      }

      if (liNode.nodeName === 'LI') {
        listTag = (liNode.parentNode.nodeName === 'OL') ? 'OL' : 'UL';
        list = selNode.ownerDocument.createElement(listTag);
        prevLi = wysihtml5.dom.getPreviousElement(liNode);

        if (prevLi) {
          list.appendChild(liNode);
          prevLi.appendChild(list);
        }
      }

    });
    return (prevLi) ? true : false;
  };

  var handleTabKeyDown = function(composer, element) {
    if (!composer.selection.isCollapsed()) {
      composer.selection.deleteContents();
    } else if (composer.selection.caretIsInTheBeginnig('LI')) {
      if (tryToPushLiLevel(composer.selection)) return;
    }

    // Is   close enough to tab. Could not find enough counter arguments for now.
    composer.commands.exec("insertHTML", " ");
  };

  wysihtml5.views.Composer.prototype.observe = function() {
    var that                = this,
        state               = this.getValue(),
        container           = (this.sandbox.getIframe) ? this.sandbox.getIframe() : this.sandbox.getContentEditable(),
        element             = this.element,
        focusBlurElement    = (browser.supportsEventsInIframeCorrectly() || this.sandbox.getContentEditable) ? element : this.sandbox.getWindow(),
        pasteEvents         = ["drop", "paste"],
        interactionEvents   = ["drop", "paste", "mouseup", "focus", "keyup"];

    // --------- destroy:composer event ---------
    dom.observe(container, "DOMNodeRemoved", function() {
      clearInterval(domNodeRemovedInterval);
      that.parent.fire("destroy:composer");
    });

    // DOMNodeRemoved event is not supported in IE 8
    if (!browser.supportsMutationEvents()) {
        var domNodeRemovedInterval = setInterval(function() {
          if (!dom.contains(document.documentElement, container)) {
            clearInterval(domNodeRemovedInterval);
            that.parent.fire("destroy:composer");
          }
        }, 250);
    }

    // --------- User interaction tracking --

    dom.observe(focusBlurElement, interactionEvents, function() {
      setTimeout(function() {
        that.parent.fire("interaction").fire("interaction:composer");
      }, 0);
    });

    if (this.config.handleTables) {
      if(this.doc.execCommand && wysihtml5.browser.supportsCommand(this.doc, "enableObjectResizing") && wysihtml5.browser.supportsCommand(this.doc, "enableInlineTableEditing")) {
        setTimeout(function() {
          that.doc.execCommand("enableObjectResizing", false, "false");
          that.doc.execCommand("enableInlineTableEditing", false, "false");
        }, 0);
      }
      this.tableSelection = wysihtml5.quirks.tableCellsSelection(element, that.parent);
    }

    // --------- Focus & blur logic ---------
    dom.observe(focusBlurElement, "focus", function() {
      that.parent.fire("focus").fire("focus:composer");

      // Delay storing of state until all focus handler are fired
      // especially the one which resets the placeholder
      setTimeout(function() { state = that.getValue(); }, 0);
    });

    dom.observe(focusBlurElement, "blur", function() {
      if (state !== that.getValue()) {
        that.parent.fire("change").fire("change:composer");
      }
      that.parent.fire("blur").fire("blur:composer");
    });

    // --------- Drag & Drop logic ---------
    dom.observe(element, "dragenter", function() {
      that.parent.fire("unset_placeholder");
    });

    dom.observe(element, pasteEvents, function() {
      setTimeout(function() {
        that.parent.fire("paste").fire("paste:composer");
      }, 0);
    });

    // --------- neword event ---------
    dom.observe(element, "keyup", function(event) {
      var keyCode = event.keyCode;
      if (keyCode === wysihtml5.SPACE_KEY || keyCode === wysihtml5.ENTER_KEY) {
        that.parent.fire("newword:composer");
      }
    });

    this.parent.on("paste:composer", function() {
      setTimeout(function() { that.parent.fire("newword:composer"); }, 0);
    });

    // --------- Make sure that images are selected when clicking on them ---------
    if (!browser.canSelectImagesInContentEditable()) {
      dom.observe(element, "mousedown", function(event) {
        var target = event.target;
        var allImages = element.querySelectorAll('img'),
            notMyImages = element.querySelectorAll('.' + that.config.uneditableContainerClassname + ' img'),
            myImages = wysihtml5.lang.array(allImages).without(notMyImages);

        if (target.nodeName === "IMG" && wysihtml5.lang.array(myImages).contains(target)) {
          that.selection.selectNode(target);
        }
      });
    }

    if (!browser.canSelectImagesInContentEditable()) {
        dom.observe(element, "drop", function(event) {
            // TODO: if I knew how to get dropped elements list from event I could limit it to only IMG element case
            setTimeout(function() {
                that.selection.getSelection().removeAllRanges();
            }, 0);
        });
    }

    if (browser.hasHistoryIssue() && browser.supportsSelectionModify()) {
      dom.observe(element, "keydown", function(event) {
        if (!event.metaKey && !event.ctrlKey) {
          return;
        }

        var keyCode   = event.keyCode,
            win       = element.ownerDocument.defaultView,
            selection = win.getSelection();

        if (keyCode === 37 || keyCode === 39) {
          if (keyCode === 37) {
            selection.modify("extend", "left", "lineboundary");
            if (!event.shiftKey) {
              selection.collapseToStart();
            }
          }
          if (keyCode === 39) {
            selection.modify("extend", "right", "lineboundary");
            if (!event.shiftKey) {
              selection.collapseToEnd();
            }
          }
          event.preventDefault();
        }
      });
    }

    // --------- Shortcut logic ---------
    dom.observe(element, "keydown", function(event) {
      var keyCode  = event.keyCode,
          command  = shortcuts[keyCode];
      if ((event.ctrlKey || event.metaKey) && !event.altKey && command) {
        that.commands.exec(command);
        event.preventDefault();
      }
      if (keyCode === 8) {
        // delete key
        handleDeleteKeyPress(event, that.selection, element);
      } else if (keyCode === 9) {
        event.preventDefault();
        handleTabKeyDown(that, element);
      }
    });

    // --------- Make sure that when pressing backspace/delete on selected images deletes the image and it's anchor ---------
    dom.observe(element, "keydown", function(event) {
      var target  = that.selection.getSelectedNode(true),
          keyCode = event.keyCode,
          parent;
      if (target && target.nodeName === "IMG" && (keyCode === wysihtml5.BACKSPACE_KEY || keyCode === wysihtml5.DELETE_KEY)) { // 8 => backspace, 46 => delete
        parent = target.parentNode;
        // delete the <img>
        parent.removeChild(target);
        // and it's parent <a> too if it hasn't got any other child nodes
        if (parent.nodeName === "A" && !parent.firstChild) {
          parent.parentNode.removeChild(parent);
        }

        setTimeout(function() { wysihtml5.quirks.redraw(element); }, 0);
        event.preventDefault();
      }
    });

    // --------- IE 8+9 focus the editor when the iframe is clicked (without actually firing the 'focus' event on the <body>) ---------
    if (!this.config.contentEditableMode && browser.hasIframeFocusIssue()) {
      dom.observe(container, "focus", function() {
        setTimeout(function() {
          if (that.doc.querySelector(":focus") !== that.element) {
            that.focus();
          }
        }, 0);
      });

      dom.observe(this.element, "blur", function() {
        setTimeout(function() {
          that.selection.getSelection().removeAllRanges();
        }, 0);
      });
    }

    // --------- Show url in tooltip when hovering links or images ---------
    var titlePrefixes = {
      IMG: "Image: ",
      A:   "Link: "
    };

    dom.observe(element, "mouseover", function(event) {
      var target   = event.target,
          nodeName = target.nodeName,
          title;
      if (nodeName !== "A" && nodeName !== "IMG") {
        return;
      }
      var hasTitle = target.hasAttribute("title");
      if(!hasTitle){
        title = titlePrefixes[nodeName] + (target.getAttribute("href") || target.getAttribute("src"));
        target.setAttribute("title", title);
      }
    });
  };
})(wysihtml5);
<|endoftext|>


<commit_before>(function(document, window){

    window['CropResize'] = CropResize;

    function CropResize(element, attributes){

        var _cropResize         = this,
            _mouseDownQueue     = [],
            _mouseUpQueue       = [],
            _mouseMoveQueue     = [],
            _windowResizeQueue  = [];

        this.remove = remove;
        this.images = {};

        element.addEventListener('change',      onFileInputChange);
        window.addEventListener('mousedown',    onMouseDown);
        window.addEventListener('mouseup',      onMouseUp);
        window.addEventListener('mousemove',    onMouseMove);
        window.addEventListener('resize',       onWindowResize);

        function remove(){
            element.removeEventListener('change',    onFileInputChange);
            element.removeEventListener('mousedown', onMouseDown);
            element.removeEventListener('mouseup',   onMouseUp);
            element.removeEventListener('mousemove', onMouseMove);
            element.removeEventListener('resize',    onWindowResize);

            //TODO:Clear Subscription arrays

        }

        function onMouseDown(e){
            onSubscription(e, _mouseDownQueue);
        }

        function onMouseUp(e){
            onSubscription(e, _mouseUpQueue);
        }

        function onMouseMove(e){
            onSubscription(e, _mouseMoveQueue);
        }

        function onWindowResize(e){
            onSubscription(e, _windowResizeQueue);
        }

        function onSubscription(e, events){
            for(var i = 0; i < events.length; i++){
                events[i](e);
            }
        }

        function onFileInputChange(e, scope){

            var files       = this.files,
                parsedFiles = [];

            for(var file in files){
                parsedFiles.push(new FileHandler(files[file]));
            }
        }

        function FileHandler(file){

            var fileHandler = {};

            fileHandler.original    = {};
            fileHandler.cropped     = {};

            if(typeof file === 'object' && file.type.match('image.*')){
                var reader = new FileReader();

                reader.onload = onReaderLoad;

                reader.readAsDataURL(file);

                function onReaderLoad(e){
                    fileHandler.original['url'] = e.target.result;
                    fileHandler.original['size'] = bytesToSize(file.size);
                    bindCanvas.call(fileHandler);
                }
            }
        }

        function bindCanvas(){
            var self = this;

            self['canvas'] = {};
            self.canvas['element'] = document.createElement('canvas');
            self.canvas['context'] = self.canvas.element.getContext('2d');

            var parent  = element.parentElement,
                image   = new Image();

            image.onload    =   onCanvasImageLoad;
            image.src       =   self.original.url;

            function onCanvasImageLoad(){
                self.original['width']  =   this.width;
                self.original['height'] =   this.height;

                self.canvas['width']    =   self['canvas'].element.width;
                self.canvas['height']   =   self['canvas'].element.height;

                var canvasParams = measurements(self.original, self.canvas);

                if(attributes['target']){
                    attributes['target'].appendChild(self.canvas.element)
                }else{
                    parent.insertBefore(self.canvas.element, element);
                }

                self.canvas.context.clearRect(0, 0, self.canvas['width'], self.canvas['height']);
                self.canvas.context.drawImage(image,
                    canvasParams.sx,
                    canvasParams.sy,
                    canvasParams.sWidth,
                    canvasParams.sHeight,
                    canvasParams.dx,
                    canvasParams.dy,
                    canvasParams.dWidth,
                    canvasParams.dHeight
                );

                createImgInstance();
                cropWindow(attributes['target'] || parent);

                function createImgInstance(){
                    var croppedImageData = self.canvas.context.getImageData(0,0,500,500),
                        buffer = document.createElement('canvas'),
                        bufferCtx = buffer.getContext("2d"),
                        croppedImageElement = document.createElement('img');

                    buffer.width    =   500;
                    buffer.height   =   500;
                    bufferCtx.putImageData(croppedImageData, 0, 0);

                    croppedImageElement.src = buffer.toDataURL('image/png');

                    parent.appendChild(croppedImageElement);
                }

                function measurements(image, canvas){
                    var hRatio      =   canvas.width  / image.width,
                        vRatio      =   canvas.height  / image.height,
                        ratio       =   Math.min ( hRatio, vRatio);

                    return {
                        sx:         0,
                        sy:         0,
                        sWidth:     image.width,
                        sHeight:    image.height,
                        dx:         (canvas['width'] - image['width'] * ratio ) / 2,
                        dy:         (canvas['height'] - image['height'] * ratio ) / 2,
                        dWidth:     image.width * ratio,
                        dHeight:    image.height * ratio
                    }
                }

            }
        }

        function cropWindow(target){
            var isHeld              = false,
                mouseStart          = {},
                cropWindowElement   = document.createElement('div'),
                childNames = [
                    'handle-top-left',
                    'handle-top-center',
                    'handle-top-right',
                    'handle-right-middle',
                    'handle-bottom-right',
                    'handle-bottom-center',
                    'handle-bottom-left',
                    'handle-left-middle',
                    'center-point'
                ];

            cropWindowElement.className = 'cr-crop-window';

            for(var i = 0; i < childNames.length; i++){
                (function(){
                    var cropHandle = document.createElement('div');
                    cropHandle.className = "cr-crop-handle cr-" + childNames[i];
                    cropWindowElement.appendChild(cropHandle);
                })();
            }

            target.appendChild(cropWindowElement);

            _mouseMoveQueue.push(onCropMove);
            _mouseDownQueue.push(onCropMouseDown);
            _mouseUpQueue.push(onCropMouseUp);

            function onCropMove(e){
                if(isHeld){
                    //TODO:Add Boundaries
                    //TODO:Add functionality for handles clicked
                    //TODO:Keep previous translate
                    cropWindowElement.style.transform = "translate(" + ((e.x - mouseStart.x)) + "px, " + ((e.y - mouseStart.y)) + "px)";
                }
            }

            function onCropMouseDown(e){
                if(e.target.className.match("-crop-")){
                    isHeld = true;
                    mouseStart['x'] = e.x;
                    mouseStart['y'] = e.y;
                }
            }

            function onCropMouseUp(e){
                isHeld = false;
            }

        }

        function bytesToSize(bytes) {
            var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
            if (bytes == 0) return '0 Byte';
            var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
            return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
        }

    }

})(document, window);<commit_msg>Added functionality to copy the section of bitmap that the crop window is displaying.<commit_after>(function(document, window){

    window['CropResize'] = CropResize;

    function CropResize(element, attributes){

        var _cropResize         = this,
            _mouseDownQueue     = [],
            _mouseUpQueue       = [],
            _mouseMoveQueue     = [],
            _windowResizeQueue  = [];

        this.remove = remove;
        this.images = {};

        element.addEventListener('change',      onFileInputChange);
        window.addEventListener('mousedown',    onMouseDown);
        window.addEventListener('mouseup',      onMouseUp);
        window.addEventListener('mousemove',    onMouseMove);
        window.addEventListener('resize',       onWindowResize);

        function remove(){
            element.removeEventListener('change',    onFileInputChange);
            element.removeEventListener('mousedown', onMouseDown);
            element.removeEventListener('mouseup',   onMouseUp);
            element.removeEventListener('mousemove', onMouseMove);
            element.removeEventListener('resize',    onWindowResize);

            //TODO:Clear Subscription arrays

        }

        function onMouseDown(e){
            onSubscription(e, _mouseDownQueue);
        }

        function onMouseUp(e){
            onSubscription(e, _mouseUpQueue);
        }

        function onMouseMove(e){
            onSubscription(e, _mouseMoveQueue);
        }

        function onWindowResize(e){
            onSubscription(e, _windowResizeQueue);
        }

        function onSubscription(e, events){
            for(var i = 0; i < events.length; i++){
                events[i](e);
            }
        }

        function onFileInputChange(e, scope){

            var files       = this.files,
                parsedFiles = [];

            for(var file in files){
                parsedFiles.push(new FileHandler(files[file]));
            }
        }

        function FileHandler(file){

            var fileHandler = {};

            fileHandler.original    = {};
            fileHandler.cropped     = {};

            if(typeof file === 'object' && file.type.match('image.*')){
                var reader = new FileReader();

                reader.onload = onReaderLoad;

                reader.readAsDataURL(file);

                function onReaderLoad(e){
                    fileHandler.original['url'] = e.target.result;
                    fileHandler.original['size'] = bytesToSize(file.size);
                    bindCanvas.call(fileHandler);
                }
            }
        }

        function bindCanvas(){
            var self = this;

            self['canvas'] = {};
            self.canvas['element'] = document.createElement('canvas');
            self.canvas['context'] = self.canvas.element.getContext('2d');

            var parent  = element.parentElement,
                image   = new Image();

            image.onload    =   onCanvasImageLoad;
            image.src       =   self.original.url;

            function onCanvasImageLoad(){
                self.original['width']  =   this.width;
                self.original['height'] =   this.height;

                self.canvas['width']    =   self['canvas'].element.width;
                self.canvas['height']   =   self['canvas'].element.height;

                var canvasParams = measurements(self.original, self.canvas);

                if(attributes['target']){
                    attributes['target'].appendChild(self.canvas.element)
                }else{
                    parent.insertBefore(self.canvas.element, element);
                }

                self.canvas.context.clearRect(0, 0, self.canvas['width'], self.canvas['height']);
                self.canvas.context.drawImage(image,
                    canvasParams.sx,
                    canvasParams.sy,
                    canvasParams.sWidth,
                    canvasParams.sHeight,
                    canvasParams.dx,
                    canvasParams.dy,
                    canvasParams.dWidth,
                    canvasParams.dHeight
                );

                cropWindow((attributes['target'] || parent), self.canvas);

                function measurements(image, canvas){
                    var hRatio      =   canvas.width  / image.width,
                        vRatio      =   canvas.height  / image.height,
                        ratio       =   Math.min ( hRatio, vRatio);

                    return {
                        sx:         0,
                        sy:         0,
                        sWidth:     image.width,
                        sHeight:    image.height,
                        dx:         (canvas['width'] - image['width'] * ratio ) / 2,
                        dy:         (canvas['height'] - image['height'] * ratio ) / 2,
                        dWidth:     image.width * ratio,
                        dHeight:    image.height * ratio
                    }
                }

            }
        }

        function createImgInstance(croppedImageData,croppedImageElement, target){
            var buffer = document.createElement('canvas'),
                bufferCtx = buffer.getContext("2d");

            buffer.width    =   500;
            buffer.height   =   500;
            bufferCtx.putImageData(croppedImageData, 0, 0);

            croppedImageElement.src = buffer.toDataURL('image/png');

            if(target && !target.contains(croppedImageElement)){
                target.appendChild(croppedImageElement);
            }
            return croppedImageElement;
        }

        function cropWindow(target, canvas, croppedSrc){

            var croppedImage = document.createElement('img');

            var isHeld              = false,
                mouseStart          = {},
                cropWindowElement   = document.createElement('div'),
                childNames = [
                    'handle-top-left',
                    'handle-top-center',
                    'handle-top-right',
                    'handle-right-middle',
                    'handle-bottom-right',
                    'handle-bottom-center',
                    'handle-bottom-left',
                    'handle-left-middle',
                    'center-point'
                ];

            cropWindowElement.className = 'cr-crop-window';

            for(var i = 0; i < childNames.length; i++){
                (function(){
                    var cropHandle = document.createElement('div');
                    cropHandle.className = "cr-crop-handle cr-" + childNames[i];
                    cropWindowElement.appendChild(cropHandle);
                })();
            }

            target.appendChild(cropWindowElement);

            _mouseMoveQueue.push(onCropMove);
            _mouseDownQueue.push(onCropMouseDown);
            _mouseUpQueue.push(onCropMouseUp);

            function onCropMove(e){
                if(isHeld){

                    //TODO:Add Boundaries
                    //TODO:Add functionality for handles clicked
                    //TODO:Keep previous translate
                    cropWindowElement.style.transform = "translate(" + ((e.x - mouseStart.x)) + "px, " + ((e.y - mouseStart.y)) + "px)";

                    var canvasBoundingRect = canvas.element.getBoundingClientRect(),
                        canvasWidth     =   canvas.element.clientWidth,
                        canvasHeight    =   canvas.element.clientHeight;

                    var heightPercent   =   cropWindowElement.clientHeight / canvasHeight,
                        widthPercent    =   cropWindowElement.clientWidth / canvasWidth,
                        leftPercent = (cropWindowElement.getBoundingClientRect().left - canvasBoundingRect.left) / canvasWidth,
                        topPercent = (cropWindowElement.getBoundingClientRect().top - canvasBoundingRect.top) / canvasHeight;

                    var newImgData = canvas.context.getImageData(
                            canvas.width * leftPercent,
                            canvas.height * topPercent,
                            canvas.width * widthPercent,
                            canvas.height * heightPercent);

                    createImgInstance(newImgData, croppedImage, _element.parentNode);
                }
            }

            function onCropMouseDown(e){
                if(e.target.className.match("-crop-")){
                    isHeld = true;
                    mouseStart['x'] = e.x;
                    mouseStart['y'] = e.y;
                }
            }

            function onCropMouseUp(e){
                isHeld = false;
            }

        }

        function bytesToSize(bytes) {
            var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
            if (bytes == 0) return '0 Byte';
            var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
            return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
        }

    }

})(document, window);<|endoftext|>


<commit_before>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');
const JSONbig = require('json-bigint');
const async = require('async');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

function processEvent(event) {
    var sender = event.sender.id.toString();

    if ((event.message && event.message.text) || (event.postback && event.postback.payload)) {
        var text = event.message ? event.message.text : event.postback.payload;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender)
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                //asd
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;
                /*console.log(responseText);
                console.log(responseData);
                console.log(action);*/
                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    if (!Array.isArray(responseData.facebook)) {
                        try {
                            console.log('Response as formatted message');
                            sendFBMessage(sender, responseData.facebook);
                        } catch (err) {
                            sendFBMessage(sender, {text: err.message});
                        }
                    } else {
                        responseData.facebook.forEach((facebookMessage) => {
                            try {
                                if (facebookMessage.sender_action) {
                                    console.log('Response as sender action');
                                    sendFBSenderAction(sender, facebookMessage.sender_action);
                                }
                                else {
                                    console.log('Response as formatted message');
                                    sendFBMessage(sender, facebookMessage);
                                }
                            } catch (err) {
                                sendFBMessage(sender, {text: err.message});
                            }
                        });
                    }
                //} else if (isDefined(responseText)) {
                } else if (isDefined(action) && isDefined(responseText)) {
                    console.log('Response as text message');
                    // facebook API limit for text length is 320,
                    // so we must split message if needed
                    var splittedText = splitResponse(responseText);
                    /*switch (action){
                        case 'show_prod':
                            console.log('generic');
                            async.eachSeries(splittedText, (textPart, callback) => {
                                sendFBMessage(sender, {text: textPart}, callback);
                            });
                            sendFBMessage(sender, generic_message, null);
                            break;
                        default:
                            console.log('default');
                            async.eachSeries(splittedText, (textPart, callback) => {
                                sendFBMessage(sender, {text: textPart}, callback);
                            });
                    }*/
                    async.eachSeries(splittedText, (textPart, callback) => {
                        sendFBMessage(sender, {text: textPart}, callback);
                    });
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function splitResponse(str) {
    if (str.length <= 320) {
        return [str];
    }

    return chunkString(str, 300);
}

function chunkString(s, len) {
    var curr = len, prev = 0;

    var output = [];

    while (s[curr]) {
        if (s[curr++] == ' ') {
            output.push(s.substring(prev, curr));
            prev = curr;
            curr += len;
        }
        else {
            var currReverse = curr;
            do {
                if (s.substring(currReverse - 1, currReverse) == ' ') {
                    output.push(s.substring(prev, currReverse));
                    prev = currReverse;
                    curr = currReverse + len;
                    break;
                }
                currReverse--;
            } while (currReverse > prev)
        }
    }
    output.push(s.substr(prev));
    //console.log(output);
    //output = ['Length of param message[text] must be less than or equal to 320'];
    return output;
}

/*const generic_message = {
    attachment: {
        type: "template",
        payload: {
            template_type: "generic",
            elements: [{
                title: "rift",
                subtitle: "Next-generation virtual reality",
                item_url: "https://www.oculus.com/en-us/rift/",
                image_url: "http://messengerdemo.parseapp.com/img/rift.png",
                buttons: [{
                    type: "web_url",
                    url: "https://www.oculus.com/en-us/rift/",
                    title: "Open Web URL"
                }, {
                    type: "postback",
                    title: "Call Postback",
                    payload: "Payload for first bubble"
                }]
            }, {
                title: "touch",
                subtitle: "Your Hands, Now in VR",
                item_url: "https://www.oculus.com/en-us/touch/",
                image_url: "http://messengerdemo.parseapp.com/img/touch.png",
                buttons: [{
                    type: "web_url",
                    url: "https://www.oculus.com/en-us/touch/",
                    title: "Open Web URL"
                }, {
                    type: "postback",
                    title: "Call Postback",
                    payload: "Payload for second bubble"
                }]
            }]
        }
    }
};*/

function sendFBMessage(sender, messageData, callback) {
    //console.log(sender);
    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
            //message: generic_message
        }
    }, (error, response, body) => {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }

        if (callback) {
            callback();
        }
    });
}

function sendFBSenderAction(sender, action, callback) {
    setTimeout(() => {
        request({
            url: 'https://graph.facebook.com/v2.6/me/messages',
            qs: {access_token: FB_PAGE_ACCESS_TOKEN},
            method: 'POST',
            json: {
                recipient: {id: sender},
                sender_action: action
            }
        }, (error, response, body) => {
            if (error) {
                console.log('Error sending action: ', error);
            } else if (response.body.error) {
                console.log('Error: ', response.body.error);
            }
            if (callback) {
                callback();
            }
        });
    }, 1000);
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        (error, response, body) => {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();

app.use(bodyParser.text({type: 'application/json'}));

app.get('/webhook/', (req, res) => {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(() => {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', (req, res) => {
    try {
        var data = JSONbig.parse(req.body);
        var asd = data;
        //console.log(asd);
        if (data.entry) {
            let entries = data.entry;
            entries.forEach((entry) => {
                let messaging_events = entry.messaging;
                if (messaging_events) {
                    messaging_events.forEach((event) => {
                        //console.log(event);
                        if (event.message && !event.message.is_echo ||
                            event.postback && event.postback.payload) {
                            processEvent(event);
                        }
                    });
                }
            });
        }

        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.post('/webhook_apiai/', (req, res) => {

    var weather_query = false;

    const generic_message = {
        attachment: {
            type: "template",
            payload: {
                template_type: "generic",
                elements: [{
                    title: "Fresh Pizza",
                    subtitle: "Be carefull and don't eat your fingers!!!",
                    item_url: "https://en.wikipedia.org/wiki/Pizza",
                    //image_url: "http://www.cbc.ca/inthekitchen/assets_c/2012/11/MargheritaPizza21-thumb-596x350-247022.jpg",
                    buttons: [{
                        type: "web_url",
                        url: "https://en.wikipedia.org/wiki/Pizza",
                        title: "Open Web URL"
                    }/*, {
                     type: "postback",
                     title: "Call Postback",
                     payload: "Payload for first bubble"
                     }*/]
                }]
            }
        }
    };

    try {
        var data = JSONbig.parse(req.body);
        //console.log(data);
        switch(data.result.action){
            case 'show_prod':
                switch(data.result.parameters.pizza_type){
                    case 'Margherita':
                        generic_message.attachment.payload.elements[0].title = data.result.parameters.pizza_type;
                        generic_message.attachment.payload.elements[0].image_url = "http://www.cbc.ca/inthekitchen/assets_c/2012/11/MargheritaPizza21-thumb-596x350-247022.jpg";
                }
            case 'show_weather':
                weather_query = true;
                if(data.result.parameters['geo-city']){
                    var city = data.result.parameters['geo-city'];
                    var base_url = "https://query.yahooapis.com/v1/public/yql?" + "q=select+%2A+from+weather.forecast+where+woeid+in+%28select+woeid+from+geo.places%281%29+where+text%3D%27"+city+"%27%29" + "&format=json";
                    request({
                        url: base_url,
                        method: 'GET', //Specify the method
                    }, function(error, response, body){
                        if(error) {
                            console.log(error);
                            return res.status(400).json({
                                status: "error",
                                error: err
                            });
                        } else {
                            console.log('here');
                            //console.log(response.statusCode, body);
                            var query = JSON.parse(body).query;
                            var results = query.results;
                            var channel = results.channel;
                            var item = channel.item;
                            var location = channel.location;
                            var units = channel.units;
                            var condition = item.condition;
                            //console.log(channel)
                            var string = "Today in " + location.city + ": " + condition.text + ", the temperature is " + condition.temp + " " + units.temperature
                            generic_message.attachment.payload.elements[0].title = 'Weather in' + city;
                            generic_message.attachment.payload.elements[0].subtitle = string;
                            generic_message.attachment.payload.elements[0].item_url = channel.link;
                            generic_message.attachment.payload.elements[0].image_url = channel.image.url;
                            generic_message.attachment.payload.elements[0].buttons[0].url = channel.link;
                            return res.status(200).json({
                                data: {
                                    facebook: generic_message
                                }
                            })
                        }
                    });
                }
        }
        if (weather_query== false){
            return res.status(200).json({
                data: {
                    facebook: generic_message
                }
            })
        }
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }
});

app.listen(REST_PORT, () => {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();
<commit_msg>'webhook_test'<commit_after>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');
const JSONbig = require('json-bigint');
const async = require('async');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

function processEvent(event) {
    var sender = event.sender.id.toString();

    if ((event.message && event.message.text) || (event.postback && event.postback.payload)) {
        var text = event.message ? event.message.text : event.postback.payload;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender)
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                //asd
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;
                /*console.log(responseText);
                console.log(responseData);
                console.log(action);*/
                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    if (!Array.isArray(responseData.facebook)) {
                        try {
                            console.log('Response as formatted message');
                            sendFBMessage(sender, responseData.facebook);
                        } catch (err) {
                            sendFBMessage(sender, {text: err.message});
                        }
                    } else {
                        responseData.facebook.forEach((facebookMessage) => {
                            try {
                                if (facebookMessage.sender_action) {
                                    console.log('Response as sender action');
                                    sendFBSenderAction(sender, facebookMessage.sender_action);
                                }
                                else {
                                    console.log('Response as formatted message');
                                    sendFBMessage(sender, facebookMessage);
                                }
                            } catch (err) {
                                sendFBMessage(sender, {text: err.message});
                            }
                        });
                    }
                //} else if (isDefined(responseText)) {
                } else if (isDefined(action) && isDefined(responseText)) {
                    console.log('Response as text message');
                    // facebook API limit for text length is 320,
                    // so we must split message if needed
                    var splittedText = splitResponse(responseText);
                    /*switch (action){
                        case 'show_prod':
                            console.log('generic');
                            async.eachSeries(splittedText, (textPart, callback) => {
                                sendFBMessage(sender, {text: textPart}, callback);
                            });
                            sendFBMessage(sender, generic_message, null);
                            break;
                        default:
                            console.log('default');
                            async.eachSeries(splittedText, (textPart, callback) => {
                                sendFBMessage(sender, {text: textPart}, callback);
                            });
                    }*/
                    async.eachSeries(splittedText, (textPart, callback) => {
                        sendFBMessage(sender, {text: textPart}, callback);
                    });
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function splitResponse(str) {
    if (str.length <= 320) {
        return [str];
    }

    return chunkString(str, 300);
}

function chunkString(s, len) {
    var curr = len, prev = 0;

    var output = [];

    while (s[curr]) {
        if (s[curr++] == ' ') {
            output.push(s.substring(prev, curr));
            prev = curr;
            curr += len;
        }
        else {
            var currReverse = curr;
            do {
                if (s.substring(currReverse - 1, currReverse) == ' ') {
                    output.push(s.substring(prev, currReverse));
                    prev = currReverse;
                    curr = currReverse + len;
                    break;
                }
                currReverse--;
            } while (currReverse > prev)
        }
    }
    output.push(s.substr(prev));
    //console.log(output);
    //output = ['Length of param message[text] must be less than or equal to 320'];
    return output;
}

/*const generic_message = {
    attachment: {
        type: "template",
        payload: {
            template_type: "generic",
            elements: [{
                title: "rift",
                subtitle: "Next-generation virtual reality",
                item_url: "https://www.oculus.com/en-us/rift/",
                image_url: "http://messengerdemo.parseapp.com/img/rift.png",
                buttons: [{
                    type: "web_url",
                    url: "https://www.oculus.com/en-us/rift/",
                    title: "Open Web URL"
                }, {
                    type: "postback",
                    title: "Call Postback",
                    payload: "Payload for first bubble"
                }]
            }, {
                title: "touch",
                subtitle: "Your Hands, Now in VR",
                item_url: "https://www.oculus.com/en-us/touch/",
                image_url: "http://messengerdemo.parseapp.com/img/touch.png",
                buttons: [{
                    type: "web_url",
                    url: "https://www.oculus.com/en-us/touch/",
                    title: "Open Web URL"
                }, {
                    type: "postback",
                    title: "Call Postback",
                    payload: "Payload for second bubble"
                }]
            }]
        }
    }
};*/

function sendFBMessage(sender, messageData, callback) {
    //console.log(sender);
    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
            //message: generic_message
        }
    }, (error, response, body) => {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }

        if (callback) {
            callback();
        }
    });
}

function sendFBSenderAction(sender, action, callback) {
    setTimeout(() => {
        request({
            url: 'https://graph.facebook.com/v2.6/me/messages',
            qs: {access_token: FB_PAGE_ACCESS_TOKEN},
            method: 'POST',
            json: {
                recipient: {id: sender},
                sender_action: action
            }
        }, (error, response, body) => {
            if (error) {
                console.log('Error sending action: ', error);
            } else if (response.body.error) {
                console.log('Error: ', response.body.error);
            }
            if (callback) {
                callback();
            }
        });
    }, 1000);
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        (error, response, body) => {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();

app.use(bodyParser.text({type: 'application/json'}));

app.get('/webhook/', (req, res) => {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(() => {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', (req, res) => {
    try {
        var data = JSONbig.parse(req.body);
        var asd = data;
        //console.log(asd);
        if (data.entry) {
            let entries = data.entry;
            entries.forEach((entry) => {
                let messaging_events = entry.messaging;
                if (messaging_events) {
                    messaging_events.forEach((event) => {
                        //console.log(event);
                        if (event.message && !event.message.is_echo ||
                            event.postback && event.postback.payload) {
                            processEvent(event);
                        }
                    });
                }
            });
        }

        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.post('/webhook_apiai/', (req, res) => {

    var weather_query = false;

    const generic_message = {
        attachment: {
            type: "template",
            payload: {
                template_type: "generic",
                elements: [{
                    title: "Fresh Pizza",
                    subtitle: "Be carefull and don't eat your fingers!!!",
                    item_url: "https://en.wikipedia.org/wiki/Pizza",
                    //image_url: "http://www.cbc.ca/inthekitchen/assets_c/2012/11/MargheritaPizza21-thumb-596x350-247022.jpg",
                    buttons: [{
                        type: "web_url",
                        url: "https://en.wikipedia.org/wiki/Pizza",
                        title: "Open Web URL"
                    }/*, {
                     type: "postback",
                     title: "Call Postback",
                     payload: "Payload for first bubble"
                     }*/]
                }]
            }
        }
    };

    try {
        var data = JSONbig.parse(req.body);
        //console.log(data);
        switch(data.result.action){
            case 'show_prod':
                switch(data.result.parameters.pizza_type){
                    case 'Margherita':
                        generic_message.attachment.payload.elements[0].title = data.result.parameters.pizza_type;
                        generic_message.attachment.payload.elements[0].image_url = "http://www.cbc.ca/inthekitchen/assets_c/2012/11/MargheritaPizza21-thumb-596x350-247022.jpg";
                }
            case 'show_weather':
                weather_query = true;
                if(data.result.parameters['geo-city']){
                    var city = data.result.parameters['geo-city'];
                    var base_url = "https://query.yahooapis.com/v1/public/yql?" + "q=select+%2A+from+weather.forecast+where+woeid+in+%28select+woeid+from+geo.places%281%29+where+text%3D%27"+city+"%27%29" + "&format=json";
                    request({
                        url: base_url,
                        method: 'GET', //Specify the method
                    }, function(error, response, body){
                        if(error) {
                            console.log(error);
                            return res.status(400).json({
                                status: "error",
                                error: err
                            });
                        } else {
                            console.log('here');
                            //console.log(response.statusCode, body);
                            var query = JSON.parse(body).query;
                            var results = query.results;
                            var channel = results.channel;
                            var item = channel.item;
                            var location = channel.location;
                            var units = channel.units;
                            var condition = item.condition;
                            //console.log(channel)
                            var string = "Today in " + location.city + ": " + condition.text + ", the temperature is " + condition.temp + " " + units.temperature
                            generic_message.attachment.payload.elements[0].title = 'Weather in' + city;
                            generic_message.attachment.payload.elements[0].subtitle = string;
                            generic_message.attachment.payload.elements[0].item_url = channel.link;
                            generic_message.attachment.payload.elements[0].image_url = channel.image.url;
                            generic_message.attachment.payload.elements[0].buttons[0].url = channel.link;
                        }
                    });
                }
        }
        return res.status(200).json({
            data: {
                facebook: generic_message
            }
        })
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }
});

app.listen(REST_PORT, () => {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();
<|endoftext|>


<commit_before>/**
 * Taking care of events
 *  - Simulating 'change' event on contentEditable element
 *  - Handling drag & drop logic
 *  - Catch paste events
 *  - Dispatch proprietary newword:composer event
 *  - Keyboard shortcuts
 */
(function(wysihtml5) {
  var dom       = wysihtml5.dom,
      browser   = wysihtml5.browser,
      /**
       * Map keyCodes to query commands
       */
      shortcuts = {
        "66": "bold",     // B
        "73": "italic",   // I
        "85": "underline" // U
      };

  wysihtml5.views.Composer.prototype.observe = function() {
    var that                = this,
        state               = this.getValue(),
        container           = (this.sandbox.getIframe) ? this.sandbox.getIframe() : this.sandbox.getContentEditable(),
        element             = this.element,
        focusBlurElement    = (browser.supportsEventsInIframeCorrectly() || this.sandbox.getContentEditable) ? element : this.sandbox.getWindow(),
        pasteEvents         = ["drop", "paste"],
        interactionEvents   = ["drop", "paste", "mouseup", "focus", "blur", "keyup"];

    // --------- destroy:composer event ---------
    dom.observe(container, "DOMNodeRemoved", function() {
      clearInterval(domNodeRemovedInterval);
      that.parent.fire("destroy:composer");
    });

    // DOMNodeRemoved event is not supported in IE 8
    var domNodeRemovedInterval = setInterval(function() {
      if (!dom.contains(document.documentElement, container)) {
        clearInterval(domNodeRemovedInterval);
        that.parent.fire("destroy:composer");
      }
    }, 250);

    // --------- User interaction tracking --
    /*
    dom.observe(focusBlurElement, interactionEvents, function() {
      setTimeout(function() {
        that.parent.fire("interaction").fire("interaction:composer");
      }, 0);
    });
    */

    if (this.config.handleTables) {
        this.tableSelection = wysihtml5.quirks.tableCellsSelection(element, that.parent);
    }

    // --------- Focus & blur logic ---------
    dom.observe(focusBlurElement, "focus", function() {
      that.parent.fire("focus").fire("focus:composer");

      // Delay storing of state until all focus handler are fired
      // especially the one which resets the placeholder
      setTimeout(function() { state = that.getValue(); }, 0);
    });

    dom.observe(focusBlurElement, "blur", function() {
      if (state !== that.getValue()) {
        that.parent.fire("change").fire("change:composer");
      }
      that.parent.fire("blur").fire("blur:composer");
    });

    // --------- Drag & Drop logic ---------
    dom.observe(element, "dragenter", function() {
      that.parent.fire("unset_placeholder");
    });

    dom.observe(element, pasteEvents, function() {
      setTimeout(function() {
        that.parent.fire("paste").fire("paste:composer");
      }, 0);
    });

    // --------- neword event ---------
    dom.observe(element, "keyup", function(event) {
      var keyCode = event.keyCode;
      if (keyCode === wysihtml5.SPACE_KEY || keyCode === wysihtml5.ENTER_KEY) {
        that.parent.fire("newword:composer");
      }
    });

    this.parent.on("paste:composer", function() {
      setTimeout(function() { that.parent.fire("newword:composer"); }, 0);
    });

    // --------- Make sure that images are selected when clicking on them ---------
    if (!browser.canSelectImagesInContentEditable()) {
      dom.observe(element, "mousedown", function(event) {
        var target = event.target;
        if (target.nodeName === "IMG") {
          event.preventDefault();
          that.selection.selectNode(target);
        }
      });
    }

    // TODO add real drop option
    if (!browser.canSelectImagesInContentEditable()) {
        dom.observe(element, "drop", function(event) {
            // TODO: if I knew how to get dropped elements list from event I could limit it to only IMG element case
            setTimeout(function() {
                that.selection.getSelection().removeAllRanges();
            }, 0);
        });
    }

    if (browser.hasHistoryIssue() && browser.supportsSelectionModify()) {
      dom.observe(element, "keydown", function(event) {
        if (!event.metaKey && !event.ctrlKey) {
          return;
        }

        var keyCode   = event.keyCode,
            win       = element.ownerDocument.defaultView,
            selection = win.getSelection();

        if (keyCode === 37 || keyCode === 39) {
          if (keyCode === 37) {
            selection.modify("extend", "left", "lineboundary");
            if (!event.shiftKey) {
              selection.collapseToStart();
            }
          }
          if (keyCode === 39) {
            selection.modify("extend", "right", "lineboundary");
            if (!event.shiftKey) {
              selection.collapseToEnd();
            }
          }
          event.preventDefault();
        }
      });
    }

    // --------- Shortcut logic ---------
    dom.observe(element, "keydown", function(event) {
      var keyCode  = event.keyCode,
          command  = shortcuts[keyCode];
      if ((event.ctrlKey || event.metaKey) && !event.altKey && command) {
        that.commands.exec(command);
        event.preventDefault();
      }
    });

    // --------- Make sure that when pressing backspace/delete on selected images deletes the image and it's anchor ---------
    dom.observe(element, "keydown", function(event) {
      var target  = that.selection.getSelectedNode(true),
          keyCode = event.keyCode,
          parent;
      if (target && target.nodeName === "IMG" && (keyCode === wysihtml5.BACKSPACE_KEY || keyCode === wysihtml5.DELETE_KEY)) { // 8 => backspace, 46 => delete
        parent = target.parentNode;
        // delete the
        parent.removeChild(target);
        // and it's parent  too if it hasn't got any other child nodes
        if (parent.nodeName === "A" && !parent.firstChild) {
          parent.parentNode.removeChild(parent);
        }

        setTimeout(function() { wysihtml5.quirks.redraw(element); }, 0);
        event.preventDefault();
      }
    });

    // --------- IE 8+9 focus the editor when the iframe is clicked (without actually firing the 'focus' event on the ) ---------
    if (!this.config.contentEditableMode && browser.hasIframeFocusIssue()) {
      dom.observe(this.iframe, "focus", function() {
        setTimeout(function() {
          if (that.doc.querySelector(":focus") !== that.element) {
            that.focus();
          }
        }, 0);
      });

      dom.observe(this.element, "blur", function() {
        setTimeout(function() {
          that.selection.getSelection().removeAllRanges();
        }, 0);
      });
    }

    // --------- Show url in tooltip when hovering links or images ---------
    var titlePrefixes = {
      IMG: "Image: ",
      A:   "Link: "
    };

    dom.observe(element, "mouseover", function(event) {
      var target   = event.target,
          nodeName = target.nodeName,
          title;
      if (nodeName !== "A" && nodeName !== "IMG") {
        return;
      }
      var hasTitle = target.hasAttribute("title");
      if(!hasTitle){
        title = titlePrefixes[nodeName] + (target.getAttribute("href") || target.getAttribute("src"));
        target.setAttribute("title", title);
      }
    });
  };
})(wysihtml5);<commit_msg>wip wip<commit_after>/**
 * Taking care of events
 *  - Simulating 'change' event on contentEditable element
 *  - Handling drag & drop logic
 *  - Catch paste events
 *  - Dispatch proprietary newword:composer event
 *  - Keyboard shortcuts
 */
(function(wysihtml5) {
  var dom       = wysihtml5.dom,
      browser   = wysihtml5.browser,
      /**
       * Map keyCodes to query commands
       */
      shortcuts = {
        "66": "bold",     // B
        "73": "italic",   // I
        "85": "underline" // U
      };

  wysihtml5.views.Composer.prototype.observe = function() {
    var that                = this,
        state               = this.getValue(),
        container           = (this.sandbox.getIframe) ? this.sandbox.getIframe() : this.sandbox.getContentEditable(),
        element             = this.element,
        focusBlurElement    = (browser.supportsEventsInIframeCorrectly() || this.sandbox.getContentEditable) ? element : this.sandbox.getWindow(),
        pasteEvents         = ["drop", "paste"],
        interactionEvents   = ["drop", "paste", "mouseup", "focus", "blur", "keyup"];

    // --------- destroy:composer event ---------
    dom.observe(container, "DOMNodeRemoved", function() {
      clearInterval(domNodeRemovedInterval);
      that.parent.fire("destroy:composer");
    });

    // DOMNodeRemoved event is not supported in IE 8
    var domNodeRemovedInterval = setInterval(function() {
      if (!dom.contains(document.documentElement, container)) {
        clearInterval(domNodeRemovedInterval);
        that.parent.fire("destroy:composer");
      }
    }, 250);

    // --------- User interaction tracking --
    /*
    dom.observe(focusBlurElement, interactionEvents, function() {
      setTimeout(function() {
        that.parent.fire("interaction").fire("interaction:composer");
      }, 0);
    });
    */

    if (this.config.handleTables) {
        this.tableSelection = wysihtml5.quirks.tableCellsSelection(element, that.parent);
    }

    // --------- Focus & blur logic ---------
    dom.observe(focusBlurElement, "focus", function() {
      that.parent.fire("focus").fire("focus:composer");

      // Delay storing of state until all focus handler are fired
      // especially the one which resets the placeholder
      setTimeout(function() { state = that.getValue(); }, 0);
    });

    dom.observe(focusBlurElement, "blur", function() {
      if (state !== that.getValue()) {
        that.parent.fire("change").fire("change:composer");
      }
      that.parent.fire("blur").fire("blur:composer");
    });

    // --------- Drag & Drop logic ---------
    dom.observe(element, "dragenter", function() {
      that.parent.fire("unset_placeholder");
    });

    dom.observe(element, pasteEvents, function() {
      setTimeout(function() {
        that.parent.fire("paste").fire("paste:composer");
      }, 0);
    });

    // --------- neword event ---------
    dom.observe(element, "keyup", function(event) {
      var keyCode = event.keyCode;
      if (keyCode === wysihtml5.SPACE_KEY || keyCode === wysihtml5.ENTER_KEY) {
        that.parent.fire("newword:composer");
      }
    });

    this.parent.on("paste:composer", function() {
      setTimeout(function() { that.parent.fire("newword:composer"); }, 0);
    });

    // --------- Make sure that images are selected when clicking on them ---------
    if (!browser.canSelectImagesInContentEditable()) {
      dom.observe(element, "mousedown", function(event) {
        var target = event.target;
        if (target.nodeName === "IMG") {
          event.preventDefault();
          that.selection.selectNode(target);
        }
      });
    }

    // TODO add real drop option
    if (!browser.canSelectImagesInContentEditable()) {
        dom.observe(element, "drop", function(event) {
            // TODO: if I knew how to get dropped elements list from event I could limit it to only IMG element case
            setTimeout(function() {
                that.selection.getSelection().removeAllRanges();
            }, 0);
        });
    }

    if (browser.hasHistoryIssue() && browser.supportsSelectionModify()) {
      dom.observe(element, "keydown", function(event) {
        if (!event.metaKey && !event.ctrlKey) {
          return;
        }

        var keyCode   = event.keyCode,
            win       = element.ownerDocument.defaultView,
            selection = win.getSelection();

        if (keyCode === 37 || keyCode === 39) {
          if (keyCode === 37) {
            selection.modify("extend", "left", "lineboundary");
            if (!event.shiftKey) {
              selection.collapseToStart();
            }
          }
          if (keyCode === 39) {
            selection.modify("extend", "right", "lineboundary");
            if (!event.shiftKey) {
              selection.collapseToEnd();
            }
          }
          event.preventDefault();
        }
      });
    }

    // --------- Shortcut logic ---------
    dom.observe(element, "keydown", function(event) {
      var keyCode  = event.keyCode,
          command  = shortcuts[keyCode];
      if ((event.ctrlKey || event.metaKey) && !event.altKey && command) {
        that.commands.exec(command);
        event.preventDefault();
      }
    });

    // --------- Make sure that when pressing backspace/delete on selected images deletes the image and it's anchor ---------
    dom.observe(element, "keydown", function(event) {
      var target  = that.selection.getSelectedNode(true),
          keyCode = event.keyCode,
          parent;
      if (target && target.nodeName === "IMG" && (keyCode === wysihtml5.BACKSPACE_KEY || keyCode === wysihtml5.DELETE_KEY)) { // 8 => backspace, 46 => delete
        parent = target.parentNode;
        // delete the
        parent.removeChild(target);
        // and it's parent  too if it hasn't got any other child nodes
        if (parent.nodeName === "A" && !parent.firstChild) {
          parent.parentNode.removeChild(parent);
        }

        setTimeout(function() { wysihtml5.quirks.redraw(element); }, 0);
        event.preventDefault();
      }
    });

    // --------- Make sure that when pressing backspace/delete on Hedaing remove span styl---------
    /*
    dom.observe(element, "keydown", function(event) {
      var target  = that.selection.getSelectedNode(true),
      		keyCode  = event.keyCode;
      		parent = target.parentNode;
      	if (keyCode === wysihtml5.BACKSPACE_KEY || keyCode === wysihtml5.DELETE_KEY) {
      		setTimeout(function() {
          	if(target) console.log(parent.nodeName);
          	// todo remove inline style.
        	}, 0);
				}
				//event.preventDefault();
    });
    */

    // --------- IE 8+9 focus the editor when the iframe is clicked (without actually firing the 'focus' event on the ) ---------
    if (!this.config.contentEditableMode && browser.hasIframeFocusIssue()) {
      dom.observe(this.iframe, "focus", function() {
        setTimeout(function() {
          if (that.doc.querySelector(":focus") !== that.element) {
            that.focus();
          }
        }, 0);
      });

      dom.observe(this.element, "blur", function() {
        setTimeout(function() {
          that.selection.getSelection().removeAllRanges();
        }, 0);
      });
    }

    // --------- Show url in tooltip when hovering links or images ---------
    var titlePrefixes = {
      IMG: "Image: ",
      A:   "Link: "
    };

    dom.observe(element, "mouseover", function(event) {
      var target   = event.target,
          nodeName = target.nodeName,
          title;
      if (nodeName !== "A" && nodeName !== "IMG") {
        return;
      }
      var hasTitle = target.hasAttribute("title");
      if(!hasTitle){
        title = titlePrefixes[nodeName] + (target.getAttribute("href") || target.getAttribute("src"));
        target.setAttribute("title", title);
      }
    });
  };
})(wysihtml5);<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var express = require('express');

var app = module.exports = express.createServer();

// Configuration

app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

// Routes

app.get('/', function(req, res){
  res.render('index', {
    title: 'Express'
  });
});

app.listen(3000);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
<commit_msg>Changed tabs.<commit_after>
/**
 * Module dependencies.
 */

var express = require('express');

var app = module.exports = express.createServer();

// Configuration

app.configure(function(){
	app.set('views', __dirname + '/views');
	app.set('view engine', 'jade');
	app.use(express.bodyParser());
	app.use(express.methodOverride());
	app.use(app.router);
	app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
	app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
	app.use(express.errorHandler());
});

// Routes

app.get('/', function(req, res){
	res.render('index', {
		title: 'Express'
	});
});

app.listen(3000);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
<|endoftext|>