SlideShare a Scribd company logo
1 of 78
Download to read offline
Mozilla Firefox
 Extension Development
   Course 2: Advanced
           Littlebtc
OSSF Workshop / MozTW Acitivity

      The text of the slide is under CC-BY-SA-3.0.
      Most photos are under CC-BY-SA compatible license,
      while screenshots / logos are under Fair Use.
      Code is under MIT license.
Review
• Do you remember…?
  – XUL and controls?
  – Some JavaScript technique?
  – install.rdf and chrome.manifest?
  – Some XPCOM introduction?
Preference System
Make options for your extension
Why preferences?
• Provide options to user
  – Which can be set in an option window
  – Or in the program operation
• Record user's choice
about:config
Available types
• String
• Integer
• Boolean: true / false
Default Preferences
•   Can be included in the Extension Dir / XPI file
•   Will be loaded as default value of preferences
•   Place .js files in [ext-dir]/defaults/preferences/
•   Example of .js file content of default
    preferences :
    pref(quot;extensions.extensionname.preferencenamequot;, false);
    – Name: has a widely used naming convention
    – Value: Boolean / Integer / String
Take an example
• See defaults/preferences/ tutorial.js

pref(quot;extensions.tutorial.option1quot;, false);
pref(quot;extensions.tutorial.option2quot;, quot;quot;);
pref(quot;extensions.tutorial.option3quot;, 32);
pref(quot;extensions.tutorial.default_editorquot;, quot;quot;);
See about:config
Preference System:
             <prefwindow>
• Way to make a quot;option windowquot;
• It is XUL, again
• But it has a special system, in that system,
  you don't need to write too much
  JavaScript/XPCOM to support changing
  preferences.
Set install.rdf, again
<em:optionsURL>chrome://tutorial/content/opt
  ions.xul</em:optionsURL>
• This will point the quot;Optionsquot; button of your
  extension to the corresponding XUL pages:
<prefpane>
• Must be a child of <prefwindow>
• Reprensent a pane (tab) in the prefwindow
• Attributes:
  – label
  – image
  – onpaneload: a onload-like on this panel
  – src: Content can be external XUL
    <prefpane id=quot;paneGeneralquot; label=quot;Generalquot;
    src=quot;chrome://path/to/paneOverlay.xulquot;/>
<preferences> <preference>
• <preferences>: Container
• <preference>: quot;Magic Attributequot; to hold the
  actual preference, attributes:
  – id
  – name: Corresponding preference name
  – type: bool/string/unichar/int/file
• In controls, use preference=quot;idquot; to connect
  the magic!
Example: options.xul
<?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?>
<?xml-stylesheet href=quot;chrome://global/skin/quot; type=quot;text/cssquot;?>
<?xml-stylesheet href=quot;chrome://mozapps/content/preferences/preferences.cssquot;?>
<?xml-stylesheet href=quot;chrome://browser/skin/preferences/preferences.cssquot;?>

<prefwindow xmlns=quot;http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xulquot;>
 <prefpane id=quot;panel1quot; label=quot;panel1quot;>
  <preferences>
   <preference name=quot;extensions.tutorial.option1quot; id=quot;extensions.tutorial.option1quot; type=quot;boolquot; />
   <preference name=quot;extensions.tutorial.option2quot; id=quot;extensions.tutorial.option2quot; type=quot;unicharquot; />
  </preferences>
  <checkbox id=quot;option1quot; preference=quot;extensions.tutorial.option1quot; label=quot;Check me!quot; />
  <hbox>
  <label value=quot;Type Your Name:quot; accesskey=quot;Nquot; control=quot;option2quot; />
  <textbox id=quot;option2quot; preference=quot;extensions.tutorial.option2quot; />
  </hbox>
 </prefpane>
 <prefpane id=quot;panel2quot; label=quot;panel2quot; src=quot;chrome://tutorial/content/panel2.xulquot;/>
</prefwindow>
Example: panel2.xul
<?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?>

<overlay id=quot;Pane2Overlayquot;
    xmlns=quot;http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xulquot;>

 <prefpane id=quot;panel2quot;>
  <preferences>
   <preference name=quot;extensions.tutorial.option3quot; id=quot;extensions.tutorial.option3quot; type=quot;intquot;
    />
  </preferences>
  <hbox>
  <label value=quot;Type a Integer:quot; accesskey=quot;Iquot; control=quot;option3quot; />
  <textbox id=quot;option3quot; preference=quot;extensions.tutorial.option3quot; type=quot;numberquot; />
  </hbox>
 </prefpane>
</overlay>
Result
Part 2: Read/Write in XPCOM
• XPCOM: nsIPrefService / nsIPrefBranch
• Changes Preferences in JavaScript
• First step: Read branch
// Get the root branch
var prefs = Components.classes[quot;@mozilla.org/preferences-service;1quot;]
    .getService(Components.interfaces.nsIPrefBranch);

// Get the quot;extensions.tutorial.quot; branch
var prefs = Components.classes[quot;@mozilla.org/preferences-service;1quot;]
    .getService(Components.interfaces.nsIPrefService);
prefs = prefs.getBranch(quot;extensions.tutorial.quot;);
Part 2: Read/Write in XPCOM
• Then, read/write
• getBoolPref(), setBoolPref()
• getCharPref(), setCharPref()
  – BEWARE: Not Unicode Compatible!
• getIntPref() and setIntPref()
Part 2: Read/Write in XPCOM
Examples to run in JavaScript Shell:
// Get the quot;extensions.tutorial.quot; branch
var prefs = Components.classes[quot;@mozilla.org/preferences-service;1quot;]
    .getService(Components.interfaces.nsIPrefService);
prefs = prefs.getBranch(quot;extensions.tutorial.quot;);

