You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by li...@apache.org on 2010/08/09 12:51:20 UTC
svn commit: r983579 - in /shindig/trunk: content/container/
extras/src/main/javascript/features-extras/
extras/src/main/javascript/features-extras/opensocial-payment/
Author: lindner
Date: Mon Aug 9 10:51:20 2010
New Revision: 983579
URL: http://svn.apache.org/viewvc?rev=983579&view=rev
Log:
SHINDIG-1353 | Modified Patch from Yizi Wu | OpenSocial Virtual Currency API
Added:
shindig/trunk/content/container/payment-processor.html
shindig/trunk/content/container/payment-records-processor.html
shindig/trunk/content/container/sample-payment-container.html
shindig/trunk/content/container/sample-payment.xml
shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/
shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/billingitem.js
shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/container.js
shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/feature.xml
shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/jsoncontainer.js
shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/jsonpayment.js
shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/opensocial.js
shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/payment.js
shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/paymentprocessor.js
Modified:
shindig/trunk/extras/src/main/javascript/features-extras/features.txt
Added: shindig/trunk/content/container/payment-processor.html
URL: http://svn.apache.org/viewvc/shindig/trunk/content/container/payment-processor.html?rev=983579&view=auto
==============================================================================
--- shindig/trunk/content/container/payment-processor.html (added)
+++ shindig/trunk/content/container/payment-processor.html Mon Aug 9 10:51:20 2010
@@ -0,0 +1,299 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Sample: Payment Processor</title>
+
+<style>
+body, td, div, span, p {
+ font-family:arial,sans-serif;
+}
+body {
+ padding:0px;
+ margin:0px;
+}
+.payment-processor-shadow {
+ filter: alpha(opacity=30);
+ -moz-opacity:.3;
+ opacity:0.3;
+ background-color:#000;
+ width:690px;
+ height:390px;
+ margin:5px 0px 0px 5px;
+ position:absolute;
+ z-index:100;
+}
+.payment-processor-border1 {
+ background-color:#E5ECF9;
+ width:690px;
+ height:390px;
+ position:absolute;
+ z-index:200;
+}
+.payment-processor-border2 {
+ background-color:#FFF;
+ margin:5px;
+ height:380px;
+}
+.payment-processor-content {
+ padding:20px;
+ font-size:13px;
+}
+.payment-processor-content #loading-tab {
+ color:#777;
+}
+.caption {
+ font-weight:bold;
+ width:80px;
+ display:inline;
+}
+.desc {
+ color:#007F00;
+}
+.head {
+ font-weight:bold;
+}
+</style>
+
+
+<script type="text/javascript">
+
+/**
+ * @static
+ * @class A sample payment process panel provides the UI and logic for the real payment excution on
+ * container api server.
+ *
+ * NOTE:
+ *
+ * All functions or logics or names in this page are customizable. Indeed containers have
+ * to customize them to make the UI consistent. This sample panel page is embeded in the
+ * parent container page as an iframe for better code structure, but indeed it is not
+ * necessary. It can be on the same page as container page.
+ *
+ * You can implement their processor panel page using this file but replace the UI and
+ * mock codes, or use your completely own codes. If you use your own page, just to make
+ * sure <code>shindig.paymentprocessor.initPayment</code> function is called with necessary
+ * callbacks (open and close event handlers) passed in when initializing the page.
+ *
+ */
+var myProcessorPanel = (function() {
+
+ /** Element which holding this processor panel page in parent window. */
+ var parentDiv;
+
+ /** Just a reference to <code>shindig.paymentprocessor</code> object, which holding necessary
+ parameters needed in the payment process */
+ var processor;
+
+ /**
+ * Called by <code>shindig.paymentprocessor</code> when the counter
+ * panel is closing.
+ */
+ function closeEvent() {
+ // Set the div in the parent window to invisible.
+ parentDiv.style.display = 'none';
+ };
+
+
+ /**
+ * Draws the pay counter panel UI itself.
+ * (NOTE that this page is a iframe in its parent container window);
+ * Assigns the submit callback and cancel callback to the buttons.
+ * So from this panel, submit or cancel actions can be made.
+ *
+ * @param {Object} paymentJson The payment parameters.
+ * @param {Object} extraParams The extra parameters for the payment
+ * procedure, including handler url, app title and spec.
+ * @param {Function} submitCallback The submit callback in
+ * <code>shindig.paymentprocessor</code>.
+ * @param {Function} cancelCallback The cancel callback in
+ * <code>shindig.paymentprocessor</code>.
+ */
+ function openEvent() {
+ // Set the UI.
+ document.getElementById('loading-tab').style.display = 'none';
+
+ document.getElementById('payment-appname').innerHTML = processor.getParam('appTitle');
+ document.getElementById('payment-appspec').innerHTML = processor.getParam('appSpec');
+
+ document.getElementById('payment-type').innerHTML = processor.getParam('payment.paymentType');
+ document.getElementById('payment-amount').innerHTML = processor.getParam('payment.amount');
+ document.getElementById('payment-message').innerHTML = processor.getParam('payment.message');
+
+ var items = processor.getParam('payment.items');
+ if (items) {
+ var html = '<table border=1><tbody><tr class=head><td>SKU_ID</td><td>Price</td>' +
+ '<td>Count</td><td>Description</td></tr>';
+ for (var i = 0; i < items.length; i++) {
+ html += '<tr>' +
+ '<td>' + items[i]['skuId'] + '</td>' +
+ '<td>' + items[i]['price'] + '</td>' +
+ '<td>' + items[i]['count'] + '</td>' +
+ '<td>' + items[i]['description'] + '</td>' +
+ '</tr>';
+ }
+ html += '</tbody></table>';
+ document.getElementById('payment-items').innerHTML = html;
+ } else {
+ document.getElementById('payment-items').innerHTML = 'No detail items';
+ }
+
+ document.getElementById('payment-orderedtime').innerHTML =
+ new Date(processor.getParam('payment.orderedTime')).toLocaleString();
+
+ if (processor.getParam('payment.paymentType') == 'credit') {
+ // If the payment type is 'credit', skip the confirm panel UI and
+ // call the submitEvent directly.
+ window.setTimeout(submitHandler, 500);
+ } else {
+ // If the payment type is normal 'payment', add click listeners and
+ // wait for user confirmation.
+ document.getElementById('button-tab').style.display = 'block';
+ document.getElementById('payment-submit').onclick = submitHandler;
+ document.getElementById('payment-cancel').onclick = cancelHandler;
+ }
+
+ // Set the div in the parent window to visible.
+ parentDiv.style.display = 'block';
+ };
+
+ /**
+ * Called by submit button clicked by the user.
+ *
+ * This function should send the pay request to container virtual currency
+ * api with Ajax POST.
+ *
+ * Then usually an acknowledge tab will be shown in the with a button to
+ * call the callback function.
+ */
+ function submitHandler() {
+ document.getElementById('button-tab').style.display = 'none';
+ document.getElementById('loading-tab').style.display = 'block';
+
+
+ var requestData = processor.getParam('payment');
+ requestData['st'] = processor.getParam('stoken'); // or other security token
+
+
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Here the logic should be on container sever with communication with app server. //
+ // See the proposal doc Rivision#4. //
+ //////////////////////////////////////////////////////////////////////////////////////
+ var sendPaymentRequest = function(ajaxCallback) {
+ // The Server will communicate with App Backend Server then response.
+ // Here is just a fake call. You should replace these codes with actual ajax.
+ // Wait 1 second to simulate the network connection.
+ window.setTimeout(function() {
+ var responseData = {};
+ responseData['submittedTime'] = new Date().getTime();
+
+
+ // Do some fake check here. Can be any type of error during server-to-server roundtrips.
+ if (requestData['amount'] > 1000) {
+ responseData['responseCode'] = 'INSUFFICIENT_MONEY';
+ responseData['responseMessage'] = 'Fake not enough money response!';
+ ajaxCallback(responseData);
+ return;
+ }
+
+ // Simulate success response.
+ responseData['orderId'] = 'ORDER_ID_FROM_APP_' + Math.round(Math.random() * 10000);
+ responseData['executedTime'] = new Date().getTime();
+ responseData['responseCode'] = 'OK';
+ responseData['responseMessage'] = 'Fake success response!';
+ ajaxCallback(responseData);
+
+ }, 1000);
+ };
+ //////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+ // Send Ajax Call to Container Virtual Currency API Server.
+ sendPaymentRequest(function(responseData) {
+
+ processor.setParam('payment.responseCode', responseData['responseCode']);
+ processor.setParam('payment.responseMessage', responseData['responseMessage']);
+
+ if (responseData['responseCode'] == 'OK') {
+ // Copy the server generated fields back to processor parameters.
+ processor.setParam('payment.submittedTime', responseData['submittedTime']);
+ processor.setParam('payment.executedTime', responseData['executedTime']);
+ processor.setParam('payment.orderId', responseData['orderId']);
+ }
+
+ // Close the processor panel and return to app.
+ processor.closePayment();
+ });
+ };
+
+
+ /**
+ * Invoked when cancel button clicked by user.
+ */
+ function cancelHandler() {
+ // You can also show a message to say the order is canceled.
+ // Here just call the callback and return.
+ processor.setParam('payment.responseCode', 'USER_CANCELLED');
+ processor.closePayment();
+ };
+
+
+
+ return {
+ /**
+ * Initializes the counter module. It can be called by this page's <code>body.onload()</code>
+ * function or in other initializing steps.
+ * Note the <code>shindig.paymentprocessor</code> object is passed from the parent window.
+ */
+ init: function() {
+ // Store the parent node in which there is an iframe holding this page.
+ parentDiv = window.frameElement.parentNode;
+
+ processor = parent.shindig.paymentprocessor;
+
+ // Initialize the paymentprocessor module with four events.
+ // The container need to fully implement these event functions for
+ // UI/Backend interaction.
+ processor.initPayment(openEvent, closeEvent);
+ }
+ };
+
+})();
+
+</script>
+</head>
+<body onload="myProcessorPanel.init();">
+ <!-- Customize the UI -->
+ <div class="payment-processor-shadow"></div>
+ <div class="payment-processor-border1">
+ <div class="payment-processor-border2">
+ <div class="payment-processor-content">
+ <p class="desc">
+ This panel is in an iframe from another page in the same container domain:<br>
+ <b><script>document.write(window.location.href);</script></b>
+ </p>
+ <div class="caption">App Name: </div><span id="payment-appname"></span><br>
+ <div class="caption">App Spec: </div><span id="payment-appspec"></span><br>
+ <br>
+ <div class="caption">Payment Type: </div><span id="payment-type"></span><br>
+ <div class="caption">Amount: </div><span id="payment-amount"></span><br>
+ <div class="caption">Message: </div><span id="payment-message"></span><br>
+ <div class="caption">Items: </div><br><div id="payment-items"></div>
+ <div class="caption">Ordered Time: </div><span id="payment-orderedtime"></span><br>
+ <br>
+ <div id="button-tab" style="display:none;">
+ <button id="payment-submit">Submit</button>
+ <button id="payment-cancel">Cancel</button>
+ </div>
+ <div id="loading-tab" style="display:none">
+ Please wait...
+ </div>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
+
Added: shindig/trunk/content/container/payment-records-processor.html
URL: http://svn.apache.org/viewvc/shindig/trunk/content/container/payment-records-processor.html?rev=983579&view=auto
==============================================================================
--- shindig/trunk/content/container/payment-records-processor.html (added)
+++ shindig/trunk/content/container/payment-records-processor.html Mon Aug 9 10:51:20 2010
@@ -0,0 +1,388 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Sample: Payment Records Processor</title>
+
+<style>
+body, td, div, span, p {
+ font-family:arial,sans-serif;
+}
+body {
+ padding:0px;
+ margin:0px;
+}
+.payment-processor-shadow {
+ filter: alpha(opacity=30);
+ -moz-opacity:.3;
+ opacity:0.3;
+ background-color:#000;
+ width:690px;
+ height:390px;
+ margin:5px 0px 0px 5px;
+ position:absolute;
+ z-index:100;
+}
+.payment-processor-border1 {
+ background-color:#E5ECF9;
+ width:690px;
+ height:390px;
+ position:absolute;
+ z-index:200;
+}
+.payment-processor-border2 {
+ background-color:#FFF;
+ margin:5px;
+ height:380px;
+}
+.payment-processor-content {
+ padding:20px;
+ font-size:13px;
+}
+.payment-processor-content #loading-tab {
+ color:#777;
+}
+.caption {
+ font-weight:bold;
+ width:80px;
+ display:inline;
+}
+.desc {
+ color:#007F00;
+}
+.head {
+ font-weight:bold;
+}
+</style>
+
+
+<script type="text/javascript">
+
+/**
+ * @static
+ * @class A sample records processor panel provides the UI and logic for the real records fetching
+ * and fixing requests to container api server.
+ *
+ * NOTE:
+ *
+ * All functions or logics or names in this page are customizable. Indeed containers have
+ * to customize them to make the UI consistent. This sample panel page is embeded in the
+ * parent container page as an iframe for better code structure, but indeed it is not
+ * necessary. It can be on the same page as container page.
+ *
+ * You can implement their processor panel page using this file but replace the UI and
+ * mock codes, or use your completely own codes. If you use your own page, just to make
+ * sure <code>shindig.paymentprocessor.initPaymentRecords</code> function is called with
+ * necessary callbacks (open and close event handlers) passed in when initializing the
+ * page.
+ *
+ */
+var myRecordsProcessorPanel = (function() {
+
+ /** Element which holding this processor panel page in parent window. */
+ var parentDiv;
+
+ /** Just a reference to <code>shindig.paymentprocessor</code> object, which holding necessary
+ parameters needed in the payment process */
+ var processor;
+
+ /**
+ * Called by <code>shindig.paymentprocessor</code> when the counter
+ * panel is closing.
+ */
+ function closeEvent() {
+ // Set the div in the parent window to invisible.
+ parentDiv.style.display = 'none';
+ };
+
+
+ /**
+ * Draws the pay counter panel UI itself.
+ * (NOTE that this page is a iframe in its parent container window);
+ * Assigns the submit callback and cancel callback to the buttons.
+ * So from this panel, submit or cancel actions can be made.
+ *
+ * @param {Object} paymentJson The payment parameters.
+ * @param {Object} extraParams The extra parameters for the payment
+ * procedure, including handler url, app title and spec.
+ * @param {Function} submitCallback The submit callback in
+ * <code>shindig.paymentprocessor</code>.
+ * @param {Function} cancelCallback The cancel callback in
+ * <code>shindig.paymentprocessor</code>.
+ */
+ function openEvent() {
+ // Set the div in the parent window to visible.
+ parentDiv.style.display = 'block';
+ document.getElementById('payment-appname').innerHTML = processor.getParam('appTitle');
+ document.getElementById('payment-appspec').innerHTML = processor.getParam('appSpec');
+
+ document.getElementById('payment-records-close').onclick = cancelHandler;
+
+ // The requestData is going to post to server.
+ var requestData = {
+ 'appSpec' : processor.getParam('appSpec'),
+ 'appTitle' : processor.getParam('appTitle'),
+ 'st' : processor.getParam('stoken'), // or other security token if needed
+
+ 'params' : processor.getParam('reqParams'),
+ 'sandbox': processor.getParam('reqParams.sandbox')
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Here the logic should be on container sever for fetching payment records. //
+ // See the proposal doc Rivision#4. //
+ //////////////////////////////////////////////////////////////////////////////////////
+ var sendFetchPaymentRecordsRequest = function(ajaxCallback) {
+ // The Server will fetch data from it's own database then response.
+ // Here is just a fake call. You should replace these codes with actual ajax.
+ // Wait 1 second to simulate the network connection.
+ window.setTimeout(function() {
+ // Get the payment records in database by querying with appSpec. Here uses mock data.
+ var mockData = [
+ {
+ 'orderId' : 'ORDER_ID_FROM_APP_' + Math.round(Math.random() * 10000),
+ 'items': [
+ {'skuId':'1234', 'price':'10', 'count': 5, 'description':'this is fake.'},
+ {'skuId':'2345', 'price':'11', 'count': 7, 'description':'this is fake2.'}
+ ],
+ 'amount': 127,
+ 'message': 'Fake message',
+ 'paymentType': 'payment',
+ 'orderedTime': new Date().getTime(),
+ 'submittedTime': new Date().getTime(),
+ 'executedTime': new Date().getTime(),
+ 'responseCode': 'OK',
+ 'responseMessage': 'Payment done.',
+ 'paymentComplete': true,
+ 'sandbox': !!requestData['sandbox']
+ }, {
+ 'orderId' : 'ORDER_ID_FROM_APP_' + Math.round(Math.random() * 10000),
+ 'items': [
+ {'skuId':'3456', 'price':'5', 'count': 30, 'description':'this is fake3.'},
+ {'skuId':'6789', 'price':'100', 'count': 1, 'description':'this is fake4.'}
+ ],
+ 'amount': 250,
+ 'message': 'Fake message2',
+ 'paymentType': 'payment',
+ 'orderedTime': new Date().getTime(),
+ 'submittedTime': new Date().getTime(),
+ 'executedTime': new Date().getTime(),
+ 'responseCode': 'APP_LOGIC_ERROR',
+ 'responseMessage': 'Payment failed on app.',
+ 'paymentComplete': false,
+ 'sandbox': !!requestData['sandbox']
+ }, {
+ 'orderId' : 'ORDER_ID_FROM_APP_' + Math.round(Math.random() * 10000),
+ 'items': [
+ {'skuId':'abcd', 'price':'3', 'count': 3, 'description':'this is fake5.'},
+ {'skuId':'efgh', 'price':'12', 'count': 4, 'description':'this is fake6.'}
+ ],
+ 'amount': 57,
+ 'message': 'Fake message3',
+ 'paymentType': 'payment',
+ 'orderedTime': new Date().getTime(),
+ 'submittedTime': new Date().getTime(),
+ 'executedTime': new Date().getTime(),
+ 'responseCode': 'PAYMENT_ERROR',
+ 'responseMessage': 'Payment failed on container.',
+ 'paymentComplete': false,
+ 'sandbox': !!requestData['sandbox']
+ }
+ ];
+
+ var max = Number(requestData['params']['max']);
+ if (!max) {
+ max = 3 // If not set or incorrectly set, set default value.
+ }
+
+ ajaxCallback(mockData.slice(0, max));
+ }, 1000);
+ };
+ ////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+ // Send ajax request
+ document.getElementById('loading-tab').style.display = 'block';
+
+ sendFetchPaymentRecordsRequest(function(responseData) {
+ document.getElementById('loading-tab').style.display = 'none';
+
+ var records = processor.getParam('records.payments');
+
+ var incompleteIds = [];
+
+ // Generate the payment records table UI
+ var html = '<table border=1><tbody><tr class="head">' +
+ '<td>Amount</td><td>Message</td><td>SubmittedTime</td>' +
+ '<td>ResponseCode</td><td>ExecutedTime</td>'+
+ '</tr>';
+ for (var i = 0; i < responseData.length; i++) {
+ var paymentJson = responseData[i];
+ var orderId = paymentJson['orderId'];
+ html += '<tr><td>' + paymentJson['amount'] + '</td>' +
+ '<td>' + paymentJson['message'] + '</td>' +
+ '<td>' + new Date(paymentJson['submittedTime']).toLocaleString() + '</td>' +
+ '<td>' + paymentJson['responseCode'] + '</td>' +
+ '<td id=\'td_' + orderId + '\'>';
+ if (!paymentJson['paymentComplete']) {
+ // Show a 'FixIt' button for non-complete payment with ID equals orderId.
+ html += '<button id=\'' + orderId + '\'>FixIt</button>';
+ // Add the incompletes to records.
+ records[orderId] = paymentJson;
+ incompleteIds.push(orderId);
+ } else {
+ html += new Date(paymentJson['executedTime']).toLocaleString();
+ }
+ html += '</td></tr>';
+ }
+ html += '</tbody></table>';
+ document.getElementById('payment-records').innerHTML = html;
+
+ // Assign onclick handler's for incomplete payments.
+ for (var j = 0; j < incompleteIds.length; j++) {
+ document.getElementById(incompleteIds[j]).onclick = submitHandler;
+ }
+ });
+
+ };
+
+ /**
+ * Called by submit button clicked by the user.
+ *
+ * This function should send the payment fixing request to container virtual currency
+ * api with Ajax POST.
+ */
+ function submitHandler() {
+ var orderId = this.id;
+ var requestData = {
+ 'appSpec' : processor.getParam('appSpec'),
+ 'appTitle' : processor.getParam('appTitle'),
+ 'st' : processor.getParam('stoken'), // or other security token
+
+ 'orderId' : orderId,
+ 'sandbox': processor.getParam('reqParams.sandbox')
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Here the logic should be on container sever for updating an incomplete payment. //
+ // See the proposal doc Rivision#4. //
+ //////////////////////////////////////////////////////////////////////////////////////
+ var sendFixPaymentRecordRequest = function(ajaxCallback) {
+ // The Server will communicate with App Backend Server then response.
+ // Here is just a fake call.
+ // Wait 1 second to simulate the network connection.
+ window.setTimeout(function() {
+ // let say it will always succeed.
+ var responseData = {};
+
+ // Simulate success response.
+ responseData['paymentComplete'] = true;
+ responseData['executedTime'] = new Date().getTime();
+ responseData['responseCode'] = 'OK';
+ if (!!requestData['sandbox']) {
+ responseData['responseMessage'] = 'Fake success response in sandbox!';
+ } else {
+ responseData['responseMessage'] = 'Fake success response!';
+ }
+
+ ajaxCallback(responseData);
+ }, 1000);
+ };
+ /////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+ // Send ajax request
+ document.getElementById('loading-tab').style.display = 'block';
+
+ sendFixPaymentRecordRequest(function(responseData) {
+ document.getElementById('loading-tab').style.display = 'none';
+
+ if (responseData['responseCode'] != 'OK') {
+ // something fail, display exception message and let user try again.
+ document.getElementById(orderId).innerHTML = 'Try again';
+ return;
+ }
+
+ // If fixing request succeeded, replay the button with payment executed time.
+ document.getElementById('td_' + orderId).innerHTML =
+ new Date(responseData['executedTime']).toLocaleString();
+
+ // Updates the payment json object in the records.
+ var paymentJson = processor.getParam('records.payments.' + orderId);
+ paymentJson['paymentComplete'] = true;
+ paymentJson['executedTime'] = responseData['executedTime'];
+ paymentJson['responseCode'] = responseData['responseCode'];
+ paymentJson['responseMessage'] = responseData['responseMessage'];
+
+ });
+
+ };
+
+ /**
+ * Invoked when cancel button clicked by user. Closes the processor.
+ */
+ function cancelHandler() {
+ // You can also show a message to say the order is canceled.
+ // Here just call the callback and return.
+
+ processor.setParam('records.responseCode', 'OK');
+
+ processor.closePaymentRecords();
+ };
+
+ return {
+
+ /**
+ * Initializes the counter module. It can be called by this page's <code>body.onload()</code>
+ * function or in other initializing steps.
+ * Note the <code>shindig.paymentprocessor</code> object is passed from the parent window.
+ */
+ init: function() {
+ // Store the parent node in which there is an iframe holding this page.
+ parentDiv = window.frameElement.parentNode;
+
+ processor = parent.shindig.paymentprocessor;
+
+ // Initialize the paymentprocessor module with four events.
+ // The container need to fully implement these event functions for
+ // UI/Backend interaction.
+ processor.initPaymentRecords(openEvent, closeEvent);
+ }
+
+ };
+})();
+
+</script>
+</head>
+<body onload="myRecordsProcessorPanel.init();">
+ <!-- Customize the UI -->
+ <div class="payment-processor-shadow"></div>
+ <div class="payment-processor-border1">
+ <div class="payment-processor-border2">
+ <div class="payment-processor-content">
+ <p class="desc">
+ This panel is in an iframe from another page in the same container domain:<br>
+ <b><script>document.write(window.location.href);</script></b>
+ </p>
+
+ <div class="caption">App Name: </div><span id="payment-appname"></span><br>
+ <div class="caption">App Spec: </div><span id="payment-appspec"></span><br>
+
+ <p id="payment-records"></p>
+
+ <div id="button-tab">
+ <button id="payment-records-close">Close</button>
+ </div>
+
+ <div id="loading-tab" style="display:none">Please wait...</div>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
+
Added: shindig/trunk/content/container/sample-payment-container.html
URL: http://svn.apache.org/viewvc/shindig/trunk/content/container/sample-payment-container.html?rev=983579&view=auto
==============================================================================
--- shindig/trunk/content/container/sample-payment-container.html (added)
+++ shindig/trunk/content/container/sample-payment-container.html Mon Aug 9 10:51:20 2010
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Sample: Virtual Currency Payment</title>
+<!-- default container look and feel -->
+<link rel="stylesheet" href="gadgets.css">
+<style>
+ .gadgets-gadget-chrome {
+ width: 80%;
+ float: none;
+ margin: auto;
+ }
+ .gadgets-gadget {
+ width: 100%;
+ }
+ .desc {
+ color:#007F00;
+ }
+ .desc script {
+ color:#FF0000;
+ }
+</style>
+
+<script type="text/javascript" src="/gadgets/js/shindig-container:rpc:opensocial-payment.js?c=1&debug=1"></script>
+<script type="text/javascript">
+
+function output(message) {
+ document.getElementById("output").innerHTML += gadgets.util.escapeString(message) + "<br/>";
+};
+
+// The container domain.
+var containerHost = 'http://' + window.location.host;
+
+// NOTE: Set the gadget serverBase here to replace 'window.location.host' which is just for demo.
+// The shindig domain must be different from the container domain for security reason.
+var shindigHost = 'http://' + window.location.host;
+
+// The location of the demo app spec. It is located on container domain.
+var demoGadgetSpecs = [
+ containerHost + '/container/sample-payment.xml',
+];
+
+function renderGadgets() {
+ var demoGadgets = [];
+ var chromeIds = [];
+ for (var i = 0; i < demoGadgetSpecs.length; ++i) {
+ var gadget = shindig.container.createGadget({
+ specUrl: demoGadgetSpecs[i],
+ title: ("Sample Payment App - " + i)
+ });
+ gadget.setServerBase(shindigHost + '/gadgets/');
+ shindig.container.addGadget(gadget);
+ chromeIds.push('gadget-chrome-' + i);
+ demoGadgets.push(gadget);
+ }
+ shindig.container.layoutManager.setGadgetChromeIds(chromeIds);
+ for (var i = 0; i < demoGadgets.length; ++i) {
+ shindig.container.renderGadget(demoGadgets[i]);
+ }
+};
+
+
+</script>
+</head>
+<body onLoad="renderGadgets();">
+ <center>
+ <h2>OpenSocial Virtual Currency Proposal Revision #4 Demo</h2>
+
+ <h4>opensocial.requestPayment<br>opensocial.requestPaymentRecords</h4>
+ <div>For detail, please checkout <a href="http://docs.google.com/View?id=dhcrsqrj_0d86fkdfv" target=_blank>proposal doc</a>,
+ <a href="http://groups.google.com/group/opensocial-and-gadgets-spec/browse_thread/thread/7341f1716e50f4d/8553e6aa696bd088?lnk=gst" target=_blank>discussion thread</a>, and
+ <a href="http://code.google.com/p/opensocial-virtual-currency" target=_blank>code project</a>.
+ </div>
+ <p class="desc">
+ This page is a container page:<br>
+ <b><script>document.write(window.location.href);</script></b>
+ </p>
+ </center>
+ <div id="gadget-chrome-0" class="gadgets-gadget-chrome"></div>
+
+ <div id="output" style="clear: left;">
+ </div>
+
+ <!-- The counter panel -->
+ <style>
+ .payment-panel {
+ width:700px;
+ height:400px;
+ left:100px;
+ top:200px;
+ position:absolute;
+ }
+ .payment-panel iframe {
+ width:700px;
+ height:400px;
+ }
+ </style>
+ <!-- The payment processor panel, the processor page's domain should be the same as container domain -->
+ <div id="payment-processor" style="display:none;" class="payment-panel">
+ <iframe name="payment-processor-frame" frameborder=0 src="/container/payment-processor.html"></iframe>
+ </div>
+
+ <!-- The payment records processor panel, the processor page's domain should be the same as container domain -->
+ <div id="payment-records-processor" style="display:none;" class="payment-panel">
+ <iframe name="payment-processor-frame" frameborder=0 src="/container/payment-records-processor.html"></iframe>
+ </div>
+
+</body>
+</html>
+
Added: shindig/trunk/content/container/sample-payment.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/content/container/sample-payment.xml?rev=983579&view=auto
==============================================================================
--- shindig/trunk/content/container/sample-payment.xml (added)
+++ shindig/trunk/content/container/sample-payment.xml Mon Aug 9 10:51:20 2010
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Module>
+ <ModulePrefs title="My App Test"
+ author_email="yizi.wu@gmail.com" height="500">
+ <Require feature="opensocial-0.9"/>
+ <Require feature="dynamic-height"/>
+ <Require feature="settitle"/>
+ <Require feature="views"/>
+ <Require feature="rpc"/>
+ </ModulePrefs>
+ <Content type="html">
+ <![CDATA[
+ <style>
+ #main {font-size:13px;}
+ .t {width:300px; margin-left:3px;}
+ .f {border-collapse:collapse;margin-left:10px;}
+ .f tbody tr td {font-size:12px;font-weight:bold;white-space:nowrap;vertical-align:top;}
+ .f tbody tr td span {font-size:10px;white-space:normal;}
+ .desc {color:#007F7F;}
+ </style>
+ <script>
+ function requestPayment() {
+ var params = {};
+ params[opensocial.Payment.Field.AMOUNT] = document.getElementById('amount').value;
+ params[opensocial.Payment.Field.MESSAGE] = document.getElementById('message').value;
+ params[opensocial.Payment.Field.PARAMETERS] = gadgets.util.escapeString(document.getElementById('parameters').value);
+ params[opensocial.Payment.Field.PAYMENT_TYPE] = document.getElementById('creditType').checked ?
+ opensocial.Payment.PaymentType.CREDIT : opensocial.Payment.PaymentType.PAYMENT;
+
+ var itemParams = {};
+ itemParams[opensocial.BillingItem.Field.SKU_ID] = 'test_sku1';
+ itemParams[opensocial.BillingItem.Field.PRICE] = 20;
+ itemParams[opensocial.BillingItem.Field.COUNT] = 2;
+ itemParams[opensocial.BillingItem.Field.DESCRIPTION] = 'demo description red flower';
+ var item1 = opensocial.newBillingItem(itemParams);
+
+ itemParams = {};
+ itemParams[opensocial.BillingItem.Field.SKU_ID] = 'test_sku2';
+ itemParams[opensocial.BillingItem.Field.PRICE] = 30;
+ itemParams[opensocial.BillingItem.Field.COUNT] = 4;
+ itemParams[opensocial.BillingItem.Field.DESCRIPTION] = 'demo description yellow flower';
+ var item2 = opensocial.newBillingItem(itemParams);
+
+
+ params[opensocial.Payment.Field.ITEMS] = [item1, item2];
+ var payment = opensocial.newPayment(params);
+
+ opensocial.requestPayment(payment, function(responseItem) {
+ document.getElementById('paymentOutput').style.display = 'block';
+ document.getElementById('status').innerHTML = responseItem.hadError() ? 'FAILED' : 'SUCCESS';
+ var data = responseItem.getData();
+ document.getElementById('type').innerHTML = data.getField(opensocial.Payment.Field.PAYMENT_TYPE);
+ document.getElementById('orderid').innerHTML = data.getField(opensocial.Payment.Field.ORDER_ID);
+ document.getElementById('code').innerHTML = data.getField(opensocial.Payment.Field.RESPONSE_CODE);
+ document.getElementById('resmsg').innerHTML = data.getField(opensocial.Payment.Field.RESPONSE_MESSAGE);
+ document.getElementById('orderedtime').innerHTML = new Date(data.getField(opensocial.Payment.Field.ORDERED_TIME)).toLocaleString();
+ document.getElementById('submittedtime').innerHTML = new Date(data.getField(opensocial.Payment.Field.SUBMITTED_TIME)).toLocaleString();
+ document.getElementById('executedtime').innerHTML = new Date(data.getField(opensocial.Payment.Field.EXECUTED_TIME)).toLocaleString();
+
+ gadgets.window.adjustHeight();
+ });
+ document.getElementById('paymentOutput').style.display = 'none';
+
+ };
+
+
+ function requestPaymentRecords() {
+
+ var params = {};
+ params[opensocial.Payment.RecordsRequestFields.MAX] = document.getElementById('max').value;
+ params[opensocial.Payment.RecordsRequestFields.SANDBOX] = document.getElementById('r_sandbox').checked;
+
+ opensocial.requestPaymentRecords(function(responseItem) {
+ document.getElementById('recordsOutput').style.display = 'block';
+ var data = responseItem.getData();
+
+ var html = 'Listing original incomplete payments before request.<br> Payments in bold are fixed manually by user afterward.<br>';
+ for (var i = 0; i < data.length; i++) {
+ var bold = data[i].getField(opensocial.Payment.Field.PAYMENT_COMPLETE);
+ if (bold) html += '<b>';
+ html += data[i].getField(opensocial.Payment.Field.ORDER_ID) + ' ' +
+ data[i].getField(opensocial.Payment.Field.AMOUNT) + ' ' +
+ data[i].getField(opensocial.Payment.Field.RESPONSE_MESSAGE) + ' ' +
+ new Date(data[i].getField(opensocial.Payment.Field.EXECUTED_TIME)).toLocaleString();
+ if (bold) html += '</b>';
+ html += '<br>';
+ }
+ document.getElementById('records').innerHTML = html;
+
+ gadgets.window.adjustHeight();
+ }, params);
+
+ document.getElementById('recordsOutput').style.display = 'none';
+ };
+
+ function init() {
+ var req = opensocial.newDataRequest();
+ req.add(req.newFetchPersonRequest(opensocial.IdSpec.PersonId.VIEWER), "req");
+ req.send(function(data) {
+ if (!data.hadError()) {
+ document.getElementById('myname').innerHTML = 'Current Viewer: <b>' + data.get("req").getData().getDisplayName() + '</b>';
+ }
+ gadgets.window.adjustHeight();
+ });
+ };
+ gadgets.util.registerOnLoadHandler(init);
+ </script>
+
+
+ <div id="main">
+ <p class="desc">
+ Here is the app domain inside the gadget iframe, usually different from container domain:<br>
+ <b><script>document.write('http://' + window.location.host + window.location.pathname + location.search.substring(0, 30) + '...');</script></b>
+ </p>
+ <p><span id="myname"></span></p><hr>
+
+ <div id=req>
+ <b>Make a Payment Request: </b><br>
+ <table class=f><tbody>
+ <tr><td>Amount: </td><td><input class=t id=amount value=100></td></tr>
+ <tr><td>Message: </td><td><input class=t id=message value="You are ordering some flowers."></td></tr>
+ <tr><td>Parameters: </td><td><input class=t id=parameters value="{type:'Tulip',quantity:5}"></td></tr>
+ <tr><td>Payment Type: </td><td>
+ <input type=radio id=paymentType name=pt checked><label for=paymentType>Payment</label>
+ <input type=radio id=creditType name=pt><label for=creditType>Credit</label>
+ </td></tr>
+ </tbody></table>
+ <button onclick="requestPayment();">Request Payment</button>
+ </div>
+
+ <div id=paymentOutput style="display:none">
+ <hr>
+ <b>Payment Response: </b><br>
+ <table class=f><tbody>
+ <tr><td>Payment Type: </td><td><span id=type></span></td></tr>
+ <tr><td>Status: </td><td><span id=status></span></td></tr>
+ <tr><td>Order ID: </td><td><span id=orderid></span></td></tr>
+ <tr><td>Response Code: </td><td><span id=code></span></td></tr>
+ <tr><td>Response Message: </td><td><span id=resmsg></span></td></tr>
+ <tr><td>Ordered Time: </td><td><span id=orderedtime></span></td></tr>
+ <tr><td>Submitted Time: </td><td><span id=submittedtime></span></td></tr>
+ <tr><td>Executed Time: </td><td><span id=executedtime></span></td></tr>
+ </tbody></table>
+ </div>
+ <hr>
+
+ <div>
+ <b>Make a Payment Records Request: </b><br>
+ <table class=f><tbody>
+ <tr><td><label for=sandbox>Sandbox: </label></td><td><input type=checkbox id=r_sandbox checked></td></tr>
+ <tr><td>Max: </td><td><input class=t id=max value=3></td></tr>
+ </tbody></table>
+ <button onclick="requestPaymentRecords();">Request Payment Records</button>
+ </div>
+ <div id=recordsOutput style="display:none">
+ <hr>
+ <div id=records></div>
+ </div>
+ </div>
+ ]]>
+ </Content>
+</Module>
+
+
Modified: shindig/trunk/extras/src/main/javascript/features-extras/features.txt
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/features.txt?rev=983579&r1=983578&r2=983579&view=diff
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/features.txt (original)
+++ shindig/trunk/extras/src/main/javascript/features-extras/features.txt Mon Aug 9 10:51:20 2010
@@ -18,3 +18,4 @@
features-extras/org.jquery.core-1.4.2/feature.xml
features-extras/wave/feature.xml
+features-extras/opensocial-payment/feature.xml
Added: shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/billingitem.js
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/billingitem.js?rev=983579&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/billingitem.js (added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/billingitem.js Mon Aug 9 10:51:20 2010
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * @class
+ * Representation of a billing item.
+ ?
+ * @name opensocial.BillingItem
+ */
+
+
+/**
+ * Base interface for billing item objects.
+ *
+ * @param {Map.<opensocial.BillingItem.Field, Object>} params
+ * Parameters defining the billing item.
+ * @private
+ * @constructor
+ */
+opensocial.BillingItem = function(params) {
+ this.fields_ = params || {};
+ this.fields_[opensocial.BillingItem.Field.COUNT] =
+ this.fields_[opensocial.BillingItem.Field.COUNT] || 1;
+};
+
+/**
+ * @static
+ * @class
+ * All of the fields that a billing item object can have.
+ *
+ * <p>The SKU_ID and PRINE are required for the request. </p>
+ *
+ * <p>
+ * <b>See also:</b>
+ * <a href="opensocial.BillingItem.html#getField">
+ * opensocial.BillingItem.getField()</a>
+ * </p>
+ *
+ * @name opensocial.Payment.Field
+ */
+opensocial.BillingItem.Field = {
+ /**
+ * @member opensocial.BillingItem.Field
+ */
+ SKU_ID : 'skuId',
+
+ /**
+ * @member opensocial.BillingItem.Field
+ */
+ PRICE : 'price',
+
+ /**
+ * @member opensocial.BillingItem.Field
+ */
+ COUNT : 'count',
+
+ /**
+ * @member opensocial.BillingItem.Field
+ */
+ DESCRIPTION : 'description'
+
+};
+
+
+/**
+ * Gets the billing item field data that's associated with the specified key.
+ *
+ * @param {String} key The key to get data for;
+ * see the <a href="opensocial.BillingItem.Field.html">Field</a> class
+ * for possible values
+ * @param {Map.<opensocial.DataRequest.DataRequestFields, Object>}
+ * opt_params Additional
+ * <a href="opensocial.DataRequest.DataRequestFields.html">params</a>
+ * to pass to the request.
+ * @return {String} The data
+ * @member opensocial.BillingItem
+ */
+opensocial.BillingItem.prototype.getField = function(key, opt_params) {
+ return opensocial.Container.getField(this.fields_, key, opt_params);
+};
+
+
+/**
+ * Sets data for this billing item associated with the given key.
+ *
+ * @param {String} key The key to set data for
+ * @param {String} data The data to set
+ */
+opensocial.BillingItem.prototype.setField = function(key, data) {
+ return this.fields_[key] = data;
+};
+
+
Added: shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/container.js
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/container.js?rev=983579&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/container.js (added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/container.js Mon Aug 9 10:51:20 2010
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * 'License'); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+/**
+ * Requests the container to open a payment processor panel to show and submit
+ * user's order. If the container does not support this method the callback
+ * will be called with a opensocial.ResponseItem. The response item will have
+ * its error code set to NOT_IMPLEMENTED.
+ *
+ * @param {opensocial.Payment} payment The Payment object.
+ * @param {function(opensocial.ResponseItem)=} opt_callback The finishing
+ * callback function.
+ */
+opensocial.Container.prototype.requestPayment = function(payment,
+ opt_callback) {
+ if (opt_callback) {
+ window.setTimeout(function() {
+ opt_callback(new opensocial.ResponseItem(
+ null, payment, opensocial.Payment.ResponseCode.NOT_IMPLEMENTED,
+ null));
+ }, 0);
+ }
+};
+
+/**
+ * Requests the container to open a payment records processor panel to list all
+ * completed or incomplete payments of the user on current app and allowing
+ * users to fix the incomplete payments. If the container does not support
+ * this method the callback will be called with a opensocial.ResponseItem.
+ * The response item will have its error code set to NOT_IMPLEMENTED.
+ *
+ * @param {function(opensocial.ResponseItem)=} opt_callback The finishing
+ * callback function.
+ * @param {Object.<opensocial.Payment.RecordsRequestFields, Object>=}
+ * opt_params Additional parameters to pass to the request.
+ */
+opensocial.Container.prototype.requestPaymentRecords = function(opt_callback,
+ opt_params) {
+ if (opt_callback) {
+ window.setTimeout(function() {
+ opt_callback(new opensocial.ResponseItem(
+ null, payment, opensocial.Payment.ResponseCode.NOT_IMPLEMENTED,
+ null));
+ }, 0);
+ }
+};
+
+
+/**
+ * Creates a payment object.
+ * Creates a payment object.
+ * @param {Map.<opensocial.Payment.Field, Object>} params
+ * Parameters defining the payment object.
+ * @return {opensocial.Payment} The new
+ * <a href="opensocial.Payment.html">Payment</a> object
+ * @private
+ */
+opensocial.Container.prototype.newPayment = function(params) {
+ return new opensocial.Payment(params);
+};
+
+
+/**
+ * Creates a billing item object.
+ * @param {Map.<opensocial.BillingItem.Field, Object>} params
+ * Parameters defining the billing item object.
+ * @return {opensocial.BillingItem} The new
+ * <a href="opensocial.BillingItem.html">BillingItem</a> object
+ * @private
+ */
+opensocial.Container.prototype.newBillingItem = function(params) {
+ return new opensocial.BillingItem(params);
+};
+
Added: shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/feature.xml?rev=983579&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/feature.xml (added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/feature.xml Mon Aug 9 10:51:20 2010
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
+-->
+<feature>
+ <name>opensocial-payment</name>
+ <dependency>core.io</dependency>
+ <dependency>rpc</dependency>
+ <container>
+ <!-- common -->
+ <script src="billingitem.js"/>
+ <script src="payment.js"/>
+ <script src="jsonpayment.js"/>
+ <script src="opensocial.js"/>
+ <!-- container specific -->
+ <script src="paymentprocessor.js"/>
+ <script src="container.js"/>
+ <script src="jsoncontainer.js"/>
+ </container>
+ <gadget>
+ <!-- common -->
+ <script src="billingitem.js"/>
+ <script src="payment.js"/>
+ <script src="jsonpayment.js"/>
+ <script src="opensocial.js"/>
+ </gadget>
+</feature>
+
Added: shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/jsoncontainer.js
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/jsoncontainer.js?rev=983579&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/jsoncontainer.js (added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/jsoncontainer.js Mon Aug 9 10:51:20 2010
@@ -0,0 +1,118 @@
+//TODO - originally done during construction
+// For opensocial virtual currency extension.
+gadgets.rpc.register('shindig.requestPayment_callback',
+ JsonRpcContainer.requestPaymentCallback_);
+// For opensocial virtual currency extension.
+gadgets.rpc.register('shindig.requestPaymentRecords_callback',
+ JsonRpcContainer.requestPaymentRecordsCallback_);
+
+/**
+ * For OpenSocial VirtualCurrency Ext.
+ * The function invokes the whole process of a payment request. It calls the
+ * payment processor open function in parent container.
+ *
+ * @param {opensocial.Payment} payment The Payment object.
+ * @param {function(opensocial.ResponseItem)=} opt_callback The finishing
+ * callback function.
+ * @private
+ */
+JsonRpcContainer.prototype.requestPayment = function(payment, opt_callback) {
+ if (!payment) {
+ if (opt_callback) {
+ opt_callback(new opensocial.ResponseItem(null, payment,
+ opensocial.Payment.ResponseCode.MALFORMED_REQUEST,
+ 'Payment object is undefined.'));
+ }
+ return;
+ }
+
+ var callbackId = "cId_" + Math.random();
+ callbackIdStore[callbackId] = opt_callback;
+ // The rpc target is registered in container payment processor page.
+ gadgets.rpc.call('..', 'shindig.requestPayment',
+ null,
+ callbackId,
+ payment.toJsonObject());
+};
+
+/**
+ * For OpenSocial VirtualCurrency Ext. The callback function of receives the
+ * returned results from the parent container.
+ *
+ * @param {Object.<string, Object>} paymentJson A jsonpayment object with
+ * parameters filled.
+ * @private
+ */
+JsonRpcContainer.requestPaymentCallback_ = function(callbackId, paymentJson) {
+ callback = callbackIdStore[callbackId];
+ if (callback) {
+ var errorCode = opensocial.Payment.ResponseCode[
+ paymentJson[opensocial.Payment.Field.RESPONSE_CODE]];
+ var message = paymentJson[opensocial.Payment.Field.RESPONSE_MESSAGE];
+
+ paymentJson[opensocial.Payment.Field.RESPONSE_CODE] = errorCode;
+ var payment = new JsonPayment(paymentJson, false);
+ var responseItem = new opensocial.ResponseItem(
+ null,
+ payment,
+ (errorCode == opensocial.Payment.ResponseCode.OK ? null : errorCode),
+ message);
+ callback(responseItem);
+ }
+};
+
+/**
+ * For OpenSocial VirtualCurrency Ext.
+ * The function invokes the payment records panel in parent container.
+ *
+ * @param {function(opensocial.ResponseItem)=} opt_callback The finishing
+ * callback function.
+ * @param {Object.<pensocial.Payment.RecordsRequestFields, Object>=}
+ * opt_params Additional parameters to pass to the request.
+ * @private
+ */
+JsonRpcContainer.prototype.requestPaymentRecords = function(opt_callback, opt_params) {
+ var callbackId = "cId_" + Math.random();
+ callbackIdStore[callbackId] = opt_callback;
+
+ // The rpc target is registered in container payment records page.
+ gadgets.rpc.call('..', 'shindig.requestPaymentRecords',
+ null, callbackId, opt_params);
+};
+
+/**
+ * For OpenSocial VirtualCurrency Ext. The callback function of receives the
+ * returned results from the parent container.
+ *
+ * @param {Object.<string, Object>} opt_resultParams The fields set with
+ * result parameters.
+ * @private
+ */
+JsonRpcContainer.requestPaymentRecordsCallback_ = function(callbackId, recordsJson) {
+ callback = callbackIdStore[callbackId];
+ if (callback) {
+ var errorCode = opensocial.Payment.ResponseCode[
+ recordsJson[opensocial.Payment.Field.RESPONSE_CODE]];
+ var message = recordsJson[opensocial.Payment.Field.RESPONSE_MESSAGE];
+ var records = [];
+ var payments = recordsJson['payments'];
+ for (var orderId in payments) {
+ records.push(new JsonPayment(payments[orderId], false));
+ }
+
+ var responseItem = new opensocial.ResponseItem(
+ null,
+ records,
+ (errorCode == opensocial.Payment.ResponseCode.OK ? null : errorCode), message);
+ callback(responseItem);
+ }
+};
+
+
+JsonRpcContainer.prototype.newPayment = function(opt_params) {
+ return new JsonPayment(opt_params, true);
+};
+
+JsonRpcContainer.prototype.newBillingItem = function(opt_params) {
+ return new JsonBillingItem(opt_params);
+};
Added: shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/jsonpayment.js
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/jsonpayment.js?rev=983579&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/jsonpayment.js (added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/jsonpayment.js Mon Aug 9 10:51:20 2010
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*global opensocial */
+
+/**
+ * Base interface for json based payment objects.
+ * NOTE: This class is mainly copied from jsonactivity.js
+ *
+ * @private
+ * @constructor
+ */
+var JsonPayment = function(opt_params, opt_skipConversions) {
+ opt_params = opt_params || {};
+ if (!opt_skipConversions) {
+ JsonPayment.constructArrayObject(opt_params, 'items', JsonBillingItem);
+ }
+ opensocial.Payment.call(this, opt_params);
+};
+JsonPayment.inherits(opensocial.Payment);
+
+JsonPayment.prototype.toJsonObject = function() {
+ var jsonObject = JsonPayment.copyFields(this.fields_);
+
+ var oldBillingItems = jsonObject['items'] || [];
+ var newBillingItems = [];
+ for (var i = 0; i < oldBillingItems.length; i++) {
+ newBillingItems[i] = oldBillingItems[i].toJsonObject();
+ }
+ jsonObject['items'] = newBillingItems;
+
+ return jsonObject;
+};
+
+
+// TODO: Split into separate class
+var JsonBillingItem = function(opt_params) {
+ opensocial.BillingItem.call(this, opt_params);
+};
+JsonBillingItem.inherits(opensocial.BillingItem);
+
+JsonBillingItem.prototype.toJsonObject = function() {
+ return JsonPayment.copyFields(this.fields_);
+};
+
+
+// TODO: Pull this method into a common class, it is from jsonperson.js
+JsonPayment.constructArrayObject = function(map, fieldName, className) {
+ var fieldValue = map[fieldName];
+ if (fieldValue) {
+ for (var i = 0; i < fieldValue.length; i++) {
+ fieldValue[i] = new className(fieldValue[i]);
+ }
+ }
+};
+
+// TODO: Pull into common class as well
+JsonPayment.copyFields = function(oldObject) {
+ var newObject = {};
+ for (var field in oldObject) {
+ newObject[field] = oldObject[field];
+ }
+ return newObject;
+};
+
Added: shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/opensocial.js
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/opensocial.js?rev=983579&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/opensocial.js (added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/opensocial.js Mon Aug 9 10:51:20 2010
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * 'License'); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+
+/**
+ * Requests the container to open a payment processor panel to show and submit
+ * user's order. If the container does not support this method the callback
+ * will be called with a opensocial.ResponseItem. The response item will have
+ * its error code set to NOT_IMPLEMENTED.
+ *
+ * @param {opensocial.Payment} payment The Payment object.
+ * @param {function(opensocial.ResponseItem)=} opt_callback The finishing
+ * callback function.
+ */
+opensocial.requestPayment = function(payment, opt_callback) {
+ opensocial.Container.get().requestPayment(payment, opt_callback);
+};
+
+/**
+ * Requests the container to open a payment records processor panel to list all
+ * completed or incomplete payments of the user on current app and allowing
+ * users to fix the incomplete payments. If the container does not support
+ * this method the callback will be called with a opensocial.ResponseItem.
+ * The response item will have its error code set to NOT_IMPLEMENTED.
+ *
+ * @param {function(opensocial.ResponseItem)=} opt_callback The finishing
+ * callback function.
+ * @param {Object.<opensocial.Payment.RecordsRequestFields, Object>=}
+ * opt_params Additional parameters to pass to the request.
+ */
+opensocial.requestPaymentRecords = function(opt_callback, opt_params) {
+ opensocial.Container.get().requestPaymentRecords(opt_callback, opt_params);
+};
+
+
+/**
+ * Creates a payment object.
+ *
+ * @param {Object.<opensocial.Payment.Field, Object>} params
+ * Parameters defining the payment object.
+ * @return {opensocial.Payment} The new
+ * <a href="opensocial.Payment.html">Payment</a> object
+ * @member opensocial
+ */
+opensocial.newPayment = function(params) {
+ return opensocial.Container.get().newPayment(params);
+};
+
+
+/**
+ * Creates a billing item object.
+ *
+ * @param {Object.<opensocial.BillingItem.Field, Object>} params
+ * Parameters defining the billing item object.
+ * @return {opensocial.BillingItem} The new
+ * <a href="opensocial.BillingItem.html">BillingItem</a> object
+ * @member opensocial
+ */
+opensocial.newBillingItem = function(params) {
+ return opensocial.Container.get().newBillingItem(params);
+};
+
Added: shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/payment.js
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/payment.js?rev=983579&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/payment.js (added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/payment.js Mon Aug 9 10:51:20 2010
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * @class
+ * Representation of a payment.
+ ?
+ * @name opensocial.Payment
+ */
+
+
+/**
+ * Base interface for all payment objects.
+ *
+ * @param {Object.<opensocial.Payment.Field, Object>} params
+ * Parameters defining the payment.
+ * @private
+ * @constructor
+ */
+opensocial.Payment = function(params) {
+ this.fields_ = params || {};
+ this.fields_[opensocial.Payment.Field.PAYMENT_TYPE] =
+ this.fields_[opensocial.Payment.Field.PAYMENT_TYPE] ||
+ opensocial.Payment.PaymentType.PAYMENT;
+};
+
+
+opensocial.Payment.prototype.isPayment = function() {
+ return this.fields_[opensocial.Payment.Field.PAYMENT_TYPE] ==
+ opensocial.Payment.PaymentType.PAYMENT;
+};
+
+opensocial.Payment.prototype.isCredit = function() {
+ return this.fields_[opensocial.Payment.Field.PAYMENT_TYPE] ==
+ opensocial.Payment.PaymentType.CREDIT;
+};
+
+opensocial.Payment.prototype.isComplete = function() {
+ return !!this.fields_[opensocial.Payment.Field.PAYMENT_COMPLETE];
+};
+
+
+/**
+ * @static
+ * @class
+ * All of the fields that a payment object can have.
+ *
+ * <p>The ITEMS, AMOUNT, MESSAGE, PARAMETERS are required for the request. </p>
+ *
+ * <p>And the ORDER_ID, ORDERED_TIME, SUBMITTED_TIME, EXECUTED_TIME fields
+ * will be filled during the procedure and return to the app. </p>
+ * <p>
+ * <b>See also:</b>
+ * <a
+ * href="opensocial.Payment.html#getField">opensocial.Payment.getField()</a>
+ * </p>
+ *
+ * @name opensocial.Payment.Field
+ */
+opensocial.Payment.Field = {
+ /**
+ * @member opensocial.Payment.Field
+ */
+ SANDBOX : 'sandbox',
+
+ /**
+ * @member opensocial.Payment.Field
+ */
+ ITEMS : 'items',
+
+ /**
+ * @member opensocial.Payment.Field
+ */
+ AMOUNT : 'amount',
+
+ /**
+ * @member opensocial.Payment.Field
+ */
+ MESSAGE : 'message',
+
+ /**
+ * @member opensocial.Payment.Field
+ */
+ PARAMETERS : 'parameters',
+
+ /**
+ * @member opensocial.Payment.Field
+ */
+ PAYMENT_TYPE : 'paymentType',
+
+ /**
+ * @member opensocial.Payment.Field
+ */
+ ORDER_ID : 'orderId',
+
+ /**
+ * @member opensocial.Payment.Field
+ */
+ ORDERED_TIME : 'orderedTime',
+
+ /**
+ * @member opensocial.Payment.Field
+ */
+ SUBMITTED_TIME : 'submittedTime',
+
+ /**
+ * @member opensocial.Payment.Field
+ */
+ EXECUTED_TIME : 'executedTime',
+
+ /**
+ * @member opensocial.Payment.Field
+ */
+ RESPONSE_CODE : 'responseCode',
+
+ /**
+ * @member opensocial.Payment.Field
+ */
+ RESPONSE_MESSAGE : 'responseMessage',
+
+ /**
+ * @member opensocial.Payment.Field
+ */
+ PAYMENT_COMPLETE : 'paymentComplete'
+
+};
+
+
+/**
+ * Gets the payment field data that's associated with the specified key.
+ *
+ * @param {string} key The key to get data for;
+ * see the <a href="opensocial.Payment.Field.html">Field</a> class
+ * for possible values
+ * @param {Object.<opensocial.DataRequest.DataRequestFields, Object>=}
+ * opt_params Additional
+ * <a href="opensocial.DataRequest.DataRequestFields.html">params</a>
+ * to pass to the request.
+ * @return {string} The data
+ * @member opensocial.Payment
+ */
+opensocial.Payment.prototype.getField = function(key, opt_params) {
+ return opensocial.Container.getField(this.fields_, key, opt_params);
+};
+
+
+/**
+ * Sets data for this payment associated with the given key.
+ *
+ * @param {string} key The key to set data for
+ * @param {string} data The data to set
+ */
+opensocial.Payment.prototype.setField = function(key, data) {
+ return this.fields_[key] = data;
+};
+
+
+/**
+ * @static
+ * @class
+ * Types for a payment.
+ *
+ * @name opensocial.Payment.PaymentType
+ */
+opensocial.Payment.PaymentType = {
+ /**
+ * @member opensocial.Payment.PaymentType
+ */
+ PAYMENT : 'payment',
+
+ /**
+ * @member opensocial.Payment.PaymentType
+ */
+ CREDIT : 'credit'
+};
+
+
+/**
+ * @static
+ * @class
+ * Possible response codes for the whole payment process.
+ *
+ * @name opensocial.Payment.ResponseCode
+ */
+opensocial.Payment.ResponseCode = {
+ /**
+ * @member opensocial.Payment.ResponseCode
+ */
+ APP_LOGIC_ERROR : 'appLogicError',
+
+ /**
+ * @member opensocial.Payment.ResponseCode
+ */
+ APP_NETWORK_FAILURE : 'appNetworkFailure',
+
+ /**
+ * @member opensocial.Payment.ResponseCode
+ */
+ INSUFFICIENT_MONEY : 'insufficientMoney',
+
+ /**
+ * @member opensocial.Payment.ResponseCode
+ */
+ INVALID_TOKEN : 'invalidToken',
+
+ /**
+ * @member opensocial.Payment.ResponseCode
+ */
+ MALFORMED_REQUEST : 'malformedRequest',
+
+ /**
+ * @member opensocial.Payment.ResponseCode
+ */
+ NOT_IMPLEMENTED : 'notImplemented',
+
+ /**
+ * @member opensocial.Payment.ResponseCode
+ */
+ OK : 'ok',
+
+ /**
+ * @member opensocial.Payment.ResponseCode
+ */
+ PAYMENT_ERROR : 'paymentError',
+
+ /**
+ * @member opensocial.Payment.ResponseCode
+ */
+ PAYMENT_PROCESSOR_ALREADY_OPENED : 'paymentProcessorAlreadyOpened',
+
+ /**
+ * @member opensocial.Payment.ResponseCode
+ */
+ UNKNOWN_ERROR : 'unknownError',
+
+ /**
+ * @member opensocial.Payment.ResponseCode
+ */
+ USER_CANCELLED : 'userCancelled'
+};
+
+
+/**
+ * @static
+ * @class
+ * Request fields for requesting payment records.
+ *
+ * @name opensocial.Payment.RecordsRequestFields
+ */
+opensocial.Payment.RecordsRequestFields = {
+
+ /**
+ * @member opensocial.Payment.RecordsRequestFields
+ */
+ SANDBOX : 'sandbox',
+
+ /**
+ * @member opensocial.Payment.RecordsRequestFields
+ */
+ MAX : 'max',
+
+ /**
+ * @member opensocial.Payment.RecordsRequestFields
+ */
+ INCOMPLETE_ONLY : 'incompleteOnly'
+
+};
+
+
+
+
Added: shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/paymentprocessor.js
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/paymentprocessor.js?rev=983579&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/paymentprocessor.js (added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/opensocial-payment/paymentprocessor.js Mon Aug 9 10:51:20 2010
@@ -0,0 +1,403 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * 'License'); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+/**
+ * @fileoverview Container-side codes as a processor logic for the virtual
+ * currency payment functionality.
+ */
+
+var shindig = shindig || {};
+
+
+/**
+ * @static
+ * @class Provides the virtual currency payment processor features on
+ container side. Handles the payment request from app, prompts the
+ container processor page for user to confirm the payment, and
+ passes the response back to the app. The container need to implement
+ the open/close event functions to fulfill the functionality.
+ * @name shindig.paymentprocessor
+ */
+shindig.paymentprocessor = (function() {
+ /**
+ * The state indicating if the processor panel is on or off.
+ * @type {boolean}
+ */
+ var isOpened_ = false;
+
+ /**
+ * A set of params for the procedure that holds necessary data needed for container
+ * processor panel page. In the implementation of the processor panel page, you can use
+ * <code>getParam</code> function and <code>setParam</code> to access the values in this set. Here
+ * <paymentJson> is the pure json format of an opensocial.Payment object defined on gadget side.
+ * E.g. getParam('payment.orderId') returns the orderId field in paymentJson.
+ *
+ * Here lists the preset data of params set:
+ *
+ * {
+ * frameId : <string>,
+ * appTitle : <string>,
+ * appSpec : <string>,
+ * stoken : <string>,
+ * callbackId : <string>,
+ *
+ * payment : <paymentJson>, // Only for requestPayment process
+ *
+ * records : { // Only for requestPaymentRecords process
+ * responseCode : <string>,
+ * responseMessage : <string>,
+ * payments : {
+ * <orderId> : <paymentJson>,
+ * <orderId> : <paymentJson>,
+ * ...
+ * }
+ * },
+ * reqParams : <object> // Only for requestPaymentRecords process
+ * }
+ *
+ * @type {Object.<string, Object>}
+ */
+ var processorParams_ = null;
+
+ /**
+ * A set of event functions which allow customizing the UI and actions of the
+ * processor panel by container. They are passed in and registered in the
+ * init functions.
+ * @type {Object.<string, function()>}
+ */
+ var events_ = {};
+
+ /**
+ * Initiates the gadget parameters for the current processor. It uses a frameId
+ * which indicates which gadget is requesting payment.
+ *
+ * NOTE: The 'shindig-container' feature is required.
+ * @see /features/shindig-container/
+ *
+ * @return {Object.<string, string>} The gadget meta data.
+ */
+ function initGadgetParams(frameId) {
+ var params = null;
+ if (shindig.container && shindig.container.gadgetService) {
+ params = {};
+ params['frameId'] = frameId;
+
+ // By default, will set the title and spec with default value.
+ params['appTitle'] = 'Unknown Title';
+ params['appSpec'] = 'Unknown SpecUrl';
+ // This part need the shindig.container service support or customized by
+ // container page.
+ var thisGadget = shindig.container.getGadget(
+ shindig.container.gadgetService.getGadgetIdFromModuleId(frameId));
+ if (thisGadget) {
+ params['appTitle'] = thisGadget['title'];
+ params['appSpec'] = thisGadget['specUrl'];
+ params['stoken'] = thisGadget['securityToken'];
+ }
+ }
+ return params;
+ };
+
+
+ /**
+ * Handles the request called via rpc from opensocial.requestPayment on the
+ * app side. Turns on the processor panel.
+ * <p>
+ * The 'this' in this function is the rpc object, thus contains
+ * some information of the app.
+ * </p>
+ * <p>
+ * See the definition of processorParams_ for the structure of the underlying
+ * object.
+ * </p>
+ *
+ * @param {Object.<string, Object>} paymentJson The json object holding the
+ * payment parameters from the app with ITEMS, AMOUNT, MESSAGE and
+ * PARAMETERS fields set. Note that this object is serialized and passed
+ * through RPC channel so all functions are lost.
+ */
+ function openPayment_(callbackId, paymentJson) {
+ // Checks if the processor panel should be opened.
+ if (isOpened_) {
+ // Shouldn't continue if the processor is already opened.
+ paymentJson['responseCode'] = 'PAYMENT_PROCESSOR_ALREADY_OPENED';
+ }
+
+ if (!paymentJson['amount'] || paymentJson['amount'] <= 0) {
+ // TODO: Need more check on the AMOUNT value and other values.
+ paymentJson['responseCode'] = 'MALFORMED_REQUEST';
+ }
+
+ if (!events_['paymentOpen']) {
+ // If the open event handle is not registered, return not-implemented.
+ paymentJson['responseCode'] = 'NOT_IMPLEMENTED';
+ }
+
+ // Initialize the processor parameters.
+ processorParams_ = initGadgetParams(this.f);
+ if (processorParams_ == null) {
+ paymentJson['responseCode'] = 'NOT_IMPLEMENTED';
+ }
+
+ if (paymentJson['responseCode'] && paymentJson['responseCode'] != 'OK') {
+ // callback immediately if any errorcode exists here.
+ try {
+ gadgets.rpc.call(this.f, 'shindig.requestPayment_callback', null,
+ callbackId, paymentJson);
+ } finally {
+ return;
+ }
+ }
+
+ isOpened_ = true;
+
+ // Fill the payment fields before the payment process.
+ paymentJson['orderedTime'] = new Date().getTime();
+ paymentJson['message'] = gadgets.util.escapeString(paymentJson['message']);
+
+ processorParams_['callbackId'] = callbackId;
+ processorParams_['payment'] = paymentJson;
+
+ // Call the container's open event to display the processor panel UI.
+ events_.paymentOpen();
+ };
+
+
+ /**
+ * Invoked by button click event in processor panel on container side to
+ * close the processor panel. Will calls the rpc callback in app.
+ */
+ function closePayment_() {
+ if (!isOpened_) {
+ return;
+ }
+
+ // Call the container's close event to hide the processor panel.
+ // The close event is optional. If not set, do nothing.
+ // (NOTE that the panel is still visible if do nothing...)
+ if (events_.paymentClose) {
+ events_.paymentClose();
+ }
+
+ // Return to the app via rpc.
+ try {
+ gadgets.rpc.call(processorParams_['frameId'],
+ 'shindig.requestPayment_callback',
+ null,
+ processorParams_['callbackId'],
+ processorParams_['payment']);
+ } catch(e) {
+ // TODO
+ } finally {
+ // Reset the underlying data.
+ isOpened_ = false;
+ processorParams_ = null;
+ }
+ };
+
+
+ /**
+ * Handles the request called via rpc from opensocial.requestPaymentRecords
+ * on the app side. Turns on the processor panel.
+ * <p>
+ * The 'this' in this function is the rpc object, thus contains
+ * some information of the app.
+ * </p>
+ * <p>
+ * See the definition of processorParams_ for the structure of the underlying object.
+ * </p>
+ *
+ * @param {Object.<opensocial.Payment.RecordsRequestFields, Object>} reqParams
+ * Additional parameters to pass to the request.
+ */
+ function openPaymentRecords_(callbackId, reqParams) {
+ // This object is for response.
+ var paymentRecordsJson = {'payments' : {}};
+
+ // Checks if the processor panel should be opened.
+ if (isOpened_) {
+ // Shouldn't continue if the processor is already opened.
+ paymentRecordsJson['responseCode'] = 'PAYMENT_PROCESSOR_ALREADY_OPENED';
+ }
+
+ if (!events_['paymentRecordsOpen']) {
+ // If the open event handler is not registered, return not-implemented.
+ paymentRecordsJson['responseCode'] = 'NOT_IMPLEMENTED';
+ }
+
+ if (paymentRecordsJson['responseCode'] &&
+ paymentRecordsJson['responseCode'] != 'OK') {
+ // callback immediately if any errorcode exists here.
+ try {
+ gadgets.rpc.call(this.f, 'shindig.requestPaymentRecords_callback', null,
+ callbackId, paymentRecordsJson);
+ } finally {
+ return;
+ }
+ }
+
+ isOpened_ = true;
+
+ // Initialize the processor parameters.
+ processorParams_ = initGadgetParams(this.f);
+ processorParams_['callbackId'] = callbackId;
+ processorParams_['records'] = paymentRecordsJson;
+
+ processorParams_['reqParams'] = reqParams;
+
+ // Call the container's open event to display the processor panel UI.
+ events_['paymentRecordsOpen']();
+ };
+
+
+ /**
+ * Invoked by button click event in processor panel on container side to
+ * close the processor panel. Will calls the rpc callback in app.
+ */
+ function closePaymentRecords_() {
+ if (!isOpened_) {
+ return;
+ }
+
+ // Call the container's cancel event to do some UI change if needed.
+ if (events_['paymentRecordsClose']) {
+ events_['paymentRecordsClose']();
+ }
+
+ try {
+ // Return to the app via rpc.
+ gadgets.rpc.call(processorParams_['frameId'],
+ 'shindig.requestPaymentRecords_callback',
+ null,
+ processorParams_['callbackId'],
+ processorParams_['records']);
+ } finally {
+ // Reset the underlying data.
+ isOpened_ = false;
+ processorParams_ = null;
+ }
+
+ };
+
+ /**
+ * Accessor to get the parameter value by a key. The key can be chained
+ * using dot symbol. E.g. getParam('foo.bar') will return
+ * processParams_.foo.bar .
+ *
+ * @param {string} key The access key.
+ * @return {Object} The value stored in processParams_ on the given key.
+ */
+ function getParam_(key) {
+ if (!key) return null;
+ var value = null;
+ try {
+ var arr = key.split('.');
+ if (arr.length > 0) {
+ var prop = processorParams_;
+ for (var i = 0; i < arr.length; i++) {
+ prop = prop[arr[i]];
+ }
+ value = prop;
+ }
+ } catch(e) {
+ value = null;
+ }
+ return value;
+ };
+
+ /**
+ * Accessor to set the parameter value by a key. The key can be chained
+ * using dot symbol. E.g. setParam('foo.bar', value) will set the value on
+ * processParams_.foo.bar .
+ *
+ * @param {string} key The access key.
+ * @param {Object} value The value to be set.
+ */
+ function setParam_(key, value) {
+ if (!key) return;
+ try {
+ var arr = key.split('.');
+ if (arr.length > 1) {
+ var prop = processorParams_;
+ for (var i = 0; i < arr.length - 1; i++) {
+ prop = prop[arr[i]];
+ }
+ prop[arr[arr.length - 1]] = value;
+ }
+ } finally {
+ return;
+ }
+ };
+
+ return /** @scope shindig.paymentprocessor */ {
+ /**
+ * Initializes the 'requestPayment' rpc. It's called by container page in
+ * onload function.
+ */
+ initPayment : function(openEvent, closeEvent) {
+ events_.paymentOpen = openEvent;
+ events_.paymentClose = closeEvent;
+ gadgets.rpc.register('shindig.requestPayment', openPayment_);
+ },
+
+ /**
+ * Initializes the 'requestPaymentRecords' rpc. It's called by container
+ * processor page in onload function.
+ */
+ initPaymentRecords : function(openEvent, closeEvent) {
+ events_.paymentRecordsOpen = openEvent;
+ events_.paymentRecordsClose = closeEvent;
+ gadgets.rpc.register('shindig.requestPaymentRecords',
+ openPaymentRecords_);
+ },
+
+ /**
+ * The open function for 'requestPayment' pannel. Invoked by rpc from app.
+ */
+ openPayment : openPayment_,
+
+ /**
+ * The close function for 'requestPayment' pannel. Invoked by button click
+ * event in processor panel on container side.
+ */
+ closePayment : closePayment_,
+
+ /**
+ * The open function for 'requestPaymentRecords' pannel. Invoked by rpc
+ * from app.
+ */
+ openPaymentRecords : openPaymentRecords_,
+
+ /**
+ * The close function for 'requestPaymentRecords' pannel. Invoked by button
+ * click event in processor panel on container side.
+ */
+ closePaymentRecords : closePaymentRecords_,
+
+ /**
+ * Exposes the processor parameters to processor panel.
+ */
+ getParam : getParam_,
+
+ /**
+ * Updates the processor parameters from processor panel.
+ */
+ setParam : setParam_
+ };
+
+})();