You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by dd...@apache.org on 2011/12/16 01:43:19 UTC

svn commit: r1215011 - in /shindig/trunk: content/samplecontainer/examples/embeddedexperiences/ features/src/main/javascript/features/open-views/ features/src/test/javascript/features/open-views/

Author: ddumont
Date: Fri Dec 16 00:43:19 2011
New Revision: 1215011

URL: http://svn.apache.org/viewvc?rev=1215011&view=rev
Log:
SHINDIG-1671: Update Open View APIs To Support Opening Of Views At Specific Locations

Modified:
    shindig/trunk/content/samplecontainer/examples/embeddedexperiences/EEContainer.js
    shindig/trunk/content/samplecontainer/examples/embeddedexperiences/PhotoList.xml
    shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements-container.js
    shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements.js
    shindig/trunk/features/src/test/javascript/features/open-views/viewEnhancements-test.js

Modified: shindig/trunk/content/samplecontainer/examples/embeddedexperiences/EEContainer.js
URL: http://svn.apache.org/viewvc/shindig/trunk/content/samplecontainer/examples/embeddedexperiences/EEContainer.js?rev=1215011&r1=1215010&r2=1215011&view=diff
==============================================================================
--- shindig/trunk/content/samplecontainer/examples/embeddedexperiences/EEContainer.js (original)
+++ shindig/trunk/content/samplecontainer/examples/embeddedexperiences/EEContainer.js Fri Dec 16 00:43:19 2011
@@ -29,13 +29,30 @@ $(document).ready(function() {
 var CommonContainer = new osapi.container.Container({});
 CommonContainer.init = new function() {
 
-	CommonContainer.views.createElementForEmbeddedExperience = function(opt_viewTarget) {
-	  return document.getElementById('preview');
-	};
-
-	CommonContainer.views.destroyElement = function(site) {
-	  CommonContainer.ee.close(site);
-	};
+  CommonContainer.views.createElementForEmbeddedExperience = function(opt_viewTarget, opt_coordinates, opt_rel) {
+    if(opt_viewTarget == 'FLOAT' && opt_coordinates && opt_rel) {
+      var offset = $(opt_rel).offset();
+
+      $('#preview').css({
+        top: (offset.top + opt_coordinates.top) +'px',
+        left: (offset.left + opt_coordinates.left) + 'px',
+        position: 'absolute'
+      });
+    }
+    else {
+      $('#preview').css({
+        top: 'auto',
+        left: 'auto',
+        position: 'static'
+      });
+    }
+
+    return $('#preview').get(0);
+  };
+
+  CommonContainer.views.destroyElement = function(site) {
+    CommonContainer.ee.close(site);
+  };
 }
 
 /**
@@ -44,16 +61,16 @@ CommonContainer.init = new function() {
  * @return void.
  */
 function renderAS(stream) {
-	jQuery.each(stream.list, createAccordianEntry);
-	$('#accordion').accordion({
-		clearStyle: true,
-		active: false,
-		change: function(event, ui) {
-			closeCurrentGadget();
-			onAccordionChange(stream, event, ui);
-		}
+  jQuery.each(stream.list, createAccordianEntry);
+  $('#accordion').accordion({
+    clearStyle: true,
+    active: false,
+    change: function(event, ui) {
+      closeCurrentGadget();
+      onAccordionChange(stream, event, ui);
+    }
 
-	});
+  });
 }
 
 /**
@@ -61,17 +78,17 @@ function renderAS(stream) {
  */
 var currentEESite;
 function closeCurrentGadget() {
-	if (currentEESite)
-		CommonContainer.ee.close(currentEESite);
+  if (currentEESite)
+    CommonContainer.ee.close(currentEESite);
 
-	var preview = document.getElementById('preview');
-	var previewChildren = preview.childNodes;
-	if (previewChildren.length > 0) {
-	  var iframe = previewChildren[0];
-	  var iframeId = iframe.getAttribute('id');
-	  var site = CommonContainer.getGadgetSiteByIframeId_(iframeId);
-	  CommonContainer.ee.close(site);
-	}
+  var preview = $('#preview').get(0);
+  var previewChildren = preview.childNodes;
+  if (previewChildren.length > 0) {
+    var iframe = previewChildren[0];
+    var iframeId = iframe.getAttribute('id');
+    var site = CommonContainer.getGadgetSiteByIframeId_(iframeId);
+    CommonContainer.ee.close(site);
+  }
 }
 
 /**
@@ -83,25 +100,27 @@ function closeCurrentGadget() {
  */
 
 function onAccordionChange(stream, event, ui) {
-	var id = ui.newHeader.context.id;
-	var localStream = stream;
-	var entry = localStream.list[id];
-	var extensions = entry.openSocial;
-	if (extensions) {
-		var embed = extensions.embed;
-		if (embed) {
-			var eeElement = document.getElementById('ee' + id);
-			var urlRenderingParams = {
-					'height' : 400,
-					'width' : 650
-			};
-			currentEESite = CommonContainer.ee.navigate(eeElement, embed,
-					{'urlRenderParams' : urlRenderingParams}, function(site, metaData) {
-					  console.log('Embedded Experiences callback called');
-					  console.log(gadgets.json.stringify(metaData));
-					});
-		}
-	}
+  var id = ui.newHeader.context.id;
+  var localStream = stream;
+  var entry = localStream.list[id];
+  var extensions = entry.openSocial;
+  if (extensions) {
+    var embed = extensions.embed;
+    if (embed) {
+      var eeElement = $('#ee' + id).get(0);
+      var urlRenderingParams = {
+          'height' : 400,
+          'width' : 650
+      };
+      CommonContainer.ee.navigate(eeElement, embed,
+        {'urlRenderParams' : urlRenderingParams}, function(site, metaData) {
+          console.log('Embedded Experiences callback called');
+          console.log(gadgets.json.stringify(metaData));
+          currentEESite = site;
+        }
+      );
+    }
+  }
 
 
 }
@@ -113,10 +132,10 @@ function onAccordionChange(stream, event
  * @return void.
  */
 function createAccordianEntry(i, entry) {
-	var result = '<h3 id=' + i + '><a href="#">' + entry.title + '</a></h3><div>';
-	if (entry.body)
-		result = result + '<p>' + entry.body + '</p>';
-	result = result + '<div id="ee' + i + '"></div></div>';
+  var result = '<h3 id=' + i + '><a href="#">' + entry.title + '</a></h3><div>';
+  if (entry.body)
+    result = result + '<p>' + entry.body + '</p>';
+  result = result + '<div id="ee' + i + '"></div></div>';
 
-	$('#accordion').append(result);
+  $('#accordion').append(result);
 }

Modified: shindig/trunk/content/samplecontainer/examples/embeddedexperiences/PhotoList.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/content/samplecontainer/examples/embeddedexperiences/PhotoList.xml?rev=1215011&r1=1215010&r2=1215011&view=diff
==============================================================================
--- shindig/trunk/content/samplecontainer/examples/embeddedexperiences/PhotoList.xml (original)
+++ shindig/trunk/content/samplecontainer/examples/embeddedexperiences/PhotoList.xml Fri Dec 16 00:43:19 2011
@@ -50,7 +50,7 @@
         }
      </style>
 
-
+	 <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
      <script type="text/javascript">
 
          var currentSite;
@@ -67,10 +67,10 @@
              var result = "";
              for(var i = 0; i < photos.length; i++){
                  count = i+1;
-                 result = result + '<li style="text-decoration: underline; color: blue; cursor: pointer" onclick="showPreviewPhoto(\''+i+'\',\''+context.eeGadget+'\')">Photo '+count+'</li></br>';
+                 result = result + '<li id="photo' + i + '" style="text-decoration: underline; color: blue; cursor: pointer; display:inline-block" onclick="showPreviewPhoto(\''+i+'\',\''+context.eeGadget+'\')">Photo '+count+'</li></br>';
              }
-             document.getElementById('header').innerHTML = context.albumName;
-             document.getElementById("album").innerHTML = result;
+             $('#header').html(context.albumName);
+             $('#album').html(result);
          };
 
          gadgets.util.registerOnLoadHandler(initAlbum);
@@ -95,9 +95,16 @@
                 }
               };
             }