// Get the value of option3 (a number)
var option3 = prefs.getIntPref('option3');
alert(option3);
// Set the value of option1 (a boolean) to true
prefs.setBoolPref('option1', true);
var option1 = prefs.getBoolPref('option1');
alert(option1);
Part 2: Read/Write in XPCOM
• Read/Write Unicode Strings:
(from https://developer.mozilla.org/en/Code_snippets/Preferences)
// Example 1: getting Unicode value
var option2 = prefs.getComplexValue(quot;option2quot;,
    Components.interfaces.nsISupportsString).data;
alert(option2);

// Example 2: setting Unicode value
var str = Components.classes[quot;@mozilla.org/supports-string;1quot;]
    .createInstance(Components.interfaces.nsISupportsString);
str.data = quot;火狐quot;;
prefs.setComplexValue(quot;option2quot;,
    Components.interfaces.nsISupportsString, str);
When you should use XPCOM
• First run:
   – Make a default pref to detect first run
     (Change it after first run processing is ended)
• Dialog to remember something:
   – Like quot;Exit Firefoxquot;:
File Processing
Access local files
https://developer.mozilla.org/en/Code_snippets/File_I%2f%2fO
The nsIFile / nsILocalFile
• nsIFile: Cross-platform File I/O interface
• nsILocalFile: extends nsIFile, can access local
  filesystem
• It is a quot;LOCATION INDICATORquot;
• What can nsILocalFile object do?
   –   Check whether the file exists
   –   Copy / Delete / Move files
   –   Create files / folders
   –   Work as a parameter to a lot of function
        • Saving webpage into files, etc…
quot;Createquot; a nsILocalFile
• With a absolute path:
var file = Components.classes[quot;@mozilla.org/file/local;1quot;]
           .createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(quot;C:quot;);



• quot;Pathquot; should be in a quot;nativequot; way
  like /home/littlebtc in Linux, C: in Windows
• file:// URI? Explained later
quot;Createquot; nsIFile pointing to special
               folders
• Get an object located to Profile Directory:
// get profile directory
var file = Components.classes[quot;@mozilla.org/file/directory_service;1quot;]
             .getService(Components.interfaces.nsIProperties)
             .get(quot;ProfDquot;, Components.interfaces.nsIFile);

• You can replace the ProfD with:
With…                   Where                    With…           Where
CurProcD                (Firefox) Installation   Desk            Desktop
                        Dir                                      C:UsersLittlebtcDesktop
Home                    User's Dir               Progs           quot;Programsquot; directory in
                        C:UsersLittlebtc                       Windows Start Menu
                        /home/littlebtc/
resource:app            XULRunner App
                        Directory
How to…
Assuming we have a nsIFile object file, how to
• Get the native path representation of a nsIFile?
   – file.path
• Know whether the path refers to a existed thing?
   – file.exists()
   – Return true or false
• Distinguish the path which this file object refers
  to from a folder, a file, or a link, or others?
   – Use file.isFile() file.isFolder()
    file.isSymlink() file.isSpecial()
How to…
• Whether the path is
  readable/writable/executable/hidden?
  • Use file.isWritable() file.isReadable()
     file.isExecutable() file.isHidden()
• Know the filesize (if it is a file)?
   – file.fileSize
• The file name without path?
   – file.leafName
• The parent of the path?
   – file.parent   (It is a nsIFile object, and can be null!)
How to…
• quot;Open the filequot; by the OS?
  •   file.launch();

• Do something like quot;Open containing folderquot; in
  download manager?
  •   file.reveal();

• Both of them are not work on Unix-like!
How to…
• Delete the path?
  – file.remove();
  – For folder, you can only remove empty folder
• Copy path?
  – file.copyTo(file2, 'newname');
  – file2     represents the parent path for the target item,
    if it is null, it will be copied to the same parent of file
• Move path?
  – file.moveTo(file2, 'newname');
  – file2 is the same as above
  – You can only move empty folder
How to…
• How to quot;run the filequot; if it is a executable?
  – file.launch(); (Not recommended)
  – Use nsIProcess:
    https://developer.mozilla.org/En/Code_snippets/
    Running_applications
  – nsIProcess cannot accept Unicode parameters on
    Windows… 
How to…
Assuming file is a nsIFile object refering to a folder path, how to:
• Access a file in this directory?
    – file.append('filename');
      Then file will be changed, will refer to this file, not the original
        folder!
• Access multiple files? Clone object, then append
    – var file1 = file.clone(); // Clone file object
      file1.append('filename');
• How to create a subfolder?
    –   file.append(quot;DIRquot;); // Still, append first
        if( !file.exists() || !file.isDirectory() ) {
          // if it doesn't exist, create
          file.create(Components.interfaces.nsIFile.DIRECTORY_TYPE,
        0777);
        }
File contents read/write
• https://developer.mozilla.org/en/Code_snippets/
  File_I%2f%2fO
• A little complex, why? When it comes to the
  encoding, it will be complex 
File Picker / <filefield>
• File Open / File Save / Select Folder Dialog
• See
  https://developer.mozilla.org/en/nsIFilePicker
• <filefield> in the <prefwindow>, like Firefox
  options (UNDOCUMENTED):
  http://www.xuldev.org/blog/?p=142
• We will have a small demo!
File I/O demo 1
• A run dialog like Windows, use undocumented
  <filefield>
run.xul
<?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?>
<?xml-stylesheet href=quot;chrome://global/skinquot; type=quot;text/cssquot;?>

<dialog title=quot;Run applicationquot;   buttons=quot;accept,cancelquot;
    ondialogaccept=quot;runApp.go();quot;
        xmlns=quot;http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xulquot;>
<script type=quot;application/x-javascriptquot; src=quot;chrome://tutorial/content/run.jsquot;/>
<hbox>
<label value=quot;Select an file:quot; accesskey=quot;Fquot; /> <filefield id=quot;filequot; />
<button label=quot;Browse...quot; oncommand=quot;runApp.browse();quot; />
</hbox>
<grid>
<columns> <column flex=quot;1quot; /> <column flex=quot;2quot; /></columns>
<rows>
  <row> <label value=quot;File name:quot; /><label value=quot;quot; id=quot;file_namequot; /> </row>
<row> <label value=quot;File size:quot; /><label value=quot;quot; id=quot;file_sizequot; /> </row>
</rows>
</grid>
</dialog>
run.js (partial)
browse: function() {
   // Initialize file picker
   var fp = Cc[quot;@mozilla.org/filepicker;1quot;].createInstance(Ci.nsIFilePicker);
   fp.init(window, 'Select a file', Ci.nsIFilePicker.modeOpen);

     // Set Filter: file types
     fp.appendFilter('Windows executable', '*.exe');
     fp.appendFilter('All Files', '*.*');

     // Show the dialog
     var result = fp.show();
     if (result == Ci.nsIFilePicker.returnOK) {
       this.file = fp.file;
       // This should not be happened, but this is a demo :P
       if (!this.file.exists() || !this.file.isFile()) {
         return;
       }
       // Include it into filefield
       document.getElementById('file').file = this.file;
       // Load file infos
       document.getElementById('file_name').value = this.file.leafName;
       document.getElementById('file_size').value = this.file.fileSize + ' bytes';
     }
},
run.js (partial 2)
go: function() {
    if (this.file && this.file.exists() &&
  this.file.isFile()) {
       this.file.launch();
    }
 }
URI Problem
• In XPCOM, nsIURI is a common interface to represent
  an URI (It can handle all types of URI)
• nsIURI <-> String URL: Use nsIIOService
   – var uri =
      Components.classes[quot;@mozilla.org/network/io-service;1quot;]
     .getService(Components.interfaces.nsIIOService)
     .newURI('http://moztw.org/', null, null);
   – uri.spec will   contain the string representation of the URI
• nsIURI <-> nsIFile
   – var file_uri =
      Components.classes[quot;@mozilla.org/network/io-service;1quot;]
      .getService(Components.interfaces.nsIIOService)
     .newFileURI(file); // Assuming file is a nsIFIle
   –    var file =
       file_uri.QueryInterface(Components.interfaces.nsIFileURL)
       .file;
When you will need nsIURI / nsIFile
• Downloading files
  https://developer.mozilla.org/en/Code_snippets/
  Downloading_Files (Basic)
  http://www.xuldev.org/blog/?p=163 (Advanced,
  by Gomita, a good intro to nsIWebBrowserPersist)
• Use Places API (Bookmarks, Tags, History)
  https://developer.mozilla.org/en/Places
• Progress listeners
  https://developer.mozilla.org/en/Code_snippets/
  Progress_Listeners
• And much more…
Tree
A somehow complex XUL structure
What is a tree?
• A complex item lists
• An item may have some childs
Why is it so complex
•   There are A LOT OF way to implement
•   But none of them are NOT trivial 
•   Some is easier but not so easy to be extended
•   Some is harder, but fully functional
The easiest: Content Tree
•   (Try XUL Editor!)
•   From https://developer.mozilla.org/En/XUL/Tree
<tree flex=quot;1quot; rows=quot;2quot;>
 <treecols>
  <treecol id=quot;senderquot; label=quot;Senderquot; flex=quot;1quot;/> <treecol id=quot;subjectquot; label=quot;Subjectquot; flex=quot;2quot;/>
 </treecols>
 <treechildren>
  <treeitem>
   <treerow>
    <treecell label=quot;joe@somewhere.comquot;/>        <treecell label=quot;Top secret plansquot;/>
   </treerow>
  </treeitem>
  <treeitem>
   <treerow>
    <treecell label=quot;mel@whereever.comquot;/>       <treecell label=quot;Let's do lunchquot;/>
   </treerow>
  </treeitem>
 </treechildren>
