How do you declare a static variable in a JavaScript function?
Not with the word “static“.
In JavaScript “function” is a variable type similar to “object“.
The difference is that the reference to a function inside itself is not this but arguments.callee.
An example of using arguments.callee is the following function that returns itself:
functionfunc(){returnarguments.callee;
}
Adding Static Variables
You can add arguments to arguments.callee. To initialize it the first time, check first if it is not defined. For example:
if (typeof(arguments.callee.myStaticVar)!="undefined")
arguments.callee.myStaticVar=0;
Following is an example function in [rhino(http://rhino.org) JavaScript(run from the command line):
function_example(){var thisFunction = arguments.callee;
if (!thisFunction.static){
thisFunction.static=0;
}
++thisFunction.static;
print("This function has been called: " + thisFunction.static + " times");
};
In this example, you can change the static variable’s value without calling the function using _example.static = "some value";.
To prevent this, encapsulate your function using a function called once, for example:
(function(){
function _example(){
var thisFunction = arguments.callee;
if (!thisFunction.static){
thisFunction.static=0;
}
++thisFunction.static;
print("This function has been called: " + thisFunction.static + " times");
};
example=function(){
_example();
}
})();
Now, each time example() is called, it will increment the variablestatic, but the variable cannot be incremented without calling example because _example is private.
cURL is a tool used for browsing the web from the shell or command-line. It supports many internet protocols, such as HTTP, FTM, POP3, IMAP, SMTP and more. See the full list here.
With libcurl installed in your system and the C API, you can browse using a C program. You can also install the extension cURL for PHP.
Steps of a cURL Program
Obtain a curl handle
For example:
$curl_handle = curl_init();
Set options to the handle.
Define the behavior of curl when executing the request: setting the URL, cookie location, variables passed to the server, etc.
In PHP, you can use curl_setop to set a single option, or curl_setopt_array to pass a PHP array.
For example:
Publishing a text message in LinkedIn is simple: surf to LinkedIn, find the relevant form in the response and submit it. I’ve found the login form and the publish form using HTML Dom documents. Then populated post vars according to them, and connected to the URL given in the “action” attribute of the form. The code is run in PHP CLI in Linux (“stty -echo” is a system call that suppresses the echoing of input characters in Linux).
Step I – Surf to LinkedIn
In this step cURL will send a request to get the content in linkedin.com This is the first time, so the user is not logged in, and there are no cookies. The option CURLOPT_USERAGENT will make the server believe that the request has been sent from a real browser. The option CURLOPT_COOKIEJAR will define the file from which to store and retrieve cookies.
Following is the code:
<?php
error_reporting(E_ERROR | E_PARSE); //Suppress warnings
$curl_handle = curl_init();
// Connect to the site for the first time.
curl_setopt($curl_handle,CURLOPT_URL,"https://www.linkedin.com");
curl_setopt($curl_handle,CURLOPT_USERAGENT,'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:35.0) Gecko/20100101 Firefox/35.0');
curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl_handle,CURLOPT_COOKIEJAR,'/tmp/cookies');
$out = curl_exec($curl_handle);
if (!$out){
echo "Error: " . curl_error($curl_handle) . "\n";
die();
}
Step II – Get the Login Form, Populate It, and Submit It
In this step your script will read your e-mail address and password from the standard input (“php://stdin”), then populate the login form, and submit it. Using the Firefox extension DOM Inspector, I found that the Id of the form element is ‘login’, the username (e-mail) field’s name is “session_key”, and the password field’s name is “session_password”. The script willl submit the form with the input fields of type ‘hidden’ and with the entered e-mail and password. If the login was successful, the http code returned in the header would be 302, which means the output is returned from another address.
After a successful login, the relevant data is stored in the cookie jar associated with the cURL handle. This time the script will read the content of the home page with the user logged in. A logged-in user can post status updates. This time, the operation is not complete until the “browser” is referred to the new address. So, we set the cURL option “CURLOPT_FOLLOWLOCATION” to true. In addition, PHP cURL allows to send an associative array as the value of the option “CURLOPT_POSTFIELDS”, a more elegant way to send POST data.
Following is the code:
// Post the message
curl_setopt($curl_handle, CURLOPT_URL, 'https://www.linkedin.com');
$out = curl_exec($curl_handle);
$doc = new DOMDocument();
$doc->loadHTML($out);
$form=$doc->getElementById('share-form');
$inputElements = $form->getElementsByTagName('input');
$length = $inputElements->length;
$inputs=Array();
for ($i=0;$i<$length;$i++){
$elem=$inputElements->item($i);
$name = $elem->getAttribute('name');
$value = $elem->getAttribute('value');
$inputs[$name]=$value;
}
$inputs['postText']="Hello! I am a message sent by a PHP script.";
$inputs['postVisibility2']='EVERYONE';
$keys=array_keys($inputs);
$formAction = $form->getAttribute('action');
if (substr($formAction,0,5)!='http:')
$formAction = 'http://www.linkedin.com' . $formAction;
curl_setopt_array($curl_handle, Array(
CURLOPT_URL=>$formAction,
CURLOPT_POST=>true,
CURLOPT_FOLLOWLOCATION=>true,
CURLOPT_POSTFIELDS=>$inputs
));
$out = curl_exec($curl_handle);
curl_close($curl_handle);
?>
You probably know the SWF file format. This is not just a movie, but also can be an interactive application. SWF files can be created with the Ming PHP extension. You can get information on how to install and use the extension here. The movie format can be extended with a special scripting language, named ActionScript. Ming is not well-documented, so you can download a little API here, and maybe it will help you. There are also class for creating GUI objects, such as buttons, text fields, etc.
Let’s Discuss Some Classes
SWFMovie -The main class for movies, used for creating movies, and writing them to output streams.
Useful functions:
The constructor of course.
add – to add various objects, such as SWFAction scripts, sprites, shapes, buttons, text, etc.
save – to save your work to a file.
output – to send the output to the browser. before you send it, define the MIME type using
header(‘Content-type: application/x-shockwave-flash’);
Notes:
Define the SWF version before you play it, or you will not be able to view the clip. Here‘s an user-contributed example of a way to determine the version and find more useful details. Set the version with ‘ming_useswfversion’.
Use scaling to avoid movies in strange sites at strange screen locations. We’ll discuss it later.
If you have created a movies from another movie, you must have access to the original movie from the new movie.
SWFAction – a class used for creating scripts. The scripts ca add functionality to the movie and make it interactive. It’s only function is the constructor, that takes scripts as its argument. You can use it for adding text fields – including input text fields -, communicate with other sites (using the LoadVars class for example), jumping to other frames, defining events, etc. Add it to your movie clips with the function ‘add’. Read more here.
an example of scaling with this class is:
Stage.scaleMode='noScale';
Note: Error messages are not sent to the log, if they are not syntax errors.
SWFShape – used for creating shapes. This can be used for defining the shape of buttons (need not be rectangular). It can also be added to movie clips. With this class you can draw lines, arcs, and quadratic and cubic Bezzier curves. You can fill your shape with colors, gradients or bitmaps. If your fill is an image, you can create an object of class SWFFill using “addFill ( SWFBitmap $bitmap [, int $flags ] ).”. Then you can fill your shape using ‘setRightFill’ or ‘setLeftFill passing your fill as the argument.
SWFFill – This class does not have a constructor. An instance of this class is created by the function addFill of class SWFShape . It is important to move the fill to the exact location using the function ‘moveTo’ and to scale it using ‘scaleTo”. If you want to use an image at its original dimension, you will probably have to scale it to (20,20) $fill->scaleTo(20,20) because the number of horizontal and vertical twips in a pixel is 20. In addition the fill can be rotated and/or skewed.
SWFButton – A button is a GUI element that triggers an action when clicked. You can add actions, sounds and shapes using the function addAction/setAction, addSound and addShape respectively. You better add a shape, to define the shape and location of the button. The prototype of addShape is ‘void addShape ( SWFShape $shape , int $flags )’. The flags are a combination (using bitwise or) of SWFBUTTON_UP, SWFBUTTON_OVER, SWFBUTTON_DOWN and SWFBUTTON_HIT. These flags define when the button is displayed.
An Example
This is an example of a script that plays a movie backwards:
If you have installed PHP, you probably have the PHP CLI as well. CLI allows you to run PHP scripts from the command line, without a browser or the definition of a virtual site. You can use it to define a Cron Job or a scheduled task, without learning PERL or other scripting languages. In linux, all you have to do is to put the following first line in your file:
#!/usr/bin/php
or
#!/usr/bin/env php
if the path to ‘php’ is ‘/usr/bin/php’ or the path to ‘env’ is ‘/usr/bin/env’.
You should make your PHP script executable as well.
Superglobals are still defined, but this time are empty hashes, i.e. $_GET[“anyname”] will hold the value null.
There are other languages in which you can write LibreOffice macros. One of them is Javascript. If you’ve installed the package “libreoffice-script-provider-js”, you can write Javascript macros. In Linux’ you can use apt-get or rpm to install it.
Javascript macros can be edited from LibreOffice, and is ready to run without compilation.
.In the Developer Guide, you will find how to write macros in Java. Those example can be easily translated to Javascript. You can even implement interfaces and extend classes. For example, you can override an “actionPerformed” method of a button, as shown in the previous post, LibreOffice – The Kakuro Cell Macro.
LibreOffice provides you with a friendlier way to create dialogs:
1. Tools=>Macros=>Organize Dialogs.
2. Edit an existing dialog or a new one.
3. If you added a control, such as a button, double-click it. a window is opened. In the General Tab, you can get or change information such as the name (important if you want to use it in the macro), color, type (“Ok” button, for example), etc. In the Event tab, you can assign macros to events.
The dialog can be created and executed by a macro. Following is an example in LibreOffice Basic:
Sub kakuro_cell DialogLibraries.LoadLibrary( “Standard” )
Clicking “Submit” will run another macro with the event details, and the “Button type” selected in the general tab was “OK”. We can also start our macro by pressing the “tab” key until our button gains focus and then pressing the Enter key, thus the event starting the macro is “Item status change”.
Now, what does event handling look like in a Javascript macro:
event=ARGUMENTS[0]; // Because this macro is a callback, it has the event for first argument.
evtSource=event.Source; // The control that fired the event.
xControl=UnoRuntime.queryInterface(XControl, evtSource);
xControlModel = xControl.getModel();
xPropertySet = UnoRuntime.queryInterface(XPropertySet, xControlModel);
peer=xControl.getPeer(); // The dialog window.
ctx=xControl.getContext();
ctxControlContainer=UnoRuntime.queryInterface(XControlContainer, ctx); // Yes, the window is a control container that contains the button and input fields.
lowerPartControl = ctxControlContainer.getControl("lowerPart");
lowerPartModel=lowerPartControl.getModel();
lowerPartPropertySet=UnoRuntime.queryInterface(XPropertySet,
lowerPartModel);
upperPartControl = ctxControlContainer.getControl("upperPart");
upperPartModel=upperPartControl.getModel();
upperPartPropertySet=UnoRuntime.queryInterface(XPropertySet,
upperPartModel);
How to Translate from Java to Javascript?
The interpreter used by the script provider is named Rhino, an interpreter developed by Mozilla. Rhino is written entirely in Java, and allows developers to embed Java objects within their code.
Importing
To embed a Java object, you should first import it using the command “importClass(Packages.<class-name>);”.
In Javascript, the first command executed is not found inside a function, so instead of an argument of class XScriptContext, a variable named XSCRIPT CONTEXT is supplied upon invocation of a Javascript macro.
Java Objects
Java objects are accessed the same way in both Java and Javascript, but without the casting in the latter because Javascript is loosely type. The “new” command in Javascript has the same syntax as in Java, except for instantiating a Java array.
Instantiating a Java Array
A Javascript array containing Java objects is not a Java array. To instantiate a Java array, you should use class “java.lang.reflect.Array”. This class and other classes from the “reflect” package should not be imported.
To instantiate an array use the function “newInstance(<class>, <integer array>);”. For example: points = java.lang.reflect.Array.newInstance(Point, [1, 3]); Will create a bi-dimensional array with one row and 3 columns of Point objects.
Implementing an Interface or Extending a Class
Use the syntax:
<var> = new <class or interface>(<args>){
<func-name>: function(<args>){
}
}
I think using a spreadsheet document for Sudoku and Kakuro puzzles is great because those documents contain cells where you can place your content: numeric value and text. As you probably know, Kakuro puzzles have squares split by diagonal lines into triangles.
A kakuro puzzle copied to a spreadsheet document
The cells split into triangles are not provided by the office suite and should be crated by the user. The best way to create them is by a macro. The macro can be written in any language that accesses UNO(Universal Network Objects) components. For example: Javascript, Java, BeanShell, Python and Basic.
To learn how to write a HelloWorld script in each language, click here.
Files And Directories
A macro needs an entry point. If your macro is written in Java, it mus have a function with a parameter of type ‘XScriptContext’. The path to function name should be found in a file named ‘parcel-descriptor.xml’. The path includes the package name, the class name, and the function name in the format ‘<pacckage-name>.<class-name>.<function-name>, for example:
“hello.HelloWorld.printHW”.
The parcel-descriptor should also contain the location of the jar file (a zipped directory containing Java classes).
The parcel descriptor is located in ‘<path>/Scripts/java/<Script Dir>/’.
Path may be one of
a user path, such as’ ${HOME}/.config/libreoffice/3/user/’ – for a specific user.
a LibreOffice path, such as ‘/usr/lib/libreoffice/share/’ – for all LibreOffice users
Example:
The function ‘printHW’ is in the class ‘HelloWorld’ in package hello. The package is stored in “${HOME}/.config/libreoffice/3/user/Scripts/java/HelloWorld1/HelloWorld1.jar”
The file “${HOME}/.config/libreoffice/3/user/Scripts/java/HelloWorld1/parcel-descriptor.xml” will look like:
<parcel language=”Java”>
<script language=”Java”>
<locale lang=”en”>
<displayname value=”HelloWorld1″/>
<description>Prints “Hello World”.</description>
</locale>
<functionname value=”hello.HelloWorld.printHW“/>
<logicalname value=”HelloWorld.printHW“/>
<languagedepprops>
<prop name=”classpath” value=”HelloWorld1.jar“/>
</languagedepprops>
</script>
</parcel>
Library Files for the Class Path
Your macro will access classes found in JAR files. Some of the jar files can be found in the Java directory (In my Ubuntu 12.04, it is ‘/usr/share/java’) and some in the ‘libreoffice/program/classes’ (‘/usr/lib/libreoffice/program/classes’).
The files are:
ridl.jar – in ‘/usr/share/java’
unoil.jar – in (‘/usr/lib/libreoffice/program/classes’
unoloader.jar – in ‘/usr/share/java’
jurt.jar – in ‘/usr/share/java’
juh.jar – in ‘/usr/share/java’
Data Types
There are 4 kinds of data types in UNO:
Simple and primitive data types, with equivalents in Java, described here.
Structures – objects with public attributes, described here
Interfaces containing the functions to be used by the programmer, described here.
Services which are everything the module (Draw, Writer, etc) provides to the user, a Spreadsheet cell, for example.
The service implements interfaces and other services. To access the service function, get the relevant interface using ‘UnoRuntime.queryInterface(InterfaceClass, object)’.
To instantiate (or create a Java object from) a service, use the function ‘createInstance’ of the MultiServiceFactory or MultiComponentFactory.
The next post will describe an example macro in java, The Kakuro Cell macro.