Home | History | Annotate | Download | only in hello-php
      1 //  Copyright 2009 Google Inc.
      2 //
      3 //  Licensed under the Apache License, Version 2.0 (the "License");
      4 //  you may not use this file except in compliance with the License.
      5 //  You may obtain a copy of the License at
      6 //
      7 //      http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 //  Unless required by applicable law or agreed to in writing, software
     10 //  distributed under the License is distributed on an "AS IS" BASIS,
     11 //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 //  See the License for the specific language governing permissions and
     13 //  limitations under the License.
     14 
     15 
     16 //  PopupManager is a library to facilitate integration with OpenID
     17 //  identity providers (OP)s that support a pop-up authentication interface.
     18 //  To create a popup window, you first construct a popupOpener customized
     19 //  for your site and a particular identity provider, E.g.:
     20 //
     21 //  var googleOpener = popupManager.createOpener(openidParams);
     22 //
     23 //  where 'openidParams' are customized for Google in this instance.
     24 //  (typically you just change the openidpoint, the version number
     25 //  (the openid.ns parameter) and the extensions based on what
     26 //  the OP supports.
     27 //  OpenID libraries can often discover these properties
     28 //  automatically from the location of an XRD document.
     29 //
     30 //  Then, you can either directly call
     31 //  googleOpener.popup(width, height), where 'width' and 'height' are your choices
     32 //  for popup size, or you can display a button 'Sign in with Google' and set the
     33 //..'onclick' handler of the button to googleOpener.popup()
     34 
     35 var popupManager = {};
     36 
     37 // Library constants
     38 
     39 popupManager.constants = {
     40   'darkCover' : 'popupManager_darkCover_div',
     41   'darkCoverStyle' : ['position:absolute;',
     42                       'top:0px;',
     43                       'left:0px;',
     44                       'padding-right:0px;',
     45                       'padding-bottom:0px;',
     46                       'background-color:#000000;',
     47                       'opacity:0.5;', //standard-compliant browsers
     48                       '-moz-opacity:0.5;',           // old Mozilla
     49                       'filter:alpha(opacity=0.5);',  // IE
     50                       'z-index:10000;',
     51                       'width:100%;',
     52                       'height:100%;'
     53                       ].join(''),
     54   'openidSpec' : {
     55      'identifier_select' : 'http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select',
     56      'namespace2' : 'http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0'
     57   } };
     58 
     59 // Computes the size of the window contents. Returns a pair of
     60 // coordinates [width, height] which can be [0, 0] if it was not possible
     61 // to compute the values.
     62 popupManager.getWindowInnerSize = function() {
     63   var width = 0;
     64   var height = 0;
     65   var elem = null;
     66   if ('innerWidth' in window) {
     67     // For non-IE
     68     width = window.innerWidth;
     69     height = window.innerHeight;
     70   } else {
     71     // For IE,
     72     if (('BackCompat' === window.document.compatMode)
     73         && ('body' in window.document)) {
     74         elem = window.document.body;
     75     } else if ('documentElement' in window.document) {
     76       elem = window.document.documentElement;
     77     }
     78     if (elem !== null) {
     79       width = elem.offsetWidth;
     80       height = elem.offsetHeight;
     81     }
     82   }
     83   return [width, height];
     84 };
     85 
     86 // Computes the coordinates of the parent window.
     87 // Gets the coordinates of the parent frame
     88 popupManager.getParentCoords = function() {
     89   var width = 0;
     90   var height = 0;
     91   if ('screenLeft' in window) {
     92     // IE-compatible variants
     93     width = window.screenLeft;
     94     height = window.screenTop;
     95   } else if ('screenX' in window) {
     96     // Firefox-compatible
     97     width = window.screenX;
     98     height = window.screenY;
     99   }
    100   return [width, height];
    101 };
    102 
    103 // Computes the coordinates of the new window, so as to center it
    104 // over the parent frame
    105 popupManager.getCenteredCoords = function(width, height) {
    106    var parentSize = this.getWindowInnerSize();
    107    var parentPos = this.getParentCoords();
    108    var xPos = parentPos[0] +
    109        Math.max(0, Math.floor((parentSize[0] - width) / 2));
    110    var yPos = parentPos[1] +
    111        Math.max(0, Math.floor((parentSize[1] - height) / 2));
    112    return [xPos, yPos];
    113 };
    114 
    115 //  A utility class, implements an onOpenHandler that darkens the screen
    116 //  by overlaying it with a semi-transparent black layer. To use, ensure that
    117 //  no screen element has a z-index at or above 10000.
    118 //  This layer will be suppressed automatically after the screen closes.
    119 //
    120 //  Note: If you want to perform other operations before opening the popup, but
    121 //  also would like the screen to darken, you can define a custom handler
    122 //  as such:
    123 //  var myOnOpenHandler = function(inputs) {
    124 //    .. do something
    125 //    popupManager.darkenScreen();
    126 //    .. something else
    127 //  };
    128 //  Then you pass myOnOpenHandler as input to the opener, as in:
    129 //  var openidParams = {};
    130 //  openidParams.onOpenHandler = myOnOpenHandler;
    131 //  ... other customizations
    132 //  var myOpener = popupManager.createOpener(openidParams);
    133 popupManager.darkenScreen = function() {
    134   var darkCover = window.document.getElementById(window.popupManager.constants['darkCover']);
    135   if (!darkCover) {
    136     darkCover = window.document.createElement('div');
    137     darkCover['id'] = window.popupManager.constants['darkCover'];
    138     darkCover.setAttribute('style', window.popupManager.constants['darkCoverStyle']);
    139     window.document.body.appendChild(darkCover);
    140   }
    141   darkCover.style.visibility = 'visible';
    142 };
    143 
    144 //  Returns a an object that can open a popup window customized for an OP & RP.
    145 //  to use you call var opener = popupManager.cretePopupOpener(openidParams);
    146 //  and then you can assign the 'onclick' handler of a button to
    147 //  opener.popup(width, height), where width and height are the values of the popup size;
    148 //
    149 //  To use it, you would typically have code such as:
    150 //  var myLoginCheckFunction = ...  some AJAXy call or page refresh operation
    151 //  that will cause the user to see the logged-in experience in the current page.
    152 //  var openidParams = { realm : 'openid.realm', returnToUrl : 'openid.return_to',
    153 //  opEndpoint : 'openid.op_endpoint', onCloseHandler : myLoginCheckFunction,
    154 //  shouldEncodeUrls : 'true' (default) or 'false', extensions : myOpenIDExtensions };
    155 //
    156 //  Here extensions include any OpenID extensions that you support. For instance,
    157 //  if you support Attribute Exchange v.1.0, you can say:
    158 //  (Example for attribute exchange request for email and name,
    159 //  assuming that shouldEncodeUrls = 'true':)
    160 //  var myOpenIDExtensions = {
    161 //      'openid.ax.ns' : 'http://openid.net/srv/ax/1.0',
    162 //      'openid.ax.type.email' : 'http://axschema.org/contact/email',
    163 //      'openid.ax.type.name1' : 'http://axschema.org/namePerson/first',
    164 //      'openid.ax.type.name2' : 'http://axschema.org/namePerson/last',
    165 //      'openid.ax.required' : 'email,name1,name2' };
    166 //  Note that the 'ui' namespace is reserved by this library for the OpenID
    167 //  UI extension, and that the mode 'popup' is automatically applied.
    168 //  If you wish to make use of the 'language' feature of the OpenID UI extension
    169 //  simply add the following entry (example assumes the language requested
    170 //  is Swiss French:
    171 //  var my OpenIDExtensions = {
    172 //    ... // other extension parameters
    173 //    'openid.ui.language' : 'fr_CH',
    174 //    ... };
    175 popupManager.createPopupOpener = (function(openidParams) {
    176   var interval_ = null;
    177   var popupWindow_ = null;
    178   var that = this;
    179   var shouldEscape_ = ('shouldEncodeUrls' in openidParams) ? openidParams.shouldEncodeUrls : true;
    180   var encodeIfRequested_ = function(url) {
    181     return (shouldEscape_ ? encodeURIComponent(url) : url);
    182   };
    183   var identifier_ = ('identifier' in openidParams) ? encodeIfRequested_(openidParams.identifier) :
    184       this.constants.openidSpec.identifier_select;
    185   var identity_ = ('identity' in openidParams) ? encodeIfRequested_(openidParams.identity) :
    186       this.constants.openidSpec.identifier_select;
    187   var openidNs_ = ('namespace' in openidParams) ? encodeIfRequested_(openidParams.namespace) :
    188       this.constants.openidSpec.namespace2;
    189   var onOpenHandler_ = (('onOpenHandler' in openidParams) &&
    190       ('function' === typeof(openidParams.onOpenHandler))) ?
    191           openidParams.onOpenHandler : this.darkenScreen;
    192   var onCloseHandler_ = (('onCloseHandler' in openidParams) &&
    193       ('function' === typeof(openidParams.onCloseHandler))) ?
    194           openidParams.onCloseHandler : null;
    195   var returnToUrl_ = ('returnToUrl' in openidParams) ? openidParams.returnToUrl : null;
    196   var realm_ = ('realm' in openidParams) ? openidParams.realm : null;
    197   var endpoint_ = ('opEndpoint' in openidParams) ? openidParams.opEndpoint : null;
    198   var extensions_ = ('extensions' in openidParams) ? openidParams.extensions : null;
    199 
    200   // processes key value pairs, escaping any input;
    201   var keyValueConcat_ = function(keyValuePairs) {
    202     var result = "";
    203     for (key in keyValuePairs) {
    204       result += ['&', key, '=', encodeIfRequested_(keyValuePairs[key])].join('');
    205     }
    206     return result;
    207   };
    208 
    209   //Assembles the OpenID request from customizable parameters
    210   var buildUrlToOpen_ = function() {
    211     var connector = '&';
    212     var encodedUrl = null;
    213     var urlToOpen = null;
    214     if ((null === endpoint_) || (null === returnToUrl_)) {
    215       return;
    216     }
    217     if (endpoint_.indexOf('?') === -1) {
    218       connector = '?';
    219     }
    220     encodedUrl = encodeIfRequested_(returnToUrl_);
    221     urlToOpen = [ endpoint_, connector,
    222         'openid.ns=', openidNs_,
    223         '&openid.mode=checkid_setup',
    224         '&openid.claimed_id=', identifier_,
    225         '&openid.identity=', identity_,
    226         '&openid.return_to=', encodedUrl ].join('');
    227     if (realm_ !== null) {
    228       urlToOpen += "&openid.realm=" + encodeIfRequested_(realm_);
    229     }
    230     if (extensions_ !== null) {
    231       urlToOpen += keyValueConcat_(extensions_);
    232     }
    233     urlToOpen += '&openid.ns.ui=' + encodeURIComponent(
    234         'http://specs.openid.net/extensions/ui/1.0');
    235     urlToOpen += '&openid.ui.mode=popup';
    236     return urlToOpen;
    237   };
    238 
    239   // Tests that the popup window has closed
    240   var isPopupClosed_ = function() {
    241     return (!popupWindow_ || popupWindow_.closed);
    242   };
    243 
    244   // Check to perform at each execution of the timed loop. It also triggers
    245   // the action that follows the closing of the popup
    246   var waitForPopupClose_ = function() {
    247     if (isPopupClosed_()) {
    248       popupWindow_ = null;
    249       var darkCover = window.document.getElementById(window.popupManager.constants['darkCover']);
    250       if (darkCover) {
    251         darkCover.style.visibility = 'hidden';
    252       }
    253       if (onCloseHandler_ !== null) {
    254         onCloseHandler_();
    255       }
    256       if ((null !== interval_)) {
    257         window.clearInterval(interval_);
    258         interval_ = null;
    259       }
    260     }
    261   };
    262 
    263   return {
    264     // Function that opens the window.
    265     popup: function(width, height) {
    266       var urlToOpen = buildUrlToOpen_();
    267       if (onOpenHandler_ !== null) {
    268         onOpenHandler_();
    269       }
    270       var coordinates = that.getCenteredCoords(width, height);
    271       popupWindow_ = window.open(urlToOpen, "",
    272           "width=" + width + ",height=" + height +
    273           ",status=1,location=1,resizable=yes" +
    274           ",left=" + coordinates[0] +",top=" + coordinates[1]);
    275       interval_ = window.setInterval(waitForPopupClose_, 80);
    276       return true;
    277     }
    278   };
    279 });
    280