</tree>
The easiest: Content Tree
• <tree>: Sent a row number as rows attribute is
  recommended?
• <treecols>, <treecol>: Define the columns
  – Use flex to modify column width in <treecol>
  – Use id to build an identifier of the column
• <treeitem>, <treerow>: Represents a row
• <treecell>: Represents a cell
  – Attribute: label
A tree with nested items
From https://developer.mozilla.org/En/XUL/Tree

<tree id=quot;myTreequot; flex=quot;1quot; hidecolumnpicker=quot;falsequot; seltype=quot;singlequot; class=quot;treequot; rows=quot;5quot;>
 <treecols id=quot;myTree2-treeColsquot;>
  <treecol id=quot;myTree2-treeCol0quot; primary=quot;truequot; flex=quot;2quot; label=quot;Column Aquot; persist=quot;widthquot; ordinal=quot;1quot;/>
  <splitter class=quot;tree-splitterquot; ordinal=quot;2quot;/>
  <treecol id=quot;myTree2-treeCol1quot; flex=quot;1quot; label=quot;Column Bquot; persist=quot;widthquot; ordinal=quot;3quot;/>
 </treecols>
 <treechildren>
  <treeitem>
   <treerow>
    <treecell label=quot;1quot;/>       <treecell label=quot;aquot;/>
   </treerow>
  </treeitem>
  <!-- Make sure to set container=quot;truequot; -->
  <treeitem container=quot;truequot; open=quot;truequot;>
   <treerow>
    <treecell label=quot;2quot;/>       <treecell label=quot;bquot;/>
   </treerow>
   <treechildren>
    <treeitem>
      <treerow>
       <treecell label=quot;2aquot;/>         <treecell label=quot;baquot;/>
      </treerow>
    </treeitem>
   </treechildren>
  </treeitem>
 </treechildren>
</tree>
Wait, a lot of new thing…?
• <splitter>: Between columns, to make them
  resizable
• Nested items: <treechildren> under <treeitem>
• hidecolumnpicker=quot;falsequot;
  – Whether to hide the column picker on the right
  – seltype=quot;singlequot;: you can select only one item
    or seltype=quot;multiplequot; for multiple selection support
• persist=quot;attributename1 attributename2quot;
  – Make Firefox quot;rememberquot; user's settings on specific
    attribute
OK, now, what is wrong?
• Though we can multiply the tree with DOM,
  but it will the code will be somehow complex
  due to the bad XUL structure
• So DOM way is not a popular way if it comes
  to dynamic content trees
The most common:
               Custom TreeView
• Implements nsITreeView to create a tree
• Set custom tree view into view property
• It can be fully functional and dynamic
   – …But somehow hard: poorly documented and buggy if having
     bad implementation
   – You should check Firefox's code to understand 
   – It takes me almost 20 hours to make <tree> on NicoFox works
     and another 20 hours to fix bugs…
• Are you ready? :D
https://developer.mozilla.org/en/XUL_Tutorial/Custom_Tree_
   Views
http://www.xuldev.org/blog/?p=127 (Thank you again,
   Gomita!)
Tree Selection / Box Object
• Tree Selection: Get currently selected items
  https://developer.mozilla.org/en/XUL_Tutorial/Tr
  ee_Selection
  – A little like text selection we had mentioned at the
    previous lecture (?)
• Box Objects: Handle Tree's display
  Needed, for example, if you need to know the
  which cell the cursor is at
  https://developer.mozilla.org/en/XUL_Tutorial/Tr
  ee_Box_Objects
Take a break, there is a final boss: SQLite!

LUNCH TIME AGAIN!
Storage: SQLite
Great storage choice
What is SQLite?
• A lightweight relational database
  management system
• Its C/C++ library is very small (418KB in Firefox
  3.5) and very easy-to-use
• Can use most of the SQL command
• Resulting database is a single file
• PUBLIC DOMAIN!(No any copyright restriction)
• Used by a lot of software / framework
SQLite is in …
•   Firefox, Safari, Google Chrome
•   Google Gears
•   Photoshop lightroom, Adobe AIR
•   Skype, McAfee, Songbird
•   PHP, Python…
•   iPhone, Symbian, Android…
•   Almost everywhere!!!!
Now, make a new database!
Now, make a new database!
• Find your profile dir and copy the path Orz
Now, make a new database!
• Close SQLite manager and restart:
Create a table
Table is ready!
Add a record
Simple way to display SQLite DB
• Use template
  https://developer.mozilla.org/en/XUL/Templat
  e_Guide/SQLite_Templates
• Simple, but useful for our demo! :D
• We will use the template technique and
  <tree> in the following demo
students.xul
<tree flex=quot;1quot;>
 <treecols>
  <treecol id=quot;col-noquot; label=quot;Noquot; flex=quot;1quot;/>
  <treecol id=quot;col-namequot; label=quot;Namequot; flex=quot;1quot;/>
  <treecol id=quot;col-scorequot; label=quot;Scorequot; flex=quot;1quot;/>
 </treecols>
 <treechildren datasources=quot;profile:tutorial.sqlitequot; ref=quot;*quot; querytype=quot;storagequot;>
  <template>
   <query>
     SELECT * FROM students ORDER BY score DESC
   </query>
   <action>
     <treeitem uri=quot;?quot;>
      <treerow>
       <treecell label=quot;?noquot;/>
       <treecell label=quot;?namequot;/>
       <treecell label=quot;?scorequot;/>
      </treerow>
     </treeitem>
   </action>
  </template>
 </treechildren>
</tree>
Explain
• <treechildren datasources=quot;profile:tutorial.sqlitequot;
  ref=quot;*quot; querytype=quot;storagequot;>
• Use SQLite database as a template datasources
• <template>: <query> and <action>
   – <query>: SQL command
      • SELECT * FROM students: Select all fields from students table
      • ORDER BY score DESC: Order by score field in descendant order
   – <action>: Applied template
      • uri=quot;?quot;: (?)
      • Read score field from ?score
mozStorage API
• Mozilla's way to multiply SQLite database
• So it is XPCOM again … 
• But it is not so difficult!

• I don't want to talk in detail, so go straight to
  examples!
Final Demo:
quot;Add a recordquot; function
A SQL preview
• INSERT INTO students (name, score) VALUES
  (quot;Littlebtcquot;, 30)
• Insert a data into students table
• Two fields: name and score
• Their values: Littlebtc and 30
students.xul, again
<hbox>
<label value=quot;Student Name:quot; accesskey=quot;Nquot; control=quot;new_namequot; />
<textbox id=quot;new_namequot; style=quot;width: 8em;quot;/>

<label value=quot;Score:quot; accesskey=quot;Squot; control=quot;new_scorequot; />
<textbox id=quot;new_scorequot; type=quot;numberquot; style=quot;width: 4em;quot;
   max=quot;100quot; min=quot;0quot;/>

<button label=quot;Addquot; oncommand=quot;students.add();quot;/>
</hbox>
student.js: student.add();
/* use nsIPromptService to alert */
    /*
   https://developer.mozilla.org/en/Code_snippets/Dialogs_and_Prom
   pts */
    var prompts = Cc[quot;@mozilla.org/embedcomp/prompt-service;1quot;]
                  .getService(Ci.nsIPromptService);

    /* Record user's choice */
    var name = document.getElementById('new-name').value;
    var score = document.getElementById('new-score').value;

    /* Required to enter a name */
    if (!name) {
      prompts.alert(null, 'Error', 'Please Enter a Name.');
      return;
    }
