Post changesets to Twitter
[potlatch2.git] / net / systemeD / potlatch2 / save / SaveDialog.mxml
1 <?xml version="1.0" encoding="utf-8"?>
2 <mx:TitleWindow
3     xmlns:fx="http://ns.adobe.com/mxml/2009"
4         xmlns:mx="library://ns.adobe.com/flex/mx"
5         layout="vertical"
6         horizontalAlign="center" title="Save Changes"
7         width="350" height="330" verticalGap="0">
8
9   <fx:Declarations>
10   <mx:ArrayCollection id="changesetTags">
11     <fx:Object k="created_by" v="Potlatch 2"/>
12     <fx:Object k="version" v="{application.version}"/>
13     <fx:Object k="build" v="{application.build_number}"/>
14   </mx:ArrayCollection>
15   </fx:Declarations>
16   
17   <mx:ViewStack id="processSequence" width="100%" height="100%" 
18       creationPolicy="all" creationComplete="if (doSkip) skipInput() else comment.setFocus()">
19   
20     <!-- section for entering tags -->
21     <mx:VBox width="100%" height="100%" verticalGap="0">
22       <mx:ViewStack id="tagStack" width="100%" height="100%">
23         <mx:VBox width="100%" height="100%" label="Simple">
24           <mx:Text id="editDescription" width="100%">
25             <mx:text>
26                Please enter a description of your edits. This will be used to give other
27                mappers an idea of what changes you are making.
28             </mx:text>
29           </mx:Text>
30           <mx:HBox width="100%">
31             <mx:Image data="@Embed('../../../../embedded/read_this.png')" />
32             <mx:Text id="databaseWarning" width="100%">
33               <mx:text>
34                  Your changes are saved to the main OpenStreetMap database for everyone to 
35                  see. This is not your own private map. Please don&apos;t save test changes 
36                  or edits for personal use only.
37               </mx:text>
38             </mx:Text>
39           </mx:HBox>
40           <mx:Label id="commentLabel" text="Comment:"/>
41           <mx:TextArea id="comment" maxChars="255" width="100%" height="100%" change="commentChanged(event);" textInput="monitorEnter(event);" />
42         </mx:VBox>
43         
44         <mx:VBox width="100%" height="100%" label="Advanced">
45           <mx:Label text="Changeset tags:"/>
46           <mx:DataGrid editable="true" width="100%" id="advancedTagGrid"
47               dataProvider="{changesetTags}"
48               itemEditBeginning="allowForEdit(event)"
49               itemEditEnd="verifyInput(event)">
50             <mx:columns>
51                 <mx:DataGridColumn editable="true" dataField="k" headerText="Key">
52                     <mx:itemEditor><fx:Component><mx:TextInput restrict="&#x0020;-&#x10FFFF;" /></fx:Component></mx:itemEditor>
53                 </mx:DataGridColumn>
54                 <mx:DataGridColumn editable="true" dataField="v" headerText="Value">
55                     <mx:itemEditor><fx:Component><mx:TextInput restrict="&#x0020;-&#x10FFFF;" /></fx:Component></mx:itemEditor>
56                 </mx:DataGridColumn>
57             </mx:columns>
58           </mx:DataGrid>        
59                   <mx:HBox horizontalAlign="right" width="100%">
60                     <mx:LinkButton label="Delete" click="removeTag()" enabled="{advancedTagGrid.selectedItem != null? true : false}"/>
61                     <mx:LinkButton label="Add" click="addNewTag()"/>
62                   </mx:HBox>
63                   <mx:HRule width="100%" />
64         </mx:VBox>
65       </mx:ViewStack>
66       <mx:LinkBar dataProvider="{tagStack}"/>
67     </mx:VBox>
68     
69     <mx:VBox width="100%" height="100%" id="createChangesetTab">
70       <mx:VBox width="100%" height="100%" id="infoBox"/>
71       <mx:Spacer height="100%"/>
72       <mx:ProgressBar label="Creating changeset" labelPlacement="bottom" width="100%"
73           indeterminate="true" id="saveProgress"/>
74     </mx:VBox>
75     
76     <mx:VBox width="100%" height="100%" id="failureTab">
77       <mx:Text width="100%" styleName="failText" text="{failureText}"/>
78     </mx:VBox>
79
80     <mx:VBox width="100%" height="100%" id="dataTab">
81       <mx:TextArea width="100%" height="100%" id="dataText"/>
82     </mx:VBox>
83
84   </mx:ViewStack>
85
86   <mx:ControlBar>
87     <mx:CheckBox id="twitter" selected="{getTwitter()}"
88                 label="Post on Twitter"
89                 change="setTwitter(twitter.selected)" />
90
91     <mx:Button id="dataButton" label="View data" visible="false" click="processSequence.selectedChild=dataTab" styleName="titleWindowButton" />
92     <mx:Spacer width="100%"/>
93     <mx:Button id="cancelButton" label="Cancel" click="close();" styleName="titleWindowButton" />
94     <mx:Button id="saveButton" label="Save >" click="startSave();" styleName="titleWindowButton" />
95   </mx:ControlBar>
96   
97   <fx:Script><![CDATA[
98   
99     import mx.controls.*;
100     import mx.managers.PopUpManager;
101         import mx.core.Application;
102         import mx.core.FlexGlobals;
103     import mx.events.DataGridEvent;
104     import mx.events.DataGridEventReason;
105     import flash.net.*;
106
107     import net.systemeD.halcyon.connection.*;
108     import net.systemeD.halcyon.AttentionEvent;
109     
110     private var _connection:Connection;
111         private var doSkip:Boolean = false;
112     private var newChangeset:Boolean = true;
113
114     [Bindable] private var failureText:String = "";
115         [Bindable] private var application:Object = FlexGlobals.topLevelApplication;
116
117         public function setConnection(connection:Connection):void {
118                 _connection=connection;
119                 newChangeset=true;
120         }
121
122         public function dontPrompt():void {
123                 newChangeset=false;
124                 if (processSequence.initialized) { skipInput(); } else { doSkip=true; }
125         }
126
127         private function skipInput():void {
128         processSequence.selectedChild = createChangesetTab;
129                 saveButton.enabled = false;
130                 changesetCreated();
131         }
132
133         private function commentChanged(event:Event):void {
134                 for (var i:int=changesetTags.length-1; i>0; i--) {
135                         if (changesetTags[i]['k']=='comment') { changesetTags.removeItemAt(i); }
136                 }
137                 if (event.target.text!='') changesetTags.addItem( { k:'comment', v: event.target.text } );
138     }
139
140         private function monitorEnter(event:TextEvent):void {
141                 if (event.text=="\n") { event.preventDefault(); startSave(); }
142         }
143
144         private function addNewTag():void {
145                 changesetTags.addItem( { k:'(new key)', v:'(new value)' } );
146                 advancedTagGrid.editedItemPosition = { rowIndex: changesetTags.length-1, columnIndex: 0 };
147         }
148
149         private function removeTag():void {
150                 changesetTags.removeItemAt(advancedTagGrid.selectedIndex);
151         }
152     
153     private function startSave():void {
154     
155         // move to next sequence
156         processSequence.selectedChild = createChangesetTab;
157         saveButton.enabled = false;
158         
159         var tags:Object = new Object();
160         for each (var tag:Object in changesetTags) {
161            tags[tag['k']] = tag['v'];
162         }
163         
164         // add the listeners
165         _connection.addEventListener(Connection.NEW_CHANGESET, changesetCreated);
166         _connection.addEventListener(Connection.NEW_CHANGESET_ERROR, changesetError);
167         _connection.createChangeset(tags);
168     }
169
170     private function allowForEdit(event:DataGridEvent):void {
171         /* check before editing the tag grid that it's neither created_by nor version tags */
172         var item:Object = ((event.currentTarget as DataGrid).dataProvider as ArrayCollection)[event.rowIndex];
173         if(item.k == 'created_by' || item.k == 'version' || item.k == 'build') {
174           event.preventDefault();
175         }
176     }
177
178     private function verifyInput(event:DataGridEvent):void {
179         /* check before saving any change that the new key isn't created_by nor version */
180         // it is OK if the user cancels the edit
181         if( event.reason == DataGridEventReason.CANCELLED ) return;
182
183         var editor:TextInput = (event.currentTarget as DataGrid).itemEditorInstance as TextInput;
184
185         if( event.dataField == "k" ) {
186           if( editor.text == 'created_by' || editor.text == 'version' || editor.text == 'build') {
187             event.preventDefault();
188           }
189         }
190     }
191
192     private function changesetCreated(event:EntityEvent=null):void {
193         var changeset:Changeset = _connection.getActiveChangeset();
194         addStatus("Saving to changeset "+changeset.id);
195         
196         saveProgress.label = "Uploading changes";
197                 twitter.visible=false; twitter.includeInLayout=false;
198         _connection.addEventListener(Connection.SAVE_COMPLETED, saveCompleted);
199         var rawData:*=_connection.uploadChanges();
200         if (rawData) {
201             dataText.text=rawData.toString();
202             dataButton.visible=true;
203         }
204     }
205     
206     private function changesetError(event:Event):void {
207         fail("Error creating changeset");
208     }
209     
210     private function saveCompleted(event:SaveCompleteEvent):void {
211         if ( event.saveOK ) {
212                         _connection.dispatchEvent(new AttentionEvent(AttentionEvent.ALERT, null, "Changes successfully saved"));
213                         if (twitter.selected && newChangeset) {
214                                 var url:String="https://twitter.com/intent/tweet?url=http%3A%2F%2Fwww.openstreetmap.org%2Fbrowse%2Fchangeset%2F";
215                                 url+=_connection.getActiveChangeset().id;
216                                 var comment:String=_connection.getActiveChangeset().getTag('comment') || "I just edited OpenStreetMap!";
217                                 url+="&text="+encodeURIComponent(comment);
218                                 navigateToURL(new URLRequest(url), "_blank");
219                         }
220             if (processSequence.selectedChild!=dataTab) close();
221         } else {
222             fail("Failure when uploading data");
223                 }
224         if (saveButton && saveButton.parent) saveButton.parent.removeChild(saveButton);
225         cancelButton.label = "Close";
226     }
227     
228     private function addStatus(text:String):void {
229         var label:Text = new Text();
230         label.text = text;
231         
232         infoBox.addChild(label);
233     }
234     
235     private function fail(text:String):void {
236         processSequence.selectedChild = failureTab;
237         failureText = text;
238     }
239
240     private function close():void {
241         _connection.removeEventListener(Connection.NEW_CHANGESET, changesetCreated);
242         _connection.removeEventListener(Connection.NEW_CHANGESET_ERROR, changesetError);
243         _connection.removeEventListener(Connection.SAVE_COMPLETED, saveCompleted);
244         PopUpManager.removePopUp(this);
245     }
246
247         public function getTwitter():Boolean {
248                 return SharedObject.getLocal('user_state','/').data['twitter'];
249         }
250
251         public function setTwitter(v:Boolean):void {
252                 var obj:SharedObject=SharedObject.getLocal("user_state","/");
253                 obj.setProperty('twitter',v);
254                 try { obj.flush(); } catch (e:Error) {}
255                 comment.setFocus();
256         }
257
258   ]]></fx:Script>
259 </mx:TitleWindow>
260