summaryrefslogtreecommitdiffabout
path: root/content
authorMichael Krelin <hacker@klever.net>2006-09-26 19:21:57 (UTC)
committer Michael Krelin <hacker@klever.net>2006-09-26 19:21:57 (UTC)
commitc5ea6ff7abd6e376ae151c9724d24f6fe156766e (patch) (unidiff)
tree0df2e4ecf02f89c4b85d1950b5c6f4fd2f67f9bd /content
parent5207247fdc837ae9de1d81db903f6cd92532595e (diff)
downloadfireflix-c5ea6ff7abd6e376ae151c9724d24f6fe156766e.zip
fireflix-c5ea6ff7abd6e376ae151c9724d24f6fe156766e.tar.gz
fireflix-c5ea6ff7abd6e376ae151c9724d24f6fe156766e.tar.bz2
Initial import into public repository0.0
git-svn-id: http://svn.klever.net/kin/fireflix/trunk@159 fe716a7a-6dde-0310-88d9-d003556173a8
Diffstat (limited to 'content') (more/less context) (show whitespace changes)
-rw-r--r--content/Makefile.am22
-rw-r--r--content/about.xul45
-rw-r--r--content/autoconf.dtd.in3
-rw-r--r--content/background.jpegbin0 -> 880 bytes
-rw-r--r--content/browser.xul19
-rw-r--r--content/copying.xul14
-rw-r--r--content/fireflix-panel.xul252
-rw-r--r--content/fireflix.css90
-rw-r--r--content/fireflix.js878
-rw-r--r--content/flickr.js403
-rw-r--r--content/generated-content.js17
-rw-r--r--content/generated-content.xul20
-rw-r--r--content/icons/16x16/fireflix.pngbin0 -> 926 bytes
-rw-r--r--content/icons/32x32/fireflix.pngbin0 -> 2017 bytes
-rw-r--r--content/md5.js154
-rw-r--r--content/photoset-props.js81
-rw-r--r--content/photoset-props.xul38
17 files changed, 2036 insertions, 0 deletions
diff --git a/content/Makefile.am b/content/Makefile.am
new file mode 100644
index 0000000..8548400
--- a/dev/null
+++ b/content/Makefile.am
@@ -0,0 +1,22 @@
1xpichromecontent_DATA = \
2 autoconf.dtd \
3 browser.xul about.xul fireflix-panel.xul photoset-props.xul \
4 generated-content.xul \
5 photoset-props.js fireflix.js flickr.js md5.js \
6 generated-content.js \
7 fireflix.css \
8 background.jpeg
9
10sized_icons = \
11 $(addsuffix .png, \
12 fireflix \
13 )
14
15nobase_xpichromecontent_DATA = \
16 $(addprefix icons/, \
17 $(addprefix 16x16/,${sized_icons}) \
18 $(addprefix 32x32/,${sized_icons}) \
19 )
20
21EXTRA_DIST = \
22 ${xpichromecontent_DATA} ${nobase_xpichromecontent_DATA}
diff --git a/content/about.xul b/content/about.xul
new file mode 100644
index 0000000..1cb13d4
--- a/dev/null
+++ b/content/about.xul
@@ -0,0 +1,45 @@
1<?xml version="1.0"?>
2<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
3<?xml-stylesheet href="fireflix.css" type="text/css"?>
4<!DOCTYPE window SYSTEM "chrome://fireflix/locale/fireflix.dtd">
5<window
6 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
7 id="aboutFireflix" title="&aboutFireflix;"
8 orient="vertical"
9 width="400" height="200"
10 >
11
12 <hbox class="about wholething" flex="1">
13 <hbox flex="1" class="insides">
14 <vbox>
15 <spacer flex="1"/>
16 <image src="icons/32x32/fireflix.png" width="32" height="32" />
17 <spacer flex="1"/>
18 </vbox>
19 <groupbox flex="1" class="text" orient="vertical">
20 <spacer flex="2"/>
21 <hbox>
22 <spacer flex="1"/>
23 <label value="Fireflix &autoconf.version;" class="title"/>
24 <spacer flex="1"/>
25 </hbox>
26 <spacer flex="1"/>
27 <hbox>
28 <label value="Copyright © 2006 "/>
29 <label value="Klever Group" class="link"
30 onclick="window.openDialog('chrome://browser/content/browser.xul','_blank','chrome,all,dialog=no','http://www.klever.net/',null,null)" />
31 </hbox>
32 <spacer flex="2"/>
33 </groupbox>
34 <vbox>
35 <spacer flex="10" />
36 <button label="&about.license.label;" tooltiptext="&about.license.tip;"
37 oncommand="window.openDialog('chrome://fireflix/content/copying.xul','copying')" />
38 <spacer flex="2" />
39 <button label="OK" oncommand="window.close()"/>
40 <spacer flex="1" />
41 </vbox>
42 </hbox>
43 </hbox>
44
45</window>
diff --git a/content/autoconf.dtd.in b/content/autoconf.dtd.in
new file mode 100644
index 0000000..e4ad217
--- a/dev/null
+++ b/content/autoconf.dtd.in
@@ -0,0 +1,3 @@
1<!ENTITY autoconf.version "@VERSION@">
2<!ENTITY autoconf.package "@PACKAGE@">
3<!ENTITY autoconf.copying "@COPYING@">
diff --git a/content/background.jpeg b/content/background.jpeg
new file mode 100644
index 0000000..43684f7
--- a/dev/null
+++ b/content/background.jpeg
Binary files differ
diff --git a/content/browser.xul b/content/browser.xul
new file mode 100644
index 0000000..aaff443
--- a/dev/null
+++ b/content/browser.xul
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<!DOCTYPE overlay SYSTEM "chrome://fireflix/locale/fireflix.dtd">
3<overlay id="fireflixOverlay"
4 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" >
5
6 <menupopup id="viewSidebarMenu">
7 <menuitem observes="viewFireflixSidebar" />
8 </menupopup>
9
10 <broadcasterset id="mainBroadcasterSet">
11 <broadcaster id="viewFireflixSidebar"
12 autoCheck="false" label="&browser.sidebar.label;"
13 type="checkbox" group="sidebar"
14 sidebarurl="chrome://fireflix/content/fireflix-panel.xul"
15 sidebartitle="&browser.sidebar.title;"
16 oncommand="toggleSidebar('viewFireflixSidebar')" />
17 </broadcasterset>
18</overlay>
19
diff --git a/content/copying.xul b/content/copying.xul
new file mode 100644
index 0000000..179dca5
--- a/dev/null
+++ b/content/copying.xul
@@ -0,0 +1,14 @@
1<?xml version="1.0"?>
2<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
3<?xml-stylesheet href="fireflix.css" type="text/css"?>
4<!DOCTYPE dialog SYSTEM "chrome://fireflix/locale/fireflix.dtd">
5<dialog
6 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
7 id="copying" title="&copying.title;" orient="vertical"
8 buttons="accept">
9
10 <div xmlns="http://www.w3.org/1999/xhtml">
11 &autoconf.copying;
12 </div>
13
14</dialog>
diff --git a/content/fireflix-panel.xul b/content/fireflix-panel.xul
new file mode 100644
index 0000000..9953761
--- a/dev/null
+++ b/content/fireflix-panel.xul
@@ -0,0 +1,252 @@
1<?xml version="1.0"?>
2<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
3<?xml-stylesheet href="fireflix.css" type="text/css"?>
4<!DOCTYPE page SYSTEM "chrome://fireflix/locale/fireflix.dtd">
5<page
6 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
7 id="fireflixwindow" title="Fireflix"
8 onload="fireflix.init()"
9 orient="vertical"
10 ondragover="nsDragAndDrop.dragOver(event,fireflix.uploadObserver)"
11 ondragdrop="nsDragAndDrop.drop(event,fireflix.uploadObserver)"
12 >
13
14 <script src="chrome://global/content/nsDragAndDrop.js"/>
15 <script src="chrome://global/content/nsTransferable.js"/>
16 <script type="application/x-javascript" src="md5.js" />
17 <script type="application/x-javascript" src="flickr.js" />
18 <script type="application/x-javascript" src="fireflix.js" />
19
20 <stringbundleset>
21 <stringbundle id="loc_strings" src="chrome://fireflix/locale/fireflix.properties" />
22 </stringbundleset>
23
24 <commandset id="cmdset_search">
25 <command id="cmd_search" label="&panel.search.cmd_search.label;"
26 oncommand="fireflix.foundphotos.search_photos()"/>
27 <command id="cmd_search_open" label="&panel.search.cmd_search_open.label;"
28 oncommand="fireflix.foundphotos.on_cmd_open(event)" />
29 </commandset>
30
31 <commandset id="cmdset_sets">
32 <command id="cmd_refresh_sets" label="&panel.sets.cmd_refresh_sets;"
33 oncommand="fireflix.on_refresh_sets()" />
34 <command id="cmd_set_props" label="&panel.sets.cmd_properties;"
35 oncommand="fireflix.on_set_props()" disabled="true" />
36 </commandset>
37
38 <popupset>
39 <popup id="sets_menu">
40 <menuitem command="cmd_set_props"/>
41 <menuitem command="cmd_refresh_sets"/>
42 <menuseparator/>
43 <menu label="&panel.sets.generate_html;" id="sets_html_menu"/>
44 </popup>
45 </popupset>
46
47 <commandset id="cmdset_uploads">
48 <command id="cmd_uploads_clear" label="&panel.uploads.clear.label;"
49 oncommand="fireflix.uploads.on_clear()" />
50 <command id="cmd_uploads_upload" label="&panel.uploads.upload.label;"
51 oncommand="fireflix.uploads.on_upload()" />
52 <command id="cmd_uploads_remove" label="&panel.uploads.remove.label;"
53 oncommand="fireflix.uploads.on_remove()" />
54 <command id="cmd_uploads_add" label="&panel.uploads.add.label;"
55 oncommand="fireflix.uploads.on_add()" />
56 </commandset>
57
58 <popupset>
59 <popup id="uploads_menu">
60 <menuitem command="cmd_uploads_add"/>
61 <menuitem command="cmd_uploads_clear"/>
62 <menuitem command="cmd_uploads_remove"/>
63 <menuseparator/>
64 <menuitem command="cmd_uploads_upload"/>
65 <menuseparator/>
66 <menu label="&panel.uploads.generate_html;" id="uploads_html_menu"/>
67 </popup>
68 </popupset>
69
70 <vbox class="wholething" flex="1">
71
72 <groupbox>
73 <caption label="&panel.auth_info;"/>
74 <hbox>
75 <label id="auth_info" value="&panel.no_auth_info;" flex="1" disabled="true"/>
76 <button id="b_auth" label="&panel.auth_button;" oncommand="fireflix.on_auth()"/>
77 <button id="b_auth_done" label="&panel.auth_complete_button;" hidden="true"
78 oncommand="fireflix.on_auth_done()"/>
79 <button label="&panel.flickr_button.label;"
80 tooltiptext="&panel.flickr_button.tip;"
81 oncommand="fireflix.openTab('http://www.flickr.com/')" />
82 </hbox>
83 </groupbox>
84
85 <tabbox flex="1" id="fireflix_tabs">
86
87 <tabs>
88 <tab label="&panel.tabs.search;"/>
89 <tab label="&panel.tabs.sets;"/>
90 <tab label="&panel.tabs.tags;" hidden="true"/> <!-- TODO: -->
91 <tab id="tab_upload" label="&panel.tabs.upload;"/>
92 </tabs>
93
94 <tabpanels flex="1">
95
96 <tabpanel id="tabpanel_search" flex="1">
97 <vbox flex="1">
98 <groupbox class="search_params" orient="vertical" onkeypress="if(event.keyCode==event.DOM_VK_RETURN) fireflix.foundphotos.search_photos()">
99 <hbox>
100 <label control="search_for" value="&panel.search.search_for.label;"
101 accesskey="s"/>
102 <textbox id="search_for" flex="1"/>
103 </hbox>
104 <hbox>
105 <checkbox id="search_tags" label="&panel.search.mode.tagsonly.label;"
106 tooltiptext="&panel.search.mode.tagsonly.tip;" checked="false"
107 accesskey="t" />
108 <checkbox id="search_mine" label="&panel.search.mode.mine.label;" checked="true" accesskey="m"/>
109 <spacer flex="1"/>
110 <button command="cmd_search"/>
111 </hbox>
112 </groupbox>
113 <tree id="searchresults" rows="4" flex="1"
114 onselect="fireflix.foundphotos.on_select()"
115 ondblclick="fireflix.foundphotos.on_cmd_open(event)"
116 onkeypress="if(event.keyCode==event.DOM_VK_RETURN)
117 fireflix.foundphotos.on_cmd_open(event)">
118 <treecols>
119 <treecol id="sr_title" label="&panel.search.col.title.label;" flex="2" crop="end" align="start" />
120 </treecols>
121 <treechildren/>
122 </tree>
123 <groupbox id="searchresult_props" orient="horizontal" hidden="true">
124 <vbox width="100" pack="center">
125 <hbox pack="center">
126 <image id="search_photo"/>
127 </hbox>
128 </vbox>
129 <vbox flex="1">
130 <label id="searchresult_title"/>
131 <textbox flex="1" multiline="true" class="plain" readonly="true" id="searchresult_description"/>
132 <hbox pack="end">
133 <button command="cmd_search_open"/>
134 </hbox>
135 </vbox>
136 </groupbox>
137 </vbox>
138 </tabpanel>
139
140 <tabpanel id="tabpanel_sets" flex="1"
141 onkeypress="if(event.keyCode==event.DOM_VK_RETURN)
142 document.getElementById('setphotos').focus()">
143 <vbox flex="1">
144 <tree id="setslist" rows="4" onselect="fireflix.photosets.on_select()"
145 flex="1" context="sets_menu"
146 >
147 <treecols>
148 <treecol id="sl_name" label="&panel.sets.name.label;" flex="4" crop="end" align="start" tooltiptext="&panel.sets.name.tip;"/>
149 <splitter class="tree-splitter" />
150 <treecol id="sl_photos" label="&panel.sets.photos.label;" flex="1" align="end" tooltiptext="&panel.sets.photos.tip;" />
151 </treecols>
152 <treechildren/>
153 </tree>
154 <hbox>
155 <button command="cmd_refresh_sets" />
156 <button command="cmd_set_props" />
157 </hbox>
158 <tree id="setphotos" rows="4" onselect="fireflix.photoset.on_select()"
159 flex="1">
160 <treecols>
161 <treecol id="sp_title" label="&panel.setphotos.title.label;" flex="1" crop="end" align="start" tooltiptext="&panel.setphotos.title.tip;" />
162 <splitter class="tree-splitter" />
163 <treecol id="sp_taken" label="&panel.setphotos.taken.label;" crop="end" align="start" tooltiptext="&panel.setphotos.taken.tip;" hidden="true" />
164 <treecol id="sp_upload" label="&panel.setphotos.upload.label;" crop="end" align="start" tooltiptext="&panel.setphotos.upload.tip;" hidden="true" />
165 </treecols>
166 <treechildren/>
167 </tree>
168 <groupbox id="set_photo_props" orient="horizontal">
169 <vbox width="100" pack="center">
170 <hbox pack="center">
171 <image id="set_photo" hidden="true"/>
172 </hbox>
173 </vbox>
174 <spacer flex="1"/>
175 </groupbox>
176 </vbox>
177 </tabpanel>
178
179 <tabpanel id="tabpanel_tags">
180 <listbox id="tagslist" rows="8" flex="1">
181 <listhead>
182 <listheader label="&panel.tagslist.tag.label;"/>
183 </listhead>
184 <listcols>
185 <listcol flex="1"/>
186 </listcols>
187 </listbox>
188 </tabpanel>
189
190 <tabpanel id="tabpanel_upload">
191 <vbox flex="1">
192 <tree id="uploadlist" rows="8" flex="1"
193 onselect="fireflix.uploads.selectionChanged()"
194 context="uploads_menu">
195 <treecols>
196 <treecol id="up_file" label="&panel.uploadlist.file.label;" flex="4" crop="start" align="start"/>
197 <splitter class="tree-splitter" />
198 <treecol id="up_title" label="&panel.uploadlist.title.label;" flex="5" crop="end" align="start" />
199 <splitter class="tree-splitter" />
200 <treecol id="up_status" label="&panel.uploadlist.status.label;" flex="1" crop="end" align="start" />
201 </treecols>
202 <treechildren/>
203 </tree>
204 <progressmeter id="upload_progress" mode="undetermined" hidden="true" />
205 <groupbox id="upload_file_props" orient="horizontal" hidden="true">
206 <image id="upload_file_preview" width="100" height="100" />
207 <grid flex="1">
208 <columns>
209 <column/>
210 <column flex="1"/>
211 </columns>
212 <rows>
213 <row>
214 <label control="upload_filename"
215 value="&panel.upload_props.filename.label;" />
216 <textbox id="upload_filename"
217 oninput="fireflix.uploads.propsToSel('filename')"/>
218 </row>
219 <row>
220 <label control="upload_title" value="&panel.upload_props.title.label;" />
221 <textbox id="upload_title"
222 oninput="fireflix.uploads.propsToSel('title')"/>
223 </row>
224 <row>
225 <label control="uplod_tags" value="&panel.upload_props.tags.label;" />
226 <textbox id="upload_tags"
227 oninput="fireflix.uploads.propsToSel('tags')"/>
228 </row>
229 <!-- TODO: description, public, friend, family -->
230 </rows>
231 </grid>
232 </groupbox>
233 <hbox>
234 <button command="cmd_uploads_add" />
235 <spacer flex="1"/>
236 <button command="cmd_uploads_remove" />
237 <spacer flex="1"/>
238 <button command="cmd_uploads_clear" />
239 </hbox>
240 <hbox pack="center">
241 <button command="cmd_uploads_upload" flex="1"/>
242 </hbox>
243 </vbox>
244 </tabpanel>
245
246 </tabpanels>
247
248 </tabbox>
249
250 </vbox>
251
252</page>
diff --git a/content/fireflix.css b/content/fireflix.css
new file mode 100644
index 0000000..188f48e
--- a/dev/null
+++ b/content/fireflix.css
@@ -0,0 +1,90 @@
1.generated.wholething,
2.about.wholething,
3tabbox, tabpanels, tabpanel {
4 background: url("background.jpeg");
5}
6tabpanels {
7 padding: 0px;
8}
9
10tree {
11 margin-top: 2px;
12 background: rgb(12,167,0);
13 color: rgb(255,255,0);
14 font-size: 90%;
15}
16tree treechildren { /* for windows */
17 background: rgb(12,167,0);
18}
19
20tree#uploadlist treechildren::-moz-tree-cell-text(pending) {
21}
22tree#uploadlist treechildren::-moz-tree-cell-text(completed) {
23 color: white;
24}
25tree#uploadlist treechildren::-moz-tree-row(failed) {
26 background: yellow;
27}
28tree#uploadlist treechildren::-moz-tree-cell-text(failed) {
29 color: red;
30}
31tree#uploadlist treechildren::-moz-tree-cell-text(uploading) {
32 font-weight: bold;
33}
34
35groupbox#searchresult_props,
36groupbox.search_params,
37groupbox#upload_file_props,
38groupbox#set_props,
39groupbox#set_photo_props {
40 background: white;
41}
42
43groupbox#upload_file_props label {
44 text-align: right;
45}
46
47image#set_photo, image#set_primary {
48 border: black 1px solid;
49}
50
51.about .insides {
52 margin: 1ex;
53}
54.about .text {
55 border: yellow solid 1px;
56 background: green;
57}
58.about .title {
59 font-size: 300%;
60 font-weight: bold;
61 color: yellow;
62}
63.about .link {
64 text-decoration: underline;
65 color: white;
66 cursor: pointer;
67}
68
69menuitem.menuhead {
70 background: gray;
71 color: black;
72 font-weight: bold;
73}
74
75label#searchresult_description {
76 font-weight: bold;
77}
78textbox#searchresult_description {
79 padding: 1px 3px !important;
80 background: white;
81}
82
83#copying div {
84 margin: 1ex 1em;
85 font-family: courier, monospace;
86 font-size: 9pt;
87 padding: 2px;
88 border: dotted 1px gray;
89 background: white;
90}
diff --git a/content/fireflix.js b/content/fireflix.js
new file mode 100644
index 0000000..9518480
--- a/dev/null
+++ b/content/fireflix.js
@@ -0,0 +1,878 @@
1function splitascii(s) {
2 var rv='';
3 for(var i=0;i<s.length;++i) {
4 var w = s.charCodeAt(i);
5 rv += String.fromCharCode(
6 w&0xff, (w>>8)&0xff );
7 }
8 return rv;
9}
10
11
12var fireflix = {
13 flickr: new Flickr(),
14 init: function() {
15 this.loc_strings = document.getElementById('loc_strings');
16 this.build_menus();
17 this.cmd_set_props = document.getElementById('cmd_set_props');
18 this.foundphotos.init(this);
19 this.photosets.init(this);
20 this.photoset.init(this);
21 this.uploads.init(this);
22 this.uploadObserver.init(this);
23 this.flickr.api_key = '9c43cd66947a57e6f29db1a9da3f72e3';
24 this.flickr.api_shs = '9c33c9e2f0f0cfd5';
25 this.flickr.prefs_root = 'net.klever.kin.fireflix';
26 this.flickr.load_token();
27 document.getElementById('setslist').view = this.photosets;
28 document.getElementById('setphotos').view = this.photoset;
29 document.getElementById('uploadlist').view = this.uploads;
30 this.flickr.no_auth_info_label = document.getElementById('auth_info').value;
31 if(this.flickr.token) {
32 this.refresh_stuff();
33 document.getElementById('auth_info').value =
34 this.flickr.user.fullname+' ['+this.flickr.user.username+']';
35 document.getElementById('auth_info').disabled = false;
36 document.getElementById('b_auth').hidden = true;
37 }
38 },
39 on_auth: function() {
40 var _this = this;
41 this.flickr.authorize_0(
42 function() {
43 document.getElementById('b_auth').hidden = true;
44 document.getElementById('b_auth_done').hidden = false;
45 }, function(x,s,c,m) {
46 _this.flickr_failure(x,s,c,m);
47 }
48 );
49 },
50 on_auth_done: function() {
51 document.getElementById('b_auth_done').hidden = true;
52 var _this = this;
53 this.flickr.authorize_1(
54 function() {
55 _this.flickr.save_token();
56 _this.refresh_stuff();
57 document.getElementById('auth_info').value =
58 _this.flickr.user.fullname+' ['+_this.flickr.user.username+']';
59 document.getElementById('auth_info').disabled = false;
60 }, function(x,s,c,m) {
61 document.getElementById('b_auth').hidden = false;
62 _this.flickr_failure(x,s,c,m);
63 }
64 );
65 },
66
67 refresh_sets: function() { this.photosets.refresh_sets(); },
68 refresh_stuff: function() {
69 this.refresh_sets();
70 this.refresh_user_tags();
71 },
72
73 /* photoset treeview */
74 photoset: {
75 photos: new Array(),
76 fireflix: null,
77 init: function(f) {
78 this.fireflix = f;
79 },
80 rowCount: 0,
81 getCellText: function(r,c) {
82 var p = this.photos[r];
83 if(c.id=='sp_title') return p.title;
84 if(c.id=='sp_taken') return p.datetaken;
85 if(c.id=='sp_upload') return p.dateupload; /* TODO: unixtime conversion */
86 return c.id;
87 },
88 setTree: function(t) { this.tree = t },
89 isContainer: function(r) { return false; },
90 isSeparator: function(r) { return false; },
91 isSorted: function(r) { return false; },
92 getLevel: function(r) { return 0; },
93 getImageSrc: function(r,c) { return null },
94 getRowProperties: function(r,p) {},
95 getCellProperties: function(cid,cel,p) {},
96 getColumnProperties: function(cid,cel,p) { },
97 cycleHeader: function(cid,e) { },
98 getParentIndex: function(r) { return -1; },
99 drop: function(r,o) { },
100 canDropBeforeAfter: function(r,b) { return false },
101
102 importXPR: function(xp) {
103 this.tree.beginUpdateBatch();
104 this.photos = new Array();
105 var n; while(n=xp.iterateNext()) {
106 this.photos.push(new Photo(n));
107 }
108 this.rowCount = this.photos.length;
109 this.tree.endUpdateBatch();
110 },
111 load_photos: function(psid) {
112 var _this = this;
113 this.fireflix.flickr.api_call(
114 {
115 method: 'flickr.photosets.getPhotos',
116 auth_token: 'default',
117 photoset_id: psid,
118 extras: 'license,date_upload,date_taken,owner_name,icon_server,original_format,last_update'
119 }, function(xr) {
120 var x = xr.responseXML;
121 var xp = x.evaluate(
122 '/rsp/photoset/photo', x, null,
123 XPathResult.ORDERED_NODE_ITERATOR_TYPE, null );
124 _this.importXPR(xp);
125 }, function(x,s,c,m) {
126 _this.fireflix.flickr_failure(x,s,c,m);
127 }
128 );
129 },
130 on_select: function() {
131 if(this.selection.count==1) {
132 var p = this.photos[this.selection.currentIndex];
133 document.getElementById('set_photo').src =
134 this.fireflix.flickr.get_photo_url(p.server,p.id,p.secret,'t');
135 document.getElementById('set_photo').hidden = false;
136 }else{
137 document.getElementById('set_photo').hidden = true;
138 }
139 }
140 },
141
142 /* photosets treeview */
143 photosets: {
144 sets: new Array(),
145 fireflix: null,
146 init: function(f) {
147 this.fireflix = f;
148 },
149 rowCount: 0,
150 getCellText: function(r,c) {
151 var s = this.sets[r];
152 if(c.id=='sl_name') return s.title;
153 if(c.id=='sl_photos') return s.photos;
154 return c.id;
155 },
156 setTree: function(t) { this.tree = t },
157 isContainer: function(r) { return false; },
158 isSeparator: function(r) { return false; },
159 isSorted: function() { return false; },
160 getLevel: function(r) { return 0; },
161 getImageSrc: function(r,c) { return null },
162 getRowProperties: function(r,p) {},
163 getCellProperties: function(cid,cel,p) { },
164 getColumnProperties: function(cid,cel,p) { },
165 cycleHeader: function(cid,e) { },
166 getParentIndex: function(r) { return -1; },
167 drop: function(r,o) { },
168 canDropBeforeAfter: function(r,b) { return false },
169
170 importXPR: function(xp) {
171 this.tree.beginUpdateBatch();
172 this.sets = new Array();
173 var n; while(n=xp.iterateNext()) {
174 this.sets.push(new Photoset(n));
175 }
176 this.rowCount = this.sets.length;
177 this.tree.endUpdateBatch();
178 },
179 refresh_sets: function() {
180 var _this = this;
181 this.fireflix.flickr.api_call(
182 {
183 method: 'flickr.photosets.getList',
184 auth_token: 'default'
185 }, function(xr) {
186 var x = xr.responseXML;
187 var xp = x.evaluate(
188 '/rsp/photosets/photoset', x, null,
189 XPathResult.ORDERED_NODE_ITERATOR_TYPE, null );
190 _this.importXPR(xp);
191 }, function(x,s,c,m) {
192 _this.fireflix.flickr_failure(x,s,c,m);
193 }
194 );
195 },
196 on_select: function() {
197 if(this.selection.count==1) {
198 this.fireflix.cmd_set_props.setAttribute('disabled','false');
199 var s = this.sets[this.selection.currentIndex];
200 this.fireflix.photoset.load_photos(s.id);
201 }else{
202 this.fireflix.cmd_set_props.setAttribute('disabled','true');
203 }
204 }
205 },
206
207 refresh_user_tags: function() {
208 var lb = document.getElementById('tagslist');
209 var _this = this;
210 this.flickr.api_call(
211 {
212 method: 'flickr.tags.getListUser',
213 auth_token: 'default',
214 }, function(xr) {
215 var x = xr.responseXML;
216 var xp = x.evaluate(
217 '/rsp/who/tags/tag', x, null,
218 XPathResult.ORDERED_NODE_ITERATOR_TYPE, null );
219 // TODO: clear list
220 var n; while(n=xp.iterateNext()) {
221 lb.appendItem(n.firstChild.nodeValue);
222 }
223 }, function(x,s,c,m) {
224 _this.flickr_failure(x,s,c,m);
225 }
226 );
227 },
228
229 uploadObserver: {
230 fireflix: null,
231 init: function(f) {
232 this.fireflix = f;
233 },
234 getSupportedFlavours: function() {
235 var rv = new FlavourSet();
236 rv.appendFlavour('application/x-moz-file','nsIFile');
237 rv.appendFlavour('application/x-moz-url');
238 rv.appendFlavour('text/uri-list');
239 rv.appendFlavour('text/unicode');
240 return rv;
241 },
242 canHandleMultipleItems: true,
243 onDragOver: function(ev,fl,sess) {
244 return true;
245 },
246 onDrop: function(ev,dd,s) {
247 var ldf = null;
248 for(var i in dd.dataList) {
249 var di = dd.dataList[i];
250 var dif = di.first;
251 if(
252 ldf==null
253 || ldf.flavour.contentType!=dif.flavour.contentType
254 || ldf.contentLength!=dif.contentLength
255 || ldf.data!=dif.data )
256 this.drop_item(ev,di,s);
257 ldf = dif;
258 }
259 },
260 drop_item: function(ev,di,s) {
261 var d = di.first;
262 switch(d.flavour.contentType) {
263 case 'text/unicode':
264 this.drop_urilist(ev,d.data,s);
265 break;
266 case 'application/x-moz-file':
267 this.fireflix.uploads.add(d.data.path);
268 document.getElementById('fireflix_tabs').selectedTab
269 = document.getElementById('tab_upload');
270 break;
271 case 'text/uri-list':
272 // is it ascii or could it be utf8?
273 this.drop_urilist(ev,splitascii(d.data),s);
274 break;
275 default: alert(d.flavour.contentType+':'+d.data); break;
276 };
277 },
278 drop_urilist: function(ev,ul,s) {
279 // TODO: check for being a file?
280 var us = decodeURIComponent(ul).split(/[\r\n]/);
281 for(var ui in us)
282 if(/\S/.test(us[ui]))
283 this.fireflix.uploads.add(us[ui]);
284 document.getElementById('fireflix_tabs').selectedTab
285 = document.getElementById('tab_upload');
286 }
287 },
288
289 uploads: {
290 fireflix: null,
291 init: function(f) {
292 this.fireflix=f;
293 this.upload_filename = document.getElementById('upload_filename');
294 this.upload_title = document.getElementById('upload_title');
295 this.upload_file_preview = document.getElementById('upload_file_preview');
296 this.upload_file_props = document.getElementById('upload_file_props');
297 this.upload_progress = document.getElementById('upload_progress');
298 this.upload_tags = document.getElementById('upload_tags');
299 },
300 files: new Array(),
301 rowCount: 0,
302 getCellText: function(r,c) {
303 var f = this.files[r];
304 if(c.id=='up_file') return f.file;
305 if(c.id=='up_title') return f.title;
306 if(c.id=='up_status') return f.state;
307 return c.id;
308 },
309 setTree: function(t) { this.tree = t },
310 isContainer: function(r) { return false; },
311 isSeparator: function(r) { return false; },
312 isSorted: function(r) { return false; },
313 getLevel: function(r) { return 0; },
314 getImageSrc: function(r,c) { return null },
315 getRowProperties: function(r,p) {
316 try {
317 if(!Components) return;
318 }catch(e) { return }
319 var f = this.files[r];
320 var as = Components.classes['@mozilla.org/atom-service;1'].
321 getService(Components.interfaces.nsIAtomService);
322 p.AppendElement(as.getAtom(f.state));
323 },
324 getCellProperties: function(r,c,p) { this.getRowProperties(r,p); },
325 getColumnProperties: function(c,p) { },
326 cycleHeader: function(cid,e) { },
327 getParentIndex: function(r) { return -1; },
328 drop: function(r,o) { },
329 canDropBeforeAfter: function(r,b) { return false },
330
331 add: function(f) {
332 if(f.indexOf('file:/')==0) {
333 f = f.substr(5);
334 while(f.substr(0,2)=='//') { // XXX: not very performant, is it? ;-)
335 f = f.substr(1);
336 }
337 }
338 var t = f;
339 var ls = t.lastIndexOf('/');
340 if(ls>0) t = t.substr(ls+1);
341 ls = t.lastIndexOf('\\');
342 if(ls>0) t = t.substr(ls+1);
343 var ld = t.lastIndexOf('.');
344 if(ld>0) t = t.substr(0,ld);
345 this.files.push( {
346 file: f,
347 title: t,
348 tags: '',
349 state: 'pending'
350 } );
351 this.rowCount = this.files.length;
352 this.tree.rowCountChanged(this.rowCount-1,1);
353 },
354
355 upload_worker: function() {
356 for(var f in this.files) {
357 if(this.files[f].state=='pending') {
358 var ff = this.files[f];
359 dump('upload '+ff.file+'\n');
360 this.on_file_upload(ff);
361 ff.state='uploading';
362 this.tree.invalidate();
363 var _this = this;
364 this.fireflix.flickr.upload_file(
365 ff.file, { title: ff.title, tags: ff.tags },
366 function(x,p) {
367 ff.photoid = p;
368 _this.batch_ids.push(p);
369 ff.state='completed';
370 _this.tree.invalidate();
371 window.setTimeout(_this.upload_to,0,_this);
372 }, function(x,s,c,m) {
373 ff.state='failed';
374 ff.flickr_errcode = c;
375 ff.flickr_errmsg = m;
376 _this.tree.invalidate();
377 window.setTimeout(_this.upload_to,0,_this);
378 }
379 );
380 return;
381 }
382 }
383 dump('uploading done\n');
384 this.on_finish_upload();
385 },
386 upload_to: function(_this) { _this.upload_worker(); },
387 on_file_upload: function(f) {
388 document.getElementById('cmd_uploads_upload').setAttribute('disabled','true');
389 for(var fi in this.files) {
390 if(this.files[fi].file==f.file) {
391 this.tree.ensureRowIsVisible(fi);
392 this.selection.rangedSelect(fi,fi,false);
393 this.selection.currentIndex = fi;
394 this.selToProps();
395 break;
396 }
397 }
398 },
399 on_finish_upload: function() {
400 if(this.batch_ids.length) {
401 var psn = prompt(this.fireflix.loc_strings.getString('postUploadPhotoset'));
402 if(psn!=null) {
403 var pids = this.batch_ids.join(',');
404 var ppid = this.batch_ids[0];
405 var _this = this;
406 this.fireflix.flickr.api_call(
407 {
408 method: 'flickr.photosets.create',
409 auth_token: 'default',
410 title: psn,
411 primary_photo_id: ppid
412 }, function(x) {
413 var npid =
414 x.responseXML.getElementsByTagName('photoset').item(0).getAttribute('id');
415 _this.fireflix.flickr.api_call(
416 {
417 method: 'flickr.photosets.editPhotos',
418 auth_token: 'default',
419 photoset_id: npid,
420 primary_photo_id: ppid,
421 photo_ids: pids
422 }, function(x) {
423 _this.fireflix.refresh_sets();
424 }, function(x,s,c,m) {
425 _this.fireflix.flickr_failure(x,s,c,m);
426 }
427 );
428 }, function(x,s,c,m) {
429 _this.fireflix.flickr_failure(x,s,c,m);
430 }
431 );
432 }
433 }
434 this.selection.clearSelection();
435 document.getElementById('cmd_uploads_upload').setAttribute('disabled','false');
436 this.upload_progress.setAttribute('hidden','true');
437 },
438
439 clear_list: function() {
440 this.tree.beginUpdateBatch();
441 this.rowCount = 0;
442 this.files = new Array();
443 this.tree.endUpdateBatch();
444 this.selToProps();
445 },
446 selectionChanged: function() {
447 this.selToProps();
448 },
449 disableProps: function() {
450 this.upload_filename.value='';
451 this.upload_filename.disabled = true;
452 this.upload_title.value='';
453 this.upload_title.disabled = true;
454 this.upload_file_preview.src = null;
455 this.upload_file_props.hidden = true;
456 this.upload_tags.value='';
457 this.upload_tags.disabled = true;
458 },
459 selToProps: function() {
460 if(!this.selection.count) {
461 this.disableProps();
462 }else if(this.selection.count==1) {
463 var f=this.files[this.selection.currentIndex];
464 if(f==null || f.state!='pending') {
465 this.disableProps();
466 }else{
467 this.upload_filename.value = f.file;
468 this.upload_filename.disabled = false;
469 this.upload_title.value = f.title;
470 this.upload_title.disabled = false;
471 this.upload_file_preview.src = 'file:///'+f.file;
472 this.upload_file_props.hidden = false;
473 this.upload_tags.value = f.tags;
474 this.upload_tags.disabled = false;
475 }
476 }else{
477 var ftitle = null; var onetitle = true;
478 var ftags = null; var onetag = true;
479 var fs = 0;
480 for(var ff in this.files) {
481 if(this.selection.isSelected(ff) && this.files[ff].state=='pending' ) {
482 ++fs;
483 if(ftitle==null) {
484 ftitle = this.files[ff].title;
485 }else if(ftitle!=this.files[ff].title) {
486 onetitle = false;
487 }
488 if(ftags==null) {
489 ftags = this.files[ff].tags;
490 }else if(ftags!=this.files[ff].tags) {
491 onetag = false;
492 }
493 }
494 }
495 if(fs) {
496 this.upload_filename.value='';
497 this.upload_filename.disabled = true;
498 if(onetitle)
499 this.upload_title.value = ftitle;
500 this.upload_title.disabled = false;
501 if(onetag)
502 this.upload_tags.value = ftags;
503 this.upload_tags.disabled = false;
504 this.upload_file_preview.src = null;
505 this.upload_file_props.hidden = false;
506 }else
507 this.disableProps();
508 }
509 },
510 propsToSel: function(prop) {
511 if(this.selection.count<=0) return;
512 for(var ff in this.files) {
513 if(this.selection.isSelected(ff) && this.files[ff].state=='pending') {
514 if(prop=='filename')
515 this.files[ff].file = this.upload_filename.value;
516 if(prop=='title')
517 this.files[ff].title = this.upload_title.value;
518 if(prop=='tags')
519 this.files[ff].tags = this.upload_tags.value;
520 this.tree.invalidateRow(ff);
521 }
522 }
523 },
524
525 on_upload: function() {
526 this.selToProps();
527 this.batch_ids = new Array();
528 this.upload_progress.value=0;
529 this.upload_progress.setAttribute('hidden','false');
530 this.upload_worker();
531 },
532 on_clear: function() {
533 this.clear_list();
534 },
535 on_remove: function() {
536 if(this.selection.count) {
537 this.tree.beginUpdateBatch();
538 for(var i=this.files.length-1;i>=0;--i) {
539 if(this.selection.isSelected(i)) {
540 this.files.splice(i,1);
541 this.rowCount--;
542 }
543 }
544 this.tree.endUpdateBatch();
545 this.selection.clearSelection();
546 }
547 },
548 on_add: function() {
549 var ifp = Components.interfaces.nsIFilePicker;
550 var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(ifp);
551 fp.init(window, "Select a File", ifp.modeOpenMultiple);
552 fp.appendFilters(ifp.filterImages);
553 var rv = fp.show();
554 if(rv==ifp.returnOK) {
555 var ff = fp.files;
556 while(ff.hasMoreElements()) {
557 var f = ff.getNext();
558 f.QueryInterface(Components.interfaces.nsIFile);
559 this.add(f.path);
560 }
561 }
562 }
563 },
564
565 on_set_props: function() {
566 var pset = this.photosets.sets[this.photosets.selection.currentIndex];
567 window.openDialog(
568 "chrome://fireflix/content/photoset-props.xul",
569 null, "dependent,modal,dialog,chrome", this,
570 pset );
571 if(pset.dirty) {
572 var _this = this;
573 this.flickr.api_call(
574 {
575 method: 'flickr.photosets.editMeta',
576 auth_token: 'default',
577 photoset_id: pset.id,
578 title: pset.title,
579 description: pset.description
580 }, function(xr) {
581 pset.dirty = false;
582 _this.flickr.api_call(
583 {
584 method: 'flickr.photosets.getPhotos',
585 auth_token: 'default',
586 photoset_id: pset.id
587 }, function(xr) {
588 var x = xr.responseXML;
589 var xp = x.evaluate(
590 '/rsp/photoset/photo', x, null,
591 XPathResult.ORDERED_NODE_ITERATOR_TYPE, null );
592 var phids = new Array();
593 var priph = null;
594 var n; while(n=xp.iterateNext()) {
595 var pid = n.getAttribute('id');
596 phids.push( pid );
597 if(pid==pset.primary && n.getAttribute('isprimary')!='1')
598 priph = pid;
599 }
600 if(priph) {
601 _this.flickr.api_call(
602 {
603 method: 'flickr.photosets.editPhotos',
604 auth_token: 'default',
605 photoset_id: pset.id,
606 primary_photo_id: priph,
607 photo_ids: phids.join(',')
608 }, function() { }, function(x,s,c,m) { /* flickr.photosets.editPhotos */
609 _this.flickr_failure(x,s,c,m);
610 }
611 );
612 }
613 }, function(x,s,c,m) { /* flickr.photosets.getPhotos */
614 _this.flickr_failure(x,s,c,m);
615 }
616 );
617 }, function(x,s,c,m) { /* flickr.photosets.editMeta */
618 _this.flickr_failure(x,s,c,m);
619 }
620 );
621 }
622 },
623 on_refresh_sets: function() {
624 this.refresh_sets();
625 },
626 on_cmd_sets_html: function(csfx,ev) {
627 var uti = csfx.charAt(0); var utl = csfx.charAt(1);
628 var rv = this.build_html(this.photoset.photos,uti,utl);
629 this.popup_content(rv);
630 },
631
632 on_cmd_uploads_html: function(csfx,ev) {
633 var uti = csfx.charAt(0); var utl = csfx.charAt(1);
634 var pids = new Array();
635 for(var f in this.uploads.files) {
636 if(this.uploads.selection.isSelected(f))
637 if(this.uploads.files[f].photoid)
638 pids.push(this.uploads.files[f].photoid);
639 }
640 var pp = this.uploads.rowCount*2; if(pp>500) pp = 500;
641 var _this = this;
642 this.flickr.api_call(
643 {
644 method: 'flickr.photos.search',
645 auth_token: 'default',
646 extras: 'original_format',
647 user_id: 'me',
648 per_page: pp
649 },
650 function(xr) {
651 var x = xr.responseXML;
652 var rv = '';
653 for(var pn in pids) {
654 var p = pids[pn];
655 var pp = new Photo(xp_node('/rsp/photos/photo[@id='+p+']',x));
656 rv += _this.photo_html(pp,uti,utl)+'\n';
657 }
658 _this.popup_content(rv);
659 }, function(x,s,c,m) {
660 _this.flickr_failure(x,s,c,m);
661 }
662 );
663 },
664
665 /*
666 *
667 */
668 foundphotos: {
669 fireflix: null,
670 init: function(f) {
671 this.fireflix = f;
672 this.search_for = document.getElementById('search_for');
673 this.search_tags= document.getElementById('search_tags');
674 this.search_mine = document.getElementById('search_mine');
675 document.getElementById('searchresults').view = this;
676 this.searchresult_props = document.getElementById('searchresult_props');
677 this.search_photo = document.getElementById('search_photo');
678 this.searchresult_title = document.getElementById('searchresult_title');
679 this.searchresult_description = document.getElementById('searchresult_description');
680 },
681 photos: new Array(),
682 rowCount: 0,
683 getCellText: function(r,c) {
684 var p = this.photos[r];
685 if(c.id=='sr_title') return p.title;
686 return c.id;
687 },
688 setTree: function(t) { this.tree = t },
689 isContainer: function(r) { return false },
690 isSeparator: function(r) { return false },
691 isSorted: function(r) { return false },
692 getLevel: function(r) { return 0 },
693 getImageSrc: function(r,c) { return null },
694 getRowProperties: function(r,p) { },
695 getCellProperties: function(cid,cel,p) { },
696 getColumnProperties: function(cid,cel,p) { },
697 cycleHeader: function(cid,e) { },
698 getParentIndex: function(r) { return -1 },
699 drop: function(r,o) { },
700 canDropBeforeAfter: function(r,b) { return false },
701
702 importXPR: function(xp) {
703 this.selection.clearSelection();
704 this.selection.currentIndex = -1;
705 this.searchresult_props.hidden = true;
706 this.tree.beginUpdateBatch();
707 this.photos = new Array();
708 var n; while(n=xp.iterateNext()) {
709 this.photos.push(new Photo(n));
710 }
711 this.rowCount = this.photos.length;
712 this.tree.endUpdateBatch();
713 },
714 search_photos: function() {
715 var pars = {
716 method: 'flickr.photos.search',
717 auth_token: 'default',
718 extras: 'license,date_upload,date_taken,owner_name,icon_server,original_format,last_update,geo'
719 };
720 if(this.search_mine.checked)
721 pars.user_id='me';
722 if(this.search_tags.checked) {
723 pars.tags=this.search_for.value.split(/ +/).join(',');
724 }else{
725 pars.text=this.search_for.value;
726 }
727 var _this = this;
728 this.fireflix.flickr.api_call( pars,
729 function(xr) {
730 var x = xr.responseXML;
731 var xp = x.evaluate(
732 '/rsp/photos/photo', x, null,
733 XPathResult.ORDERED_NODE_ITERATOR_TYPE, null );
734 _this.importXPR(xp);
735 _this.on_select();
736 }, function(x,s,c,m) {
737 _this.fireflix.flickr_failure(x,s,c,m);
738 }
739 );
740 },
741 on_select: function() {
742 if(this.selection.currentIndex<0) {
743 this.searchresult_props.hidden = true;
744 }else{
745 var p = this.photos[this.selection.currentIndex];
746 if(!p) {
747 this.searchresult_props.hidden = true;
748 }else{
749 this.search_photo.src = this.fireflix.flickr.make_photo_url(p,'t');
750 this.searchresult_title.value = p.title;
751 this.searchresult_description.value = null;
752 if(p.description==null && p.description==undefined) {
753 var pid = p.id;
754 var ci = this.selection.currentIndex;
755 var _this = this;
756 this.fireflix.flickr.api_call(
757 {
758 method: 'flickr.photos.getInfo',
759 auth_token: 'default',
760 photo_id: p.id,
761 secret: p.secret
762 }, function(xr) {
763 var pp = _this.photos[ci];
764 if(ci==_this.selection.currentIndex && pp.id==pid) {
765 var n = xp_node('/rsp/photo',xr.responseXML);
766 pp.fromNode_(n);
767 _this.searchresult_description.value=pp.description?pp.description:null;
768 }
769 }, function(x,s,c,m) {
770 _this.fireflix.flickr_failure(x,s,c,m);
771 }
772 );
773 this.searchresult_props.hidden = false;
774 }else{
775 this.searchresult_description.value=p.description?p.description:null;
776 }
777 }
778 }
779 },
780 on_cmd_open: function(ev) {
781 if(this.selection.currentIndex<0)
782 return;
783 var p = this.photos[this.selection.currentIndex];
784 if(!p.id)
785 return;
786 this.fireflix.openTab(this.fireflix.flickr.make_photo_url(p,'p'));
787 }
788 },
789
790 photo_html: function(p,i,l) {
791 // TODO: add alt/title when possible
792 var rv =
793 '<a href="'+this.flickr.make_photo_url(p,l)+'">' +
794 '<img src="'+this.flickr.make_photo_url(p,i)+'" />'+
795 '</a>';
796 return rv;
797 },
798 build_html: function(photos,uti,utl) {
799 var rv = '';
800 for(var i in photos) {
801 var p = photos[i];
802 rv += this.photo_html(p,utl,uti)+'\n';
803 }
804 return rv;
805 },
806
807 popup_content: function(s) {
808 window.openDialog(
809 "chrome://fireflix/content/generated-content.xul",
810 null, "dialog,chrome", this, s );
811 },
812 copy_to_clipboard: function(s) {
813 var ch = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
814 .getService(Components.interfaces.nsIClipboardHelper);
815 ch.copyString(s);
816 },
817 openTab: function(l) {
818 var wm = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService(
819 Components.interfaces.nsIWindowMediator );
820 var bw = wm.getMostRecentWindow('navigator:browser');
821 var b = bw.getBrowser();
822 var t = b.addTab(l);
823 b.selectedTab = t;
824 },
825
826 build_menus: function() {
827 this.append_html_menu(
828 document.getElementById('sets_html_menu'),
829 'stm_','m_bop','cmdset_sets','cmd_sets_html'
830 );
831 this.append_html_menu(
832 document.getElementById('uploads_html_menu'),
833 'stm_','m_bop','cmdset_uploads','cmd_uploads_html'
834 );
835 return;
836 },
837 append_html_menu: function(m,imgt,lnkt,csid,cpfx) {
838 var mp = m.appendChild(document.createElement('menupopup'));
839 var t;
840 t=mp.appendChild(document.createElement('menuitem'));
841 t.setAttribute('label',this.loc_strings.getString('menutitle_Images'));
842 t.setAttribute('class','menuhead');t.setAttribute('disabled','true');
843 mp.appendChild(document.createElement('menuseparator'));
844 var cs = document.getElementById(csid);
845 for(var iti=0;iti<imgt.length;++iti) {
846 t = mp.appendChild(document.createElement('menu'));
847 t.setAttribute('label',this.loc_strings.getString('urltype_'+imgt.charAt(iti)));
848 var smp = t.appendChild(document.createElement('menupopup'));
849 t=smp.appendChild(document.createElement('menuitem'));
850 t.setAttribute('label',this.loc_strings.getString('menutitle_Links'));
851 t.setAttribute('class','menuhead');t.setAttribute('disabled','true');
852 smp.appendChild(document.createElement('menuseparator'));
853 for(var lti=0;lti<lnkt.length;++lti) {
854 var csfx = imgt.charAt(iti)+lnkt.charAt(lti);
855 t=smp.appendChild(document.createElement('menuitem'));
856 t.setAttribute('label',this.loc_strings.getString('urltype_'+lnkt.charAt(lti)));
857 t.setAttribute('command',cpfx+'_'+csfx);
858 t=cs.appendChild(document.createElement('command'));
859 t.setAttribute('id',cpfx+'_'+csfx);
860 t.setAttribute('oncommand','fireflix.on_'+cpfx+"('"+csfx+"',event)");
861 }
862 }
863 return mp;
864 },
865
866 flickr_failure: function(x,s,c,m) {
867 if(c==98) { // Invalid auth token
868 this.flickr.reset_token();
869 document.getElementById('auth_info').value = this.no_auth_info_label;
870 document.getElementById('auth_info').disabled = true;
871 document.getElementById('b_auth').hidden = false;
872 return;
873 }
874 // TODO: is that beauty
875 alert('flickr api call failed\n'+c+' '+m);
876 }
877
878};
diff --git a/content/flickr.js b/content/flickr.js
new file mode 100644
index 0000000..3554796
--- a/dev/null
+++ b/content/flickr.js
@@ -0,0 +1,403 @@
1/*
2 * Photoset
3 */
4
5function Photoset(s) {
6 if(s instanceof Photoset) {
7 for(var p in s) this[p]=s[p];
8 }else
9 this.fromNode(s);
10}
11Photoset.prototype = {
12 id: null,
13 primary: null,
14 secret: null,
15 server: null,
16 photos: null,
17 title: null,
18 description: null,
19 fromNode: function(n) {
20 this.id = n.getAttribute('id');
21 this.primary = n.getAttribute('primary');
22 this.secret = n.getAttribute('secret');
23 this.server = n.getAttribute('server');
24 this.photos = n.getAttribute('photos');
25 this.title = n.getElementsByTagName('title').item(0).firstChild.nodeValue;
26 this.description = n.getElementsByTagName('description').item(0).firstChild;
27 if(this.description) this.description = this.description.nodeValue;
28 }
29};
30
31/*
32 * Photo
33 */
34function Photo(s) {
35 if(s instanceof Photo) {
36 for(var p in s) this[p]=s[p];
37 }else
38 this.fromNode(s);
39}
40Photo.prototype = {
41 id: null, secret: null,
42 server: null,
43 title: null,
44 isprimary: null,
45 license: null,
46 dateupload: null, datetaken: null, datetakengranularity: null,
47 ownername: null,
48 iconserver: null,
49 originalformat: null,
50 lastupdate: null,
51 fromNode: function(n) {
52 this.id = n.getAttribute('id'); this.secret = n.getAttribute('secret');
53 this.server = n.getAttribute('server');
54 this.title = n.getAttribute('title');
55 this.isprimary = n.getAttribute('isprimary');
56 this.license = n.getAttribute('license');
57 this.dateupload = n.getAttribute('dateupload');
58 this.datetaken = n.getAttribute('datetaken'); this.datetakengranularity = n.getAttribute('datetakengranularity');
59 this.ownername = n.getAttribute('ownername');
60 this.iconserver = n.getAttribute('iconserver');
61 this.originalformat = n.getAttribute('originalformat');
62 this.lastupdate = n.getAttribute('lastupdate');
63 },
64 fromNode_: function(n) {
65 var t;
66 // TODO: @rotation @isfavorite
67 this.owner = {};
68 t = n.getElementsByTagName('owner').item(0);
69 if(t) {
70 this.owner.nsid=t.getAttribute('nsid');
71 this.owner.username=t.getAttribute('username');
72 this.owner.realname=t.getAttribute('realname');
73 this.owner.location=t.getAttribute.location;
74 }
75 t = n.getElementsByTagName('description').item(0);
76 if(t && t.firstChild) {
77 this.description = t.firstChild.nodeValue;
78 }
79 // TODO: visibility/@ispublic visibility/@isfriend visibility/@isfamily
80 // TODO: dates/@posted dates/@taken dates/@takengranularity dates/@lastupdate
81 // TODO: permissions/@permcomment permsiions/@permaddmeta
82 // TODO: editability/@canaddcomment editability/@canaddmeta
83 // TODO: comments
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
86 // TODO: notes/note
87 // TODO: tags/tag/@id tags/tag/@author tags/tag/@raw tags/tag
88 // TODO: urls/url/@type urls/url
89 }
90};
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() { }
143Flickr.prototype = {
144
145 rest_url: 'http://www.flickr.com/services/rest/',
146 auth_url: 'http://flickr.com/services/auth/',
147 photo_url: 'http://static.flickr.com/',
148 photos_url: 'http://www.flickr.com/photos/',
149 upload_url: 'http://www.flickr.com/services/upload/',
150
151 api_sig: function(paramstr) {
152 return MD5(toutf8(this.api_shs+paramstr));
153 },
154 api_call_url: function(params,url) {
155 params.api_key = this.api_key;
156 var pp = new Array();
157 for(var p in params) {
158 pp.push(p);
159 }
160 var pstr = '';
161 var rv = (url?url:this.rest_url)+'?';
162 for(var p in pp.sort()) {
163 var pn = pp[p];
164 pstr += pn+params[pn];
165 rv += pn+'='+params[pn]+'&';
166 }
167 rv += 'api_sig='+this.api_sig(pstr);
168 return rv;
169 },
170 api_call: function(params, on_success, on_failure) {
171 if(params.auth_token == 'default')
172 params.auth_token = this.token;
173 var x = new XMLHttpRequest();
174 x.open("GET",this.api_call_url(params));
175 x.onreadystatechange=function() {
176 if(x.readyState!=4) return false;
177 if(x.status==200) {
178 var stat = x.responseXML.firstChild.getAttribute('stat');
179 if(stat=='ok') {
180 if(on_success) on_success(x);
181 }else{
182 var e = x.responseXML.getElementsByTagName('err').item(0);
183 var ecode = e.getAttribute('code');
184 var emsg = e.getAttribute('msg');
185 dump(params.method+' failed: '+ecode+' '+emsg+'\n');
186 if(on_failure) on_failure(x,stat,ecode,emsg);
187 }
188 }else{
189 if(on_failure) on_failure(x);
190 }
191 return true;
192 }
193 x.send(null);
194 return true;
195 },
196
197 frob: null,
198 authorize_0: function(on_s, on_f) {
199 var _this = this;
200 this.api_call(
201 { method: 'flickr.auth.getFrob' },
202 function(x) {
203 _this.frob = xp_str('/rsp/frob',x.responseXML);
204 var u = _this.api_call_url(
205 { frob: _this.frob, perms: 'delete' }, _this.auth_url );
206 var wm = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService(
207 Components.interfaces.nsIWindowMediator );
208 var bw = wm.getMostRecentWindow('navigator:browser');
209 var b = bw.getBrowser();
210 var t = b.addTab(u);
211 b.selectedTab = t;
212 if(on_s) on_s();
213 }, function(x,s,c,m) {
214 if(on_f) on_f(x,s,c,m);
215 }
216 );
217 },
218 token: null,
219 perms: null,
220 user: null,
221 authorize_1: function(on_s, on_f) {
222 var _this = this;
223 this.api_call(
224 { method: 'flickr.auth.getToken', frob: this.frob },
225 function(x) {
226 _this.token = xp_str('/rsp/auth/token',x.responseXML);
227 _this.perms = xp_str('/rsp/auth/perms',x.responseXML);
228 var u = xp_node('/rsp/auth/user',x.responseXML);
229 _this.user = {
230 nsid: u.getAttribute('nsid'),
231 username: u.getAttribute('username'),
232 fullname: u.getAttribute('fullname')
233 };
234 if(on_s) on_s(x);
235 }, function(x,s,c,m) {
236 if(on_f) on_f(x,s,c,m);
237 }
238 );
239 },
240
241 prefs: Components.classes['@mozilla.org/preferences-service;1'].getService(
242 Components.interfaces.nsIPrefBranch
243 ),
244 prefs_root: 'net.klever.kin.flickr',
245 save_token: function() {
246 // TODO: don't clear when there's nothing to clear or catch exceptions
247 if(this.token)
248 this.prefs.setCharPref(this.prefs_root+'.auth_token',this.token);
249 else
250 this.prefs.clearUserPref(this.prefs_root+'.auth_token');
251 if(this.perms)
252 this.prefs.setCharPref(this.prefs_root+'.auth_perms',this.perms);
253 else
254 this.prefs.clearUserPref(this.prefs_root+'.auth_perms');
255 if(this.user && this.user.nsid!=null && this.user.nsid!=undefined)
256 this.prefs.setCharPref(this.prefs_root+'.auth_user.nsid',this.user.nsid);
257 else
258 this.prefs.clearUserPref(this.prefs_root+'.auth_user.nsid');
259 if(this.user && this.user.username!=null && this.user.username!=undefined)
260 this.prefs.setCharPref(this.prefs_root+'.auth_user.username',this.user.username);
261 else
262 this.prefs.clearUserPref(this.prefs_root+'.auth_user.username');
263 if(this.user && this.user.fullname!=null && this.user.fullname!=undefined)
264 this.prefs.setCharPref(this.prefs_root+'.auth_user.fullname',this.user.fullname);
265 else
266 this.prefs.clearUserPref(this.prefs_root+'.auth_user.fullname');
267 },
268 _reset_token: function() {
269 this.token = null; this.perms = null; this.user = null;
270 return false;
271 },
272 load_token: function() {
273 try {
274 if(this.prefs.getPrefType(this.prefs_root+'.auth_token')!=this.prefs.PREF_STRING)
275 return this._reset_token();
276 this.token = this.prefs.getCharPref(this.prefs_root+'.auth_token');
277 if(this.prefs.getPrefType(this.prefs_root+'.auth_perms')!=this.prefs.PREF_STRING)
278 return this._reset_token();
279 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)
281 return this._reset_token();
282 this.user = new Object();
283 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)
285 return this._reset_token();
286 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)
288 return this._reset_token();
289 this.user.fullname = this.prefs.getCharPref(this.prefs_root+'.auth_user.fullname');
290 }catch(e) { return this._reset_token(); }
291 return true;
292 },
293 reset_token: function() {
294 this._reset_token();
295 this.save_token();
296 },
297
298 get_photo_url: function(ser,id,sec,sfx,ext) {
299 var rv = this.photo_url + ser + '/' + id + '_' + sec;
300 if(sfx && sfx!='_') rv += '_'+sfx;
301 rv += ext?'.'+ext:'.jpg';
302 return rv;
303 },
304 get_image_url: function(o,sfx) {
305 return this.get_photo_url(
306 o.server,
307 (o instanceof Photoset)? o.primary : o.id,
308 o.secret,
309 sfx,
310 (sfx=='o')?o.originalformat:null
311 );
312 },
313 get_photo_page_url: function(p) {
314 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;
316 else // TODO: take owner into account?
317 return this.photos_url + this.user.nsid + '/' + p;
318 },
319 make_photo_url: function(p,sfx) {
320 if(sfx=='p')
321 return this.get_photo_page_url(p);
322 else
323 return this.get_image_url(p,sfx);
324 },
325
326 upload_file: function(f,fa,on_success,on_failure) {
327 try {
328 var fi = Components.classes["@mozilla.org/file/local;1"]
329 .createInstance(Components.interfaces.nsILocalFile);
330 fi.initWithPath( f );
331 var st = Components.classes["@mozilla.org/network/file-input-stream;1"]
332 .createInstance(Components.interfaces.nsIFileInputStream);
333 st.init(fi,0x01,00004,null);
334 var bis = Components.classes["@mozilla.org/binaryinputstream;1"]
335 .createInstance(Components.interfaces.nsIBinaryInputStream);
336 bis.setInputStream(st);
337
338 // allocate and initialize temp storage string
339 var pbs = Components.classes["@mozilla.org/storagestream;1"]
340 .createInstance(Components.interfaces.nsIStorageStream);
341 pbs.init(1024,10000000,null);
342 // create output stream
343 var pbos = pbs.getOutputStream(0);
344 // and a binaryoutputstream interface
345 var pbbos = Components.classes["@mozilla.org/binaryoutputstream;1"]
346 .createInstance(Components.interfaces.nsIBinaryOutputStream);
347 pbbos.setOutputStream(pbos);
348
349 /* create POST body */
350 var boundarytoken = 'kadaroloongazaduviaxamma';
351 var boundary = '--'+boundarytoken;
352 var b = '';
353
354 var parms = { api_key: this.api_key, auth_token: this.token };
355 for(var p in fa) parms[p] = fa[p];
356 var pns = new Array();
357 for(var p in parms) pns.push(p);
358 var pstr = '';
359 for(var p in pns.sort()) {
360 var pn = pns[p];
361 pstr += pn+parms[pn];
362 b += boundary+'\nContent-Disposition: form-data; name="'+pn+'"\n\n'+toutf8(parms[pn])+'\n';
363 }
364 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';
366 pbbos.writeBytes(b,b.length);
367 var bisbytes = bis.available();
368 pbbos.writeBytes(bis.readBytes(bisbytes),bisbytes);
369 pbbos.writeBytes('\n'+boundary+'--',3+boundary.length); bis.close(); st.close();
370
371 pbbos.close(); pbos.close();
372
373 var x = new XMLHttpRequest();
374 x.open("POST",this.upload_url);
375 x.setRequestHeader('Content-Type', 'multipart/form-data; boundary="'+boundarytoken+'"');
376 x.setRequestHeader('Connection','close');
377 x.setRequestHeader('Content-Length',b.length);
378 x.onreadystatechange=function() {
379 if(x.readyState!=4) return false;
380 if(x.status==200) {
381 var stat = x.responseXML.firstChild.getAttribute('stat');
382 if(stat=='ok') {
383 var pid = xp_str('/rsp/photoid',x.responseXML);
384 if(on_success) on_success(x,pid);
385 }else{
386 var e = x.responseXML.getElementsByTagName('err').item(0);
387 var ecode = e.getAttribute('code');
388 var emsg = e.getAttribute('msg');
389 dump('upload failed: '+ecode+' '+emsg+'\n');
390 if(on_failure) on_failure(x,stat,ecode,emsg);
391 }
392 }else{
393 if(on_failure) on_failure(x);
394 }
395 return true;
396 };
397 x.send(pbs.newInputStream(0));
398 }catch(e) {
399 if(on_failure) on_failure(e,null,-1,e.message);
400 }
401 }
402
403};
diff --git a/content/generated-content.js b/content/generated-content.js
new file mode 100644
index 0000000..0ad08bb
--- a/dev/null
+++ b/content/generated-content.js
@@ -0,0 +1,17 @@
1var generated = {
2 fireflix: null,
3 data: null,
4
5 init: function() {
6 this.fireflix = window.arguments[0];
7 this.data = window.arguments[1];
8 this.databox = document.getElementById('data');
9 this.databox.value = this.data;
10 this.databox.select();
11 },
12 copy: function() {
13 var ch = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
14 .getService(Components.interfaces.nsIClipboardHelper);
15 ch.copyString(this.data);
16 }
17};
diff --git a/content/generated-content.xul b/content/generated-content.xul
new file mode 100644
index 0000000..2a91efa
--- a/dev/null
+++ b/content/generated-content.xul
@@ -0,0 +1,20 @@
1<?xml version="1.0" encoding="utf-8"?>
2<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
3<?xsml-stylesheet href="fireflix.css" type="text/css"?>
4<!DOCTYPE dialog SYSTEM "chrome://fireflix/locale/fireflix.dtd">
5<dialog
6 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
7 id="generated_content"
8 buttons="accept"
9 defaultbutton="accept"
10 title="&generated.title;"
11 onload="generated.init()"
12 >
13
14 <script src="generated-content.js" type="application/x-javascript"/>
15
16 <vbox class="generated wholething" flex="1">
17 <textbox flex="1" minheight="300" minwidth="300" id="data" multiline="true" readonly="true" />
18 <button id="copy" label="&generated.copy;" oncommand="generated.copy()" />
19 </vbox>
20</dialog>
diff --git a/content/icons/16x16/fireflix.png b/content/icons/16x16/fireflix.png
new file mode 100644
index 0000000..377ab28
--- a/dev/null
+++ b/content/icons/16x16/fireflix.png
Binary files differ
diff --git a/content/icons/32x32/fireflix.png b/content/icons/32x32/fireflix.png
new file mode 100644
index 0000000..374ebbd
--- a/dev/null
+++ b/content/icons/32x32/fireflix.png
Binary files differ
diff --git a/content/md5.js b/content/md5.js
new file mode 100644
index 0000000..f22db2b
--- a/dev/null
+++ b/content/md5.js
@@ -0,0 +1,154 @@
1/* MD5 Message-Digest Algorithm - JavaScript
2' MODIFICATION HISTORY:
3' 1.0 16-Feb-2001 - Phil Fresle (sales@frez.co.uk) - Initial Version (VB/ASP code)
4' 1.0 21-Feb-2001 - Enrico Mosanghini (erik504@yahoo.com) - JavaScript porting
5*/
6function MD5(sMessage) {
7 function RotateLeft(lValue, iShiftBits) { return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits)); }
8 function AddUnsigned(lX,lY) {
9 var lX4,lY4,lX8,lY8,lResult;
10 lX8 = (lX & 0x80000000);
11 lY8 = (lY & 0x80000000);
12 lX4 = (lX & 0x40000000);
13 lY4 = (lY & 0x40000000);
14 lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
15 if (lX4 & lY4) return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
16 if (lX4 | lY4) {
17 if (lResult & 0x40000000) return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
18 else return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
19 } else return (lResult ^ lX8 ^ lY8);
20 }
21 function F(x,y,z) { return (x & y) | ((~x) & z); }
22 function G(x,y,z) { return (x & z) | (y & (~z)); }
23 function H(x,y,z) { return (x ^ y ^ z); }
24 function I(x,y,z) { return (y ^ (x | (~z))); }
25 function FF(a,b,c,d,x,s,ac) {
26 a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
27 return AddUnsigned(RotateLeft(a, s), b);
28 }
29 function GG(a,b,c,d,x,s,ac) {
30 a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
31 return AddUnsigned(RotateLeft(a, s), b);
32 }
33 function HH(a,b,c,d,x,s,ac) {
34 a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
35 return AddUnsigned(RotateLeft(a, s), b);
36 }
37 function II(a,b,c,d,x,s,ac) {
38 a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
39 return AddUnsigned(RotateLeft(a, s), b);
40 }
41 function ConvertToWordArray(sMessage) {
42 var lWordCount;
43 var lMessageLength = sMessage.length;
44 var lNumberOfWords_temp1=lMessageLength + 8;
45 var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;
46 var lNumberOfWords = (lNumberOfWords_temp2+1)*16;
47 var lWordArray=Array(lNumberOfWords-1);
48 var lBytePosition = 0;
49 var lByteCount = 0;
50 while ( lByteCount < lMessageLength ) {
51 lWordCount = (lByteCount-(lByteCount % 4))/4;
52 lBytePosition = (lByteCount % 4)*8;
53 lWordArray[lWordCount] = (lWordArray[lWordCount] | (sMessage.charCodeAt(lByteCount)<<lBytePosition));
54 lByteCount++;
55 }
56 lWordCount = (lByteCount-(lByteCount % 4))/4;
57 lBytePosition = (lByteCount % 4)*8;
58 lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);
59 lWordArray[lNumberOfWords-2] = lMessageLength<<3;
60 lWordArray[lNumberOfWords-1] = lMessageLength>>>29;
61 return lWordArray;
62 }
63 function WordToHex(lValue) {
64 var WordToHexValue="",WordToHexValue_temp="",lByte,lCount;
65 for (lCount = 0;lCount<=3;lCount++) {
66 lByte = (lValue>>>(lCount*8)) & 255;
67 WordToHexValue_temp = "0" + lByte.toString(16);
68 WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2);
69 }
70 return WordToHexValue;
71 }
72 var x=Array();
73 var k,AA,BB,CC,DD,a,b,c,d
74 var S11=7, S12=12, S13=17, S14=22;
75 var S21=5, S22=9 , S23=14, S24=20;
76 var S31=4, S32=11, S33=16, S34=23;
77 var S41=6, S42=10, S43=15, S44=21;
78 // Steps 1 and 2. Append padding bits and length and convert to words
79 x = ConvertToWordArray(sMessage);
80 // Step 3. Initialise
81 a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
82 // Step 4. Process the message in 16-word blocks
83 for (k=0;k<x.length;k+=16) {
84 AA=a; BB=b; CC=c; DD=d;
85 a=FF(a,b,c,d,x[k+0], S11,0xD76AA478);
86 d=FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
87 c=FF(c,d,a,b,x[k+2], S13,0x242070DB);
88 b=FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
89 a=FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);
90 d=FF(d,a,b,c,x[k+5], S12,0x4787C62A);
91 c=FF(c,d,a,b,x[k+6], S13,0xA8304613);
92 b=FF(b,c,d,a,x[k+7], S14,0xFD469501);
93 a=FF(a,b,c,d,x[k+8], S11,0x698098D8);
94 d=FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
95 c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);
96 b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
97 a=FF(a,b,c,d,x[k+12],S11,0x6B901122);
98 d=FF(d,a,b,c,x[k+13],S12,0xFD987193);
99 c=FF(c,d,a,b,x[k+14],S13,0xA679438E);
100 b=FF(b,c,d,a,x[k+15],S14,0x49B40821);
101 a=GG(a,b,c,d,x[k+1], S21,0xF61E2562);
102 d=GG(d,a,b,c,x[k+6], S22,0xC040B340);
103 c=GG(c,d,a,b,x[k+11],S23,0x265E5A51);
104 b=GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
105 a=GG(a,b,c,d,x[k+5], S21,0xD62F105D);
106 d=GG(d,a,b,c,x[k+10],S22,0x2441453);
107 c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681);
108 b=GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
109 a=GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);
110 d=GG(d,a,b,c,x[k+14],S22,0xC33707D6);
111 c=GG(c,d,a,b,x[k+3], S23,0xF4D50D87);
112 b=GG(b,c,d,a,x[k+8], S24,0x455A14ED);
113 a=GG(a,b,c,d,x[k+13],S21,0xA9E3E905);
114 d=GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
115 c=GG(c,d,a,b,x[k+7], S23,0x676F02D9);
116 b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
117 a=HH(a,b,c,d,x[k+5], S31,0xFFFA3942);
118 d=HH(d,a,b,c,x[k+8], S32,0x8771F681);
119 c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122);
120 b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
121 a=HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);
122 d=HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
123 c=HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);
124 b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
125 a=HH(a,b,c,d,x[k+13],S31,0x289B7EC6);
126 d=HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
127 c=HH(c,d,a,b,x[k+3], S33,0xD4EF3085);
128 b=HH(b,c,d,a,x[k+6], S34,0x4881D05);
129 a=HH(a,b,c,d,x[k+9], S31,0xD9D4D039);
130 d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
131 c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);
132 b=HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
133 a=II(a,b,c,d,x[k+0], S41,0xF4292244);
134 d=II(d,a,b,c,x[k+7], S42,0x432AFF97);
135 c=II(c,d,a,b,x[k+14],S43,0xAB9423A7);
136 b=II(b,c,d,a,x[k+5], S44,0xFC93A039);
137 a=II(a,b,c,d,x[k+12],S41,0x655B59C3);
138 d=II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
139 c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D);
140 b=II(b,c,d,a,x[k+1], S44,0x85845DD1);
141 a=II(a,b,c,d,x[k+8], S41,0x6FA87E4F);
142 d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
143 c=II(c,d,a,b,x[k+6], S43,0xA3014314);
144 b=II(b,c,d,a,x[k+13],S44,0x4E0811A1);
145 a=II(a,b,c,d,x[k+4], S41,0xF7537E82);
146 d=II(d,a,b,c,x[k+11],S42,0xBD3AF235);
147 c=II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);
148 b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
149 a=AddUnsigned(a,AA); b=AddUnsigned(b,BB); c=AddUnsigned(c,CC); d=AddUnsigned(d,DD);
150 }
151 // Step 5. Output the 128 bit digest
152 var temp= WordToHex(a)+WordToHex(b)+WordToHex(c)+WordToHex(d);
153 return temp.toLowerCase();
154}
diff --git a/content/photoset-props.js b/content/photoset-props.js
new file mode 100644
index 0000000..43dc1b9
--- a/dev/null
+++ b/content/photoset-props.js
@@ -0,0 +1,81 @@
1
2var psetprops = {
3 fireflix: null,
4 photoset: null,
5 pripic: null,
6
7 settitle: null, setdesc: null,
8 primarypic: null,
9 photos: new Array(),
10 init: function() {
11 this.fireflix = window.arguments[0];
12 this.photoset = window.arguments[1];
13 this.settitle = document.getElementById('set_title');
14 this.settitle.value = this.photoset.title;
15 this.setdesc = document.getElementById('set_desc');
16 this.setdesc.value = this.photoset.description;
17 this.primarypic = document.getElementById('primary_picture');
18 this.primarypic.src =
19 this.fireflix.flickr.get_image_url( this.photoset, 't' );
20 this.primarypic.hidden = false;
21 this.picslist = document.getElementById('primary_picture_list');
22
23 var _this = this;
24 this.fireflix.flickr.api_call(
25 {
26 method: 'flickr.photosets.getPhotos',
27 auth_token: 'default',
28 photoset_id: this.photoset.id
29 }, function(xr) {
30 var x = xr.responseXML;
31 var xp = x.evaluate(
32 '/rsp/photoset/photo', x, null,
33 XPathResult.ORDERED_NODE_ITERATOR_TYPE, null );
34 _this.picslist.removeAllItems(); _this.photos= new Array();
35 var n; while(n=xp.iterateNext()) {
36 _this.photos.push(
37 {
38 id: n.getAttribute('id'),
39 secret: n.getAttribute('secret'),
40 server: n.getAttribute('server')
41 }
42 );
43 var ni = _this.picslist.appendItem(
44 n.getAttribute('title'), _this.photos.length-1
45 );
46 ni.setAttribute('command','cmd_select_picture');
47 if(n.getAttribute('isprimary')==1) {
48 _this.picslist.selectedItem = ni;
49 _this.pripic = _this.photos[_this.photos.length-1];
50 }
51 }
52 _this.picslist.hidden = false;
53 }, function() { }
54 );
55 },
56 on_select_picture: function(ev) {
57 var epic = ev.explicitOriginalTarget;
58 this.picslist.selectedItem = epic;
59 var pic = this.photos[this.picslist.selectedItem.value];
60 this.pripic = pic;
61 this.primarypic.src =
62 this.fireflix.flickr.get_photo_url(
63 pic.server,
64 pic.id,
65 pic.secret,
66 't'
67 );
68 },
69 on_accept: function() {
70 this.photoset.title =
71 document.getElementById('set_title').value;
72 this.photoset.description =
73 document.getElementById('set_desc').value;
74 this.photoset.server = this.pripic.server;
75 this.photoset.primary = this.pripic.id;
76 this.photoset.secret = this.pripic.secret;
77 this.photoset.dirty = true;
78 return;
79 }
80};
81
diff --git a/content/photoset-props.xul b/content/photoset-props.xul
new file mode 100644
index 0000000..e8f6d13
--- a/dev/null
+++ b/content/photoset-props.xul
@@ -0,0 +1,38 @@
1<?xml version="1.0" encoding="utf-8"?>
2<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
3<?xsml-stylesheet href="fireflix.css" type="text/css"?>
4<!DOCTYPE dialog SYSTEM "chrome://fireflix/locale/fireflix.dtd">
5<dialog
6 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
7 id="photoset_props"
8 buttons="accept,cancel"
9 defaultbutton="accept"
10 title="&photosetprops.title;"
11 onload="psetprops.init()"
12 ondialogaccept="psetprops.on_accept()"
13 >
14
15 <script src="photoset-props.js" type="application/x-javascript"/>
16
17 <commandset>
18 <command id="cmd_select_picture"
19 oncommand="psetprops.on_select_picture(event)"/>
20 </commandset>
21
22 <hbox class="wholething">
23 <vbox>
24 <menulist id="primary_picture_list" hidden="true" sizetopopup="always"/>
25 <hbox pack="center">
26 <box width="100" pack="center">
27 <image id="primary_picture" hidden="true"/>
28 </box>
29 </hbox>
30 </vbox>
31 <vbox flex="1" minwidth="300">
32 <label control="set_title" value="&photosetprops.set_title.label;"/>
33 <textbox id="set_title" />
34 <label control="set_desc" value="&photosetprops.set_desc.label;"/>
35 <textbox id="set_desc" multiline="true" rows="5" />
36 </vbox>
37 </hbox>
38</dialog>