1 /* See license.txt for terms of usage */ 2 3 define([ 4 "firebug/lib/trace", 5 "firebug/lib/object", 6 "firebug/chrome/privacy", 7 ], 8 function(FBTrace, Obj, Privacy) { 9 10 // ********************************************************************************************* // 11 // Constants 12 13 const Cc = Components.classes; 14 const Ci = Components.interfaces; 15 16 var dirService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties); 17 18 // ********************************************************************************************* // 19 // Annotation 20 21 /** 22 * @class Represents an internal Firebug annotation service. This service is used to 23 * annotate sites with an info whether Firebug should be activated for them or not. 24 */ 25 var Annotations = Obj.extend(Firebug.Module, 26 { 27 annotations: [], 28 29 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 30 31 initialize: function() 32 { 33 // Get annotation file stored within the profile directory. 34 this.file = dirService.get("ProfD", Ci.nsIFile); 35 this.file.append("firebug"); 36 this.file.append("annotations.json"); 37 38 // Load annotations. 39 this.loadAnnotations(); 40 41 Privacy.addListener(this); 42 }, 43 44 shutdown: function() 45 { 46 this.flush(); 47 48 Privacy.removeListener(this); 49 }, 50 51 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 52 // Public Methods 53 54 setPageAnnotation: function(uri, value) 55 { 56 if (FBTrace.DBG_ANNOTATIONS) 57 FBTrace.sysout("Annotations.setPageAnnotation; " + value + ", " + uri.spec); 58 59 this.annotations[uri.spec] = value; 60 }, 61 62 getPageAnnotation: function(uri) 63 { 64 return this.annotations[uri.spec]; 65 }, 66 67 pageHasAnnotation: function(uri) 68 { 69 return this.annotations[uri.spec] ? true : false; 70 }, 71 72 removePageAnnotation: function(uri) 73 { 74 if (FBTrace.DBG_ANNOTATIONS) 75 FBTrace.sysout("Annotations.removePageAnnotation; " + uri.spec); 76 77 delete this.annotations[uri.spec]; 78 }, 79 80 getAnnotations: function() 81 { 82 return this.annotations; 83 }, 84 85 clear: function() 86 { 87 this.annotations = []; 88 }, 89 90 flush: function(force) 91 { 92 // Do not store anything if private-browsing mode is on. 93 if (!force && Privacy.isPrivateBrowsing()) 94 return; 95 96 try 97 { 98 // Initialize output stream. 99 var outputStream = Cc["@mozilla.org/network/file-output-stream;1"] 100 .createInstance(Ci.nsIFileOutputStream); 101 // write, create, truncate 102 // see https://developer.mozilla.org/en-US/docs/PR_Open#Parameters 103 outputStream.init(this.file, 0x02 | 0x08 | 0x20, 0666, 0); 104 105 // Convert data to JSON. 106 var arr = []; 107 for (var uri in this.annotations) 108 { 109 arr.push({ 110 uri: uri, 111 value: this.annotations[uri] 112 }); 113 } 114 115 var jsonString = JSON.stringify(arr); 116 117 // Store annotations 118 outputStream.write(jsonString, jsonString.length); 119 outputStream.close(); 120 121 if (FBTrace.DBG_ANNOTATIONS) 122 FBTrace.sysout("Annotations.loadAnnotations; Annotations stored to " + 123 this.file.path, jsonString); 124 } 125 catch (err) 126 { 127 if (FBTrace.DBG_ERRORS || FBTrace.DBG_ANNOTATIONS) 128 FBTrace.sysout("Annotations.flush; EXCEPTION", err); 129 } 130 }, 131 132 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 133 // Internals 134 135 // Persistence 136 loadAnnotations: function() 137 { 138 try 139 { 140 this.clear(); 141 142 if (!this.file.exists()) 143 { 144 this.file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0666); 145 if (FBTrace.DBG_ANNOTATIONS) 146 FBTrace.sysout("Annotations.loadAnnotations; Annotations file created " + 147 this.file.path); 148 return; 149 } 150 151 var inputStream = Cc["@mozilla.org/network/file-input-stream;1"] 152 .createInstance(Ci.nsIFileInputStream); 153 var cstream = Cc["@mozilla.org/intl/converter-input-stream;1"] 154 .createInstance(Ci.nsIConverterInputStream); 155 156 // loadAnnotations input stream 157 // read, create 158 inputStream.init(this.file, 0x01 | 0x08, 0666, 0); 159 cstream.init(inputStream, "UTF-8", 0, 0); 160 161 // Load annotations 162 var json = ""; 163 var data = {}; 164 while (cstream.readString(-1, data) != 0) 165 json += data.value; 166 167 if (!json.length) 168 return; 169 170 var arr = JSON.parse(json); 171 if (!arr) 172 return; 173 174 // convert to map for faster lookup 175 for (var i=0; i<arr.length; i++) 176 this.annotations[arr[i].uri] = arr[i].value; 177 178 if (FBTrace.DBG_ANNOTATIONS) 179 FBTrace.sysout("Annotations.loadAnnotations; Annotations loaded from " + 180 this.file.path, arr); 181 } 182 catch (err) 183 { 184 if (FBTrace.DBG_ERRORS || FBTrace.DBG_ANNOTATIONS) 185 FBTrace.sysout("Annotations.loadAnnotations; EXCEPTION", err); 186 } 187 }, 188 189 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 190 // Privacy 191 192 onPrivateBrowsingChange: function(enabled) 193 { 194 if (enabled) 195 { 196 this.flush(true); 197 this.clear(); 198 } 199 else 200 { 201 this.loadAnnotations(); 202 } 203 }, 204 205 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 206 // Options 207 208 resetAllOptions: function() 209 { 210 this.clear(); 211 this.flush(true); 212 } 213 }); 214 215 // ********************************************************************************************* // 216 // Registration 217 218 Firebug.Annotations = Annotations; 219 220 Firebug.registerModule(Annotations); 221 222 return Annotations; 223 224 // ********************************************************************************************* // 225 }); 226