Release 5.2
diff --git a/src/js/page.js b/src/js/page.js
new file mode 100644
index 0000000..2c5702d
--- /dev/null
+++ b/src/js/page.js
@@ -0,0 +1,907 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+var page = {

+  startX: 150,

+  startY: 150,

+  endX: 400,

+  endY: 300,

+  moveX: 0,

+  moveY: 0,

+  pageWidth: 0,

+  pageHeight: 0,

+  visibleWidth: 0,

+  visibleHeight: 0,

+  dragging: false,

+  moving: false,

+  resizing: false,

+  isMouseDown: false,

+  scrollXCount: 0,

+  scrollYCount: 0,

+  scrollX: 0,

+  scrollY: 0,

+  captureWidth: 0,

+  captureHeight: 0,

+  isSelectionAreaTurnOn: false,

+  fixedElements_ : [],

+  marginTop: 0,

+  marginLeft: 0,

+  modifiedBottomRightFixedElements: [],

+  originalViewPortWidth: document.documentElement.clientWidth,

+  defaultScrollBarWidth: 17, // Default scroll bar width on windows platform.

+

+  hookBodyScrollValue: function(needHook) {

+    document.documentElement.setAttribute(

+        "__screen_capture_need_hook_scroll_value__", needHook);

+    var event = document.createEvent('Event');

+    event.initEvent('__screen_capture_check_hook_status_event__', true, true);

+    document.documentElement.dispatchEvent(event);

+  },

+

+  /**

+   * Determine if the page scrolled to bottom or right.

+   */

+  isScrollToPageEnd: function(coordinate) {

+    var body = document.body;

+    var docElement = document.documentElement;

+    if (coordinate == 'x')

+      return docElement.clientWidth + body.scrollLeft == body.scrollWidth;

+    else if (coordinate == 'y')

+      return docElement.clientHeight + body.scrollTop == body.scrollHeight;

+  },

+

+  /**

+   * Detect if the view port is located to the corner of page.

+   */

+  detectPagePosition: function() {

+    var body = document.body;

+    var pageScrollTop = body.scrollTop;

+    var pageScrollLeft = body.scrollLeft;

+    if (pageScrollTop == 0 && pageScrollLeft == 0) {

+      return 'top_left';

+    } else if (pageScrollTop == 0 && this.isScrollToPageEnd('x')) {

+      return 'top_right';

+    } else if (this.isScrollToPageEnd('y') && pageScrollLeft == 0) {

+      return 'bottom_left';

+    } else if (this.isScrollToPageEnd('y') && this.isScrollToPageEnd('x')) {

+      return 'bottom_right';

+    }

+    return null;

+  },

+

+  /**

+   * Detect fixed-positioned element's position in the view port.

+   * @param {Element} elem

+   * @return {String|Object} Return position of the element in the view port:

+   *   top_left, top_right, bottom_left, bottom_right, or null.

+   */

+  detectCapturePositionOfFixedElement: function(elem) {

+    var docElement = document.documentElement;

+    var viewPortWidth = docElement.clientWidth;

+    var viewPortHeight = docElement.clientHeight;

+    var offsetWidth = elem.offsetWidth;

+    var offsetHeight = elem.offsetHeight;

+    var offsetTop = elem.offsetTop;

+    var offsetLeft = elem.offsetLeft;

+    var result = [];

+

+    // Compare distance between element and the edge of view port to determine

+    // the capture position of element.

+    if (offsetTop <= viewPortHeight - offsetTop - offsetHeight) {

+      result.push('top');

+    } else if (offsetTop < viewPortHeight) {

+      result.push('bottom');

+    }

+    if (offsetLeft <= viewPortWidth - offsetLeft - offsetWidth) {

+      result.push('left');

+    } else if (offsetLeft < viewPortWidth) {

+      result.push('right');

+    }

+

+    // If the element is out of view port, then ignore.

+    if (result.length != 2)

+      return null;

+    return result.join('_');

+  },

+

+  restoreFixedElements: function() {

+    this.fixedElements_.forEach(function(element) {

+      element[1].style.visibility = 'visible';

+    });

+    this.fixedElements_ = [];

+  },

+

+  /**

+   * Iterate DOM tree and cache visible fixed-position elements.

+   */

+  cacheVisibleFixedPositionedElements: function() {

+    var nodeIterator = document.createNodeIterator(

+        document.documentElement,

+        NodeFilter.SHOW_ELEMENT,

+        null,

+        false

+    );

+    var currentNode;

+    while (currentNode = nodeIterator.nextNode()) {

+      var nodeComputedStyle =

+          document.defaultView.getComputedStyle(currentNode, "");

+      // Skip nodes which don't have computeStyle or are invisible.

+      if (!nodeComputedStyle)

+        continue;

+      if (nodeComputedStyle.position == "fixed" &&

+          nodeComputedStyle.display != 'none' &&

+          nodeComputedStyle.visibility != 'hidden') {

+        var position =

+          this.detectCapturePositionOfFixedElement(currentNode);

+        if (position)

+          this.fixedElements_.push([position, currentNode]);

+      }

+    }

+  },

+

+  // Handle fixed-position elements for capture.

+  handleFixedElements: function(capturePosition) {

+    var docElement = document.documentElement;

+    var body = document.body;

+

+    // If page has no scroll bar, then return directly.

+    if (docElement.clientHeight == body.scrollHeight &&

+        docElement.clientWidth == body.scrollWidth)

+      return;

+    

+    if (!this.fixedElements_.length) {

+      this.cacheVisibleFixedPositionedElements();

+    }

+

+    this.fixedElements_.forEach(function(element) {

+      if (element[0] == capturePosition)

+        element[1].style.visibility = 'visible';

+      else

+        element[1].style.visibility = 'hidden';

+    });

+  },

+

+  handleSecondToLastCapture: function() {

+    var docElement = document.documentElement;

+    var body = document.body;

+    var bottomPositionElements = [];

+    var rightPositionElements = [];

+    var that = this;

+    this.fixedElements_.forEach(function(element) {

+      var position = element[0];

+      if (position == 'bottom_left' || position == 'bottom_right') {

+        bottomPositionElements.push(element[1]);

+      } else if (position == 'bottom_right' || position == 'top_right') {

+        rightPositionElements.push(element[1]);

+      }

+    });

+

+    // Determine if the current capture is last but one.

+    var remainingCaptureHeight = body.scrollHeight - docElement.clientHeight -

+      body.scrollTop;

+    if (remainingCaptureHeight > 0 &&

+        remainingCaptureHeight < docElement.clientHeight) {

+      bottomPositionElements.forEach(function(element) {

+        if (element.offsetHeight > remainingCaptureHeight) {

+          element.style.visibility = 'visible';

+          var originalBottom = window.getComputedStyle(element).bottom;

+          that.modifiedBottomRightFixedElements.push(

+            ['bottom', element, originalBottom]);

+          element.style.bottom = -remainingCaptureHeight + 'px';

+        }

+      });

+    }

+

+    var remainingCaptureWidth = body.scrollWidth - docElement.clientWidth -

+      body.scrollLeft;

+    if (remainingCaptureWidth > 0 &&

+        remainingCaptureWidth < docElement.clientWidth) {

+      rightPositionElements.forEach(function(element) {

+        if (element.offsetWidth > remainingCaptureWidth) {

+          element.style.visibility = 'visible';

+          var originalRight = window.getComputedStyle(element).right;

+          that.modifiedBottomRightFixedElements.push(

+            ['right', element, originalRight]);

+          element.style.right = -remainingCaptureWidth + 'px';

+        }

+      });

+    }

+  },

+

+  restoreBottomRightOfFixedPositionElements: function() {

+    this.modifiedBottomRightFixedElements.forEach(function(data) {

+      var property = data[0];

+      var element = data[1];

+      var originalValue = data[2];

+      element.style[property] = originalValue;

+    });

+    this.modifiedBottomRightFixedElements = [];

+  },

+  

+  hideAllFixedPositionedElements: function() {

+    this.fixedElements_.forEach(function(element) {

+      element[1].style.visibility = 'hidden';

+    });

+  },

+

+  hasScrollBar: function(axis) {

+    var body = document.body;

+    var docElement = document.documentElement;

+    if (axis == 'x') {

+      if (window.getComputedStyle(body).overflowX == 'scroll')

+        return true;

+      return Math.abs(body.scrollWidth - docElement.clientWidth) >=

+          page.defaultScrollBarWidth;

+    } else if (axis == 'y') {

+      if (window.getComputedStyle(body).overflowY == 'scroll')

+        return true;

+      return Math.abs(body.scrollHeight - docElement.clientHeight) >=

+          page.defaultScrollBarWidth;

+    }

+  },

+

+  getOriginalViewPortWidth: function() {

+    chrome.extension.sendMessage({ msg: 'original_view_port_width'},

+      function(originalViewPortWidth) {

+        if (originalViewPortWidth) {

+          page.originalViewPortWidth = page.hasScrollBar('y') ?

+            originalViewPortWidth - page.defaultScrollBarWidth : originalViewPortWidth;

+        } else {

+          page.originalViewPortWidth = document.documentElement.clientWidth;

+        }

+      });

+  },

+  

+  calculateSizeAfterZooming: function(originalSize) {

+    var originalViewPortWidth = page.originalViewPortWidth;

+    var currentViewPortWidth = document.documentElement.clientWidth;

+    if (originalViewPortWidth == currentViewPortWidth)

+      return originalSize;

+    return Math.round(

+        originalViewPortWidth * originalSize / currentViewPortWidth);

+  },

+

+  getZoomLevel: function() {

+    return page.originalViewPortWidth / document.documentElement.clientWidth;

+  },

+

+  handleRightFloatBoxInGmail: function() {

+    var mainframe = document.getElementById('canvas_frame');

+    var boxContainer = document.querySelector('body > .dw');

+    var fBody = mainframe.contentDocument.body;

+    if (fBody.clientHeight + fBody.scrollTop == fBody.scrollHeight) {

+      boxContainer.style.display = 'block';

+    } else {

+      boxContainer.style.display = 'none';

+    }

+  },

+

+  getViewPortSize: function() {

+    var result = {

+      width: document.documentElement.clientWidth,

+      height: document.documentElement.clientHeight

+    };

+

+    if (document.compatMode == 'BackCompat') {

+      result.width = document.body.clientWidth;

+      result.height = document.body.clientHeight;

+    }

+

+    return result;

+  },

+

+  /**

+   * Check if the page is only made of invisible embed elements.

+   */

+  checkPageIsOnlyEmbedElement: function() {

+    var bodyNode = document.body.children;

+    var isOnlyEmbed = false;

+    for (var i = 0; i < bodyNode.length; i++) {

+      var tagName = bodyNode[i].tagName;

+      if (tagName == 'OBJECT' || tagName == 'EMBED' || tagName == 'VIDEO' ||

+          tagName == 'SCRIPT' || tagName == 'LINK') {

+        isOnlyEmbed = true;

+      } else if (bodyNode[i].style.display != 'none'){

+        isOnlyEmbed = false;

+        break;

+      }

+    }

+    return isOnlyEmbed;

+  },

+

+  isGMailPage: function(){

+    var hostName = window.location.hostname;

+    if (hostName == 'mail.google.com' &&

+        document.getElementById('canvas_frame')) {

+      return true;

+    }

+    return false;

+  },

+

+  /**

+  * Receive messages from background page, and then decide what to do next

+  */

+  addMessageListener: function() {

+    chrome.extension.onMessage.addListener(function(request, sender, response) {

+      if (page.isSelectionAreaTurnOn) {

+        page.removeSelectionArea();

+      }

+      switch (request.msg) {

+        case 'capture_window': response(page.getWindowSize()); break;

+        case 'show_selection_area': page.showSelectionArea(); break;

+        case 'scroll_init': // Capture whole page.

+          response(page.scrollInit(0, 0, document.body.scrollWidth,

+              document.body.scrollHeight, 'captureWhole'));

+          break;

+        case 'scroll_next':

+          page.visibleWidth = request.visibleWidth;

+          page.visibleHeight = request.visibleHeight;

+          response(page.scrollNext());

+          break;

+        case 'capture_selected':

+          response(page.scrollInit(

+              page.startX, page.startY,

+              page.calculateSizeAfterZooming(page.endX - page.startX),

+              page.calculateSizeAfterZooming(page.endY - page.startY),

+              'captureSelected'));

+          break;

+      }

+    });

+  },

+

+  /**

+  * Send Message to background page

+  */

+  sendMessage: function(message) {

+    chrome.extension.sendMessage(message);

+  },

+

+  /**

+  * Initialize scrollbar position, and get the data browser

+  */

+  scrollInit: function(startX, startY, canvasWidth, canvasHeight, type) {

+    this.hookBodyScrollValue(true);

+    page.captureHeight = canvasHeight;

+    page.captureWidth = canvasWidth;

+    var docWidth = document.body.scrollWidth;

+    var docHeight = document.body.scrollHeight;

+    window.scrollTo(startX, startY);

+

+    this.handleFixedElements('top_left');

+    this.handleSecondToLastCapture();

+

+    if (page.isGMailPage() && type == 'captureWhole') {

+      var frame = document.getElementById('canvas_frame');

+      docHeight = page.captureHeight = canvasHeight =

+          frame.contentDocument.height;

+      docWidth = page.captureWidth = canvasWidth = frame.contentDocument.width;

+      frame.contentDocument.body.scrollTop = 0;

+      frame.contentDocument.body.scrollLeft = 0;

+      page.handleRightFloatBoxInGmail();

+    }

+    page.scrollXCount = 0;

+    page.scrollYCount = 1;

+    page.scrollX = window.scrollX; // document.body.scrollLeft

+    page.scrollY = window.scrollY;

+    var viewPortSize = page.getViewPortSize();

+    return {

+      'msg': 'scroll_init_done',

+      'startX': page.calculateSizeAfterZooming(startX),

+      'startY': page.calculateSizeAfterZooming(startY),

+      'scrollX': window.scrollX,

+      'scrollY': window.scrollY,

+      'docHeight': docHeight,

+      'docWidth': docWidth,

+      'visibleWidth': viewPortSize.width,

+      'visibleHeight': viewPortSize.height,

+      'canvasWidth': canvasWidth,

+      'canvasHeight': canvasHeight,

+      'scrollXCount': 0,

+      'scrollYCount': 0,

+      'zoom': page.getZoomLevel()

+    };

+  },

+

+  /**

+  * Calculate the next position of the scrollbar

+  */

+  scrollNext: function() {

+    if (page.scrollYCount * page.visibleWidth >= page.captureWidth) {

+      page.scrollXCount++;

+      page.scrollYCount = 0;

+    }

+    if (page.scrollXCount * page.visibleHeight < page.captureHeight) {

+      this.restoreBottomRightOfFixedPositionElements();

+      var viewPortSize = page.getViewPortSize();

+      window.scrollTo(

+          page.scrollYCount * viewPortSize.width + page.scrollX,

+          page.scrollXCount * viewPortSize.height + page.scrollY);

+

+      var pagePosition = this.detectPagePosition();

+      if (pagePosition) {

+        this.handleFixedElements(pagePosition);

+      } else {

+        this.hideAllFixedPositionedElements();

+      }

+      this.handleSecondToLastCapture();

+

+      if (page.isGMailPage()) {

+        var frame = document.getElementById('canvas_frame');

+        frame.contentDocument.body.scrollLeft =

+            page.scrollYCount * viewPortSize.width;

+        frame.contentDocument.body.scrollTop =

+            page.scrollXCount * viewPortSize.height;

+        page.handleRightFloatBoxInGmail();

+      }

+      var x = page.scrollXCount;

+      var y = page.scrollYCount;

+      page.scrollYCount++;

+      return { msg: 'scroll_next_done',scrollXCount: x, scrollYCount: y };

+    }  else {

+      window.scrollTo(page.startX, page.startY);

+      this.restoreFixedElements();

+      this.hookBodyScrollValue(false);

+      return {'msg': 'scroll_finished'};

+    }

+  },

+

+  /**

+  * Show the selection Area

+  */

+  showSelectionArea: function() {

+    page.createFloatLayer();

+    setTimeout(page.createSelectionArea, 100);

+  },

+

+  getWindowSize: function() {

+    var docWidth = document.body.clientWidth;

+    var docHeight = document.body.clientHeight;

+    if (page.isGMailPage()) {

+      var frame = document.getElementById('canvas_frame');

+      docHeight = frame.contentDocument.height;

+      docWidth = frame.contentDocument.width;

+    }

+    return {'msg':'capture_window',

+            'docWidth': docWidth,

+            'docHeight': docHeight};

+  },

+

+  getSelectionSize: function() {

+    page.removeSelectionArea();

+    setTimeout(function() {

+      page.sendMessage({

+        'msg': 'capture_selected',

+        'x': page.startX,

+        'y': page.startY,

+        'width': page.endX - page.startX,

+        'height': page.endY - page.startY,

+        'visibleWidth': document.documentElement.clientWidth,

+        'visibleHeight': document.documentElement.clientHeight,

+        'docWidth': document.body.clientWidth,

+        'docHeight': document.body.clientHeight

+      })}, 100);

+  },

+

+  /**

+  * Create a float layer on the webpage

+  */

+  createFloatLayer: function() {

+    page.createDiv(document.body, 'sc_drag_area_protector');

+  },

+  

+  matchMarginValue: function(str) {

+    return str.match(/\d+/);

+  },

+

+  /**

+  * Load the screenshot area interface

+  */

+  createSelectionArea: function() {

+    var areaProtector = $('sc_drag_area_protector');

+    var zoom = page.getZoomLevel();

+    var bodyStyle = window.getComputedStyle(document.body, null);

+    if ('relative' == bodyStyle['position']) {

+      page.marginTop = page.matchMarginValue(bodyStyle['marginTop']);

+      page.marginLeft = page.matchMarginValue(bodyStyle['marginLeft']);

+      areaProtector.style.top =  - parseInt(page.marginTop) + 'px';

+      areaProtector.style.left =  - parseInt(page.marginLeft) + 'px';

+    }

+    areaProtector.style.width =

+      Math.round((document.body.clientWidth + parseInt(page.marginLeft)) / zoom) + 'px';

+    areaProtector.style.height =

+      Math.round((document.body.clientHeight + parseInt(page.marginTop)) / zoom) + 'px';

+    areaProtector.onclick = function() {

+      event.stopPropagation();

+      return false;

+    };

+

+    // Create elements for area capture.

+    page.createDiv(areaProtector, 'sc_drag_shadow_top');

+    page.createDiv(areaProtector, 'sc_drag_shadow_bottom');

+    page.createDiv(areaProtector, 'sc_drag_shadow_left');

+    page.createDiv(areaProtector, 'sc_drag_shadow_right');

+

+    var areaElement = page.createDiv(areaProtector, 'sc_drag_area');

+    page.createDiv(areaElement, 'sc_drag_container');

+    page.createDiv(areaElement, 'sc_drag_size');

+

+    // Add event listener for 'cancel' and 'capture' button.

+    var cancel = page.createDiv(areaElement, 'sc_drag_cancel');

+    cancel.addEventListener('mousedown', function () {

+      // Remove area capture containers and event listeners.

+      page.removeSelectionArea();

+    }, true);

+    cancel.innerHTML = chrome.i18n.getMessage("cancel");

+

+    var crop = page.createDiv(areaElement, 'sc_drag_crop');

+    crop.addEventListener('mousedown', function() {

+      page.removeSelectionArea();

+      page.sendMessage({msg: 'capture_selected'});

+    }, false);

+    crop.innerHTML = chrome.i18n.getMessage('ok');

+

+    page.createDiv(areaElement, 'sc_drag_north_west');

+    page.createDiv(areaElement, 'sc_drag_north_east');

+    page.createDiv(areaElement, 'sc_drag_south_east');

+    page.createDiv(areaElement, 'sc_drag_south_west');

+

+    areaProtector.addEventListener('mousedown', page.onMouseDown, false);

+    document.addEventListener('mousemove', page.onMouseMove, false);

+    document.addEventListener('mouseup', page.onMouseUp, false);

+    $('sc_drag_container').addEventListener('dblclick', function() {

+      page.removeSelectionArea();

+      page.sendMessage({msg: 'capture_selected'});

+    }, false);

+

+    page.pageHeight = $('sc_drag_area_protector').clientHeight;

+    page.pageWidth = $('sc_drag_area_protector').clientWidth;

+

+    var areaElement = $('sc_drag_area');

+    areaElement.style.left = page.getElementLeft(areaElement) + 'px';

+    areaElement.style.top = page.getElementTop(areaElement) + 'px';

+    

+    page.startX = page.getElementLeft(areaElement);

+    page.startY = page.getElementTop(areaElement); 

+    page.endX = page.getElementLeft(areaElement) + 250;

+    page.endY = page.getElementTop(areaElement) + 150;

+    

+    areaElement.style.width = '250px';

+    areaElement.style.height = '150px';

+    page.isSelectionAreaTurnOn = true;

+    page.updateShadow(areaElement);

+    page.updateSize();

+  },

+  

+  getElementLeft: function(obj) {

+    return (document.body.scrollLeft +

+        (document.documentElement.clientWidth - 

+        obj.offsetWidth) / 2);

+  },

+  

+  getElementTop: function(obj) {

+    return (document.body.scrollTop + 

+        (document.documentElement.clientHeight - 200 - 

+        obj.offsetHeight) / 2);

+  },

+

+  /**

+  * Init selection area due to the position of the mouse when mouse down

+  */

+  onMouseDown: function() {

+    if (event.button != 2) {

+      var element = event.target;

+

+      if (element) {

+        var elementName = element.tagName;

+        if (elementName && document) {

+          page.isMouseDown = true;

+

+          var areaElement = $('sc_drag_area');

+          var xPosition = event.pageX;

+          var yPosition = event.pageY;

+

+          if (areaElement) {

+            if (element == $('sc_drag_container')) {

+              page.moving = true;

+              page.moveX = xPosition - areaElement.offsetLeft;

+              page.moveY = yPosition - areaElement.offsetTop;

+            } else if (element == $('sc_drag_north_east')) {

+              page.resizing = true;

+              page.startX = areaElement.offsetLeft;

+              page.startY = areaElement.offsetTop + areaElement.clientHeight;

+            } else if (element == $('sc_drag_north_west')) {

+              page.resizing = true;

+              page.startX = areaElement.offsetLeft + areaElement.clientWidth;

+              page.startY = areaElement.offsetTop + areaElement.clientHeight;

+            } else if (element == $('sc_drag_south_east')) {

+              page.resizing = true;

+              page.startX = areaElement.offsetLeft;

+              page.startY = areaElement.offsetTop;

+            } else if (element == $('sc_drag_south_west')) {

+              page.resizing = true;

+              page.startX = areaElement.offsetLeft + areaElement.clientWidth;

+              page.startY = areaElement.offsetTop;

+            } else {

+              page.dragging = true;

+              page.endX = 0;

+              page.endY = 0;

+              page.endX = page.startX = xPosition;

+              page.endY = page.startY = yPosition;

+            }

+          }

+          event.preventDefault();

+        }

+      }

+    }

+  },

+

+  /**

+  * Change selection area position when mouse moved

+  */

+  onMouseMove: function() {

+    var element = event.target;

+    if (element && page.isMouseDown) {

+      var areaElement = $('sc_drag_area');

+      if (areaElement) {

+        var xPosition = event.pageX;

+        var yPosition = event.pageY;

+        if (page.dragging || page.resizing) {

+          var width = 0;

+          var height = 0;

+          var zoom = page.getZoomLevel();

+          var viewWidth = Math.round(document.body.clientWidth / zoom);

+          var viewHeight = Math.round(document.body.clientHeight / zoom);

+          if (xPosition > viewWidth) {

+            xPosition = viewWidth;

+          } else if (xPosition < 0) {

+            xPosition = 0;

+          }

+          if (yPosition > viewHeight) {

+            yPosition = viewHeight;

+          } else if (yPosition < 0) {

+            yPosition = 0;

+          }

+          page.endX = xPosition;

+          page.endY = yPosition;

+          if (page.startX > page.endX) {

+            width = page.startX - page.endX;

+            areaElement.style.left = xPosition + 'px';

+          } else {

+            width = page.endX - page.startX;

+            areaElement.style.left = page.startX + 'px';

+          }

+          if (page.startY > page.endY) {

+            height = page.startY - page.endY;

+            areaElement.style.top = page.endY + 'px';

+          } else {

+            height = page.endY - page.startY;

+            areaElement.style.top = page.startY + 'px';

+          }

+          areaElement.style.height = height + 'px';

+          areaElement.style.width  = width + 'px';

+          if (window.innerWidth < xPosition) {

+            document.body.scrollLeft = xPosition - window.innerWidth;

+          }

+          if (document.body.scrollTop + window.innerHeight < yPosition + 25) {

+            document.body.scrollTop = yPosition - window.innerHeight + 25;

+          }

+          if (yPosition < document.body.scrollTop) {

+            document.body.scrollTop -= 25;

+          }

+        } else if (page.moving) {

+          var newXPosition = xPosition - page.moveX;

+          var newYPosition = yPosition - page.moveY;

+          if (newXPosition < 0) {

+            newXPosition = 0;

+          } else if (newXPosition + areaElement.clientWidth > page.pageWidth) {

+            newXPosition = page.pageWidth - areaElement.clientWidth;

+          }

+          if (newYPosition < 0) {

+            newYPosition = 0;

+          } else if (newYPosition + areaElement.clientHeight >

+                     page.pageHeight) {

+            newYPosition = page.pageHeight - areaElement.clientHeight;

+          }

+

+          areaElement.style.left = newXPosition + 'px';

+          areaElement.style.top = newYPosition + 'px';

+          page.endX = newXPosition + areaElement.clientWidth;

+          page.startX = newXPosition;

+          page.endY = newYPosition + areaElement.clientHeight;

+          page.startY = newYPosition;

+

+        }

+        var crop = document.getElementById('sc_drag_crop');

+        var cancel = document.getElementById('sc_drag_cancel');

+        if (event.pageY + 25 > document.body.clientHeight) {

+          crop.style.bottom = 0;

+          cancel.style.bottom = 0

+        } else {

+          crop.style.bottom = '-25px';

+          cancel.style.bottom = '-25px';

+        }

+

+        var dragSizeContainer = document.getElementById('sc_drag_size');

+        if (event.pageY < 18) {

+          dragSizeContainer.style.top = 0;

+        } else {

+          dragSizeContainer.style.top = '-18px';

+        }

+        page.updateShadow(areaElement);

+        page.updateSize();

+

+      }

+    }

+  },

+

+ /**

+  * Fix the selection area position when mouse up

+  */

+  onMouseUp: function() {

+    page.isMouseDown = false;

+    if (event.button != 2) {

+      page.resizing = false;

+      page.dragging = false;

+      page.moving = false;

+      page.moveX = 0;

+      page.moveY = 0;

+      var temp;

+      if (page.endX < page.startX) {

+        temp = page.endX;

+        page.endX = page.startX;

+        page.startX = temp;

+      }

+      if (page.endY < page.startY) {

+        temp = page.endY;

+        page.endY = page.startY;

+        page.startY = temp;

+      }

+    }

+  },

+

+  /**

+  * Update the location of the shadow layer

+  */

+  updateShadow: function(areaElement) {

+    $('sc_drag_shadow_top').style.height =

+        parseInt(areaElement.style.top) + 'px';

+    $('sc_drag_shadow_top').style.width = (parseInt(areaElement.style.left) +

+        parseInt(areaElement.style.width) + 1) + 'px';

+    $('sc_drag_shadow_left').style.height =

+        (page.pageHeight - parseInt(areaElement.style.top)) + 'px';

+    $('sc_drag_shadow_left').style.width =

+        parseInt(areaElement.style.left) + 'px';

+

+    var height = (parseInt(areaElement.style.top) +

+        parseInt(areaElement.style.height) + 1);

+    height = (height < 0) ? 0 : height;

+    var width = (page.pageWidth) - 1 - (parseInt(areaElement.style.left) +

+        parseInt(areaElement.style.width));

+    width = (width < 0) ? 0 : width;

+    $('sc_drag_shadow_right').style.height = height + 'px';

+    $('sc_drag_shadow_right').style.width =  width + 'px';

+

+    height = (page.pageHeight - 1 - (parseInt(areaElement.style.top) +

+        parseInt(areaElement.style.height)));

+    height = (height < 0) ? 0 : height;

+    width = (page.pageWidth) - parseInt(areaElement.style.left);

+    width = (width < 0) ? 0 : width;

+    $('sc_drag_shadow_bottom').style.height = height + 'px';

+    $('sc_drag_shadow_bottom').style.width = width + 'px';

+  },

+

+  /**

+  * Remove selection area

+  */

+  removeSelectionArea: function() {

+    document.removeEventListener('mousedown', page.onMouseDown, false);

+    document.removeEventListener('mousemove', page.onMouseMove, false);

+    document.removeEventListener('mouseup', page.onMouseUp, false);

+    $('sc_drag_container').removeEventListener('dblclick',function() {

+      page.removeSelectionArea();

+      page.sendMessage({msg: 'capture_selected'});}, false);

+    page.removeElement('sc_drag_area_protector');

+    page.removeElement('sc_drag_area');

+    page.isSelectionAreaTurnOn = false;

+  },

+

+  /**

+  * Refresh the size info

+  */

+  updateSize: function() {

+    var width = Math.abs(page.endX - page.startX);

+    var height = Math.abs(page.endY - page.startY);

+    $('sc_drag_size').innerText = page.calculateSizeAfterZooming(width) +

+      ' x ' + page.calculateSizeAfterZooming(height);

+  },

+

+  /**

+  * create div

+  */

+  createDiv: function(parent, id) {

+    var divElement = document.createElement('div');

+    divElement.id = id;

+    parent.appendChild(divElement);

+    return divElement;

+  },

+

+  /**

+  * Remove an element

+  */

+  removeElement: function(id) {

+    if($(id)) {

+      $(id).parentNode.removeChild($(id));

+    }

+  },

+

+  injectCssResource: function(cssResource) {

+    var css = document.createElement('LINK');

+    css.type = 'text/css';

+    css.rel = 'stylesheet';

+    css.href = chrome.extension.getURL(cssResource);

+    (document.head || document.body || document.documentElement).

+        appendChild(css);

+  },

+

+  injectJavaScriptResource: function(scriptResource) {

+    var script = document.createElement("script");

+    script.type = "text/javascript";

+    script.charset = "utf-8";

+    script.src = chrome.extension.getURL(scriptResource);

+    (document.head || document.body || document.documentElement).

+        appendChild(script);

+  },

+

+  /**

+  * Remove an element

+  */

+  init: function() { 

+    if (document.body.hasAttribute('screen_capture_injected')) {

+      return;

+    }

+    if (isPageCapturable()) {

+      chrome.extension.sendMessage({msg: 'page_capturable'});

+    } else {

+      chrome.extension.sendMessage({msg: 'page_uncapturable'});

+    }

+    this.injectCssResource('style.css');

+    this.addMessageListener();

+    this.injectJavaScriptResource("js/page_context.js");

+

+    // Retrieve original width of view port and cache.

+    page.getOriginalViewPortWidth();

+  }

+};

+

+/**

+ * Indicate if the current page can be captured.

+ */

+var isPageCapturable = function() {

+  return !page.checkPageIsOnlyEmbedElement();

+};

+

+function $(id) {

+  return document.getElementById(id);

+}

+

+page.init();

+

+window.addEventListener('resize', function() {

+  if (page.isSelectionAreaTurnOn) {

+    page.removeSelectionArea();

+    page.showSelectionArea();

+  }

+

+  // Reget original width of view port if browser window resized or page zoomed.

+  page.getOriginalViewPortWidth();

+}, false);

+

+// Send page url for retriving and parsing access token for facebook and picasa.

+var message = {

+  msg: 'url_for_access_token',

+  url: window.location.href

+}

+if (window.location.href.indexOf('https://api.weibo.com/oauth2/default.html') == 0) {

+  message.siteId = 'sina'

+}

+page.sendMessage(message);