…continued
   try { // try-catch exception handling

     /* We will see here later */
   } catch(e) { // There may be some error in XPCOM, we can handle it
     prompts.alert(null, 'Error', 'Database/XPCOM Error:' + e);
   }


• XPCOM Will throw exception when error
• So we need a good way to handle it
• …Or it will be displayed in the error console
Connect to DB
/* Find the tutorial.sqlite */
var file = Components.classes[quot;@mozilla.org/file/directory_service;1quot;]
                     .getService(Components.interfaces.nsIProperties)
                     .get(quot;ProfDquot;, Components.interfaces.nsIFile);
file.append(quot;tutorial.sqlitequot;);

/* Open database */
var storageService = Cc[quot;@mozilla.org/storage/service;1quot;]
                     .getService(Ci.mozIStorageService);
var db = storageService.openDatabase(file);
Execute a quot;statementquot;
var sql = quot;INSERT INTO students (name, score) VALUES
  (?1, ?2)quot;;
var statement = db.createStatement(sql);
statement.bindUTF8StringParameter(0, name);
statement.bindInt32Parameter(1, score);
/* Execute the statement */
statement.execute();
/* Finallize */
statement.finalize();

•   quot;Statementquot; is a SQL command in mozStorage
•   Why we should use the quot;bindingquot; way?
    Prevent SQL injection, make database safe
•   https://developer.mozilla.org/en/mozIStorageStatemen
    t#Binding_Functions
Finally…
• Don't forget to close your DB!

   db.close();
After try{…} catch{…}
• We should update the tree and show a
  message
/* Update the tree */
document.getElementById('students-treechildren')
.builder.rebuild();

/* Prompt the user */
prompts.alert(null, 'OK', 'Thank you!');
Working Example
How to do for you later
• Understand how to CRUD (Create, Read,
  Update, Delete) in SQLite
  – SQL commands: INSERT, SELECT, UPDATE, DELETE
• Remember: Always Binding, NEVER directly
  apply variables into SQL command strings
  – Google quot;SQL Injectionquot; for details
• SQLite is simple but powerful – have fun!
This is the basic!
• Actually, SQLite storage access with <tree> is
  usually implemented in Custom Tree View way,
  both in Firefox and NicoFox
• That is another reason that I had spent 40 hours
  on a tree
• Edit / Remove may be a very hard work
It is 5:34am, I had finished my slide 

THANK YOU!
…….NOT YET!!!
Ext 0523

More Related Content

What's hot

Test legacy apps with Behat
Test legacy apps with BehatTest legacy apps with Behat
Test legacy apps with Behatagpavlakis
 
Introduction To Ant
Introduction To AntIntroduction To Ant
Introduction To AntRajesh Kumar
 
Jumpstart Django
Jumpstart DjangoJumpstart Django
Jumpstart Djangoryates
 
JSUG - Spring by Christoph Pickl
JSUG - Spring by Christoph PicklJSUG - Spring by Christoph Pickl
JSUG - Spring by Christoph PicklChristoph Pickl
 
Laravel 로 배우는 서버사이드 #5
Laravel 로 배우는 서버사이드 #5Laravel 로 배우는 서버사이드 #5
Laravel 로 배우는 서버사이드 #5성일 한
 
Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Fabien Potencier
 
Web applications with Catalyst
Web applications with CatalystWeb applications with Catalyst
Web applications with Catalystsvilen.ivanov
 
Service approach for development REST API in Symfony2
Service approach for development REST API in Symfony2Service approach for development REST API in Symfony2
Service approach for development REST API in Symfony2Sumy PHP User Grpoup
 
05 File Handling Upload Mysql
05 File Handling Upload Mysql05 File Handling Upload Mysql
05 File Handling Upload MysqlGeshan Manandhar
 
B-Translator as a Software Engineering Project
B-Translator as a Software Engineering ProjectB-Translator as a Software Engineering Project
B-Translator as a Software Engineering ProjectDashamir Hoxha
 
Django Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, TricksDjango Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, TricksShawn Rider
 
Codeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept ImplementationCodeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept ImplementationAbdul Malik Ikhsan
 
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...Puppet
 
Zend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_ToolZend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_ToolGordon Forsythe
 

What's hot (20)

Ant User Guide
Ant User GuideAnt User Guide
Ant User Guide
 
Test legacy apps with Behat
Test legacy apps with BehatTest legacy apps with Behat
Test legacy apps with Behat
 
Introduction To Ant
Introduction To AntIntroduction To Ant
Introduction To Ant
 
Jumpstart Django
Jumpstart DjangoJumpstart Django
Jumpstart Django
 
Sprockets
SprocketsSprockets
Sprockets
 
Anatomy of a reusable module
Anatomy of a reusable moduleAnatomy of a reusable module
Anatomy of a reusable module
 
JSUG - Spring by Christoph Pickl
JSUG - Spring by Christoph PicklJSUG - Spring by Christoph Pickl
JSUG - Spring by Christoph Pickl
 
Laravel 로 배우는 서버사이드 #5
Laravel 로 배우는 서버사이드 #5Laravel 로 배우는 서버사이드 #5
Laravel 로 배우는 서버사이드 #5
 
Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3
 
Django
DjangoDjango
Django
 
Web applications with Catalyst
Web applications with CatalystWeb applications with Catalyst
Web applications with Catalyst
 
Service approach for development REST API in Symfony2
Service approach for development REST API in Symfony2Service approach for development REST API in Symfony2
Service approach for development REST API in Symfony2
 
05 File Handling Upload Mysql
05 File Handling Upload Mysql05 File Handling Upload Mysql
05 File Handling Upload Mysql
 
B-Translator as a Software Engineering Project
B-Translator as a Software Engineering ProjectB-Translator as a Software Engineering Project
B-Translator as a Software Engineering Project
 
Django Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, TricksDjango Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, Tricks
 
Codeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept ImplementationCodeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept Implementation
 
Spl in the wild
Spl in the wildSpl in the wild
Spl in the wild
 
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...
 
Zend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_ToolZend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_Tool
 
Pluggin creation
Pluggin creationPluggin creation
Pluggin creation
 

Viewers also liked

090807social
090807social090807social
090807sociallittlebtc
 
Jetpack and Jetpack Reboot
Jetpack and Jetpack RebootJetpack and Jetpack Reboot
Jetpack and Jetpack Rebootlittlebtc
 
FURP12-Snappy
FURP12-SnappyFURP12-Snappy
FURP12-Snappylittlebtc
 
MozTW YZU CSE Lecture
MozTW YZU CSE LectureMozTW YZU CSE Lecture
MozTW YZU CSE Lecturelittlebtc
 
Mozilla Firefox Extension Development, Course 1: Basic
Mozilla Firefox Extension Development, Course 1: BasicMozilla Firefox Extension Development, Course 1: Basic
Mozilla Firefox Extension Development, Course 1: Basiclittlebtc
 
MoZH propose
MoZH proposeMoZH propose
MoZH proposelittlebtc
 
寫給大家的 Git 教學
寫給大家的 Git 教學寫給大家的 Git 教學
寫給大家的 Git 教學littlebtc
 

Viewers also liked (7)

090807social
090807social090807social
090807social
 
Jetpack and Jetpack Reboot
Jetpack and Jetpack RebootJetpack and Jetpack Reboot
Jetpack and Jetpack Reboot
 
