BMTD 's Yard of Fun

Technology, Sports, Music, Chinese Essays

Browsing Posts in scripting languages

In my last blog post (http://www.smartpeer.net/2013/10/closeable-kiosk-with-firefox-user-styles/) I used user styles to create a “closeable kiosk” with firefox. Google chrome also supports user styles so similar styles can be applied to Chrome too.

Both firefox and Chrome support another “user scripts”, which “Allows you to customize the way a web page displays or behaves, by using small bits of JavaScript.”. it can be applied to selected pages only, or to all the sites/pages. Here is a way to use user scripts to create a “closeable kiosk.”

steps for chrome:
(1) install the chrome extension “TamperMonkey” from https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo?hl=en.
(2) compose a new user script with the following code:

/ ==UserScript==
// @name       closeit
// @namespace  http://www.smartpeer.net/
// @version    0.1
// @description  close buton
// @copyright  Jie Li
// ==/UserScript==

var closeButton = document.createElement( 'img' );
closeButton.id = 'myCloseButton';
closeButton.title= 'Close the Window';
closeButton.src= 'http://gbpayment.net/hangout/close.png';
GM_addStyle(
    ' #myCloseButton {            ' +
    '    position: fixed;    ' +
    '    top: 2px; right: 8px;   ' +
    '   z-index:1000;   ' +
    ' } '
);
closeButton.addEventListener( 'click', function () {
    window.open('', '_self', '');
    window.close();
    top.close();
}, true );

document.body.appendChild( closeButton );

and click on “settings” tab on the script editor, choose “yes” for “Run only in top frame”. and then enable the script.

for firefox, it’similar, just replace TamperMonkey with the firfox addon “greaseMonkey”.

now if you open the browser in kiosk mode ( fore chrome it needs to be started from command line option “–kiosk”), there is always a big round red “X” close button at the top right corner. clicking on it will close the browser. see screen shot below:

Recently I got request to create a “closeable browser-based kiosk”– basically a browser in full screen mode, can’t be minimized/resized/moved or returned to non-full screen mode, no browser file menus, no address bar/navigation bar so user have to be stay on the same page, and can’t go to other urls. However user should be able to close it using mouse. This is to be deployed on some real kiosk booths like the ones often seen in a museum. There is no keyboard on the kiosk so short cut key combinations like alt-F4 won’t work.

Browsers like Chrome or Internet Explorer already have the built-in kiosk feature. for IE it’s the -k option; for Chrome there is the –kiosk option. if you start the browser with these options you will see the browser in kiosk mode. for firefox, there is the r-kiosk addon. Problem is that there is no way to close the browser with just a mouse once you are in kiosk mode.

One simple solution is to use firefox ‘s userscripts feature to create my own closeable kiosk mode.

the steps are:

(1) from firefox menu. option “tools”–>”options”–>”privacy”–>history, for “firefox will” dripdown, choose “use custom settings for history”, then choose the option (checkbox) “clear history when forefox closes”, then click OK button.

(2) install the “stylish” firefox extension from https://addons.mozilla.org/en-US/firefox/addon/stylish/

(3) open stylish add on, click “write new style”, an editor will open. enter the following code in the editor, then save the style and enable it.

@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);
@media not all and (-moz-windows-compositor){

.statuspanel-label {display:none !important;}
#nav-bar {display:none !important;}
#navigator-toolbox {display:none !important;}
#urlbar-container, #openLocation {display:none !important;}
#minimize-button,#restore-button,#close-button {display:none !important;}

#titlebar-max, #titlebar-min {display:none !important;}
}

now if you start firefox you will see a “closeable kiosk”. for example, “firefox https//accounts.google.com/” you will see the following “kiosk” with only the “X” close window icon on the title bar:

There are other ways to do this as well. For example, we can write some UserScripts in firefox or Chrome to inject some “close window” button onto al the web pages. so that user can always close the browser with mouse even in the native browser kiosk mode. Will give an example how that works later.

One recent problem I encountered was that I had to write a PERL client for an existing document/literal web service. The service is using polymorphism– there are two methods:

Product[] getProducts1(Products[] products1);
Product[] getProducts2();

“Product” is only an interface. Product1 and Product2 are concret classes that implement the “product’ interface. and the objects in the products array are either Product1 objects or Product2 objects;

Interface Product {
    public String getName();
    public void setName(String name);
    public void setIndex( int index);
    public int getIndex();

}

class Product1:Product{
...
}

class Product2:Product{
...
}

