Browse Source

Refactored JS to use observer-notifier system.

git-svn-id: file:///tmp/snv/trunk@9 12951d8a-c33d-4b7c-b961-822215c816
Abhinav Sarkar 13 years ago
parent
commit
0aa71851ef
5 changed files with 503 additions and 43 deletions
  1. 3
    3
      chrome/content/TODO.txt
  2. 141
    38
      chrome/content/diggsidebar.js
  3. 3
    1
      chrome/content/diggsidebar.xul
  4. 355
    0
      chrome/content/jpath.js
  5. 1
    1
      install.rdf

+ 3
- 3
chrome/content/TODO.txt View File

@@ -1,7 +1,7 @@
1 1
 move to JSON data format -- done
2 2
 XBL -- done
3 3
 format JS/refactor JS/Use FUEL -- done
4
-put license
5
-caching/db, threading, XUL templates
6
-new UI
4
+caching/db, threading
5
+new UI, icons, thumbnails
7 6
 JQuery
7
+put license

+ 141
- 38
chrome/content/diggsidebar.js View File

@@ -1,9 +1,38 @@
1
-var DiggSidebar = {
1
+/*
2
+    Digg Sidebar - Shows Digg stories in the Firefox sidebar in real time.
3
+    Copyright (C) 2008  Abhinav Sarkar <abhinav dot sarkar at gmail dot com>
4
+
5
+    This program is free software: you can redistribute it and/or modify
6
+    it under the terms of the GNU General Public License as published by
7
+    the Free Software Foundation, either version 3 of the License, or
8
+    (at your option) any later version.
9
+
10
+    This program is distributed in the hope that it will be useful,
11
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+    GNU General Public License for more details.
14
+
15
+    You should have received a copy of the GNU General Public License
16
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
+
18
+*/
19
+
20
+DiggSidebar = {
2 21
     prefs: Application.extensions.get("diggsidebar@abhinavsarkar.net").prefs,
22
+    storyListRefreshEventTopic: "extension-diggsidebar-abhinavsarkar-net-storylist-refresh",
23
+    endpoint: {
24
+        container: null,
25
+        topic: null,
26
+        category: "all"
27
+    },
28
+    updateInterval: 10,
29
+    updateIntervalDecay: 0,
30
+    shownStoriesCount: 30,
3 31
     categories: ['All', 'Popular', 'Upcoming', 'Hot', 'Top'],
4
-    timerId : null,
5
-    currentStories : new Array(),
6
-    playing : true,
32
+    timerId: null,
33
+    storyIds: [],
34
+    playing: true,
35
+    stories: [],
7 36
 
8 37
     fetchData: function(url, handler) {
9 38
         DiggSidebar.diggIndicator.style.display = '';
@@ -95,31 +124,36 @@ var DiggSidebar = {
95 124
         DiggSidebar.diggIndicator.style.display = 'none';
96 125
     },
97 126
 
98
-    populateStoryList: function(e) {
99
-        var XHR = e.target;
100
-        //Application.console.log(XHR.responseText);
101
-        var data = DiggSidebar.Utils.decodeJson(XHR.responseText);
102
-        var stories = data.stories;
103
-
127
+    populateStoryList: function() {
104 128
         while (DiggSidebar.storyList.firstChild) {
105 129
             DiggSidebar.storyList.removeChild(DiggSidebar.storyList.firstChild);
106 130
         }
107 131
 
108
-        var newStories = new Array();
109
-        //Application.console.log(stories.length);
110
-
111
-        stories.forEach(function (story) {
112
-            newStories.push(story.id);
113
-            //Application.console.log(i + " " + story.title + " " + story.id);
114
-
115
-            var listitem = DiggSidebar.storyList.appendChild(document.createElement('richlistitem'));
116
-            listitem.id = "story_" + story.id;
117
-            listitem.setAttribute('title', story.title);
118
-
119
-            if (DiggSidebar.currentStories.indexOf(story.id) != -1) listitem.new = false;
132
+        var newStoryIds = new Array();
133
+        Application.console.log(DiggSidebar.stories.length);
134
+
135
+        var jp = new JPath(DiggSidebar.stories);
136
+        var filtedStories = DiggSidebar.stories;
137
+        if (DiggSidebar.endpoint.topic)
138
+            filtedStories = jp.$(function(story){
139
+                return story.$("topic/short_name").json == DiggSidebar.endpoint.topic;
140
+            }).json;
141
+        if (DiggSidebar.endpoint.container)
142
+            filtedStories = jp.$(function(story){
143
+                return story.$("container/short_name").json == DiggSidebar.endpoint.container;
144
+            }).json;
145
+
146
+        filtedStories.forEach(function (story, index) {
147
+            if (index < DiggSidebar.shownStoriesCount) {
148
+                var listitem = DiggSidebar.storyList.appendChild(document.createElement('richlistitem'));
149
+                listitem.id = "story_" + story.id;
150
+                listitem.setAttribute('title', story.title);
151
+                if (DiggSidebar.storyIds.indexOf(story.id) != -1) listitem.new = false;
152
+            }
153
+            if (DiggSidebar.storyIds.indexOf(story.id) == -1) newStoryIds.push(story.id);
120 154
         });
121
-        DiggSidebar.currentStories = newStories;
122
-        DiggSidebar.setUpdateInterval(stories);
155
+        DiggSidebar.storyIds = DiggSidebar.storyIds.concat(newStoryIds);
156
+        DiggSidebar.setUpdateInterval(DiggSidebar.stories.slice(-5));
123 157
         DiggSidebar.diggIndicator.style.display = 'none';
124 158
     },
125 159
 
@@ -178,7 +212,20 @@ var DiggSidebar = {
178 212
         DiggSidebar.fetchData("http://services.digg.com/stories" + ep.replace(/\/all/g, '') +
179 213
             "?count=30" + "&type=json" +
180 214
             "&appkey=" + encodeURIComponent("http://diggsidebar.googlepages.com"),
181
-            DiggSidebar.populateStoryList);
215
+            function(e) {
216
+                var newStories = DiggSidebar.Utils.decodeJson(e.target.responseText).stories.filter(
217
+                    function(story) {
218
+                        return !(DiggSidebar.storyIds.indexOf(story.id) != -1);
219
+                    });
220
+                newStories.forEach(function(story) {
221
+                    story.category = DiggSidebar.endpoint.category;
222
+                    story.read = false;
223
+                });
224
+                DiggSidebar.stories = newStories.concat(DiggSidebar.stories);
225
+                var observerService = Components.classes["@mozilla.org/observer-service;1"]
226
+                    .getService(Components.interfaces.nsIObserverService);
227
+                observerService.notifyObservers(null, DiggSidebar.storyListRefreshEventTopic, null);
228
+            });
182 229
     },
183 230
 
184 231
     getDescription: function(storyId) {
@@ -196,6 +243,12 @@ var DiggSidebar = {
196 243
 
197 244
     setUpdateInterval: function(stories) {
198 245
         //Adaptive update interval code START
246
+        if (stories.length == 0) {
247
+            window.clearTimeout(DiggSidebar.timerId);
248
+            var timeout = Math.round(DiggSidebar.updateInterval*(Math.pow(1.5, DiggSidebar.updateIntervalDecay)));
249
+            DiggSidebar.timerId = window.setTimeout(DiggSidebar.getStories, timeout);
250
+            return;
251
+        }
199 252
         var sum = 0;
200 253
         var weights = [4, 3, 2, 1]
201 254
         var date = (stories[0].promote_date != null) ? 'promote_date' : 'submit_date';
@@ -216,32 +269,46 @@ var DiggSidebar = {
216 269
         //Application.console.log(updateInterval);
217 270
 
218 271
         if (updateInterval > 0) {
219
-            var previousUpdateInterval = DiggSidebar.prefs.get("updateinterval").value;
220
-            DiggSidebar.prefs.get("updateinterval").value = updateInterval;
272
+            var previousUpdateInterval = DiggSidebar.updateInterval;
273
+            DiggSidebar.updateInterval = updateInterval;
221 274
 
222
-            var updateIntervalDecay = DiggSidebar.prefs.get("updateintervaldecay").value;
275
+            var updateIntervalDecay = DiggSidebar.updateIntervalDecay;
223 276
 
224 277
             if (previousUpdateInterval == updateInterval)
225
-                DiggSidebar.prefs.get("updateintervaldecay").value = updateIntervalDecay + 1;
278
+                DiggSidebar.updateIntervalDecay = updateIntervalDecay + 1;
226 279
             else
227
-                DiggSidebar.prefs.get("updateintervaldecay").value = 0;
280
+                DiggSidebar.updateIntervalDecay = 0;
228 281
         }
229 282
         window.clearTimeout(DiggSidebar.timerId);
230 283
 
231
-        var updateInterval = DiggSidebar.prefs.get("updateinterval").value;
232
-        var updateIntervalDecay = DiggSidebar.prefs.get("updateintervaldecay").value;
233
-
234
-        var timeout = Math.round(updateInterval*(Math.pow(1.5, updateIntervalDecay)));
284
+        var timeout = Math.round(DiggSidebar.updateInterval*(Math.pow(1.5, DiggSidebar.updateIntervalDecay)));
235 285
         DiggSidebar.timerId = window.setTimeout(DiggSidebar.getStories, timeout);
236 286
         //Adaptive update interval code END
237 287
     },
238 288
 
239 289
     setEndPoint: function(ep) {
240 290
         DiggSidebar.prefs.get("endpoint").value = ep;
291
+        DiggSidebar.endpoint = DiggSidebar.getEndpointParts(ep);
241 292
         window.clearTimeout(DiggSidebar.timerId);
242 293
         DiggSidebar.getStories();
243 294
     },
244 295
 
296
+    getEndpointParts: function(ep) {
297
+        var tmp = {
298
+            topic: null,
299
+            container: null,
300
+            category: "all"
301
+        };
302
+        parts = ep.split("/");
303
+        if (parts.length == 2)
304
+            tmp.category = parts[1];
305
+        else if (parts.length == 4) {
306
+            tmp[parts[1]] = parts[2];
307
+            tmp.category = parts[3];
308
+        }
309
+        return tmp;
310
+    },
311
+
245 312
     togglePlayPause: function() {
246 313
         if (DiggSidebar.playing) {
247 314
             window.clearTimeout(DiggSidebar.timerId);
@@ -249,10 +316,7 @@ var DiggSidebar = {
249 316
             DiggSidebar.diggPlayPause.setAttribute("tooltiptext", "Click to Start autoupdate");
250 317
             DiggSidebar.playing = false;
251 318
         } else {
252
-            var updateInterval = DiggSidebar.prefs.get("updateinterval").value;
253
-            var updateIntervalDecay = DiggSidebar.prefs.get("updateintervaldecay").value;
254
-
255
-            var timeout = Math.round(updateInterval*(Math.pow(1.5, updateIntervalDecay)));
319
+            var timeout = Math.round(DiggSidebar.updateInterval*(Math.pow(1.5, DiggSidebar.updateIntervalDecay)));
256 320
             DiggSidebar.timerId = window.setTimeout(DiggSidebar.getStories, timeout);
257 321
             DiggSidebar.diggPlayPause.image = "chrome://diggsidebar/content/image/Pause.png";
258 322
             DiggSidebar.diggPlayPause.setAttribute("tooltiptext", "Click to Pause autoupdate");
@@ -261,6 +325,7 @@ var DiggSidebar = {
261 325
     },
262 326
 
263 327
     initialize: function(){
328
+        DiggSidebar.endpoint = DiggSidebar.getEndpointParts(DiggSidebar.prefs.get("endpoint").value);
264 329
         var $ = function(id) {return document.getElementById(id)};
265 330
         DiggSidebar.diggIndicator = $('diggIndicator');
266 331
         DiggSidebar.topicPopup = $('topicPopup');
@@ -268,8 +333,14 @@ var DiggSidebar = {
268 333
         DiggSidebar.storyList = $('storyList');
269 334
         DiggSidebar.diggEndPoint = $('diggEndPoint');
270 335
         DiggSidebar.diggPlayPause = $('diggPlayPause');
336
+
337
+        DiggSidebar.storyListObserver = new StoryListObserver();
271 338
         DiggSidebar.createMenu();
272 339
         DiggSidebar.getStories();
340
+    },
341
+
342
+    destroy: function(){
343
+        DiggSidebar.storyListObserver.unregister();
273 344
     }
274 345
 };
275 346
 
@@ -290,6 +361,38 @@ DiggSidebar.Utils = {
290 361
         return json.decode(string);
291 362
     }
292 363
 }
364
+
365
+var StoryListObserver = function() {
366
+   this.registered = false;
367
+   this.register();
368
+}
369
+
370
+StoryListObserver.prototype = {
371
+    observe: function(subject, topic, data) {
372
+        if (topic == window.DiggSidebar.storyListRefreshEventTopic) {
373
+            window.DiggSidebar.populateStoryList();
374
+        }
375
+    },
376
+
377
+    register: function() {
378
+        if (this.registered == false) {
379
+            var observerService = Components.classes["@mozilla.org/observer-service;1"]
380
+                .getService(Components.interfaces.nsIObserverService);
381
+            observerService.addObserver(this, DiggSidebar.storyListRefreshEventTopic, false);
382
+            this.registered = true;
383
+        }
384
+    },
385
+
386
+    unregister: function() {
387
+        if (this.registered == true) {
388
+            var observerService = Components.classes["@mozilla.org/observer-service;1"]
389
+                .getService(Components.interfaces.nsIObserverService);
390
+            observerService.removeObserver(this, DiggSidebar.storyListRefreshEventTopic);
391
+            this.registered = false;
392
+        }
393
+    }
394
+}
395
+
293 396
 /*TODO
294 397
  preferences
295 398
  toolbar button

+ 3
- 1
chrome/content/diggsidebar.xul View File

@@ -6,8 +6,10 @@
6 6
 
7 7
 <page id="sbDiggSidebar" title="&diggsidebar.title;"
8 8
     xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
9
-    onload="DiggSidebar.initialize()">
9
+    onload="DiggSidebar.initialize()"
10
+    onunload="DiggSidebar.destroy()">
10 11
     <script src="chrome://diggsidebar/content/diggsidebar.js" type="application/x-javascript" />
12
+    <script src="chrome://diggsidebar/content/jpath.js" type="application/x-javascript" />
11 13
     <hbox>
12 14
         <toolbar flex="1">
13 15
             <toolbaritem>

+ 355
- 0
chrome/content/jpath.js View File

@@ -0,0 +1,355 @@
1
+/*
2
+   JPath 1.0.3 - json equivalent to xpath
3
+   Copyright (C) 2007  Bryan English <bryan at bluelinecity dot com>
4
+
5
+   This program is free software; you can redistribute it and/or
6
+   modify it under the terms of the GNU General Public License
7
+   as published by the Free Software Foundation; either version 2
8
+   of the License, or (at your option) any later version.
9
+
10
+   This program is distributed in the hope that it will be useful,
11
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+   GNU General Public License for more details.
14
+
15
+   You should have received a copy of the GNU General Public License
16
+   along with this program; if not, write to the Free Software
17
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18
+
19
+   Usage:      
20
+      var jpath = new JPath( myjsonobj );
21
+
22
+      var somevalue = jpath.$('book/title').json;  //results in title
23
+         //or
24
+      var somevalue = jpath.query('book/title');   //results in title
25
+
26
+   Supported XPath-like Syntax:
27
+      /tagname
28
+      //tagname
29
+      tagname
30
+      * wildcard
31
+      [] predicates
32
+      operators ( >=, ==, <= )
33
+      array selection
34
+      .. 	         
35
+      *
36
+      and, or
37
+      nodename[0]
38
+      nodename[last()]
39
+      nodename[position()]
40
+      nodename[last()-1]
41
+      nodename[somenode > 3]/node
42
+      nodename[count() > 3]/node
43
+
44
+   Tested With:
45
+      Firefox 2-3, IE 6-7
46
+   
47
+   Update Log:
48
+      1.0.1 - Bugfix for zero-based element selection
49
+      1.0.2 - Bugfix for IE not handling eval() and returning a function
50
+      1.0.3 - Bugfix added support for underscore and dash in query() function
51
+                  Bugfix improper use of Array.concat which was flattening arrays
52
+                  Added support for single equal sign in query() function
53
+                  Added support for count() xpath function
54
+                  Added support for and, or boolean expression in predicate blocks
55
+                  Added support for global selector $$ and //
56
+                  Added support for wildcard (*) selector support 
57
+*/
58
+
59
+function JPath( json, parent )
60
+{ 
61
+    this.json = json; 
62
+    this._parent = parent; 
63
+}
64
+
65
+JPath.prototype = {
66
+
67
+   /*
68
+      Property: json
69
+      Copy of current json segment to operate on
70
+   */
71
+   json: null,
72
+   
73
+   /*
74
+      Property: parent
75
+      Parent json object, null if root.
76
+   */
77
+   parent: null,
78
+
79
+   /*
80
+      Method: $
81
+      Performs a find query on the current jpath object.
82
+
83
+      Parameters:
84
+        str - mixed, find query to perform. Can consist of a nodename or nodename path or function object or integer.
85
+
86
+      Return:
87
+        jpath - Returns the resulting jpath object after performing find query.
88
+
89
+   */
90
+   '$': function ( str )
91
+   {
92
+      var result = null;
93
+      var working = this;
94
+      
95
+      if ( this.json && str !== null )
96
+      {
97
+         switch ( typeof(str) )
98
+         {
99
+            case 'function':
100
+               result = this.f(str).json;
101
+            break;
102
+
103
+            case 'number':
104
+               result = this.json[str] || null;
105
+            break;
106
+
107
+            case 'string':
108
+               var names = str.split('/');     
109
+
110
+               //foreach slash delimited node name//
111
+               for ( var i=0; i<names.length ; i++ )
112
+               {
113
+                  var name = new RegExp('^' + names[i].replace(/\*/g,'.*') + '$');                  
114
+                  var isArray = (working.json instanceof Array);
115
+                  var a = new Array();
116
+                  
117
+                  //foreach working node property//
118
+                  for ( var p in working.json )
119
+                  {
120
+                     if ( typeof( working.json[p] ) != 'function' )
121
+                     {
122
+                        if ( isArray && (arguments.callee.caller != this.$$) )
123
+                        {
124
+                           a = a.concat( this.findAllByRegExp( name, working.json[p] ) );
125
+                        }
126
+                        else if ( name.test(p) )
127
+                        {                        
128
+                           a.push( working.json[p] );
129
+                        }
130
+                     }                  
131
+                  }
132
+
133
+                  working = new JPath( ( a.length==0 ? null : ( ( a.length == 1) ? a[0] : a ) ), working );
134
+               }
135
+
136
+               return working;
137
+            break;
138
+         }   
139
+      }
140
+      
141
+      return new JPath( result, this );
142
+   },
143
+
144
+   /*
145
+      Method: $$
146
+      Performs a global, recursive find query on the current jpath object.
147
+
148
+      Parameters:
149
+        str - mixed, find query to perform. Can consist of a nodename or nodename path or function object or integer.
150
+
151
+      Return:
152
+        jpath - Returns the resulting jpath object after performing find query.
153
+
154
+   */   
155
+   '$$': function( str )
156
+   {   
157
+      var r = this.$(str,true).json;
158
+      var arr = new Array();
159
+      
160
+      if ( r instanceof Array ) 
161
+         arr = arr.concat(r); 
162
+      else if ( r !== null )
163
+         arr.push(r);
164
+         
165
+      for ( var p in this.json )
166
+      {
167
+         if ( typeof( this.json[p] ) == 'object' )
168
+         {
169
+            arr = arr.concat( new JPath( this.json[p], this ).$$(str).json );
170
+         }
171
+      }
172
+      
173
+      return new JPath( arr, this );
174
+   },
175
+   
176
+   /*
177
+      Method: findAllByRegExp
178
+      Looks through a list of an object properties using a regular expression
179
+
180
+      Parameters:
181
+         re - regular expression, to use to search with
182
+         obj - object, the object to search through
183
+
184
+      Returns:
185
+         array - resulting properties
186
+   */
187
+   findAllByRegExp: function( re, obj )
188
+   {
189
+      var a = new Array();
190
+   
191
+      for ( var p in obj )
192
+      {
193
+         if ( obj instanceof Array )
194
+         {
195
+            a = a.concat( this.findAllByRegExp( re, obj[p] ) );
196
+         }
197
+         else if ( typeof( obj[p] ) != 'function' && re.test(p) )
198
+         {
199
+            a.push( obj[p] );
200
+         }
201
+      }
202
+
203
+      return a;
204
+   },
205
+
206
+   /*
207
+      Method: query (beta)
208
+      Performs a find query on the current jpath object using a single string similar to xpath. This method
209
+      is currently expirimental.
210
+
211
+      Parameters:
212
+        str - string, full xpath-like query to perform on the current object.
213
+
214
+      Return:
215
+        mixed - Returns the resulting json value after performing find query.
216
+
217
+   */
218
+   query: function( str )
219
+   {
220
+      var re = {
221
+         " and ":" && ",
222
+         " or ":" || ",
223
+         "([\\#\\*\\@a-z\\_][\\*a-z0-9_\\-]*)(?=(?:\\s|$|\\[|\\]|\\/))" : "\$('$1').",
224
+         "\\[([0-9])+\\]" : "\$($1).",
225
+         "\\.\\." : "parent().",
226
+         "\/\/" : "$",
227
+         "(^|\\[|\\s)\\/" : "$1root().",
228
+         "\\/" : '',
229
+         "([^\\=\\>\\<\\!])\\=([^\\=])" : '$1==$2',
230
+         "\\[" : "$(function(j){ with(j){return(",
231
+         "\\]" : ");}}).",
232
+         "\\(\\.":'(',
233
+         "(\\.|\\])(?!\\$|\\p)":"$1json",
234
+         "count\\(([^\\)]+)\\)":"count('$1')"
235
+      };
236
+
237
+      //save quoted strings//
238
+      var quotes = /(\'|\")([^\1]*)\1/;
239
+      var saves = new Array();
240
+      while ( quotes.test(str) )
241
+      {
242
+         saves.push( str.match(quotes)[2] ); 
243
+         str = str.replace(quotes,'%'+ (saves.length-1) +'%');
244
+      }
245
+
246
+      for ( var e in re )
247
+      {
248
+         str = str.replace( new RegExp(e,'ig'), re[e] );
249
+      }
250
+      //alert('this.' + str.replace(/\%(\d+)\%/g,'saves[$1]') + ";");
251
+
252
+      return eval('this.' + str.replace(/\%(\d+)\%/g,'saves[$1]') + ";");
253
+   },
254
+
255
+   /*
256
+      Method: f
257
+      Performs the equivilant to an xpath predicate eval on the current nodeset.
258
+
259
+      Parameters:
260
+        f - function, an iterator function that is executed for every json node and is expected to return a boolean
261
+        value which determines if that particular node is selected. Alternativly you can submit a string which will be
262
+        inserted into a prepared function.
263
+
264
+      Return:
265
+        jpath - Returns the resulting jpath object after performing find query.
266
+
267
+   */
268
+   f: function ( iterator )
269
+   {
270
+      var a = new Array();
271
+
272
+      if ( typeof(iterator) == 'string' )
273
+      {
274
+         eval('iterator = function(j){with(j){return('+ iterator +');}}');
275
+      }
276
+
277
+      for ( var p in this.json )
278
+      {
279
+         var j = new JPath(this.json[p], this);
280
+         j.index = p;
281
+         if ( iterator( j ) )
282
+         {
283
+            a.push( this.json[p] );
284
+         }
285
+      }
286
+
287
+      return new JPath( a, this );
288
+   },
289
+
290
+   /*
291
+      Method: parent
292
+      Returns the parent jpath object or itself if its the root node
293
+
294
+      Return:
295
+        jpath - Returns the parent jpath object or itself if its the root node
296
+
297
+   */
298
+   parent: function()
299
+   {
300
+      return ( (this._parent) ? this._parent : this );
301
+   },
302
+
303
+   /*
304
+      Method: position
305
+      Returns the index position of the current node. Only valid within a function or predicate
306
+
307
+      Return:
308
+        int - array index position of this json object.
309
+   */
310
+   position: function()
311
+   {
312
+      return this.index;
313
+   },
314
+
315
+   /*
316
+      Method: last
317
+      Returns true if this is the last node in the nodeset. Only valid within a function or predicate
318
+
319
+      Return:
320
+        booean - Returns true if this is the last node in the nodeset
321
+   */
322
+   last: function()
323
+   {
324
+      return (this.index == (this._parent.json.length-1));
325
+   },
326
+
327
+   /*
328
+      Method: count
329
+      Returns the count of child nodes in the current node
330
+
331
+      Parameters:
332
+         string - optional node name to count, defaults to all
333
+      
334
+      Return:
335
+        booean - Returns number of child nodes found
336
+   */
337
+   count: function(n)
338
+   {
339
+      var found = this.$( n || '*').json;         
340
+      return ( found ? ( found instanceof Array ? found.length : 1 ) : 0 );
341
+   },
342
+
343
+   /*
344
+      Method: root
345
+      Returns the root jpath object.
346
+
347
+      Return:
348
+        jpath - The top level, root jpath object.
349
+   */
350
+   root: function ()
351
+   {
352
+      return ( this._parent ? this._parent.root() : this );
353
+   }
354
+
355
+};

+ 1
- 1
install.rdf View File

@@ -5,7 +5,7 @@
5 5
   <RDF:Description RDF:about="rdf:#$55wJ23"
6 6
                    em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
7 7
                    em:minVersion="3.0"
8
-                   em:maxVersion="3.1.*" />
8
+                   em:maxVersion="3.1b1" />
9 9
   <RDF:Description RDF:about="urn:mozilla:install-manifest"
10 10
                    em:id="diggsidebar@abhinavsarkar.net"
11 11
                    em:name="Digg Sidebar"

Loading…
Cancel
Save