FURP12-Snappy
FURP12-SnappyFURP12-Snappy
FURP12-Snappy
 
MozTW YZU CSE Lecture
MozTW YZU CSE LectureMozTW YZU CSE Lecture
MozTW YZU CSE Lecture
 
Mozilla Firefox Extension Development, Course 1: Basic
Mozilla Firefox Extension Development, Course 1: BasicMozilla Firefox Extension Development, Course 1: Basic
Mozilla Firefox Extension Development, Course 1: Basic
 
MoZH propose
MoZH proposeMoZH propose
MoZH propose
 
寫給大家的 Git 教學
寫給大家的 Git 教學寫給大家的 Git 教學
寫給大家的 Git 教學
 

Similar to Ext 0523

Slides Aquarium Paris 2008
Slides Aquarium Paris 2008Slides Aquarium Paris 2008
Slides Aquarium Paris 2008julien.ponge
 
Php Documentor The Beauty And The Beast
Php Documentor The Beauty And The BeastPhp Documentor The Beauty And The Beast
Php Documentor The Beauty And The BeastBastian Feder
 
CICON2010: Adam Griffiths - CodeIgniter 2
CICON2010: Adam Griffiths - CodeIgniter 2CICON2010: Adam Griffiths - CodeIgniter 2
CICON2010: Adam Griffiths - CodeIgniter 2CodeIgniter Conference
 
How to? Drupal developer toolkit. Dennis Povshedny.
How to? Drupal developer toolkit. Dennis Povshedny.How to? Drupal developer toolkit. Dennis Povshedny.
How to? Drupal developer toolkit. Dennis Povshedny.DrupalCampDN
 
Troubleshooting Plone
Troubleshooting PloneTroubleshooting Plone
Troubleshooting PloneRicado Alves
 
Eclipse Pdt2.0 26.05.2009
Eclipse Pdt2.0 26.05.2009Eclipse Pdt2.0 26.05.2009
Eclipse Pdt2.0 26.05.2009Bastian Feder
 
Php Development With Eclipde PDT
Php Development With Eclipde PDTPhp Development With Eclipde PDT
Php Development With Eclipde PDTBastian Feder
 
Drupal 8, Where Did the Code Go? From Info Hook to Plugin
Drupal 8, Where Did the Code Go? From Info Hook to PluginDrupal 8, Where Did the Code Go? From Info Hook to Plugin
Drupal 8, Where Did the Code Go? From Info Hook to PluginAcquia
 
Fluent Development with FLOW3 1.0
Fluent Development with FLOW3 1.0Fluent Development with FLOW3 1.0
Fluent Development with FLOW3 1.0Robert Lemke
 
NYPHP March 2009 Presentation
NYPHP March 2009 PresentationNYPHP March 2009 Presentation
NYPHP March 2009 Presentationbrian_dailey
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy CodeRowan Merewood
 
Optimize Site Deployments with Drush (DrupalCamp WNY 2011)
Optimize Site Deployments with Drush (DrupalCamp WNY 2011)Optimize Site Deployments with Drush (DrupalCamp WNY 2011)
Optimize Site Deployments with Drush (DrupalCamp WNY 2011)Jon Peck
 
Java Builds with Maven and Ant
Java Builds with Maven and AntJava Builds with Maven and Ant
Java Builds with Maven and AntDavid Noble
 

Similar to Ext 0523 (20)

Demystifying Maven
Demystifying MavenDemystifying Maven
Demystifying Maven
 
Deploy Flex with Apache Ant
Deploy Flex with Apache AntDeploy Flex with Apache Ant
Deploy Flex with Apache Ant
 
Ch23 system administration
Ch23 system administration Ch23 system administration
Ch23 system administration
 
Slides Aquarium Paris 2008
Slides Aquarium Paris 2008Slides Aquarium Paris 2008
Slides Aquarium Paris 2008
 
Php Documentor The Beauty And The Beast
Php Documentor The Beauty And The BeastPhp Documentor The Beauty And The Beast
Php Documentor The Beauty And The Beast
 
CICON2010: Adam Griffiths - CodeIgniter 2
CICON2010: Adam Griffiths - CodeIgniter 2CICON2010: Adam Griffiths - CodeIgniter 2
CICON2010: Adam Griffiths - CodeIgniter 2
 
How to? Drupal developer toolkit. Dennis Povshedny.
How to? Drupal developer toolkit. Dennis Povshedny.How to? Drupal developer toolkit. Dennis Povshedny.
How to? Drupal developer toolkit. Dennis Povshedny.
 
Troubleshooting Plone
Troubleshooting PloneTroubleshooting Plone
Troubleshooting Plone
 
Eclipse Pdt2.0 26.05.2009
Eclipse Pdt2.0 26.05.2009Eclipse Pdt2.0 26.05.2009
Eclipse Pdt2.0 26.05.2009
 
Php Development With Eclipde PDT
Php Development With Eclipde PDTPhp Development With Eclipde PDT
Php Development With Eclipde PDT
 
Drupal 8, Where Did the Code Go? From Info Hook to Plugin
Drupal 8, Where Did the Code Go? From Info Hook to PluginDrupal 8, Where Did the Code Go? From Info Hook to Plugin
Drupal 8, Where Did the Code Go? From Info Hook to Plugin
 
Having Fun with Play
Having Fun with PlayHaving Fun with Play
Having Fun with Play
 
Fluent Development with FLOW3 1.0
Fluent Development with FLOW3 1.0Fluent Development with FLOW3 1.0
Fluent Development with FLOW3 1.0
 
Cooking with Chef
Cooking with ChefCooking with Chef
Cooking with Chef
 
Introduction To JSFL
Introduction To JSFLIntroduction To JSFL
Introduction To JSFL
 
NYPHP March 2009 Presentation
NYPHP March 2009 PresentationNYPHP March 2009 Presentation
NYPHP March 2009 Presentation
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
Drupal development
Drupal development Drupal development
Drupal development
 
Optimize Site Deployments with Drush (DrupalCamp WNY 2011)
Optimize Site Deployments with Drush (DrupalCamp WNY 2011)Optimize Site Deployments with Drush (DrupalCamp WNY 2011)
Optimize Site Deployments with Drush (DrupalCamp WNY 2011)
 
Java Builds with Maven and Ant
Java Builds with Maven and AntJava Builds with Maven and Ant
Java Builds with Maven and Ant
 

Recently uploaded

Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 

Recently uploaded (20)

Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 

