summaryrefslogtreecommitdiffabout
path: root/content
authorMichael Krelin <hacker@klever.net>2006-09-29 22:27:02 (UTC)
committer Michael Krelin <hacker@klever.net>2006-09-29 22:27:02 (UTC)
commit3cf3cf1000ce6b27ac622c75fc3d114874e2f3a8 (patch) (unidiff)
treeb76d0ba42afa8252747bc2c9a0bfd6c5b8b3f07b /content
parentdcd46fa0189aa1893eb2faa7da4fd823dc6c392d (diff)
downloadfireflix-3cf3cf1000ce6b27ac622c75fc3d114874e2f3a8.zip
fireflix-3cf3cf1000ce6b27ac622c75fc3d114874e2f3a8.tar.gz
fireflix-3cf3cf1000ce6b27ac622c75fc3d114874e2f3a8.tar.bz2
code beauty: moved some code into util.js
git-svn-id: http://svn.klever.net/kin/fireflix/trunk@168 fe716a7a-6dde-0310-88d9-d003556173a8
Diffstat (limited to 'content') (more/less context) (ignore whitespace changes)
-rw-r--r--content/Makefile.am2
-rw-r--r--content/fireflix-panel.xul1
-rw-r--r--content/flickr.js50
-rw-r--r--content/util.js61
4 files changed, 63 insertions, 51 deletions
diff --git a/content/Makefile.am b/content/Makefile.am
index 8548400..d8607fb 100644
--- a/content/Makefile.am
+++ b/content/Makefile.am
@@ -1,22 +1,22 @@
1xpichromecontent_DATA = \ 1xpichromecontent_DATA = \
2 autoconf.dtd \ 2 autoconf.dtd \
3 browser.xul about.xul fireflix-panel.xul photoset-props.xul \ 3 browser.xul about.xul fireflix-panel.xul photoset-props.xul \
4 generated-content.xul \ 4 generated-content.xul \
5 photoset-props.js fireflix.js flickr.js md5.js \ 5 photoset-props.js fireflix.js flickr.js util.js md5.js \
6 generated-content.js \ 6 generated-content.js \
7 fireflix.css \ 7 fireflix.css \
8 background.jpeg 8 background.jpeg
9 9
10sized_icons = \ 10sized_icons = \
11 $(addsuffix .png, \ 11 $(addsuffix .png, \
12 fireflix \ 12 fireflix \
13 ) 13 )
14 14
15nobase_xpichromecontent_DATA = \ 15nobase_xpichromecontent_DATA = \
16 $(addprefix icons/, \ 16 $(addprefix icons/, \
17 $(addprefix 16x16/,${sized_icons}) \ 17 $(addprefix 16x16/,${sized_icons}) \
18 $(addprefix 32x32/,${sized_icons}) \ 18 $(addprefix 32x32/,${sized_icons}) \
19 ) 19 )
20 20
21EXTRA_DIST = \ 21EXTRA_DIST = \
22 ${xpichromecontent_DATA} ${nobase_xpichromecontent_DATA} 22 ${xpichromecontent_DATA} ${nobase_xpichromecontent_DATA}
diff --git a/content/fireflix-panel.xul b/content/fireflix-panel.xul
index 569beb0..2a15a51 100644
--- a/content/fireflix-panel.xul
+++ b/content/fireflix-panel.xul
@@ -1,271 +1,272 @@
1<?xml version="1.0"?> 1<?xml version="1.0"?>
2<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> 2<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
3<?xml-stylesheet href="fireflix.css" type="text/css"?> 3<?xml-stylesheet href="fireflix.css" type="text/css"?>
4<!DOCTYPE page SYSTEM "chrome://fireflix/locale/fireflix.dtd"> 4<!DOCTYPE page SYSTEM "chrome://fireflix/locale/fireflix.dtd">
5<page 5<page
6 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 6 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
7 id="fireflixwindow" title="Fireflix" 7 id="fireflixwindow" title="Fireflix"
8 onload="fireflix.init()" 8 onload="fireflix.init()"
9 orient="vertical" 9 orient="vertical"
10 ondragover="nsDragAndDrop.dragOver(event,fireflix.uploadObserver)" 10 ondragover="nsDragAndDrop.dragOver(event,fireflix.uploadObserver)"
11 ondragdrop="nsDragAndDrop.drop(event,fireflix.uploadObserver)" 11 ondragdrop="nsDragAndDrop.drop(event,fireflix.uploadObserver)"
12 > 12 >
13 13
14 <script src="chrome://global/content/nsDragAndDrop.js"/> 14 <script src="chrome://global/content/nsDragAndDrop.js"/>
15 <script src="chrome://global/content/nsTransferable.js"/> 15 <script src="chrome://global/content/nsTransferable.js"/>
16 <script type="application/x-javascript" src="md5.js" /> 16 <script type="application/x-javascript" src="md5.js" />
17 <script type="application/x-javascript" src="util.js" />
17 <script type="application/x-javascript" src="flickr.js" /> 18 <script type="application/x-javascript" src="flickr.js" />
18 <script type="application/x-javascript" src="fireflix.js" /> 19 <script type="application/x-javascript" src="fireflix.js" />
19 20
20 <stringbundleset> 21 <stringbundleset>
21 <stringbundle id="loc_strings" src="chrome://fireflix/locale/fireflix.properties" /> 22 <stringbundle id="loc_strings" src="chrome://fireflix/locale/fireflix.properties" />
22 </stringbundleset> 23 </stringbundleset>
23 24
24 <commandset> 25 <commandset>
25 <command id="cmd_auth_auth" label="&panel.auth.auth.label;" 26 <command id="cmd_auth_auth" label="&panel.auth.auth.label;"
26 oncommand="fireflix.on_cmd_auth()"/> 27 oncommand="fireflix.on_cmd_auth()"/>
27 <command id="cmd_auth_done" label="&panel.auth.done.label;" 28 <command id="cmd_auth_done" label="&panel.auth.done.label;"
28 oncommand="fireflix.on_cmd_auth_done()" disabled="true"/> 29 oncommand="fireflix.on_cmd_auth_done()" disabled="true"/>
29 <command id="cmd_auth_open_flickr" label="&panel.auth.flickr.label;" 30 <command id="cmd_auth_open_flickr" label="&panel.auth.flickr.label;"
30 oncommand="fireflix.openTab('htp://www.flickr.com/')" /> 31 oncommand="fireflix.openTab('htp://www.flickr.com/')" />
31 <command id="cmd_auth_unauth" label="&panel.auth.unauth.label;" 32 <command id="cmd_auth_unauth" label="&panel.auth.unauth.label;"
32 oncommand="fireflix.on_cmd_auth_unauth()" /> 33 oncommand="fireflix.on_cmd_auth_unauth()" />
33 </commandset> 34 </commandset>
34 35
35 <popupset> 36 <popupset>
36 <popup id="auth_menu"> 37 <popup id="auth_menu">
37 <menuitem command="cmd_auth_auth"/> 38 <menuitem command="cmd_auth_auth"/>
38 <menuitem command="cmd_auth_done" hidden="true" id="menu_auth_done"/> 39 <menuitem command="cmd_auth_done" hidden="true" id="menu_auth_done"/>
39 <menuitem command="cmd_auth_unauth" /> 40 <menuitem command="cmd_auth_unauth" />
40 <menuseparator/> 41 <menuseparator/>
41 <menuitem command="cmd_auth_open_flickr"/> 42 <menuitem command="cmd_auth_open_flickr"/>
42 </popup> 43 </popup>
43 </popupset> 44 </popupset>
44 45
45 <commandset id="cmdset_search"> 46 <commandset id="cmdset_search">
46 <command id="cmd_search" label="&panel.search.cmd_search.label;" 47 <command id="cmd_search" label="&panel.search.cmd_search.label;"
47 oncommand="fireflix.foundphotos.search_photos()"/> 48 oncommand="fireflix.foundphotos.search_photos()"/>
48 <command id="cmd_search_open" label="&panel.search.cmd_search_open.label;" 49 <command id="cmd_search_open" label="&panel.search.cmd_search_open.label;"
49 oncommand="fireflix.foundphotos.on_cmd_open(event)" /> 50 oncommand="fireflix.foundphotos.on_cmd_open(event)" />
50 </commandset> 51 </commandset>
51 52
52 <commandset id="cmdset_sets"> 53 <commandset id="cmdset_sets">
53 <command id="cmd_refresh_sets" label="&panel.sets.cmd_refresh_sets;" 54 <command id="cmd_refresh_sets" label="&panel.sets.cmd_refresh_sets;"
54 oncommand="fireflix.on_refresh_sets()" /> 55 oncommand="fireflix.on_refresh_sets()" />
55 <command id="cmd_set_props" label="&panel.sets.cmd_properties;" 56 <command id="cmd_set_props" label="&panel.sets.cmd_properties;"
56 oncommand="fireflix.on_set_props()" disabled="true" /> 57 oncommand="fireflix.on_set_props()" disabled="true" />
57 </commandset> 58 </commandset>
58 59
59 <popupset> 60 <popupset>
60 <popup id="sets_menu"> 61 <popup id="sets_menu">
61 <menuitem command="cmd_set_props"/> 62 <menuitem command="cmd_set_props"/>
62 <menuitem command="cmd_refresh_sets"/> 63 <menuitem command="cmd_refresh_sets"/>
63 <menuseparator/> 64 <menuseparator/>
64 <menu label="&panel.sets.generate_html;" id="sets_html_menu"/> 65 <menu label="&panel.sets.generate_html;" id="sets_html_menu"/>
65 </popup> 66 </popup>
66 </popupset> 67 </popupset>
67 68
68 <commandset id="cmdset_uploads"> 69 <commandset id="cmdset_uploads">
69 <command id="cmd_uploads_clear" label="&panel.uploads.clear.label;" 70 <command id="cmd_uploads_clear" label="&panel.uploads.clear.label;"
70 oncommand="fireflix.uploads.on_clear()" /> 71 oncommand="fireflix.uploads.on_clear()" />
71 <command id="cmd_uploads_upload" label="&panel.uploads.upload.label;" 72 <command id="cmd_uploads_upload" label="&panel.uploads.upload.label;"
72 oncommand="fireflix.uploads.on_upload()" /> 73 oncommand="fireflix.uploads.on_upload()" />
73 <command id="cmd_uploads_remove" label="&panel.uploads.remove.label;" 74 <command id="cmd_uploads_remove" label="&panel.uploads.remove.label;"
74 oncommand="fireflix.uploads.on_remove()" /> 75 oncommand="fireflix.uploads.on_remove()" />
75 <command id="cmd_uploads_add" label="&panel.uploads.add.label;" 76 <command id="cmd_uploads_add" label="&panel.uploads.add.label;"
76 oncommand="fireflix.uploads.on_add()" /> 77 oncommand="fireflix.uploads.on_add()" />
77 </commandset> 78 </commandset>
78 79
79 <popupset> 80 <popupset>
80 <popup id="uploads_menu"> 81 <popup id="uploads_menu">
81 <menuitem command="cmd_uploads_add"/> 82 <menuitem command="cmd_uploads_add"/>
82 <menuitem command="cmd_uploads_clear"/> 83 <menuitem command="cmd_uploads_clear"/>
83 <menuitem command="cmd_uploads_remove"/> 84 <menuitem command="cmd_uploads_remove"/>
84 <menuseparator/> 85 <menuseparator/>
85 <menuitem command="cmd_uploads_upload"/> 86 <menuitem command="cmd_uploads_upload"/>
86 <menuseparator/> 87 <menuseparator/>
87 <menu label="&panel.uploads.generate_html;" id="uploads_html_menu"/> 88 <menu label="&panel.uploads.generate_html;" id="uploads_html_menu"/>
88 </popup> 89 </popup>
89 </popupset> 90 </popupset>
90 91
91 <vbox class="wholething" flex="1"> 92 <vbox class="wholething" flex="1">
92 93
93 <groupbox context="auth_menu"> 94 <groupbox context="auth_menu">
94 <caption label="&panel.auth_info;"/> 95 <caption label="&panel.auth_info;"/>
95 <hbox> 96 <hbox>
96 <label id="auth_info" value="&panel.no_auth_info;" flex="1" disabled="true" crop="end"/> 97 <label id="auth_info" value="&panel.no_auth_info;" flex="1" disabled="true" crop="end"/>
97 <button id="b_auth" command="cmd_auth_auth"/> 98 <button id="b_auth" command="cmd_auth_auth"/>
98 <button id="b_auth_done" command="cmd_auth_done" hidden="true"/> 99 <button id="b_auth_done" command="cmd_auth_done" hidden="true"/>
99 <button command="cmd_auth_open_flickr" 100 <button command="cmd_auth_open_flickr"
100 tooltiptext="&panel.auth.flickr.tip;"/> 101 tooltiptext="&panel.auth.flickr.tip;"/>
101 </hbox> 102 </hbox>
102 </groupbox> 103 </groupbox>
103 104
104 <tabbox flex="1" id="fireflix_tabs"> 105 <tabbox flex="1" id="fireflix_tabs">
105 106
106 <tabs> 107 <tabs>
107 <tab label="&panel.tabs.search;"/> 108 <tab label="&panel.tabs.search;"/>
108 <tab label="&panel.tabs.sets;"/> 109 <tab label="&panel.tabs.sets;"/>
109 <tab label="&panel.tabs.tags;" hidden="true"/> <!-- TODO: --> 110 <tab label="&panel.tabs.tags;" hidden="true"/> <!-- TODO: -->
110 <tab id="tab_upload" label="&panel.tabs.upload;"/> 111 <tab id="tab_upload" label="&panel.tabs.upload;"/>
111 </tabs> 112 </tabs>
112 113
113 <tabpanels flex="1"> 114 <tabpanels flex="1">
114 115
115 <tabpanel id="tabpanel_search" flex="1"> 116 <tabpanel id="tabpanel_search" flex="1">
116 <vbox flex="1"> 117 <vbox flex="1">
117 <groupbox class="search_params" orient="vertical" onkeypress="if(event.keyCode==event.DOM_VK_RETURN) fireflix.foundphotos.search_photos()"> 118 <groupbox class="search_params" orient="vertical" onkeypress="if(event.keyCode==event.DOM_VK_RETURN) fireflix.foundphotos.search_photos()">
118 <hbox> 119 <hbox>
119 <label control="search_for" value="&panel.search.search_for.label;" 120 <label control="search_for" value="&panel.search.search_for.label;"
120 accesskey="s"/> 121 accesskey="s"/>
121 <textbox id="search_for" flex="1"/> 122 <textbox id="search_for" flex="1"/>
122 </hbox> 123 </hbox>
123 <hbox> 124 <hbox>
124 <checkbox id="search_tags" label="&panel.search.mode.tagsonly.label;" 125 <checkbox id="search_tags" label="&panel.search.mode.tagsonly.label;"
125 tooltiptext="&panel.search.mode.tagsonly.tip;" checked="false" 126 tooltiptext="&panel.search.mode.tagsonly.tip;" checked="false"
126 accesskey="t" /> 127 accesskey="t" />
127 <checkbox id="search_mine" label="&panel.search.mode.mine.label;" checked="true" accesskey="m"/> 128 <checkbox id="search_mine" label="&panel.search.mode.mine.label;" checked="true" accesskey="m"/>
128 <spacer flex="1"/> 129 <spacer flex="1"/>
129 <button command="cmd_search"/> 130 <button command="cmd_search"/>
130 </hbox> 131 </hbox>
131 </groupbox> 132 </groupbox>
132 <tree id="searchresults" rows="2" flex="1" 133 <tree id="searchresults" rows="2" flex="1"
133 onselect="fireflix.foundphotos.on_select()" 134 onselect="fireflix.foundphotos.on_select()"
134 ondblclick="fireflix.foundphotos.on_cmd_open(event)" 135 ondblclick="fireflix.foundphotos.on_cmd_open(event)"
135 onkeypress="if(event.keyCode==event.DOM_VK_RETURN) 136 onkeypress="if(event.keyCode==event.DOM_VK_RETURN)
136 fireflix.foundphotos.on_cmd_open(event)"> 137 fireflix.foundphotos.on_cmd_open(event)">
137 <treecols> 138 <treecols>
138 <treecol id="sr_title" label="&panel.search.col.title.label;" flex="2" crop="end" align="start" /> 139 <treecol id="sr_title" label="&panel.search.col.title.label;" flex="2" crop="end" align="start" />
139 </treecols> 140 </treecols>
140 <treechildren/> 141 <treechildren/>
141 </tree> 142 </tree>
142 <groupbox id="searchresult_props" orient="horizontal" hidden="true"> 143 <groupbox id="searchresult_props" orient="horizontal" hidden="true">
143 <vbox width="100" pack="center"> 144 <vbox width="100" pack="center">
144 <hbox pack="center"> 145 <hbox pack="center">
145 <image id="search_photo"/> 146 <image id="search_photo"/>
146 </hbox> 147 </hbox>
147 </vbox> 148 </vbox>
148 <vbox flex="1"> 149 <vbox flex="1">
149 <label id="searchresult_title"/> 150 <label id="searchresult_title"/>
150 <textbox flex="1" multiline="true" class="plain" readonly="true" id="searchresult_description"/> 151 <textbox flex="1" multiline="true" class="plain" readonly="true" id="searchresult_description"/>
151 <hbox pack="end"> 152 <hbox pack="end">
152 <button command="cmd_search_open"/> 153 <button command="cmd_search_open"/>
153 </hbox> 154 </hbox>
154 </vbox> 155 </vbox>
155 </groupbox> 156 </groupbox>
156 </vbox> 157 </vbox>
157 </tabpanel> 158 </tabpanel>
158 159
159 <tabpanel id="tabpanel_sets" flex="1" 160 <tabpanel id="tabpanel_sets" flex="1"
160 onkeypress="if(event.keyCode==event.DOM_VK_RETURN) 161 onkeypress="if(event.keyCode==event.DOM_VK_RETURN)
161 document.getElementById('setphotos').focus()"> 162 document.getElementById('setphotos').focus()">
162 <vbox flex="1"> 163 <vbox flex="1">
163 <tree id="setslist" rows="2" onselect="fireflix.photosets.on_select()" 164 <tree id="setslist" rows="2" onselect="fireflix.photosets.on_select()"
164 flex="1" context="sets_menu" 165 flex="1" context="sets_menu"
165 > 166 >
166 <treecols> 167 <treecols>
167 <treecol id="sl_name" label="&panel.sets.name.label;" flex="4" crop="end" align="start" tooltiptext="&panel.sets.name.tip;"/> 168 <treecol id="sl_name" label="&panel.sets.name.label;" flex="4" crop="end" align="start" tooltiptext="&panel.sets.name.tip;"/>
168 <splitter class="tree-splitter" /> 169 <splitter class="tree-splitter" />
169 <treecol id="sl_photos" label="&panel.sets.photos.label;" flex="1" align="end" tooltiptext="&panel.sets.photos.tip;" /> 170 <treecol id="sl_photos" label="&panel.sets.photos.label;" flex="1" align="end" tooltiptext="&panel.sets.photos.tip;" />
170 </treecols> 171 </treecols>
171 <treechildren/> 172 <treechildren/>
172 </tree> 173 </tree>
173 <hbox> 174 <hbox>
174 <button command="cmd_refresh_sets" /> 175 <button command="cmd_refresh_sets" />
175 <button command="cmd_set_props" /> 176 <button command="cmd_set_props" />
176 </hbox> 177 </hbox>
177 <tree id="setphotos" rows="2" onselect="fireflix.photoset.on_select()" 178 <tree id="setphotos" rows="2" onselect="fireflix.photoset.on_select()"
178 flex="1"> 179 flex="1">
179 <treecols> 180 <treecols>
180 <treecol id="sp_title" label="&panel.setphotos.title.label;" flex="1" crop="end" align="start" tooltiptext="&panel.setphotos.title.tip;" /> 181 <treecol id="sp_title" label="&panel.setphotos.title.label;" flex="1" crop="end" align="start" tooltiptext="&panel.setphotos.title.tip;" />
181 <splitter class="tree-splitter" /> 182 <splitter class="tree-splitter" />
182 <treecol id="sp_taken" label="&panel.setphotos.taken.label;" crop="end" align="start" tooltiptext="&panel.setphotos.taken.tip;" hidden="true" /> 183 <treecol id="sp_taken" label="&panel.setphotos.taken.label;" crop="end" align="start" tooltiptext="&panel.setphotos.taken.tip;" hidden="true" />
183 <treecol id="sp_upload" label="&panel.setphotos.upload.label;" crop="end" align="start" tooltiptext="&panel.setphotos.upload.tip;" hidden="true" /> 184 <treecol id="sp_upload" label="&panel.setphotos.upload.label;" crop="end" align="start" tooltiptext="&panel.setphotos.upload.tip;" hidden="true" />
184 </treecols> 185 </treecols>
185 <treechildren/> 186 <treechildren/>
186 </tree> 187 </tree>
187 <groupbox id="set_photo_props" orient="horizontal"> 188 <groupbox id="set_photo_props" orient="horizontal">
188 <vbox width="100" pack="center"> 189 <vbox width="100" pack="center">
189 <hbox pack="center"> 190 <hbox pack="center">
190 <image id="set_photo" hidden="true"/> 191 <image id="set_photo" hidden="true"/>
191 </hbox> 192 </hbox>
192 </vbox> 193 </vbox>
193 <spacer flex="1"/> 194 <spacer flex="1"/>
194 </groupbox> 195 </groupbox>
195 </vbox> 196 </vbox>
196 </tabpanel> 197 </tabpanel>
197 198
198 <tabpanel id="tabpanel_tags"> 199 <tabpanel id="tabpanel_tags">
199 <listbox id="tagslist" rows="8" flex="1"> 200 <listbox id="tagslist" rows="8" flex="1">
200 <listhead> 201 <listhead>
201 <listheader label="&panel.tagslist.tag.label;"/> 202 <listheader label="&panel.tagslist.tag.label;"/>
202 </listhead> 203 </listhead>
203 <listcols> 204 <listcols>
204 <listcol flex="1"/> 205 <listcol flex="1"/>
205 </listcols> 206 </listcols>
206 </listbox> 207 </listbox>
207 </tabpanel> 208 </tabpanel>
208 209
209 <tabpanel id="tabpanel_upload"> 210 <tabpanel id="tabpanel_upload">
210 <vbox flex="1"> 211 <vbox flex="1">
211 <tree id="uploadlist" rows="2" flex="1" 212 <tree id="uploadlist" rows="2" flex="1"
212 onselect="fireflix.uploads.selectionChanged()" 213 onselect="fireflix.uploads.selectionChanged()"
213 context="uploads_menu"> 214 context="uploads_menu">
214 <treecols> 215 <treecols>
215 <treecol id="up_file" label="&panel.uploadlist.file.label;" flex="4" crop="start" align="start"/> 216 <treecol id="up_file" label="&panel.uploadlist.file.label;" flex="4" crop="start" align="start"/>
216 <splitter class="tree-splitter" /> 217 <splitter class="tree-splitter" />
217 <treecol id="up_title" label="&panel.uploadlist.title.label;" flex="5" crop="end" align="start" /> 218 <treecol id="up_title" label="&panel.uploadlist.title.label;" flex="5" crop="end" align="start" />
218 <splitter class="tree-splitter" /> 219 <splitter class="tree-splitter" />
219 <treecol id="up_status" label="&panel.uploadlist.status.label;" flex="1" crop="end" align="start" /> 220 <treecol id="up_status" label="&panel.uploadlist.status.label;" flex="1" crop="end" align="start" />
220 </treecols> 221 </treecols>
221 <treechildren/> 222 <treechildren/>
222 </tree> 223 </tree>
223 <progressmeter id="upload_progress" mode="undetermined" hidden="true" /> 224 <progressmeter id="upload_progress" mode="undetermined" hidden="true" />
224 <groupbox id="upload_file_props" orient="horizontal" hidden="true"> 225 <groupbox id="upload_file_props" orient="horizontal" hidden="true">
225 <image id="upload_file_preview" width="100" height="100" /> 226 <image id="upload_file_preview" width="100" height="100" />
226 <grid flex="1"> 227 <grid flex="1">
227 <columns> 228 <columns>
228 <column/> 229 <column/>
229 <column flex="1"/> 230 <column flex="1"/>
230 </columns> 231 </columns>
231 <rows> 232 <rows>
232 <row> 233 <row>
233 <label control="upload_filename" 234 <label control="upload_filename"
234 value="&panel.upload_props.filename.label;" /> 235 value="&panel.upload_props.filename.label;" />
235 <textbox id="upload_filename" 236 <textbox id="upload_filename"
236 oninput="fireflix.uploads.propsToSel('filename')"/> 237 oninput="fireflix.uploads.propsToSel('filename')"/>
237 </row> 238 </row>
238 <row> 239 <row>
239 <label control="upload_title" value="&panel.upload_props.title.label;" /> 240 <label control="upload_title" value="&panel.upload_props.title.label;" />
240 <textbox id="upload_title" 241 <textbox id="upload_title"
241 oninput="fireflix.uploads.propsToSel('title')"/> 242 oninput="fireflix.uploads.propsToSel('title')"/>
242 </row> 243 </row>
243 <row> 244 <row>
244 <label control="uplod_tags" value="&panel.upload_props.tags.label;" /> 245 <label control="uplod_tags" value="&panel.upload_props.tags.label;" />
245 <textbox id="upload_tags" 246 <textbox id="upload_tags"
246 oninput="fireflix.uploads.propsToSel('tags')"/> 247 oninput="fireflix.uploads.propsToSel('tags')"/>
247 </row> 248 </row>
248 <!-- TODO: description, public, friend, family --> 249 <!-- TODO: description, public, friend, family -->
249 </rows> 250 </rows>
250 </grid> 251 </grid>
251 </groupbox> 252 </groupbox>
252 <hbox> 253 <hbox>
253 <button command="cmd_uploads_add" /> 254 <button command="cmd_uploads_add" />
254 <spacer flex="1"/> 255 <spacer flex="1"/>
255 <button command="cmd_uploads_remove" /> 256 <button command="cmd_uploads_remove" />
256 <spacer flex="1"/> 257 <spacer flex="1"/>
257 <button command="cmd_uploads_clear" /> 258 <button command="cmd_uploads_clear" />
258 </hbox> 259 </hbox>
259 <hbox pack="center"> 260 <hbox pack="center">
260 <button command="cmd_uploads_upload" flex="1"/> 261 <button command="cmd_uploads_upload" flex="1"/>
261 </hbox> 262 </hbox>
262 </vbox> 263 </vbox>
263 </tabpanel> 264 </tabpanel>
264 265
265 </tabpanels> 266 </tabpanels>
266 267
267 </tabbox> 268 </tabbox>
268 269
269 </vbox> 270 </vbox>
270 271
271</page> 272</page>
diff --git a/content/flickr.js b/content/flickr.js
index 3554796..add628a 100644
--- a/content/flickr.js
+++ b/content/flickr.js
@@ -1,403 +1,353 @@
1/* 1/*
2 * Photoset 2 * Photoset
3 */ 3 */
4 4
5function Photoset(s) { 5function Photoset(s) {
6 if(s instanceof Photoset) { 6 if(s instanceof Photoset) {
7 for(var p in s) this[p]=s[p]; 7 for(var p in s) this[p]=s[p];
8 }else 8 }else
9 this.fromNode(s); 9 this.fromNode(s);
10} 10}
11Photoset.prototype = { 11Photoset.prototype = {
12 id: null, 12 id: null,
13 primary: null, 13 primary: null,
14 secret: null, 14 secret: null,
15 server: null, 15 server: null,
16 photos: null, 16 photos: null,
17 title: null, 17 title: null,
18 description: null, 18 description: null,
19 fromNode: function(n) { 19 fromNode: function(n) {
20 this.id = n.getAttribute('id'); 20 this.id = n.getAttribute('id');
21 this.primary = n.getAttribute('primary'); 21 this.primary = n.getAttribute('primary');
22 this.secret = n.getAttribute('secret'); 22 this.secret = n.getAttribute('secret');
23 this.server = n.getAttribute('server'); 23 this.server = n.getAttribute('server');
24 this.photos = n.getAttribute('photos'); 24 this.photos = n.getAttribute('photos');
25 this.title = n.getElementsByTagName('title').item(0).firstChild.nodeValue; 25 this.title = n.getElementsByTagName('title').item(0).firstChild.nodeValue;
26 this.description = n.getElementsByTagName('description').item(0).firstChild; 26 this.description = n.getElementsByTagName('description').item(0).firstChild;
27 if(this.description) this.description = this.description.nodeValue; 27 if(this.description) this.description = this.description.nodeValue;
28 } 28 }
29}; 29};
30 30
31/* 31/*
32 * Photo 32 * Photo
33 */ 33 */
34function Photo(s) { 34function Photo(s) {
35 if(s instanceof Photo) { 35 if(s instanceof Photo) {
36 for(var p in s) this[p]=s[p]; 36 for(var p in s) this[p]=s[p];
37 }else 37 }else
38 this.fromNode(s); 38 this.fromNode(s);
39} 39}
40Photo.prototype = { 40Photo.prototype = {
41 id: null, secret: null, 41 id: null, secret: null,
42 server: null, 42 server: null,
43 title: null, 43 title: null,
44 isprimary: null, 44 isprimary: null,
45 license: null, 45 license: null,
46 dateupload: null, datetaken: null, datetakengranularity: null, 46 dateupload: null, datetaken: null, datetakengranularity: null,
47 ownername: null, 47 ownername: null,
48 iconserver: null, 48 iconserver: null,
49 originalformat: null, 49 originalformat: null,
50 lastupdate: null, 50 lastupdate: null,
51 fromNode: function(n) { 51 fromNode: function(n) {
52 this.id = n.getAttribute('id'); this.secret = n.getAttribute('secret'); 52 this.id = n.getAttribute('id'); this.secret = n.getAttribute('secret');
53 this.server = n.getAttribute('server'); 53 this.server = n.getAttribute('server');
54 this.title = n.getAttribute('title'); 54 this.title = n.getAttribute('title');
55 this.isprimary = n.getAttribute('isprimary'); 55 this.isprimary = n.getAttribute('isprimary');
56 this.license = n.getAttribute('license'); 56 this.license = n.getAttribute('license');
57 this.dateupload = n.getAttribute('dateupload'); 57 this.dateupload = n.getAttribute('dateupload');
58 this.datetaken = n.getAttribute('datetaken'); this.datetakengranularity = n.getAttribute('datetakengranularity'); 58 this.datetaken = n.getAttribute('datetaken'); this.datetakengranularity = n.getAttribute('datetakengranularity');
59 this.ownername = n.getAttribute('ownername'); 59 this.ownername = n.getAttribute('ownername');
60 this.iconserver = n.getAttribute('iconserver'); 60 this.iconserver = n.getAttribute('iconserver');
61 this.originalformat = n.getAttribute('originalformat'); 61 this.originalformat = n.getAttribute('originalformat');
62 this.lastupdate = n.getAttribute('lastupdate'); 62 this.lastupdate = n.getAttribute('lastupdate');
63 }, 63 },
64 fromNode_: function(n) { 64 fromNode_: function(n) {
65 var t; 65 var t;
66 // TODO: @rotation @isfavorite 66 // TODO: @rotation @isfavorite
67 this.owner = {}; 67 this.owner = {};
68 t = n.getElementsByTagName('owner').item(0); 68 t = n.getElementsByTagName('owner').item(0);
69 if(t) { 69 if(t) {
70 this.owner.nsid=t.getAttribute('nsid'); 70 this.owner.nsid=t.getAttribute('nsid');
71 this.owner.username=t.getAttribute('username'); 71 this.owner.username=t.getAttribute('username');
72 this.owner.realname=t.getAttribute('realname'); 72 this.owner.realname=t.getAttribute('realname');
73 this.owner.location=t.getAttribute.location; 73 this.owner.location=t.getAttribute.location;
74 } 74 }
75 t = n.getElementsByTagName('description').item(0); 75 t = n.getElementsByTagName('description').item(0);
76 if(t && t.firstChild) { 76 if(t && t.firstChild) {
77 this.description = t.firstChild.nodeValue; 77 this.description = t.firstChild.nodeValue;
78 } 78 }
79 // TODO: visibility/@ispublic visibility/@isfriend visibility/@isfamily 79 // TODO: visibility/@ispublic visibility/@isfriend visibility/@isfamily
80 // TODO: dates/@posted dates/@taken dates/@takengranularity dates/@lastupdate 80 // TODO: dates/@posted dates/@taken dates/@takengranularity dates/@lastupdate
81 // TODO: permissions/@permcomment permsiions/@permaddmeta 81 // TODO: permissions/@permcomment permsiions/@permaddmeta
82 // TODO: editability/@canaddcomment editability/@canaddmeta 82 // TODO: editability/@canaddcomment editability/@canaddmeta
83 // TODO: comments 83 // TODO: comments
84 // TODO: notes/note/@id notes/note/@author notes/note/@authorname 84 // TODO: notes/note/@id notes/note/@author notes/note/@authorname
85 // TODO: notes/note/@x notes/note/@y notes/note/@w notes/note/@h 85 // TODO: notes/note/@x notes/note/@y notes/note/@w notes/note/@h
86 // TODO: notes/note 86 // TODO: notes/note
87 // TODO: tags/tag/@id tags/tag/@author tags/tag/@raw tags/tag 87 // TODO: tags/tag/@id tags/tag/@author tags/tag/@raw tags/tag
88 // TODO: urls/url/@type urls/url 88 // TODO: urls/url/@type urls/url
89 } 89 }
90}; 90};
91 91
92function toutf8(ucode) {
93 var rv = '';
94 for(var i=0;i<ucode.length;++i) {
95 var cc = ucode.charCodeAt(i);
96 if(cc<=0x7F)
97 rv += ucode.charAt(i);
98 else if(cc<=0x7ff)
99 rv += String.fromCharCode(
100 0xc0|((cc>> 6)&0x1f),
101 0x80|( cc &0x3f) );
102 else if(cc<=0xffff)
103 rv += String.fromCharCode(
104 0xe0|((cc>>12)&0x0f),
105 0x80|((cc>> 6)&0x3f),
106 0x80|( cc &0x3f) );
107 else if(cc<=0x1fffff)
108 rv += String.fromCharCode(
109 0xf0|((cc>>18)&0x07),
110 0x80|((cc>>12)&0x3f),
111 0x80|((cc>> 6)&0x3f),
112 0x80|( cc &0x3f) );
113 else if(cc<=0x03ffffff)
114 rv += String.fromCharCode(
115 0xf8|((cc>>24)&0x03),
116 0x80|((cc>>18)&0x3f),
117 0x80|((cc>>12)&0x3f),
118 0x80|((cc>> 6)&0x3f),
119 0x80|( cc &0x3f) );
120 else if(cc<=0x7fffffff)
121 rv += String.fromCharCode(
122 0xfc|((cc>>30)&0x01),
123 0x80|((cc>>24)&0x3f),
124 0x80|((cc>>18)&0x3f),
125 0x80|((cc>>12)&0x3f),
126 0x80|((cc>> 6)&0x3f),
127 0x80|( cc &0x3f) );
128 }
129 return rv;
130}
131function xp_str(xp,x) {
132 var rv = x.evaluate(
133 xp, x, null, XPathResult.STRING_TYPE, null );
134 return rv.stringValue;
135}
136function xp_node(xp,x) {
137 var rv = x.evaluate(
138 xp, x, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null );
139 return rv.singleNodeValue;
140}
141
142function Flickr() { } 92function Flickr() { }
143Flickr.prototype = { 93Flickr.prototype = {
144 94
145 rest_url: 'http://www.flickr.com/services/rest/', 95 rest_url: 'http://www.flickr.com/services/rest/',
146 auth_url: 'http://flickr.com/services/auth/', 96 auth_url: 'http://flickr.com/services/auth/',
147 photo_url: 'http://static.flickr.com/', 97 photo_url: 'http://static.flickr.com/',
148 photos_url: 'http://www.flickr.com/photos/', 98 photos_url: 'http://www.flickr.com/photos/',
149 upload_url: 'http://www.flickr.com/services/upload/', 99 upload_url: 'http://www.flickr.com/services/upload/',
150 100
151 api_sig: function(paramstr) { 101 api_sig: function(paramstr) {
152 return MD5(toutf8(this.api_shs+paramstr)); 102 return MD5(toutf8(this.api_shs+paramstr));
153 }, 103 },
154 api_call_url: function(params,url) { 104 api_call_url: function(params,url) {
155 params.api_key = this.api_key; 105 params.api_key = this.api_key;
156 var pp = new Array(); 106 var pp = new Array();
157 for(var p in params) { 107 for(var p in params) {
158 pp.push(p); 108 pp.push(p);
159 } 109 }
160 var pstr = ''; 110 var pstr = '';
161 var rv = (url?url:this.rest_url)+'?'; 111 var rv = (url?url:this.rest_url)+'?';
162 for(var p in pp.sort()) { 112 for(var p in pp.sort()) {
163 var pn = pp[p]; 113 var pn = pp[p];
164 pstr += pn+params[pn]; 114 pstr += pn+params[pn];
165 rv += pn+'='+params[pn]+'&'; 115 rv += pn+'='+params[pn]+'&';
166 } 116 }
167 rv += 'api_sig='+this.api_sig(pstr); 117 rv += 'api_sig='+this.api_sig(pstr);
168 return rv; 118 return rv;
169 }, 119 },
170 api_call: function(params, on_success, on_failure) { 120 api_call: function(params, on_success, on_failure) {
171 if(params.auth_token == 'default') 121 if(params.auth_token == 'default')
172 params.auth_token = this.token; 122 params.auth_token = this.token;
173 var x = new XMLHttpRequest(); 123 var x = new XMLHttpRequest();
174 x.open("GET",this.api_call_url(params)); 124 x.open("GET",this.api_call_url(params));
175 x.onreadystatechange=function() { 125 x.onreadystatechange=function() {
176 if(x.readyState!=4) return false; 126 if(x.readyState!=4) return false;
177 if(x.status==200) { 127 if(x.status==200) {
178 var stat = x.responseXML.firstChild.getAttribute('stat'); 128 var stat = x.responseXML.firstChild.getAttribute('stat');
179 if(stat=='ok') { 129 if(stat=='ok') {
180 if(on_success) on_success(x); 130 if(on_success) on_success(x);
181 }else{ 131 }else{
182 var e = x.responseXML.getElementsByTagName('err').item(0); 132 var e = x.responseXML.getElementsByTagName('err').item(0);
183 var ecode = e.getAttribute('code'); 133 var ecode = e.getAttribute('code');
184 var emsg = e.getAttribute('msg'); 134 var emsg = e.getAttribute('msg');
185 dump(params.method+' failed: '+ecode+' '+emsg+'\n'); 135 dump(params.method+' failed: '+ecode+' '+emsg+'\n');
186 if(on_failure) on_failure(x,stat,ecode,emsg); 136 if(on_failure) on_failure(x,stat,ecode,emsg);
187 } 137 }
188 }else{ 138 }else{
189 if(on_failure) on_failure(x); 139 if(on_failure) on_failure(x);
190 } 140 }
191 return true; 141 return true;
192 } 142 }
193 x.send(null); 143 x.send(null);
194 return true; 144 return true;
195 }, 145 },
196 146
197 frob: null, 147 frob: null,
198 authorize_0: function(on_s, on_f) { 148 authorize_0: function(on_s, on_f) {
199 var _this = this; 149 var _this = this;
200 this.api_call( 150 this.api_call(
201 { method: 'flickr.auth.getFrob' }, 151 { method: 'flickr.auth.getFrob' },
202 function(x) { 152 function(x) {
203 _this.frob = xp_str('/rsp/frob',x.responseXML); 153 _this.frob = xp_str('/rsp/frob',x.responseXML);
204 var u = _this.api_call_url( 154 var u = _this.api_call_url(
205 { frob: _this.frob, perms: 'delete' }, _this.auth_url ); 155 { frob: _this.frob, perms: 'delete' }, _this.auth_url );
206 var wm = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService( 156 var wm = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService(
207 Components.interfaces.nsIWindowMediator ); 157 Components.interfaces.nsIWindowMediator );
208 var bw = wm.getMostRecentWindow('navigator:browser'); 158 var bw = wm.getMostRecentWindow('navigator:browser');
209 var b = bw.getBrowser(); 159 var b = bw.getBrowser();
210 var t = b.addTab(u); 160 var t = b.addTab(u);
211 b.selectedTab = t; 161 b.selectedTab = t;
212 if(on_s) on_s(); 162 if(on_s) on_s();
213 }, function(x,s,c,m) { 163 }, function(x,s,c,m) {
214 if(on_f) on_f(x,s,c,m); 164 if(on_f) on_f(x,s,c,m);
215 } 165 }
216 ); 166 );
217 }, 167 },
218 token: null, 168 token: null,
219 perms: null, 169 perms: null,
220 user: null, 170 user: null,
221 authorize_1: function(on_s, on_f) { 171 authorize_1: function(on_s, on_f) {
222 var _this = this; 172 var _this = this;
223 this.api_call( 173 this.api_call(
224 { method: 'flickr.auth.getToken', frob: this.frob }, 174 { method: 'flickr.auth.getToken', frob: this.frob },
225 function(x) { 175 function(x) {
226 _this.token = xp_str('/rsp/auth/token',x.responseXML); 176 _this.token = xp_str('/rsp/auth/token',x.responseXML);
227 _this.perms = xp_str('/rsp/auth/perms',x.responseXML); 177 _this.perms = xp_str('/rsp/auth/perms',x.responseXML);
228 var u = xp_node('/rsp/auth/user',x.responseXML); 178 var u = xp_node('/rsp/auth/user',x.responseXML);
229 _this.user = { 179 _this.user = {
230 nsid: u.getAttribute('nsid'), 180 nsid: u.getAttribute('nsid'),
231 username: u.getAttribute('username'), 181 username: u.getAttribute('username'),
232 fullname: u.getAttribute('fullname') 182 fullname: u.getAttribute('fullname')
233 }; 183 };
234 if(on_s) on_s(x); 184 if(on_s) on_s(x);
235 }, function(x,s,c,m) { 185 }, function(x,s,c,m) {
236 if(on_f) on_f(x,s,c,m); 186 if(on_f) on_f(x,s,c,m);
237 } 187 }
238 ); 188 );
239 }, 189 },
240 190
241 prefs: Components.classes['@mozilla.org/preferences-service;1'].getService( 191 prefs: Components.classes['@mozilla.org/preferences-service;1'].getService(
242 Components.interfaces.nsIPrefBranch 192 Components.interfaces.nsIPrefBranch
243 ), 193 ),
244 prefs_root: 'net.klever.kin.flickr', 194 prefs_root: 'net.klever.kin.flickr',
245 save_token: function() { 195 save_token: function() {
246 // TODO: don't clear when there's nothing to clear or catch exceptions 196 // TODO: don't clear when there's nothing to clear or catch exceptions
247 if(this.token) 197 if(this.token)
248 this.prefs.setCharPref(this.prefs_root+'.auth_token',this.token); 198 this.prefs.setCharPref(this.prefs_root+'.auth_token',this.token);
249 else 199 else
250 this.prefs.clearUserPref(this.prefs_root+'.auth_token'); 200 this.prefs.clearUserPref(this.prefs_root+'.auth_token');
251 if(this.perms) 201 if(this.perms)
252 this.prefs.setCharPref(this.prefs_root+'.auth_perms',this.perms); 202 this.prefs.setCharPref(this.prefs_root+'.auth_perms',this.perms);
253 else 203 else
254 this.prefs.clearUserPref(this.prefs_root+'.auth_perms'); 204 this.prefs.clearUserPref(this.prefs_root+'.auth_perms');
255 if(this.user && this.user.nsid!=null && this.user.nsid!=undefined) 205 if(this.user && this.user.nsid!=null && this.user.nsid!=undefined)
256 this.prefs.setCharPref(this.prefs_root+'.auth_user.nsid',this.user.nsid); 206 this.prefs.setCharPref(this.prefs_root+'.auth_user.nsid',this.user.nsid);
257 else 207 else
258 this.prefs.clearUserPref(this.prefs_root+'.auth_user.nsid'); 208 this.prefs.clearUserPref(this.prefs_root+'.auth_user.nsid');
259 if(this.user && this.user.username!=null && this.user.username!=undefined) 209 if(this.user && this.user.username!=null && this.user.username!=undefined)
260 this.prefs.setCharPref(this.prefs_root+'.auth_user.username',this.user.username); 210 this.prefs.setCharPref(this.prefs_root+'.auth_user.username',this.user.username);
261 else 211 else
262 this.prefs.clearUserPref(this.prefs_root+'.auth_user.username'); 212 this.prefs.clearUserPref(this.prefs_root+'.auth_user.username');
263 if(this.user && this.user.fullname!=null && this.user.fullname!=undefined) 213 if(this.user && this.user.fullname!=null && this.user.fullname!=undefined)
264 this.prefs.setCharPref(this.prefs_root+'.auth_user.fullname',this.user.fullname); 214 this.prefs.setCharPref(this.prefs_root+'.auth_user.fullname',this.user.fullname);
265 else 215 else
266 this.prefs.clearUserPref(this.prefs_root+'.auth_user.fullname'); 216 this.prefs.clearUserPref(this.prefs_root+'.auth_user.fullname');
267 }, 217 },
268 _reset_token: function() { 218 _reset_token: function() {
269 this.token = null; this.perms = null; this.user = null; 219 this.token = null; this.perms = null; this.user = null;
270 return false; 220 return false;
271 }, 221 },
272 load_token: function() { 222 load_token: function() {
273 try { 223 try {
274 if(this.prefs.getPrefType(this.prefs_root+'.auth_token')!=this.prefs.PREF_STRING) 224 if(this.prefs.getPrefType(this.prefs_root+'.auth_token')!=this.prefs.PREF_STRING)
275 return this._reset_token(); 225 return this._reset_token();
276 this.token = this.prefs.getCharPref(this.prefs_root+'.auth_token'); 226 this.token = this.prefs.getCharPref(this.prefs_root+'.auth_token');
277 if(this.prefs.getPrefType(this.prefs_root+'.auth_perms')!=this.prefs.PREF_STRING) 227 if(this.prefs.getPrefType(this.prefs_root+'.auth_perms')!=this.prefs.PREF_STRING)
278 return this._reset_token(); 228 return this._reset_token();
279 this.perms = this.prefs.getCharPref(this.prefs_root+'.auth_perms'); 229 this.perms = this.prefs.getCharPref(this.prefs_root+'.auth_perms');
280 if(this.prefs.getPrefType(this.prefs_root+'.auth_user.nsid')!=this.prefs.PREF_STRING) 230 if(this.prefs.getPrefType(this.prefs_root+'.auth_user.nsid')!=this.prefs.PREF_STRING)
281 return this._reset_token(); 231 return this._reset_token();
282 this.user = new Object(); 232 this.user = new Object();
283 this.user.nsid = this.prefs.getCharPref(this.prefs_root+'.auth_user.nsid'); 233 this.user.nsid = this.prefs.getCharPref(this.prefs_root+'.auth_user.nsid');
284 if(this.prefs.getPrefType(this.prefs_root+'.auth_user.username')!=this.prefs.PREF_STRING) 234 if(this.prefs.getPrefType(this.prefs_root+'.auth_user.username')!=this.prefs.PREF_STRING)
285 return this._reset_token(); 235 return this._reset_token();
286 this.user.username = this.prefs.getCharPref(this.prefs_root+'.auth_user.username'); 236 this.user.username = this.prefs.getCharPref(this.prefs_root+'.auth_user.username');
287 if(this.prefs.getPrefType(this.prefs_root+'.auth_user.fullname')!=this.prefs.PREF_STRING) 237 if(this.prefs.getPrefType(this.prefs_root+'.auth_user.fullname')!=this.prefs.PREF_STRING)
288 return this._reset_token(); 238 return this._reset_token();
289 this.user.fullname = this.prefs.getCharPref(this.prefs_root+'.auth_user.fullname'); 239 this.user.fullname = this.prefs.getCharPref(this.prefs_root+'.auth_user.fullname');
290 }catch(e) { return this._reset_token(); } 240 }catch(e) { return this._reset_token(); }
291 return true; 241 return true;
292 }, 242 },
293 reset_token: function() { 243 reset_token: function() {
294 this._reset_token(); 244 this._reset_token();
295 this.save_token(); 245 this.save_token();
296 }, 246 },
297 247
298 get_photo_url: function(ser,id,sec,sfx,ext) { 248 get_photo_url: function(ser,id,sec,sfx,ext) {
299 var rv = this.photo_url + ser + '/' + id + '_' + sec; 249 var rv = this.photo_url + ser + '/' + id + '_' + sec;
300 if(sfx && sfx!='_') rv += '_'+sfx; 250 if(sfx && sfx!='_') rv += '_'+sfx;
301 rv += ext?'.'+ext:'.jpg'; 251 rv += ext?'.'+ext:'.jpg';
302 return rv; 252 return rv;
303 }, 253 },
304 get_image_url: function(o,sfx) { 254 get_image_url: function(o,sfx) {
305 return this.get_photo_url( 255 return this.get_photo_url(
306 o.server, 256 o.server,
307 (o instanceof Photoset)? o.primary : o.id, 257 (o instanceof Photoset)? o.primary : o.id,
308 o.secret, 258 o.secret,
309 sfx, 259 sfx,
310 (sfx=='o')?o.originalformat:null 260 (sfx=='o')?o.originalformat:null
311 ); 261 );
312 }, 262 },
313 get_photo_page_url: function(p) { 263 get_photo_page_url: function(p) {
314 if(p instanceof Photo) // TODO: half wrong, what if no owner? 264 if(p instanceof Photo) // TODO: half wrong, what if no owner?
315 return this.photos_url + (p.owner.nsid?p.owner.nsid:this.user.nsid) + '/' + p.id; 265 return this.photos_url + (p.owner.nsid?p.owner.nsid:this.user.nsid) + '/' + p.id;
316 else // TODO: take owner into account? 266 else // TODO: take owner into account?
317 return this.photos_url + this.user.nsid + '/' + p; 267 return this.photos_url + this.user.nsid + '/' + p;
318 }, 268 },
319 make_photo_url: function(p,sfx) { 269 make_photo_url: function(p,sfx) {
320 if(sfx=='p') 270 if(sfx=='p')
321 return this.get_photo_page_url(p); 271 return this.get_photo_page_url(p);
322 else 272 else
323 return this.get_image_url(p,sfx); 273 return this.get_image_url(p,sfx);
324 }, 274 },
325 275
326 upload_file: function(f,fa,on_success,on_failure) { 276 upload_file: function(f,fa,on_success,on_failure) {
327 try { 277 try {
328 var fi = Components.classes["@mozilla.org/file/local;1"] 278 var fi = Components.classes["@mozilla.org/file/local;1"]
329 .createInstance(Components.interfaces.nsILocalFile); 279 .createInstance(Components.interfaces.nsILocalFile);
330 fi.initWithPath( f ); 280 fi.initWithPath( f );
331 var st = Components.classes["@mozilla.org/network/file-input-stream;1"] 281 var st = Components.classes["@mozilla.org/network/file-input-stream;1"]
332 .createInstance(Components.interfaces.nsIFileInputStream); 282 .createInstance(Components.interfaces.nsIFileInputStream);
333 st.init(fi,0x01,00004,null); 283 st.init(fi,0x01,00004,null);
334 var bis = Components.classes["@mozilla.org/binaryinputstream;1"] 284 var bis = Components.classes["@mozilla.org/binaryinputstream;1"]
335 .createInstance(Components.interfaces.nsIBinaryInputStream); 285 .createInstance(Components.interfaces.nsIBinaryInputStream);
336 bis.setInputStream(st); 286 bis.setInputStream(st);
337 287
338 // allocate and initialize temp storage string 288 // allocate and initialize temp storage string
339 var pbs = Components.classes["@mozilla.org/storagestream;1"] 289 var pbs = Components.classes["@mozilla.org/storagestream;1"]
340 .createInstance(Components.interfaces.nsIStorageStream); 290 .createInstance(Components.interfaces.nsIStorageStream);
341 pbs.init(1024,10000000,null); 291 pbs.init(1024,10000000,null);
342 // create output stream 292 // create output stream
343 var pbos = pbs.getOutputStream(0); 293 var pbos = pbs.getOutputStream(0);
344 // and a binaryoutputstream interface 294 // and a binaryoutputstream interface
345 var pbbos = Components.classes["@mozilla.org/binaryoutputstream;1"] 295 var pbbos = Components.classes["@mozilla.org/binaryoutputstream;1"]
346 .createInstance(Components.interfaces.nsIBinaryOutputStream); 296 .createInstance(Components.interfaces.nsIBinaryOutputStream);
347 pbbos.setOutputStream(pbos); 297 pbbos.setOutputStream(pbos);
348 298
349 /* create POST body */ 299 /* create POST body */
350 var boundarytoken = 'kadaroloongazaduviaxamma'; 300 var boundarytoken = 'kadaroloongazaduviaxamma';
351 var boundary = '--'+boundarytoken; 301 var boundary = '--'+boundarytoken;
352 var b = ''; 302 var b = '';
353 303
354 var parms = { api_key: this.api_key, auth_token: this.token }; 304 var parms = { api_key: this.api_key, auth_token: this.token };
355 for(var p in fa) parms[p] = fa[p]; 305 for(var p in fa) parms[p] = fa[p];
356 var pns = new Array(); 306 var pns = new Array();
357 for(var p in parms) pns.push(p); 307 for(var p in parms) pns.push(p);
358 var pstr = ''; 308 var pstr = '';
359 for(var p in pns.sort()) { 309 for(var p in pns.sort()) {
360 var pn = pns[p]; 310 var pn = pns[p];
361 pstr += pn+parms[pn]; 311 pstr += pn+parms[pn];
362 b += boundary+'\nContent-Disposition: form-data; name="'+pn+'"\n\n'+toutf8(parms[pn])+'\n'; 312 b += boundary+'\nContent-Disposition: form-data; name="'+pn+'"\n\n'+toutf8(parms[pn])+'\n';
363 } 313 }
364 b += boundary+'\nContent-Disposition: form-data; name="api_sig"\n\n'+this.api_sig(pstr)+'\n'; 314 b += boundary+'\nContent-Disposition: form-data; name="api_sig"\n\n'+this.api_sig(pstr)+'\n';
365 b += boundary+'\nContent-Disposition: form-data; name="photo"; filename="'+f+'"\nContent-Type: image/jpeg\nContent-Transfer-Encoding: binary\n\n'; 315 b += boundary+'\nContent-Disposition: form-data; name="photo"; filename="'+f+'"\nContent-Type: image/jpeg\nContent-Transfer-Encoding: binary\n\n';
366 pbbos.writeBytes(b,b.length); 316 pbbos.writeBytes(b,b.length);
367 var bisbytes = bis.available(); 317 var bisbytes = bis.available();
368 pbbos.writeBytes(bis.readBytes(bisbytes),bisbytes); 318 pbbos.writeBytes(bis.readBytes(bisbytes),bisbytes);
369 pbbos.writeBytes('\n'+boundary+'--',3+boundary.length); bis.close(); st.close(); 319 pbbos.writeBytes('\n'+boundary+'--',3+boundary.length); bis.close(); st.close();
370 320
371 pbbos.close(); pbos.close(); 321 pbbos.close(); pbos.close();
372 322
373 var x = new XMLHttpRequest(); 323 var x = new XMLHttpRequest();
374 x.open("POST",this.upload_url); 324 x.open("POST",this.upload_url);
375 x.setRequestHeader('Content-Type', 'multipart/form-data; boundary="'+boundarytoken+'"'); 325 x.setRequestHeader('Content-Type', 'multipart/form-data; boundary="'+boundarytoken+'"');
376 x.setRequestHeader('Connection','close'); 326 x.setRequestHeader('Connection','close');
377 x.setRequestHeader('Content-Length',b.length); 327 x.setRequestHeader('Content-Length',b.length);
378 x.onreadystatechange=function() { 328 x.onreadystatechange=function() {
379 if(x.readyState!=4) return false; 329 if(x.readyState!=4) return false;
380 if(x.status==200) { 330 if(x.status==200) {
381 var stat = x.responseXML.firstChild.getAttribute('stat'); 331 var stat = x.responseXML.firstChild.getAttribute('stat');
382 if(stat=='ok') { 332 if(stat=='ok') {
383 var pid = xp_str('/rsp/photoid',x.responseXML); 333 var pid = xp_str('/rsp/photoid',x.responseXML);
384 if(on_success) on_success(x,pid); 334 if(on_success) on_success(x,pid);
385 }else{ 335 }else{
386 var e = x.responseXML.getElementsByTagName('err').item(0); 336 var e = x.responseXML.getElementsByTagName('err').item(0);
387 var ecode = e.getAttribute('code'); 337 var ecode = e.getAttribute('code');
388 var emsg = e.getAttribute('msg'); 338 var emsg = e.getAttribute('msg');
389 dump('upload failed: '+ecode+' '+emsg+'\n'); 339 dump('upload failed: '+ecode+' '+emsg+'\n');
390 if(on_failure) on_failure(x,stat,ecode,emsg); 340 if(on_failure) on_failure(x,stat,ecode,emsg);
391 } 341 }
392 }else{ 342 }else{
393 if(on_failure) on_failure(x); 343 if(on_failure) on_failure(x);
394 } 344 }
395 return true; 345 return true;
396 }; 346 };
397 x.send(pbs.newInputStream(0)); 347 x.send(pbs.newInputStream(0));
398 }catch(e) { 348 }catch(e) {
399 if(on_failure) on_failure(e,null,-1,e.message); 349 if(on_failure) on_failure(e,null,-1,e.message);
400 } 350 }
401 } 351 }
402 352
403}; 353};
diff --git a/content/util.js b/content/util.js
new file mode 100644
index 0000000..5af0978
--- a/dev/null
+++ b/content/util.js
@@ -0,0 +1,61 @@
1/*
2 * convert unicode string to utf-8 representation.
3 * needed for correct md5 hash calculation.
4 */
5function toutf8(ucode) {
6 var rv = '';
7 for(var i=0;i<ucode.length;++i) {
8 var cc = ucode.charCodeAt(i);
9 if(cc<=0x7F)
10 rv += ucode.charAt(i);
11 else if(cc<=0x7ff)
12 rv += String.fromCharCode(
13 0xc0|((cc>> 6)&0x1f),
14 0x80|( cc &0x3f) );
15 else if(cc<=0xffff)
16 rv += String.fromCharCode(
17 0xe0|((cc>>12)&0x0f),
18 0x80|((cc>> 6)&0x3f),
19 0x80|( cc &0x3f) );
20 else if(cc<=0x1fffff)
21 rv += String.fromCharCode(
22 0xf0|((cc>>18)&0x07),
23 0x80|((cc>>12)&0x3f),
24 0x80|((cc>> 6)&0x3f),
25 0x80|( cc &0x3f) );
26 else if(cc<=0x03ffffff)
27 rv += String.fromCharCode(
28 0xf8|((cc>>24)&0x03),
29 0x80|((cc>>18)&0x3f),
30 0x80|((cc>>12)&0x3f),
31 0x80|((cc>> 6)&0x3f),
32 0x80|( cc &0x3f) );
33 else if(cc<=0x7fffffff)
34 rv += String.fromCharCode(
35 0xfc|((cc>>30)&0x01),
36 0x80|((cc>>24)&0x3f),
37 0x80|((cc>>18)&0x3f),
38 0x80|((cc>>12)&0x3f),
39 0x80|((cc>> 6)&0x3f),
40 0x80|( cc &0x3f) );
41 }
42 return rv;
43}
44
45/*
46 * extract xpath-specified string value
47 */
48function xp_str(xp,x) {
49 var rv = x.evaluate(
50 xp, x, null, XPathResult.STRING_TYPE, null );
51 return rv.stringValue;
52}
53/*
54 * extract xpath-specified node
55 */
56function xp_node(xp,x) {
57 var rv = x.evaluate(
58 xp, x, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null );
59 return rv.singleNodeValue;
60}
61