Mozilla Firefox Extension Development Course 2: Advanced

  • 1,893 views
Uploaded on

 

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
1,893
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
32
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 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
  • 5. about:config
  • 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("extensions. extensionname .preferencename", false);
      • Name: has a widely used naming convention
      • Value: Boolean / Integer / String
  • 8. Take an example
    • See defaults/preferences/ tutorial.js
    • pref("extensions.tutorial.option1", false);
    • pref("extensions.tutorial.option2", "");
    • pref("extensions.tutorial.option3", 32);
    • pref("extensions.tutorial.default_editor", "");
  • 9. See about:config
  • 10. Preference System: <prefwindow>
    • Way to make a &quot;option window&quot;
    • 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/options.xul</em:optionsURL>
    • This will point the &quot;Options&quot; 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;paneGeneral&quot; label=&quot;General&quot; src=&quot;chrome://path/to/paneOverlay.xul&quot;/>
  • 13. <preferences> <preference>
    • <preferences>: Container
    • <preference>: &quot;Magic Attribute&quot; to hold the actual preference, attributes:
      • id
      • name: Corresponding preference name
      • type: bool/string/ unichar /int/file
    • In controls, use preference=&quot;id&quot; to connect the magic!
  • 14. Example: options.xul
    • <?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?>
    • <?xml-stylesheet href=&quot;chrome://global/skin/&quot; type=&quot;text/css&quot;?>
    • <?xml-stylesheet href=&quot;chrome://mozapps/content/preferences/preferences.css&quot;?>
    • <?xml-stylesheet href=&quot;chrome://browser/skin/preferences/preferences.css&quot;?>
    • <prefwindow xmlns=&quot;http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul&quot;>
    • <prefpane id=&quot;panel1&quot; label=&quot;panel1&quot;>
    • <preferences>
    • <preference name=&quot;extensions.tutorial.option1&quot; id=&quot;extensions.tutorial.option1&quot; type=&quot;bool&quot; />
    • <preference name=&quot;extensions.tutorial.option2&quot; id=&quot;extensions.tutorial.option2&quot; type=&quot;unichar&quot; />
    • </preferences>
    • <checkbox id=&quot;option1&quot; preference=&quot;extensions.tutorial.option1&quot; label=&quot;Check me!&quot; />
    • <hbox>
    • <label value=&quot;Type Your Name:&quot; accesskey=&quot;N&quot; control=&quot;option2&quot; />
    • <textbox id=&quot;option2&quot; preference=&quot;extensions.tutorial.option2&quot; />
    • </hbox>
    • </prefpane>
    • <prefpane id=&quot;panel2&quot; label=&quot;panel2&quot; src=&quot;chrome://tutorial/content/panel2.xul&quot;/>
    • </prefwindow>
  • 15. Example: panel2.xul
    • <?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?>
    • <overlay id=&quot;Pane2Overlay&quot;
    • xmlns=&quot;http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul&quot;>
    • <prefpane id=&quot;panel2&quot;>
    • <preferences>
    • <preference name=&quot;extensions.tutorial.option3&quot; id=&quot;extensions.tutorial.option3&quot; type=&quot;int&quot; />
    • </preferences>
    • <hbox>
    • <label value=&quot;Type a Integer:&quot; accesskey=&quot;I&quot; control=&quot;option3&quot; />
    • <textbox id=&quot;option3&quot; preference=&quot;extensions.tutorial.option3&quot; type=&quot;number&quot; />
    • </hbox>
    • </prefpane>
    • </overlay>
  • 16. Result
  • 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;1&quot;] .getService(Components.interfaces.nsIPrefBranch);
    • // Get the &quot;extensions.tutorial.&quot; branch
    • var prefs = Components.classes[&quot;@mozilla.org/preferences-service;1&quot;] .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;1&quot;] .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;option2&quot;, Components.interfaces.nsISupportsString).data;
    • alert(option2);
    • // Example 2: setting Unicode value
    • var str = Components.classes[&quot;@mozilla.org/supports-string;1&quot;]
    • .createInstance(Components.interfaces.nsISupportsString);
    • str.data = &quot; 火狐 &quot;;
    • prefs.setComplexValue(&quot;option2&quot;,
    • 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 Firefox&quot;:
  • 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 INDICATOR&quot;
    • 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;Create&quot; a nsILocalFile
    • With a absolute path:
    • var file = Components.classes[&quot;@mozilla.org/file/local;1&quot;]
    • .createInstance(Components.interfaces.nsILocalFile);
    • file.initWithPath(&quot;C:amp;quot;);
    • &quot;Path&quot; should be in a &quot;native&quot; way like /home/littlebtc in Linux, C: in Windows
    • file:// URI? Explained later
  • 25. &quot;Create&quot; 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;1&quot;]
    • .getService(Components.interfaces.nsIProperties)
    • .get(&quot;ProfD&quot;, Components.interfaces.nsIFile);
    • You can replace the ProfD with:
    With… Where With… Where CurProcD (Firefox) Installation Dir Desk Desktop C:UsersLittlebtcDesktop Home User's Dir C:UsersLittlebtc /home/littlebtc/ Progs &quot;Programs&quot; directory in Windows Start Menu 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 file&quot; by the OS?
        • file.launch();
    • Do something like &quot;Open containing folder&quot; 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 file&quot; 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;DIR&quot;); // 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.0&quot; encoding=&quot;UTF-8&quot;?>
    • <?xml-stylesheet href=&quot;chrome://global/skin&quot; type=&quot;text/css&quot;?>
    • <dialog title=&quot;Run application&quot; buttons=&quot;accept,cancel&quot; ondialogaccept=&quot;runApp.go();&quot;
    • xmlns=&quot;http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul&quot;>
    • <script type=&quot;application/x-javascript&quot; src=&quot;chrome://tutorial/content/run.js&quot;/>
    • <hbox>
    • <label value=&quot;Select an file:&quot; accesskey=&quot;F&quot; /> <filefield id=&quot;file&quot; />
    • <button label=&quot;Browse...&quot; oncommand=&quot;runApp.browse();&quot; />
    • </hbox>
    • <grid>
    • <columns> <column flex=&quot;1&quot; /> <column flex=&quot;2&quot; /></columns>
    • <rows>
    • <row> <label value=&quot;File name:&quot; /> <label value=&quot;&quot; id=&quot;file_name&quot; /> </row>
    • <row> <label value=&quot;File size:&quot; /> <label value=&quot;&quot; id=&quot;file_size&quot; /> </row>
    • </rows>
    • </grid>
    • </dialog>
  • 36. run.js (partial)
    • browse: function() {
    • // Initialize file picker
    • var fp = Cc[&quot;@mozilla.org/filepicker;1&quot;].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;1&quot;] .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;1&quot;] .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;1&quot; rows=&quot;2&quot;>
    • <treecols>
    • <treecol id=&quot;sender&quot; label=&quot;Sender&quot; flex=&quot;1&quot;/> <treecol id=&quot;subject&quot; label=&quot;Subject&quot; flex=&quot;2&quot;/>
    • </treecols>
    • <treechildren>
    • <treeitem>
    • <treerow>
    • <treecell label=&quot;joe@somewhere.com&quot;/> <treecell label=&quot;Top secret plans&quot;/>
    • </treerow>
    • </treeitem>
    • <treeitem>
    • <treerow>
    • <treecell label=&quot;mel@whereever.com&quot;/> <treecell label=&quot;Let's do lunch&quot;/>
    • </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;myTree&quot; flex=&quot;1&quot; hidecolumnpicker=&quot;false&quot; seltype=&quot;single&quot; class=&quot;tree&quot; rows=&quot;5&quot;>
    • <treecols id=&quot;myTree2-treeCols&quot;>
    • <treecol id=&quot;myTree2-treeCol0&quot; primary=&quot;true&quot; flex=&quot;2&quot; label=&quot;Column A&quot; persist=&quot;width&quot; ordinal=&quot;1&quot;/>
    • <splitter class=&quot;tree-splitter&quot; ordinal=&quot;2&quot;/>
    • <treecol id=&quot;myTree2-treeCol1&quot; flex=&quot;1&quot; label=&quot;Column B&quot; persist=&quot;width&quot; ordinal=&quot;3&quot;/>
    • </treecols>
    • <treechildren>
    • <treeitem>
    • <treerow>
    • <treecell label=&quot;1&quot;/> <treecell label=&quot;a&quot;/>
    • </treerow>
    • </treeitem>
    • <!-- Make sure to set container=&quot;true&quot; -->
    • <treeitem container=&quot;true&quot; open=&quot;true&quot;>
    • <treerow>
    • <treecell label=&quot;2&quot;/> <treecell label=&quot;b&quot;/>
    • </treerow>
    • <treechildren>
    • <treeitem>
    • <treerow>
    • <treecell label=&quot;2a&quot;/> <treecell label=&quot;ba&quot;/>
    • </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;false&quot;
      • Whether to hide the column picker on the right
      • seltype=&quot;single&quot;: you can select only one item or seltype=&quot;multiple&quot; for multiple selection support
    • persist=&quot;attributename1 attributename2&quot;
      • Make Firefox &quot;remember&quot; 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/Tree_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/Tree_Box_Objects
  • 50. LUNCH TIME AGAIN!
    • Take a break, there is a final boss: SQLite!
  • 51. Storage: SQLite
    • Great storage choice
  • 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:
  • 57. Create a table
  • 58. Table is ready!
  • 59. Add a record
  • 60. Simple way to display SQLite DB
    • Use template https://developer.mozilla.org/en/XUL/Template_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;1&quot;>
    • <treecols>
    • <treecol id=&quot;col-no&quot; label=&quot;No&quot; flex=&quot;1&quot;/>
    • <treecol id=&quot;col-name&quot; label=&quot;Name&quot; flex=&quot;1&quot;/>
    • <treecol id=&quot;col-score&quot; label=&quot;Score&quot; flex=&quot;1&quot;/>
    • </treecols>
    • <treechildren datasources=&quot;profile:tutorial.sqlite&quot; ref=&quot;*&quot; querytype=&quot;storage&quot; >
    • <template>
    • <query>
    • SELECT * FROM students ORDER BY score DESC
    • </query>
    • <action>
    • <treeitem uri=&quot;?&quot;>
    • <treerow>
    • <treecell label=&quot;?no&quot;/>
    • <treecell label=&quot;?name&quot;/>
    • <treecell label=&quot;?score&quot;/>
    • </treerow>
    • </treeitem>
    • </action>
    • </template>
    • </treechildren>
    • </tree>
  • 62. Explain
    • <treechildren datasources=&quot;profile:tutorial.sqlite&quot; ref=&quot;*&quot; querytype=&quot;storage&quot; >
    • 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 record&quot; function
  • 65. A SQL preview
    • INSERT INTO students (name, score) VALUES (&quot;Littlebtc&quot;, 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;N&quot; control=&quot;new_name&quot; />
    • <textbox id=&quot;new_name&quot; style=&quot;width: 8em;&quot;/>
    • <label value=&quot;Score:&quot; accesskey=&quot;S&quot; control=&quot;new_score&quot; />
    • <textbox id=&quot;new_score&quot; type=&quot;number&quot; style=&quot;width: 4em;&quot; max=&quot;100&quot; min=&quot;0&quot;/>
    • <button label=&quot;Add&quot; oncommand=&quot;students.add();&quot;/>
    • </hbox>
  • 67. student.js: student.add();
    • /* use nsIPromptService to alert */
    • /* https://developer.mozilla.org/en/Code_snippets/Dialogs_and_Prompts */
    • var prompts = Cc[&quot;@mozilla.org/embedcomp/prompt-service;1&quot;]
    • .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;1&quot;]
    • .getService(Components.interfaces.nsIProperties)
    • .get(&quot;ProfD&quot;, Components.interfaces.nsIFile);
    • file.append(&quot;tutorial.sqlite&quot;);
    • /* Open database */
    • var storageService = Cc[&quot;@mozilla.org/storage/service;1&quot;]
    • .getService(Ci.mozIStorageService);
    • var db = storageService.openDatabase(file);
  • 70. Execute a &quot;statement&quot;
    • 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;Statement&quot; is a SQL command in mozStorage
    • Why we should use the &quot;binding&quot; way? Prevent SQL injection , make database safe
    • https://developer.mozilla.org/en/mozIStorageStatement#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!');
  • 73. Working Example
  • 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 Injection&quot; 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. THANK YOU!
    • It is 5:34am, I had finished my slide 
  • 77. …… .NOT YET!!!