+
+            var coordinates = $('#photo' + index).offset();
+            coordinates.left = coordinates.left + $('#photo' + index).width();
+
             var navigateCallback = function(site, result){currentSite = site; console.log("Nagivate callback");};
             var returnCallback = function(returnValue){console.log("Return Value: " + returnValue);};
-            gadgets.views.openEmbeddedExperience(returnCallback, navigateCallback, eeDataModel, {'viewTarget' : 'preview'});
+            gadgets.views.openEmbeddedExperience(returnCallback, navigateCallback, eeDataModel, {
+              'viewTarget' : index == 0 ? 'preview' : 'FLOAT',
+              'coordinates' : coordinates
+            });
          };
 
          function closePreview(){

Modified: shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements-container.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements-container.js?rev=1215011&r1=1215010&r2=1215011&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements-container.js (original)
+++ shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements-container.js Fri Dec 16 00:43:19 2011
@@ -62,13 +62,26 @@
    *          parameter.
    * @param {Object.<string, string|Object>=}
    *          opt_params: These are optional parameters which can be used to
-   *          open gadgets. The following parameters may be included in this
-   *          object. {string} view: The view to render. Should be one of the
-   *          views returned by calling gadgets.views.getSupportedViews. If the
-   *          view is not included the default view will be rendered. {string}
-   *          viewTarget: The view that indicates where to open the gadget. For
-   *          example, tab, dialog or modaldialog {Object} viewParams: View
-   *          parameters for the view being rendered.
+   *            open gadgets. The following parameters may be included in this
+   *            object.
+   *            {string} view: The view to render. Should be one of the
+   *              views returned by calling gadgets.views.getSupportedViews. If
+   *              the view is not included the default view will be rendered.
+   *            {string} viewTarget: The view that indicates where to open the
+   *              gadget. For example, tab, dialog or modaldialog
+   *            {Object} viewParams: View parameters for the view being
+   *              rendered.
+   *            {Object} coordinates: Object containing the desired absolute
+   *              positioning css parameters (top|bottom|left|right) with
+   *              appropriate values. All values are relative to the calling
+   *              gadget.
+   *              Do not specify top AND bottom or left AND right parameters to
+   *              indirectly define height and width, use viewParams for that.
+   *              The result of doing so here is undefined.
+   *              It is expected that coordinates will only be used with
+   *              viewTargets of FLOAT. Containers may implement the behavior
+   *              for other viewTargets, and custom viewTargets at their
+   *              discretion.
    */
   function openGadget(resultCallback, opt_params) {
 
@@ -83,16 +96,23 @@
       gadgetUrl = orig_site.getActiveGadgetHolder().getUrl();
     }
 
-    var view = '';
-    var viewTarget = '';
-    var viewParams = {};
-    if (opt_params !== undefined) {
-      if (opt_params.view !== undefined)
+    var view = '',
+        viewTarget = '',
+        viewParams = {},
+        coordinates,
+        rel;
+    if (opt_params) {
+      if (opt_params.view)
         view = opt_params.view;
-      if (opt_params.viewTarget !== undefined)
+      if (opt_params.viewTarget)
         viewTarget = opt_params.viewTarget;
-      if (opt_params.viewParams !== undefined)
+      if (opt_params.viewParams)
         viewParams = opt_params.viewParams;
+      if(opt_params.coordinates) {
+        coordinates = opt_params.coordinates;
+        rel = context.getGadgetSiteByIframeId_(this.f).getActiveGadgetHolder()
+          .getIframeElement();
+      }
     }
     context.preloadGadget(gadgetUrl, function(result) {
       /*
@@ -112,9 +132,12 @@
       }
 
       var renderParams = {},
-      site = context.newGadgetSite(
-              context.views.createElementForGadget(metadata, view, viewTarget)
-      );
+           site = context.newGadgetSite(
+	     context.views.createElementForGadget(
+               metadata, view, viewTarget, coordinates, rel
+             )
+           );
+
       site.ownerId_ = siteOwnerId;
 
       if (view !== undefined && view !== '') {
@@ -148,27 +171,48 @@
    *          dataModel: The embedded experiences data model.
    * @param {Object}
    *          opt_params: These are optional parameters which can be used to
-   *          open gadgets. The following parameters may be included in this
-   *          object. {string} viewTarget: The view that indicates where to open
-   *          the gadget. For example, tab, dialog or modaldialog {Object}
-   *          viewParams: View parameters for the view being rendered.
+   *            open gadgets. The following parameters may be included in this
+   *            object.
+   *            {string} viewTarget: The view that indicates where to open
+   *              the gadget. For example, tab, dialog or modaldialog
+   *            {Object} viewParams: View parameters for the view being
+   *              rendered.
+   *            {Object} coordinates: Object containing the desired absolute
+   *              positioning css parameters (top|bottom|left|right) with
+   *              appropriate values.  All values are relative to the calling
+   *              gadget.
+   *              Do not specify top AND bottom or left AND right parameters to
+   *              indirectly define height and width. Use viewParams for that.
+   *              The result of doing so here is undefined.
+   *              It is expected that coordinates will only be used with
+   *              viewTargets of FLOAT. Containers may implement the behavior
+   *              for other viewTargets, and custom viewTargets at their
+   *              discretion.
    */
   function openEE(resultCallback, dataModel, opt_params) {
     var navigateCallback = this.callback,
         siteOwnerId = this.f,
         gadgetUrl = dataModel.gadget;
     var navigateEE = function() {
-      var viewTarget = '';
-      var viewParams = {};
-      if (opt_params != undefined) {
-        if (opt_params.viewTarget != undefined)
-          viewTarget = opt_params.viewTarget;
-        if (opt_params.viewParams != undefined)
+      var viewTarget = '',
+          viewParams = {},
+          coordinates,
+          rel;
+      if (opt_params) {
+        if (opt_params.viewTarget)
+	        viewTarget = opt_params.viewTarget;
+        if (opt_params.viewParams)
           viewParams = opt_params.viewParams;
+        if (opt_params.coordinates) {
+          coordinates = opt_params.coordinates;
+          rel = context.getGadgetSiteByIframeId_(siteOwnerId).getActiveGadgetHolder()
+            .getIframeElement();
+        }
       }
 
       var element = context.views.createElementForEmbeddedExperience(
-          viewTarget);
+        viewTarget, coordinates, rel
+      );
 
       var gadgetRenderParams = {};
       gadgetRenderParams[osapi.container.RenderParam.VIEW] =
@@ -231,12 +275,29 @@
    *          url: URL to a web page to open in a URL site in the container.
    *          (Note this should not be a URL to a gadget definition.).
    * @param {string=}
-   *          opt_viewTarget: Optional parameter,the view that indicates where
+   *          opt_viewTarget: Optional parameter, the view that indicates where
    *          to open the URL.
+   * @param {Object=} opt_coordinates: Object containing the desired absolute
+   *          positioning css parameters (top|bottom|left|right) with
+   *          appropriate values.  All values are relative to the calling
+   *          gadget.
+   *          You may specify top AND bottom or left AND right parameters to
+   *          indirectly define height and width.
+   *          It is expected that coordinates will only be used with
+   *          viewTargets of FLOAT. Containers may implement the behavior
+   *          for other viewTargets, and custom viewTargets at their
+   *          discretion.
    * @returns {string} The ID of the site created, if a callback was registered.
    */
-  function openUrl(url, opt_viewTarget) {
-    var content_div = context.views.createElementForUrl(opt_viewTarget);
+  function openUrl(url, opt_viewTarget, opt_coordinates) {
+    var rel;
+    if (opt_coordinates) {
+      rel = context.getGadgetSiteByIframeId_(this.f).getActiveGadgetHolder()
+        .getIframeElement();
+    }
+    var content_div = context.views.createElementForUrl(
+      opt_viewTarget, opt_coordinates, rel
+    );
 
     var site = context.newUrlSite(content_div);
 
@@ -337,9 +398,18 @@
        * @param {string=}
        *          opt_viewTarget: Optional parameter, the view target indicates
        *          where to open the gadget.
+       * @param {Object=}
+       *          opt_coordinates: Object containing the desired absolute
+       *          positioning css parameters (top|bottom|left|right) with
+       *          appropriate values. All values are relative to the calling
+       *          gadget.
+       * @param {Element=}
+       *          opt_rel: The element to which opt_coordinates values are
+       *          relative.
        * @return {Object} The DOM element to place the GadgetSite in.
        */
-      'createElementForGadget' : function(metadata, opt_view, opt_viewTarget) {
+      'createElementForGadget' : function(metadata, opt_view, opt_viewTarget,
+          opt_coordinates, opt_rel) {
         console.log('container need to define createElementForGadget function');
       },
 
@@ -350,12 +420,22 @@
        * @param {string=}
        *          opt_viewTarget:  Optional parameter, the view target indicates
        *          where to open.
+       *
+       * @param {Object=}
+       *          opt_coordinates: Object containing the desired absolute
+       *          positioning css parameters (top|bottom|left|right) with
+       *          appropriate values. All values are relative to the calling
+       *          gadget.
+       * @param {Element=}
+       *          opt_rel: The element to which opt_coordinates values are
+       *          relative.
        * @return {Object} The DOM element to place the embedded experience in.
        */
 
-      'createElementForEmbeddedExperience' : function(opt_viewTarget) {
+      'createElementForEmbeddedExperience' : function(opt_viewTarget,
+          opt_coordinates, opt_rel) {
         console.log('container need to define ' +
-                'createElementForEmbeddedExperience function');
+            'createElementForEmbeddedExperience function');
       },
 
       /**
@@ -365,10 +445,19 @@
        * @param {string=}
        *          opt_view: Optional parameter, the view to open. If not
        *          included the container should use its default view.
+       * @param {Object=}
+       *          opt_coordinates: Object containing the desired absolute
+       *          positioning css parameters (top|bottom|left|right) with
+       *          appropriate values. All values are relative to the calling
+       *          gadget.
+       * @param {Element=}
+       *          opt_rel: The element to which opt_coordinates values are
+       *          relative.
        * @return {Object} The DOM element to place the UrlSite object in.
        */
 
-      'createElementForUrl' : function(opt_viewTarget) {
+      'createElementForUrl' : function(opt_viewTarget, opt_coordinates,
+          opt_rel) {
         console.log('container need to define createElementForUrl function');
       },
 

Modified: shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements.js?rev=1215011&r1=1215010&r2=1215011&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements.js (original)
+++ shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements.js Fri Dec 16 00:43:19 2011
@@ -53,12 +53,21 @@ gadgets['window'] = gadgets['window'] ||
    * @param {Object}
    *          opt_params: These are optional parameters which can be used to
    *          open gadgets. The following parameters may be included in this
-   *          object. {string} view: The view to render. Should be one of the
-   *          views returned by calling gadgets.views.getSupportedViews. If the
-   *          view is not included the default view will be rendered. {string}
-   *          viewTarget: The view that indicates where to open the gadget. For
-   *          example, tab, dialog or modaldialog {Object} viewParams: View
-   *          parameters for the view being rendered.
+   *          object.
+   *            {string} view: The view to render. Should be one of the views
+   *              returned by calling gadgets.views.getSupportedViews. If the
+   *              view is not included the default view will be rendered.
+   *            {string} viewTarget: The view that indicates where to open the
+   *              gadget. For example, tab, dialog or modaldialog
+   *            {Object} viewParams: View parameters for the view being
+   *              rendered.
+   *            {Object} coordinates: Object containing the desired absolute
+   *              positioning css parameters (top|bottom|left|right) with
+   *              appropriate values. All values are relative to the calling
+   *              gadget.
+   *              Do not specify top AND bottom or left AND right parameters to
+   *              indirectly define height and width. Use viewParams for that.
+   *              The result of doing so here is undefined.
    */
 
   gadgets.views.openGadget = function(resultCallback, navigateCallback,
@@ -88,10 +97,19 @@ gadgets['window'] = gadgets['window'] ||
    *          dataModel: The embedded experiences data model.
    * @param {Object}
    *          opt_params: These are optional parameters which can be used to
-   *          open gadgets. The following parameters may be included in this
-   *          object. {string} viewTarget: The view that indicates where to open
-   *          the gadget. For example, tab, dialog or modaldialog {Object}
-   *          viewParams: View parameters for the view being rendered.
+   *            open gadgets. The following parameters may be included in this
+   *            object.
+   *            {string} viewTarget: The view that indicates where to open the
+   *              gadget. For example, tab, dialog or modaldialog
+   *            {Object} viewParams: View parameters for the view being
+   *              rendered.
+   *            {Object} coordinates: Object containing the desired absolute
+   *              positioning css parameters (top|bottom|left|right) with
+   *              appropriate values. All values are relative to the calling
+   *              gadget.
+   *              Do not specify top AND bottom or left AND right parameters to
+   *              indirectly define height and width. Use viewParams for that.
+   *              The result of doing so here is undefined.
    */
   gadgets.views.openEmbeddedExperience = function(resultCallback,
           navigateCallback, dataModel, opt_params) {
@@ -116,13 +134,19 @@ gadgets['window'] = gadgets['window'] ||
    *          navigateCallback: Callback function to be called with the
    *          site which has been opened.
    * @param {string=}
-   *          opt_viewTarget: Optional parameter,the view that indicates where
+   *          opt_viewTarget: Optional parameter, the view that indicates where
    *          to open the URL.
+   * @param {Object=} opt_coordinates: Object containing the desired absolute
+   *          positioning css parameters (top|bottom|left|right) with
+   *          appropriate values. All values are relative to the calling
+   *          gadget.
+   *          You may specify top AND bottom or left AND right parameters to
+   *          indirectly define height and width
    */
-  gadgets.views.openUrl = function(url, navigateCallback, opt_viewTarget) {
+   gadgets.views.openUrl = function(url, navigateCallback, opt_viewTarget, opt_coordinates) {
     gadgets.rpc.call('..', 'gadgets.views.openUrl', function(result) {
         navigateCallback.call(this, result);
-      }, url, opt_viewTarget
+      }, url, opt_viewTarget, opt_coordinates
     );
   }
 

Modified: shindig/trunk/features/src/test/javascript/features/open-views/viewEnhancements-test.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/test/javascript/features/open-views/viewEnhancements-test.js?rev=1215011&r1=1215010&r2=1215011&view=diff
==============================================================================
--- shindig/trunk/features/src/test/javascript/features/open-views/viewEnhancements-test.js (original)
+++ shindig/trunk/features/src/test/javascript/features/open-views/viewEnhancements-test.js Fri Dec 16 00:43:19 2011
@@ -44,7 +44,7 @@ ViewEnhancementsTest.inherits(TestCase);
   ViewEnhancementsTest.prototype.testOpenGadget = function() {
     var resultCallback = function() {};
     var navigateCallback = function() {};
-    var params = {};
+    var params = {coordinates: {top: 100, left: 100}};
 
     gadgets.views.openGadget(resultCallback, navigateCallback);
 
@@ -62,7 +62,7 @@ ViewEnhancementsTest.inherits(TestCase);
     var resultCallback = function() {};
     var navigateCallback = function() {};
     var dataModel = {'url': 'http://www.example.com'};
-    var params = {};
+    var params = {coordinates: {top: 100, left: 100}};
 
     gadgets.views.openEmbeddedExperience(resultCallback, navigateCallback,
         dataModel, params);
@@ -90,6 +90,10 @@ ViewEnhancementsTest.inherits(TestCase);
 
     gadgets.views.openUrl(url, navigateCallback, viewTarget);
     this.assertEquals(viewTarget, rpcs[0][4]);
+
+    var coordinates = {coordinates: {top: 100, left: 100}};
+    gadgets.views.openUrl(url, navigateCallback, viewTarget, coordinates);
+    this.assertEquals(coordinates, rpcs[0][5]);
   };
 
   ViewEnhancementsTest.prototype.testClose = function() {