Ext 0523

  • 1. Mozilla Firefox Extension Development Course 2: Advanced Littlebtc OSSF Workshop / MozTW Acitivity The text of the slide is under CC-BY-SA-3.0. Most photos are under CC-BY-SA compatible license, while screenshots / logos are under Fair Use. Code is under MIT license.
  • 2. Review • Do you remember…? – XUL and controls? – Some JavaScript technique? – install.rdf and chrome.manifest? – Some XPCOM introduction?
  • 3. Preference System Make options for your extension
  • 4. Why preferences? • Provide options to user – Which can be set in an option window – Or in the program operation • Record user's choice
  • 6. Available types • String • Integer • Boolean: true / false
  • 7. Default Preferences • Can be included in the Extension Dir / XPI file • Will be loaded as default value of preferences • Place .js files in [ext-dir]/defaults/preferences/ • Example of .js file content of default preferences : pref(quot;extensions.extensionname.preferencenamequot;, false); – Name: has a widely used naming convention – Value: Boolean / Integer / String
  • 8. Take an example • See defaults/preferences/ tutorial.js pref(quot;extensions.tutorial.option1quot;, false); pref(quot;extensions.tutorial.option2quot;, quot;quot;); pref(quot;extensions.tutorial.option3quot;, 32); pref(quot;extensions.tutorial.default_editorquot;, quot;quot;);
  • 10. Preference System: <prefwindow> • Way to make a quot;option windowquot; • It is XUL, again • But it has a special system, in that system, you don't need to write too much JavaScript/XPCOM to support changing preferences.
  • 11. Set install.rdf, again <em:optionsURL>chrome://tutorial/content/opt ions.xul</em:optionsURL> • This will point the quot;Optionsquot; button of your extension to the corresponding XUL pages:
  • 12. <prefpane> • Must be a child of <prefwindow> • Reprensent a pane (tab) in the prefwindow • Attributes: – label – image – onpaneload: a onload-like on this panel – src: Content can be external XUL <prefpane id=quot;paneGeneralquot; label=quot;Generalquot; src=quot;chrome://path/to/paneOverlay.xulquot;/>
  • 13. <preferences> <preference> • <preferences>: Container • <preference>: quot;Magic Attributequot; to hold the actual preference, attributes: – id – name: Corresponding preference name – type: bool/string/unichar/int/file • In controls, use preference=quot;idquot; to connect the magic!
  • 14. Example: options.xul <?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?> <?xml-stylesheet href=quot;chrome://global/skin/quot; type=quot;text/cssquot;?> <?xml-stylesheet href=quot;chrome://mozapps/content/preferences/preferences.cssquot;?> <?xml-stylesheet href=quot;chrome://browser/skin/preferences/preferences.cssquot;?> <prefwindow xmlns=quot;http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xulquot;> <prefpane id=quot;panel1quot; label=quot;panel1quot;> <preferences> <preference name=quot;extensions.tutorial.option1quot; id=quot;extensions.tutorial.option1quot; type=quot;boolquot; /> <preference name=quot;extensions.tutorial.option2quot; id=quot;extensions.tutorial.option2quot; type=quot;unicharquot; /> </preferences> <checkbox id=quot;option1quot; preference=quot;extensions.tutorial.option1quot; label=quot;Check me!quot; /> <hbox> <label value=quot;Type Your Name:quot; accesskey=quot;Nquot; control=quot;option2quot; /> <textbox id=quot;option2quot; preference=quot;extensions.tutorial.option2quot; /> </hbox> </prefpane> <prefpane id=quot;panel2quot; label=quot;panel2quot; src=quot;chrome://tutorial/content/panel2.xulquot;/> </prefwindow>
  • 15. Example: panel2.xul <?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?> <overlay id=quot;Pane2Overlayquot; xmlns=quot;http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xulquot;> <prefpane id=quot;panel2quot;> <preferences> <preference name=quot;extensions.tutorial.option3quot; id=quot;extensions.tutorial.option3quot; type=quot;intquot; /> </preferences> <hbox> <label value=quot;Type a Integer:quot; accesskey=quot;Iquot; control=quot;option3quot; /> <textbox id=quot;option3quot; preference=quot;extensions.tutorial.option3quot; type=quot;numberquot; /> </hbox> </prefpane> </overlay>
  • 17. Part 2: Read/Write in XPCOM • XPCOM: nsIPrefService / nsIPrefBranch • Changes Preferences in JavaScript • First step: Read branch // Get the root branch var prefs = Components.classes[quot;@mozilla.org/preferences-service;1quot;] .getService(Components.interfaces.nsIPrefBranch); // Get the quot;extensions.tutorial.quot; branch var prefs = Components.classes[quot;@mozilla.org/preferences-service;1quot;] .getService(Components.interfaces.nsIPrefService); prefs = prefs.getBranch(quot;extensions.tutorial.quot;);
  • 18. Part 2: Read/Write in XPCOM • Then, read/write • getBoolPref(), setBoolPref() • getCharPref(), setCharPref() – BEWARE: Not Unicode Compatible! • getIntPref() and setIntPref()
  • 19. Part 2: Read/Write in XPCOM Examples to run in JavaScript Shell: // Get the quot;extensions.tutorial.quot; branch var prefs = Components.classes[quot;@mozilla.org/preferences-service;1quot;] .getService(Components.interfaces.nsIPrefService); prefs = prefs.getBranch(quot;extensions.tutorial.quot;); // Get the value of option3 (a number) var option3 = prefs.getIntPref('option3'); alert(option3); // Set the value of option1 (a boolean) to true prefs.setBoolPref('option1', true); var option1 = prefs.getBoolPref('option1'); alert(option1);
  • 20. Part 2: Read/Write in XPCOM • Read/Write Unicode Strings: (from https://developer.mozilla.org/en/Code_snippets/Preferences) // Example 1: getting Unicode value var option2 = prefs.getComplexValue(quot;option2quot;, Components.interfaces.nsISupportsString).data; alert(option2); // Example 2: setting Unicode value var str = Components.classes[quot;@mozilla.org/supports-string;1quot;] .createInstance(Components.interfaces.nsISupportsString); str.data = quot;火狐quot;; prefs.setComplexValue(quot;option2quot;, Components.interfaces.nsISupportsString, str);
  • 21. When you should use XPCOM • First run: – Make a default pref to detect first run (Change it after first run processing is ended) • Dialog to remember something: – Like quot;Exit Firefoxquot;:
  • 22. File Processing Access local files https://developer.mozilla.org/en/Code_snippets/File_I%2f%2fO
  • 23. The nsIFile / nsILocalFile • nsIFile: Cross-platform File I/O interface • nsILocalFile: extends nsIFile, can access local filesystem • It is a quot;LOCATION INDICATORquot; • What can nsILocalFile object do? – Check whether the file exists – Copy / Delete / Move files – Create files / folders – Work as a parameter to a lot of function • Saving webpage into files, etc…
  • 24. quot;Createquot; a nsILocalFile • With a absolute path: var file = Components.classes[quot;@mozilla.org/file/local;1quot;] .createInstance(Components.interfaces.nsILocalFile); file.initWithPath(quot;C:quot;); • quot;Pathquot; should be in a quot;nativequot; way like /home/littlebtc in Linux, C: in Windows • file:// URI? Explained later
  • 25. quot;Createquot; nsIFile pointing to special folders • Get an object located to Profile Directory: // get profile directory var file = Components.classes[quot;@mozilla.org/file/directory_service;1quot;] .getService(Components.interfaces.nsIProperties) .get(quot;ProfDquot;, Components.interfaces.nsIFile); • You can replace the ProfD with: With… Where With… Where CurProcD (Firefox) Installation Desk Desktop Dir C:UsersLittlebtcDesktop Home User's Dir Progs quot;Programsquot; directory in C:UsersLittlebtc Windows Start Menu /home/littlebtc/ resource:app XULRunner App Directory
  • 26. How to… Assuming we have a nsIFile object file, how to • Get the native path representation of a nsIFile? – file.path • Know whether the path refers to a existed thing? – file.exists() – Return true or false • Distinguish the path which this file object refers to from a folder, a file, or a link, or others? – Use file.isFile() file.isFolder() file.isSymlink() file.isSpecial()
  • 27. How to… • Whether the path is readable/writable/executable/hidden? • Use file.isWritable() file.isReadable() file.isExecutable() file.isHidden() • Know the filesize (if it is a file)? – file.fileSize • The file name without path? – file.leafName • The parent of the path? – file.parent (It is a nsIFile object, and can be null!)
  • 28. How to… • quot;Open the filequot; by the OS? • file.launch(); • Do something like quot;Open containing folderquot; in download manager? • file.reveal(); • Both of them are not work on Unix-like!
  • 29. How to… • Delete the path? – file.remove(); – For folder, you can only remove empty folder • Copy path? – file.copyTo(file2, 'newname'); – file2 represents the parent path for the target item, if it is null, it will be copied to the same parent of file • Move path? – file.moveTo(file2, 'newname'); – file2 is the same as above – You can only move empty folder
  • 30. How to… • How to quot;run the filequot; if it is a executable? – file.launch(); (Not recommended) – Use nsIProcess: https://developer.mozilla.org/En/Code_snippets/ Running_applications – nsIProcess cannot accept Unicode parameters on Windows… 
  • 31. How to… Assuming file is a nsIFile object refering to a folder path, how to: • Access a file in this directory? – file.append('filename'); Then file will be changed, will refer to this file, not the original folder! • Access multiple files? Clone object, then append – var file1 = file.clone(); // Clone file object file1.append('filename'); • How to create a subfolder? – file.append(quot;DIRquot;); // Still, append first if( !file.exists() || !file.isDirectory() ) { // if it doesn't exist, create file.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0777); }
  • 32. File contents read/write • https://developer.mozilla.org/en/Code_snippets/ File_I%2f%2fO • A little complex, why? When it comes to the encoding, it will be complex 
  • 33. File Picker / <filefield> • File Open / File Save / Select Folder Dialog • See https://developer.mozilla.org/en/nsIFilePicker • <filefield> in the <prefwindow>, like Firefox options (UNDOCUMENTED): http://www.xuldev.org/blog/?p=142 • We will have a small demo!
  • 34. File I/O demo 1 • A run dialog like Windows, use undocumented <filefield>
  • 35. run.xul <?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?> <?xml-stylesheet href=quot;chrome://global/skinquot; type=quot;text/cssquot;?> <dialog title=quot;Run applicationquot; buttons=quot;accept,cancelquot; ondialogaccept=quot;runApp.go();quot; xmlns=quot;http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xulquot;> <script type=quot;application/x-javascriptquot; src=quot;chrome://tutorial/content/run.jsquot;/> <hbox> <label value=quot;Select an file:quot; accesskey=quot;Fquot; /> <filefield id=quot;filequot; /> <button label=quot;Browse...quot; oncommand=quot;runApp.browse();quot; /> </hbox> <grid> <columns> <column flex=quot;1quot; /> <column flex=quot;2quot; /></columns> <rows> <row> <label value=quot;File name:quot; /><label value=quot;quot; id=quot;file_namequot; /> </row> <row> <label value=quot;File size:quot; /><label value=quot;quot; id=quot;file_sizequot; /> </row> </rows> </grid> </dialog>
  • 36. run.js (partial) browse: function() { // Initialize file picker var fp = Cc[quot;@mozilla.org/filepicker;1quot;].createInstance(Ci.nsIFilePicker); fp.init(window, 'Select a file', Ci.nsIFilePicker.modeOpen); // Set Filter: file types fp.appendFilter('Windows executable', '*.exe'); fp.appendFilter('All Files', '*.*'); // Show the dialog var result = fp.show(); if (result == Ci.nsIFilePicker.returnOK) { this.file = fp.file; // This should not be happened, but this is a demo :P if (!this.file.exists() || !this.file.isFile()) { return; } // Include it into filefield document.getElementById('file').file = this.file; // Load file infos document.getElementById('file_name').value = this.file.leafName; document.getElementById('file_size').value = this.file.fileSize + ' bytes'; } },
  • 37. run.js (partial 2) go: function() { if (this.file && this.file.exists() && this.file.isFile()) { this.file.launch(); } }
  • 38. URI Problem • In XPCOM, nsIURI is a common interface to represent an URI (It can handle all types of URI) • nsIURI <-> String URL: Use nsIIOService – var uri = Components.classes[quot;@mozilla.org/network/io-service;1quot;] .getService(Components.interfaces.nsIIOService) .newURI('http://moztw.org/', null, null); – uri.spec will contain the string representation of the URI • nsIURI <-> nsIFile – var file_uri = Components.classes[quot;@mozilla.org/network/io-service;1quot;] .getService(Components.interfaces.nsIIOService) .newFileURI(file); // Assuming file is a nsIFIle – var file = file_uri.QueryInterface(Components.interfaces.nsIFileURL) .file;
  • 39. When you will need nsIURI / nsIFile • Downloading files https://developer.mozilla.org/en/Code_snippets/ Downloading_Files (Basic) http://www.xuldev.org/blog/?p=163 (Advanced, by Gomita, a good intro to nsIWebBrowserPersist) • Use Places API (Bookmarks, Tags, History) https://developer.mozilla.org/en/Places • Progress listeners https://developer.mozilla.org/en/Code_snippets/ Progress_Listeners • And much more…
  • 40. Tree A somehow complex XUL structure
  • 41. What is a tree? • A complex item lists • An item may have some childs
  • 42. Why is it so complex • There are A LOT OF way to implement • But none of them are NOT trivial  • Some is easier but not so easy to be extended • Some is harder, but fully functional
  • 43. The easiest: Content Tree • (Try XUL Editor!) • From https://developer.mozilla.org/En/XUL/Tree <tree flex=quot;1quot; rows=quot;2quot;> <treecols> <treecol id=quot;senderquot; label=quot;Senderquot; flex=quot;1quot;/> <treecol id=quot;subjectquot; label=quot;Subjectquot; flex=quot;2quot;/> </treecols> <treechildren> <treeitem> <treerow> <treecell label=quot;joe@somewhere.comquot;/> <treecell label=quot;Top secret plansquot;/> </treerow> </treeitem> <treeitem> <treerow> <treecell label=quot;mel@whereever.comquot;/> <treecell label=quot;Let's do lunchquot;/> </treerow> </treeitem> </treechildren> </tree>
  • 44. The easiest: Content Tree • <tree>: Sent a row number as rows attribute is recommended? • <treecols>, <treecol>: Define the columns – Use flex to modify column width in <treecol> – Use id to build an identifier of the column • <treeitem>, <treerow>: Represents a row • <treecell>: Represents a cell – Attribute: label
  • 45. A tree with nested items From https://developer.mozilla.org/En/XUL/Tree <tree id=quot;myTreequot; flex=quot;1quot; hidecolumnpicker=quot;falsequot; seltype=quot;singlequot; class=quot;treequot; rows=quot;5quot;> <treecols id=quot;myTree2-treeColsquot;> <treecol id=quot;myTree2-treeCol0quot; primary=quot;truequot; flex=quot;2quot; label=quot;Column Aquot; persist=quot;widthquot; ordinal=quot;1quot;/> <splitter class=quot;tree-splitterquot; ordinal=quot;2quot;/> <treecol id=quot;myTree2-treeCol1quot; flex=quot;1quot; label=quot;Column Bquot; persist=quot;widthquot; ordinal=quot;3quot;/> </treecols> <treechildren> <treeitem> <treerow> <treecell label=quot;1quot;/> <treecell label=quot;aquot;/> </treerow> </treeitem> <!-- Make sure to set container=quot;truequot; --> <treeitem container=quot;truequot; open=quot;truequot;> <treerow> <treecell label=quot;2quot;/> <treecell label=quot;bquot;/> </treerow> <treechildren> <treeitem> <treerow> <treecell label=quot;2aquot;/> <treecell label=quot;baquot;/> </treerow> </treeitem> </treechildren> </treeitem> </treechildren> </tree>
  • 46. Wait, a lot of new thing…? • <splitter>: Between columns, to make them resizable • Nested items: <treechildren> under <treeitem> • hidecolumnpicker=quot;falsequot; – Whether to hide the column picker on the right – seltype=quot;singlequot;: you can select only one item or seltype=quot;multiplequot; for multiple selection support • persist=quot;attributename1 attributename2quot; – Make Firefox quot;rememberquot; user's settings on specific attribute
  • 47. OK, now, what is wrong? • Though we can multiply the tree with DOM, but it will the code will be somehow complex due to the bad XUL structure • So DOM way is not a popular way if it comes to dynamic content trees
  • 48. The most common: Custom TreeView • Implements nsITreeView to create a tree • Set custom tree view into view property • It can be fully functional and dynamic – …But somehow hard: poorly documented and buggy if having bad implementation – You should check Firefox's code to understand  – It takes me almost 20 hours to make <tree> on NicoFox works and another 20 hours to fix bugs… • Are you ready? :D https://developer.mozilla.org/en/XUL_Tutorial/Custom_Tree_ Views http://www.xuldev.org/blog/?p=127 (Thank you again, Gomita!)
  • 49. Tree Selection / Box Object • Tree Selection: Get currently selected items https://developer.mozilla.org/en/XUL_Tutorial/Tr ee_Selection – A little like text selection we had mentioned at the previous lecture (?) • Box Objects: Handle Tree's display Needed, for example, if you need to know the which cell the cursor is at https://developer.mozilla.org/en/XUL_Tutorial/Tr ee_Box_Objects
  • 50. Take a break, there is a final boss: SQLite! LUNCH TIME AGAIN!
  • 52. What is SQLite? • A lightweight relational database management system • Its C/C++ library is very small (418KB in Firefox 3.5) and very easy-to-use • Can use most of the SQL command • Resulting database is a single file • PUBLIC DOMAIN!(No any copyright restriction) • Used by a lot of software / framework
  • 53. SQLite is in … • Firefox, Safari, Google Chrome • Google Gears • Photoshop lightroom, Adobe AIR • Skype, McAfee, Songbird • PHP, Python… • iPhone, Symbian, Android… • Almost everywhere!!!!
  • 54. Now, make a new database!
  • 55. Now, make a new database! • Find your profile dir and copy the path Orz
  • 56. Now, make a new database! • Close SQLite manager and restart:
  • 60. Simple way to display SQLite DB • Use template https://developer.mozilla.org/en/XUL/Templat e_Guide/SQLite_Templates • Simple, but useful for our demo! :D • We will use the template technique and <tree> in the following demo
  • 61. students.xul <tree flex=quot;1quot;> <treecols> <treecol id=quot;col-noquot; label=quot;Noquot; flex=quot;1quot;/> <treecol id=quot;col-namequot; label=quot;Namequot; flex=quot;1quot;/> <treecol id=quot;col-scorequot; label=quot;Scorequot; flex=quot;1quot;/> </treecols> <treechildren datasources=quot;profile:tutorial.sqlitequot; ref=quot;*quot; querytype=quot;storagequot;> <template> <query> SELECT * FROM students ORDER BY score DESC </query> <action> <treeitem uri=quot;?quot;> <treerow> <treecell label=quot;?noquot;/> <treecell label=quot;?namequot;/> <treecell label=quot;?scorequot;/> </treerow> </treeitem> </action> </template> </treechildren> </tree>
  • 62. Explain • <treechildren datasources=quot;profile:tutorial.sqlitequot; ref=quot;*quot; querytype=quot;storagequot;> • Use SQLite database as a template datasources • <template>: <query> and <action> – <query>: SQL command • SELECT * FROM students: Select all fields from students table • ORDER BY score DESC: Order by score field in descendant order – <action>: Applied template • uri=quot;?quot;: (?) • Read score field from ?score
  • 63. mozStorage API • Mozilla's way to multiply SQLite database • So it is XPCOM again …  • But it is not so difficult! • I don't want to talk in detail, so go straight to examples!
  • 64. Final Demo: quot;Add a recordquot; function
  • 65. A SQL preview • INSERT INTO students (name, score) VALUES (quot;Littlebtcquot;, 30) • Insert a data into students table • Two fields: name and score • Their values: Littlebtc and 30
  • 66. students.xul, again <hbox> <label value=quot;Student Name:quot; accesskey=quot;Nquot; control=quot;new_namequot; /> <textbox id=quot;new_namequot; style=quot;width: 8em;quot;/> <label value=quot;Score:quot; accesskey=quot;Squot; control=quot;new_scorequot; /> <textbox id=quot;new_scorequot; type=quot;numberquot; style=quot;width: 4em;quot; max=quot;100quot; min=quot;0quot;/> <button label=quot;Addquot; oncommand=quot;students.add();quot;/> </hbox>
  • 67. student.js: student.add(); /* use nsIPromptService to alert */ /* https://developer.mozilla.org/en/Code_snippets/Dialogs_and_Prom pts */ var prompts = Cc[quot;@mozilla.org/embedcomp/prompt-service;1quot;] .getService(Ci.nsIPromptService); /* Record user's choice */ var name = document.getElementById('new-name').value; var score = document.getElementById('new-score').value; /* Required to enter a name */ if (!name) { prompts.alert(null, 'Error', 'Please Enter a Name.'); return; }
  • 68. …continued try { // try-catch exception handling /* We will see here later */ } catch(e) { // There may be some error in XPCOM, we can handle it prompts.alert(null, 'Error', 'Database/XPCOM Error:' + e); } • XPCOM Will throw exception when error • So we need a good way to handle it • …Or it will be displayed in the error console
  • 69. Connect to DB /* Find the tutorial.sqlite */ var file = Components.classes[quot;@mozilla.org/file/directory_service;1quot;] .getService(Components.interfaces.nsIProperties) .get(quot;ProfDquot;, Components.interfaces.nsIFile); file.append(quot;tutorial.sqlitequot;); /* Open database */ var storageService = Cc[quot;@mozilla.org/storage/service;1quot;] .getService(Ci.mozIStorageService); var db = storageService.openDatabase(file);
  • 70. Execute a quot;statementquot; var sql = quot;INSERT INTO students (name, score) VALUES (?1, ?2)quot;; var statement = db.createStatement(sql); statement.bindUTF8StringParameter(0, name); statement.bindInt32Parameter(1, score); /* Execute the statement */ statement.execute(); /* Finallize */ statement.finalize(); • quot;Statementquot; is a SQL command in mozStorage • Why we should use the quot;bindingquot; way? Prevent SQL injection, make database safe • https://developer.mozilla.org/en/mozIStorageStatemen t#Binding_Functions
  • 71. Finally… • Don't forget to close your DB! db.close();
  • 72. After try{…} catch{…} • We should update the tree and show a message /* Update the tree */ document.getElementById('students-treechildren') .builder.rebuild(); /* Prompt the user */ prompts.alert(null, 'OK', 'Thank you!');
  • 74. How to do for you later • Understand how to CRUD (Create, Read, Update, Delete) in SQLite – SQL commands: INSERT, SELECT, UPDATE, DELETE • Remember: Always Binding, NEVER directly apply variables into SQL command strings – Google quot;SQL Injectionquot; for details • SQLite is simple but powerful – have fun!
  • 75. This is the basic! • Actually, SQLite storage access with <tree> is usually implemented in Custom Tree View way, both in Firefox and NicoFox • That is another reason that I had spent 40 hours on a tree • Edit / Remove may be a very hard work
  • 76. It is 5:34am, I had finished my slide  THANK YOU!