By default Soap::lite sends RPC/Encoding messages to the web services. Fortunately there are some resources for how to call a document/literal services such as this MSDN article . The client perl snippet I have below can call the second method “getProducts2” and retrieve the products succesfully:

#!perl -w
  use SOAP::Lite +trace => 'debug';

  my $soap_response = SOAP::Lite
    -> uri('http://localhost:2372/jaxrpc-simple/types')
   -> on_action( sub { join '/', 'http://localhost:2372/jaxrpc-simple/types', $_[1] } )
    -> proxy('http://mmpower:2372/jaxrpc-simple/simple')
    ->getProducts2();

if ($soap_response->fault) {
    print $soap_response->faultcode, " ", $soap_response->faultstring, "\n";
}    

  print $soap_response;
  $results =   $soap_response->result;

for my $t ($soap_response->valueof('//getProducts2Response/result')) {
  while ( my ($key, $value) = each(%$t) ) {
        print "$key => $value\n";
    }
}    

#use custom deserializer to deserialzie it ro objects if necessary
...

But still I don’t know how to call the first method since I need to pass an array of “Products” as a parameter; As suggested in OO Perl packages are used as classes, and objects are normally blessed references of arrays or hashes. This is not straight forward though. After try and error multiple times finally the following code works:

use Tie::IxHash;

{
package Product2;
    sub new {
        my $class = $_[0];
        my %objref;
        $t = tie(%objref, Tie::IxHash);
        %objref = (
                     index    => $_[1],
                     name  => $_[2],
                     ppp => $_[3]
                 );

    bless \%objref, $class;
    return \%objref;
    }

}

{
package Product1;

    sub new {
        my $class = $_[0];
        my %objref;
        $t = tie(%objref, Tie::IxHash);
        %objref = (
                     index    => $_[1],
                     name  => $_[2],
                     ooo => $_[3],
                 );
        @keys = keys %objref;
    @values = values %objref;
    bless \%objref, $class;
    return \%objref;
    }

}

use SOAP::Lite ( +trace => 'debug', maptype => {} );

my $service1 = SOAP::Lite
    -> uri('http://localhost:2372/jaxrpc-simple/types')
   ->maptype({Product1=>'http://localhost:2372/jaxrpc-simple/types', Product2=>'http://localhost:2372/jaxrpc-simple/types', SOAPStruct => 'http://localhost:2372/jaxrpc-simple/types'})
   -> on_action( sub { join '/', 'http://localhost:2372/jaxrpc-simple/types', $_[1] } )
    -> proxy('http://localhost:2372/jaxrpc-simple/simple');

    $service1->serializer->namespaces({"http://schemas.xmlsoap.org/soap/encoding/"=>"SOAP-ENC",
                                        "http://schemas.xmlsoap.org/soap/envelope/"=>"SOAP-ENV","http://www.w3.org/2001/XMLSchema"=>"xsd",
                                        "http://www.w3.org/2001/XMLSchema-instance"=>"xsi"});

my @products;

@products[0] = Product1->new(2,'pro1','ooo1');
@products[1] = Product2->new(3,'pro2','ppp1');
@products[2] = Product1->new(4,'pro3','ooo3');
@products[3] = Product2->new(5,'poro4','pppll4');

my @params = ( SOAP::Data->name("arrayOfProduct_1" => @products)->attr({xmlns => ''}));

my $method = SOAP::Data->name('getProducts')-> attr({xmlns => 'http://localhost:2372/jaxrpc-simple/types'});

$soap_response = $service1->call($method => @params);

if ($soap_response->fault) {
    print $soap_response->faultcode, " ", $soap_response->faultstring, "\n";
}    

for my $t ($soap_response->valueof('//getProductsResponse/result')) {
  while ( my ($key, $value) = each(%$t) ) {
        print "$key => $value\n";
    }
}

Several things to note in the above code:

  • needs to use the “maptype()” method to map the namespace for the Product1 and Product2.
  • need to change the XSD and XSI namespaces to 2001 version. by default soap::lite sets them to “http://www.w3.org/1999/XMLSchema” and “http://www.w3.org/1999/XMLSchema-instance”;
  • since object instance variable is stored in a hash. In perl the default Hash does not gurantee hash key order, so when a “Product1” object is passed as a parameter, the generated soap message is like:
            1
           oooooo
         prodcut1
    
    

    but the server side expects the elements of a product to be in the strict order “index”, “name” and “ooo”, not “index”, “ooo” and “name”. So I have to use a special hash that preserves the key order.

continue reading…