source: subversion/applications/editors/potlatch/properties.as @ 17889

Last change on this file since 17889 was 17889, checked in by richard, 10 years ago

Potlatch 1.2c. Not checking in SWF until I've spoken to avar and am reasonably confident about the i18n stuff

File size: 32.4 KB
Line 
1 
2        // =====================================================================================
3        // properties.as
4        // Potlatch property window functions
5        // =====================================================================================
6
7        // UTF8 character remappings
8        var cp1252=new Object();
9        cp1252[0x20ac]=0x80;
10        cp1252[0x201a]=0x82;
11        cp1252[0x0192]=0x83;
12        cp1252[0x201e]=0x84;
13        cp1252[0x2026]=0x85;
14        cp1252[0x2020]=0x86;
15        cp1252[0x2021]=0x87;
16        cp1252[0x02c6]=0x88;
17        cp1252[0x2030]=0x89;
18        cp1252[0x0160]=0x8a;
19        cp1252[0x2039]=0x8b;
20        cp1252[0x0152]=0x8c;
21        cp1252[0x017d]=0x8e;
22        cp1252[0x2018]=0x91;
23        cp1252[0x2019]=0x92;
24        cp1252[0x201c]=0x93;
25        cp1252[0x201d]=0x94;
26        cp1252[0x2022]=0x95;
27        cp1252[0x2013]=0x96;
28        cp1252[0x2014]=0x97;
29        cp1252[0x02dc]=0x98;
30        cp1252[0x2122]=0x99;
31        cp1252[0x0161]=0x9a;
32        cp1252[0x203a]=0x9b;
33        cp1252[0x0153]=0x9c;
34        cp1252[0x017e]=0x9e;
35        cp1252[0x0178]=0x9f;
36
37
38        // to do later:
39        // -- relations:
40        //              sort colouring/highlighting
41        //              better presentation for drop-down "choose a relation" menu
42        //              search for relations
43        //              link icon?
44        //              repeat relations
45        //              preset menu
46        //              autocomplete
47        //                      will need to be a higher stacking level than modal
48        // -- scrollbar background/clicking?
49
50        // properties is cleared/inited on:
51        // - anchorpoint.select
52        // - POI.reload and POI.select
53        // - potlatch.as: mapClickEnd, deselectAll
54        // - (relations, not a problem as yet)
55        // - Way.select
56       
57        // =====================================================================================
58        // Preset menu
59       
60        PresetMenu=function() {};
61        PresetMenu.prototype=new MovieClip();
62
63        PresetMenu.prototype.init=function(pw) {
64                if (pw) {
65                        this.pw=pw;                     // reference to property window
66                        pw.presetmenu=this;     // and back again!
67                        this.group=_root.lastgroup;     // what group of tags? (e.g. 'road')
68                        this.setIcon();
69                        this.reflect();
70                } else {
71                        removeMovieClip(this.dropdown);
72                        removeMovieClip(this.icon);
73                }
74        };
75        PresetMenu.prototype.initMenu=function(value) {
76                this.attachMovie("menu","dropdown",1);
77                this.dropdown.init(30,5,value,
78                                                   presetnames[this.pw.proptype][this.group],
79                                                   'Choose from a menu of preset tags describing the '+pw.proptype,
80                                                   this.setAttributesFromPreset,this,151);
81        };
82        PresetMenu.prototype.reflect=function() {
83                var i,t;
84                var pt=this.pw.proptype;
85                var found=this.pw.findInPresetMenu(this.group);
86                if (found) { this.initMenu(found); return; }
87                for (i=0; i<presetmenus[pt].length; i+=1) {
88                        t=this.pw.findInPresetMenu(presetmenus[pt][i]); if (t) { found=t; this.group=presetmenus[pt][i]; }
89                }
90                if (found) { this.initMenu(found);
91                                         this.setIcon(); }
92                          else { this.initMenu(0); }
93        };
94        PresetMenu.prototype.setIcon=function() {
95                _root.lastgroup=this.group;
96                this.attachMovie("preset_"+this.group,"icon",2);
97                with (this.icon) { _x=10; _y=15; }
98                this.icon.onPress   =function() { this._parent.cycleIcon(); };
99                this.icon.onRollOver=function() { setFloater(iText('tip_presettype')); };
100                this.icon.onRollOut =function() { clearFloater(); };
101        };
102        PresetMenu.prototype.cycleIcon=function() {
103                var j=0;
104                var pt=this.pw.proptype;
105                for (var i=0; i<presetmenus[pt].length; i+=1) {
106                        if (presetmenus[pt][i]==this.group) { j=i+1; }
107                }
108                this.group=presetmenus[pt][j%i];
109                this.setIcon();
110                this.initMenu(this.pw.findInPresetMenu(this.group));
111        };
112        PresetMenu.prototype.setAttributesFromPreset=function(pre) {
113                var pname=presetnames[this.pw.proptype][this.group][pre];
114                this.pw.setAttributes(presets[pname]);
115        };
116
117        Object.registerClass("presetmenu",PresetMenu);
118
119
120        // =====================================================================================
121        // Autocomplete
122
123        // Still to do
124        // - some way of stopping keys being added twice with same name
125        //   (probably rename to highway_2?)
126        // - wipe preset menu when POI reverted
127        // - some way of invoking full autocomplete menu when value deleted
128        //   (probably using up cursor/down cursor)
129
130        AutoMenu=function() {};
131        AutoMenu.prototype=new MovieClip();
132        AutoMenu.prototype.redraw=function(tf) {
133
134                this.tf=tf;                                                     // textfield instance
135                this.pw=tf._parent._parent._parent;     // PropertyWindow instance
136                this.field=tf._name;                            // keyname|value
137                this.key=tf._parent.keyname.text;
138                var curval=tf.text;
139
140                if (this.field=='value' && curval=='' &&
141                   (_root.lastkeypressed==8 || _root.lastkeypressed==46)) {
142                        // if user has just deleted value, don't show autocomplete!
143                        this.remove(); return;
144                }
145
146                // Find possible values for autocomplete
147                if (curval=='key') { curval=''; }                                       // full menu on 'key'
148                var possible=new Array();
149                if (this.field=='keyname') {
150                        z=_root.autotags[this.pw.proptype];                             // key
151                        for (i in z) {
152                                if (!this.pw.proparr[i]) {                                      // don't add if there's already a key of that name
153                                        if (i.slice(0,curval.length)==curval) { possible.push(i); }
154                                } 
155                        }
156                        possible.sort();
157                } else {
158                        z=_root.autotags[this.pw.proptype][this.key];   // value
159                        for (i in z) {
160                                if (z[i].slice(0,curval.length)==curval) { possible.push(z[i]); }
161                        }
162                }
163
164                // Draw autocomplete window
165                var p=getGlobalCoord(tf); var wx=p[0]; var wy=p[1];
166                this.autonumkeys=Math.min(possible.length,Math.floor(wy/16));
167                if (this.autonumkeys==0) { this.remove(); return; }
168                if (this.autonumkeys==1 && possible[0]==curval) { this.remove(); return; }
169
170                this.createEmptyMovieClip("autolist",1);
171               
172                with (this.autolist) {
173                        _x=wx; _y=wy-16*this.autonumkeys-3;
174                        clear();
175                        beginFill(0x0000FF,100);
176                        moveTo(0,0); lineTo(100,0);
177                        lineTo(100,16*this.autonumkeys+3);
178                        lineTo(0,16*this.autonumkeys+3); lineTo(0,0);
179                        endFill();
180                };
181
182                this.useHandCursor=true;
183                this.onPress=function() {
184                        this.select(Math.floor(this.autolist._ymouse/16));
185                        this.paste();
186                        var f=this.field;
187                        var k=this.key;
188                        if (f=='keyname') {
189                                renameKey(this.tf);
190                                _root.reinstatefocus=this.tf._parent.value;
191                        } else {
192                                this.remove();
193                                Selection.setFocus(null);
194                                _root.keytarget='';
195                        }
196                        this.pw.redrawObject();
197                };
198
199                this.createEmptyMovieClip("triangle",2);
200                with (this.triangle) {
201                        clear();
202                        beginFill(0x0000FF,100);
203                        moveTo(5,0);  lineTo(15,0);
204                        lineTo(10,5); lineTo(5,0);
205                        endFill();
206                        _x=wx; _y=wy;
207                };
208               
209                for (i=0; i<this.autonumkeys; i++) {
210                        this.autolist.createTextField("o"+i,i,0,i*16,100,20);
211                        with (this.autolist["o"+i]) {
212                                text=possible[i]; setTextFormat(boldWhite); type='dynamic'; 
213                                background=true; backgroundColor=0x0000FF; selectable=false;
214                        };
215                }
216                this.select(0);
217        };
218        AutoMenu.prototype.remove=function() {
219                removeMovieClip(this);
220        };
221
222        // AutoMenu.select              - set and highlight autocomplete value
223
224        AutoMenu.prototype.select=function(n) {
225                this.autolist["o"+this.selected].backgroundColor=0x0000FF;
226                this.autolist["o"+this.selected].setTextFormat(auto_off);
227                this.selected=n;
228                this.autolist["o"+n].backgroundColor=0x00FFFF;
229                this.autolist["o"+n].setTextFormat(auto_on);
230        };
231       
232        // AutoMenu.paste               - write currently selected value into textfield
233
234        AutoMenu.prototype.paste=function() {
235                var newval=this.autolist["o"+this.selected].text;
236                var tf=this.tf;
237                tf.text=newval;
238                if (this.field=='keyname') { renameKey(tf); }
239                                                          else { setValueFromTextfield(tf); }
240                Selection.setSelection(newval.length,newval.length);
241        };
242       
243
244        // keyRespond                   - respond to up/down/enter keypresses
245       
246        AutoMenu.prototype.keyRespond=function(k) {
247                switch (k) {
248                        case Key.UP:    if (this.selected>0  ) { this.select(this.selected-1); }
249                                                        this.paste(); break;
250                        case Key.DOWN:  if (this.selected+1<this.autonumkeys) { this.select(this.selected+1); }
251                                                        this.paste(); break;
252                        case 13:                this.paste();
253                                                        this.remove();
254                                                        autoEnter(); break;
255                        case 27:                this.remove(); break;
256                };
257        };
258       
259        // autoEnter                    - Enter pressed, move to next field
260
261        function autoEnter() {
262                if (Selection.getFocus().split('.').pop()=='keyname') {
263                        Selection.setFocus(eval(Selection.getFocus())._parent.value);
264                } else {
265                        Selection.setFocus(null);
266                }
267        }
268
269        Object.registerClass("auto",AutoMenu);
270
271
272        // =====================================================================================
273        // PropertyWindow object
274
275        PropertyWindow=function() {
276                this.proptype='';
277        };
278        PropertyWindow.prototype=new MovieClip();
279       
280        PropertyWindow.prototype.reinit=function() {
281                var n=this.savedundo;
282                this.init(this.proptype,this.xnumber,this.ynumber);
283                this.savedundo=n;
284        };
285
286        PropertyWindow.prototype.init=function(proptype,w,h) {
287                this.createEmptyMovieClip("attributes",1);
288                this.createEmptyMovieClip("attrmask",2);
289                this.createEmptyMovieClip("scrollbar",3);
290//              if (proptype=='') { this.saveAttributes(); }
291                this.proptype=proptype;
292                this.tab=0;
293                this.xnumber=w;
294                this.ynumber=h;
295                this.tagcount=0;
296                this.savedundo=false;
297                this.learn=new Object();
298                if (proptype=='') { return; }
299
300                this.relarr = new Object();
301                switch (proptype) {
302                        case 'point':
303                                this.proparr=_root.ws.path[_root.pointselected].attr;
304                                this.relarr=_root.noderels[_root.ws.path[pointselected].id];
305                                break;
306                        case 'POI':
307                                this.proparr=_root.map.pois[poiselected].attr;
308                                this.relarr=_root.noderels[poiselected];
309                                break;
310                        case 'way':
311                                this.proparr=_root.ws.attr;
312                                this.relarr=_root.wayrels[wayselected];
313                                break;
314                        case 'relation':
315                                this.proparr=_root.editingrelation.attr;
316                                break;
317                }
318
319                this.xpos=0; this.ypos=0;
320
321                // Attach relations
322                relarr=this.relarr;
323                for (var rel in relarr) {
324                        if (_root.map.relations[rel]) {
325                                this.attributes.attachMovie("relmember",this.tagcount, this.tagcount);
326                                var pos = this.getXY(this.tagcount);
327                                this.attributes[this.tagcount]._x=pos[0];
328                                this.attributes[this.tagcount]._y=pos[1];
329                                this.attributes[this.tagcount].init(rel);
330                                this.attributes[this.tagcount].value.tabIndex=++this.tab;
331                                this.attributes[this.tagcount].value.tabEnabled=true;
332                                this.tagcount+=1;
333                        }
334                }
335
336                // Attach keys/values
337                // sorted alphabetically, but with namespaced tags at the end
338
339                proparr=this.proparr;   // annoying scope issues
340                proplist=new Array();
341                for (el in proparr) { proplist.push(el); }
342                proplist.sort(function(a,b) {
343                        if      (a.indexOf(':')<b.indexOf(':')) { return -1; }
344                        else if (a.indexOf(':')>b.indexOf(':')) { return  1; }
345                        else if (a<b) { return -1; }
346                        else if (a>b) { return  1; }
347                        else              { return  0; }
348                });
349                for (i=0; i<proplist.length; i++) {
350                        el=proplist[i];
351                        if (proparr[el]!='' && el!='created_by' && el!='edited_by') {
352                                this.attributes.attachMovie("keyvalue",this.tagcount,this.tagcount);
353                                var pos = this.getXY(this.tagcount);
354                                this.attributes[this.tagcount]._x=pos[0];
355                                this.attributes[this.tagcount]._y=pos[1];
356                                this.attributes[this.tagcount].init(el);
357                                this.attributes[this.tagcount].keyname.tabIndex=++this.tab;
358                                this.attributes[this.tagcount].value.tabIndex=++this.tab;
359                                this.tagcount+=1;
360                        }
361                }
362
363
364                this.scrollbar._x=0; this.scrollbar._y=this.ynumber*19;
365                this.updateMask();                                      // Draw scrollbar
366        };
367
368        PropertyWindow.prototype.saveUndo=function() {
369                // don't have more than two consecutive undos for the same way
370                if (this.savedundo) { return; }
371                this.savedundo=true;
372                var task  =_root.undo[_root.undo.length-1][0];
373                var params=_root.undo[_root.undo.length-1][1];
374
375                switch (this.proptype) {
376                        case 'way':             _root.undo.append(UndoStack.prototype.undo_waytags,
377                                                                                          new Array(_root.ws,deepCopy(this.proparr)),
378                                                                                          iText('action_waytags')); break;
379                        case 'point':   _root.undo.append(UndoStack.prototype.undo_pointtags,
380                                                                                          new Array(_root.ws,_root.pointselected,deepCopy(this.proparr)),
381                                                                                          iText('action_pointtags')); break;
382                        case 'POI':             _root.undo.append(UndoStack.prototype.undo_poitags,
383                                                                                          new Array(_root.map.pois[poiselected],deepCopy(this.proparr)),
384                                                                                          iText('action_poitags')); break;
385                };
386        };
387
388        PropertyWindow.prototype.getXY=function(i) {
389                var x = Math.floor(i / this.ynumber);
390                var y = i % this.ynumber;
391                return [x*190, y*19];
392        };
393
394        PropertyWindow.prototype.enableTabs=function(a) {
395                for (var i in this.attributes) {
396                        this.attributes[i].keyname.tabEnabled=a;
397                        this.attributes[i].value.tabEnabled  =a;
398                }
399        };
400
401        // PropertyWindow.enterNewAttribute
402
403        PropertyWindow.prototype.enterNewAttribute=function() {
404                // ** check nothing already exists called "key"
405                this.saveUndo();
406                this.attributes.attachMovie("keyvalue",this.tagcount,this.tagcount);
407                var pos = this.getXY(this.tagcount);
408                this.attributes[this.tagcount]._x=pos[0];
409                this.attributes[this.tagcount]._y=pos[1];
410                this.attributes[this.tagcount].init('key');
411                this.attributes[this.tagcount].keyname.tabIndex=++this.tab;
412                this.attributes[this.tagcount].value.tabIndex=++this.tab;
413                Selection.setFocus(this.attributes[this.tagcount].keyname);
414                Selection.setSelection(0,3);
415                this.tagcount+=1;
416                this.updateMask();
417                this.attributes[this.tagcount-1].scrollToField();
418        };
419
420        // PropertyWindow.updateMask
421        // create mask given size of window, create scrollbar
422
423        PropertyWindow.prototype.updateMask=function() {
424                this.cols=Math.floor((this.tagcount+(this.ynumber-1))/this.ynumber);// number of columns used
425                var pxwidth=this.xnumber*190-5;
426
427                // Create and apply mask
428                with (this.attrmask) {
429                        clear();
430                        beginFill(0,100);
431                        moveTo(0,0); lineTo(pxwidth,0);
432                        lineTo(pxwidth,this.ynumber*19); lineTo(0,this.ynumber*19);
433                        lineTo(0,0); endFill();
434                }
435                this.attributes.setMask(this.attrmask);
436
437                // Draw scrollbar
438                var percent=(Math.min(this.xnumber/this.cols,1));       // what percentage of scrollbar to show?
439                var swidth=pxwidth*percent;                                                     // how wide is the scrollbar?
440                this.mwidth=pxwidth-swidth;                                                     // furthest right scrollbar can go
441                this.sscope=(this.cols-this.xnumber)*190;                       // how many unshown pixels in attributes
442                if (percent==1) { var c=0xE0E0E0; }                                     // colour to show scrollbar
443                                   else { var c=0xCCCCCC; }                                     //  |
444                with (this.scrollbar) {
445                        clear();
446                        beginFill(c,100);
447                        moveTo(0,0); lineTo(swidth,0);
448                        lineTo(swidth,4); lineTo(0,4);
449                        lineTo(0,0); endFill();
450                };
451
452                // Scrollbar move events
453                if (percent<1) {
454                        this.scrollbar.onPress=function() {
455                                this.onMouseMove=function() {
456                                        this._parent.attributes._x=-(this._x/this._parent.mwidth)*this._parent.sscope;
457                                };
458                                this.startDrag(false,0,this._y,this._parent.mwidth,this._y);
459                        };
460                        this.scrollbar.onRelease=function() {
461                                delete this.onMouseMove;
462                                this.stopDrag();
463                        };
464                }
465        };
466       
467        PropertyWindow.prototype.repeatAttributes=function(dotags) {
468                var i,proparr,relarr;
469                this.saveUndo();
470                switch (this.proptype) {
471                        case 'point':   proparr=_root.savedpointway.path[_root.saved['point']].attr; 
472                                                        relarr=_root.noderels[_root.savedpointway.path[_root.saved['point']].id];
473                                                        break;
474                        case 'POI':             proparr=_root.saved['POI'].attr;
475                                                        relarr=_root.noderels[_root.saved['POI']._name];
476                                                        break; // ** formerly had _root.map.pois[poiselected].attr=new Array(); in here, no obvious reason why
477                        case 'way':             proparr=_root.saved['way'].attr;
478                                                        relarr=_root.wayrels[_root.saved['way']._name];
479                                                        break;
480                }
481
482                // repeat tags
483                if (dotags) {
484                        for (i in proparr) {
485                                if (Key.isDown(Key.SHIFT) && (i=='name' || i=='ref') || i=='created_by') {
486                                        // ignore name and ref if SHIFT pressed
487                                } else {
488                                        switch (this.proptype) {
489                                                case 'point':   j=_root.savedpointway.path[_root.saved['point']].attr[i]; break;
490                                                case 'POI':             j=_root.saved['POI'].attr[i]; break;
491                                                case 'way':             j=_root.saved['way'].attr[i]; break;
492                                        }
493                                        setValueInObject(this.proptype,i,j);
494                                }
495                        }
496                }
497
498                // repeat relations
499                for (i in relarr) {
500                        var r=_root.map.relations[i];   // reference to this relation
501                        switch (this.proptype) {
502                                case 'point':   r.setNodeRole(_root.ws.path[_root.pointselected].id,relarr[i]); break;
503                                case 'POI':             r.setNodeRole(poiselected,relarr[i]); break;
504                                case 'way':             r.setWayRole (wayselected,relarr[i]); break;
505                        }
506                }
507                this.redrawObject();
508                this.reflect();
509                this.reinit();
510        };
511
512        PropertyWindow.prototype.redrawObject=function() {
513                switch (this.proptype) {
514                        case 'POI':     _root.map.pois[poiselected].redraw(); break;
515                        default:        _root.ws.redraw(); updateInspector(); break;
516                }
517        };
518
519        PropertyWindow.prototype.setAttributes=function(pkeys) {
520                this.saveUndo();
521                for (var pkey in pkeys) {
522                        if (this.proparr[pkey].length>0 && pkeys[pkey].substr(0,6)=='(type ') {}
523                        else { setValueInObject(this.proptype, pkey, pkeys[pkey]); }
524                }
525                this.reinit();
526                this.saveAttributes();
527                this.redrawObject();
528        };
529
530        PropertyWindow.prototype.nukeAttributes=function() {
531                var proparr=this.proparr;
532                this.saveUndo();
533                for (var el in proparr) { delete this.proparr[el]; setValueInObject(this.proptype,el,''); }
534                this.redrawObject();
535                this.reflect();
536                this.reinit();
537        };
538
539        PropertyWindow.prototype.saveAttributes=function() {
540                if (this.tagcount==0) { return; }
541                switch (this.proptype) {
542                        case 'point':   _root.saved[this.proptype]=_root.pointselected; _root.savedpointway=_root.ws; break;
543                        case 'POI':             _root.saved[this.proptype]=_root.map.pois[poiselected]; break;
544                        case 'way':             _root.saved[this.proptype]=_root.ws; break;
545                };
546        };
547
548        PropertyWindow.prototype.findInPresetMenu=function(group) {
549                if (group=='address') { return 0; }     // shouldn't match addresses as they're "additional" tags
550                var pname,pkeys,pre,ok,cvalue;
551                var f=0;
552                for (pre=presetnames[this.proptype][group].length-1; pre>-1; pre-=1) {
553                        pname=presetnames[this.proptype][group][pre];
554                        pkeys=_root.presets[pname];
555                        if (pkeys) {
556                                ok=1;
557                                for (pkey in pkeys) {
558                                        cvalue=this.proparr[pkey];
559                                        if (cvalue==null) { cvalue=''; }
560                                        if (cvalue!=presets[pname][pkey] && presets[pname][pkey].substr(0,6)!='(type ') { ok=0; }
561                                }
562                                if (ok==1) { f=pre; }
563                        }
564                }
565                return f;
566        };
567
568        PropertyWindow.prototype.reflect=function() {
569                if (this.presetmenu) { this.presetmenu.reflect(); }
570        };
571
572        PropertyWindow.prototype.setTag=function(k,v) {
573                this.saveUndo();
574                setValueInObject(this.proptype,k,v);
575                this.reinit();
576                this.saveAttributes();
577        };
578       
579
580       
581        // Remove any '(type...' or blank keys before uploading
582
583        PropertyWindow.prototype.tidy=function() {
584                var proparr=this.proparr;
585                for (var el in proparr) {
586                        var p=proparr[el];
587                        if (p=='' || p=='created_by' || p.substr(0,6)=='(type ' || !p) { delete this.proparr[el]; }
588                        else if (this.learn[el][p] && !freeform[el]) {
589                                var already=false;
590                                var z=_root.autotags[this.proptype][el];
591                                for (var i in z) { if (z[i]==p) { already=true; } }
592                                if (!already) {
593                                        if (!z) { _root.autotags[this.proptype][el]=new Array(); }
594                                        _root.autotags[this.proptype][el].push(p);
595                                        _root.autotags[this.proptype][el].sort(2);
596                                }
597                        }
598                }
599        };
600
601        Object.registerClass("propwindow",PropertyWindow);
602
603
604
605
606
607        // =====================================================================================
608        // KeyValue object
609
610        function KeyValue() {};
611        KeyValue.prototype=new MovieClip();
612
613        KeyValue.prototype.init=function(key,value) {
614
615                // Initialise key
616
617                this.createTextField('keyname',1,0,-1,70,18);
618                with (this.keyname) {
619                        backgroundColor=0xBBBBBB;
620                        background=true;
621                        text=key;
622                        type='input';
623                        setTextFormat(boldSmall);
624                        setNewTextFormat(boldSmall);
625                        restrict="^"+chr(0)+"-"+chr(31);
626                        maxChars=255;
627                };
628                this.keyname.onSetFocus =function() {
629                        this._parent.scrollToField();
630                        _root.keytarget='keyname';
631                };
632                this.keyname.onKillFocus=function() {
633                        renameKey(this);
634                        if (_root.lastkeypressed==-1 && _root.auto.autolist.hitTest(_root._xmouse,_root._ymouse)) { return; }
635                        if (this.text=='') { _root.redopropertywindow=this._parent._parent._parent; }
636                        _root.keytarget='';
637                        _root.auto.remove();
638                        this._parent._parent._parent.reflect();
639                };
640                this.keyname.onChanged=function(tf) {
641                        fixUTF8();
642                        if (tf.text=='+' || tf.text=='=') {
643                                // if FP has picked up the "+" keypress, ignore it and set back to 'key'
644                                tf.text='key';
645                                tf.setTextFormat(boldSmall);
646                                tf.setNewTextFormat(boldSmall);
647                                Selection.setFocus(tf); Selection.setSelection(0,3);
648                        }
649                        if (!_root.auto) { _root.attachMovie("auto","auto",75); }
650                        _root.auto.redraw(tf);
651                        this._parent._parent._parent.saveAttributes();
652                };
653
654                // Initialise value
655
656                this.createTextField('value',2,72,-1,100,18);
657                this.value.onSetFocus =function() {
658                        this._parent.scrollToField();
659                        if (this.textColor==0x888888) { this.text=''; this.textColor=0; }
660                        if (!_root.auto) { _root.attachMovie("auto","auto",75); }
661                        _root.auto.redraw(this);
662                        _root.keytarget='value'; 
663                };
664                this.value.onKillFocus=function() {
665                        if (_root.reinstatefocus) { return; }
666                        if (_root.lastkeypressed==-1 && _root.auto.autolist.hitTest(_root._xmouse,_root._ymouse)) { return; }
667                        _root.keytarget='';
668                        if (this.text=='') {
669                                if (this._parent.lastvalue.substr(0,6)=='(type ') {
670                                        this.text=this._parent.lastvalue; this.textColor=0x888888;
671                                } else {
672                                        _root.redopropertywindow=this._parent._parent._parent; 
673                                }
674                        }
675                        this._parent._parent._parent.redrawObject();
676                        _root.auto.remove();
677                        this._parent._parent._parent.reflect();
678                        this._parent.lastvalue=this.text;
679
680                        var k=this._parent.keyname.text;
681                        var l=this._parent._parent._parent.learn;
682                        if (l[k]==undefined) { l[k]=new Object(); }
683                        l[k][this.text]=true;
684                };
685                this.value.onChanged=function(tf) {
686                        fixUTF8();
687                        setValueFromTextfield(tf);
688                        if (!_root.auto) { _root.attachMovie("auto","auto",75); }
689                        _root.auto.redraw(tf);
690                        this._parent._parent._parent.saveAttributes();
691                };
692                with (this.value) {
693                        backgroundColor=0xDDDDDD;
694                        background=true;
695                        type='input';
696                        setTextFormat(plainSmall);
697                        setNewTextFormat(plainSmall);
698                        restrict="^"+chr(0)+"-"+chr(31);
699                        maxChars=255;
700                };
701                this.value.text=this.getValueFromObject(key);
702                if (this.value.text.substr(0,6)=='(type ') { this.value.textColor=0x888888; }
703                this.lastkey=key;
704                this.lastvalue=this.value.text;
705               
706                // Initialise close box
707               
708                this.createEmptyMovieClip('grey',3);
709                with (this.grey) {
710                        beginFill(0xDDDDDD,100);
711                        moveTo(172,-1); lineTo(182,-1);
712                        lineTo(182,17); lineTo(172,17);
713                        endFill();
714                };
715
716                this.attachMovie("closecross", "i_remove", 4);
717                with (this.i_remove) { _x=174; _y=8; };
718                this.i_remove.onPress=function() {
719                        this._parent.value.text='';
720                        setValueFromTextfield(this._parent.value);
721                        _root.auto.remove();
722                        this._parent._parent._parent.reflect();
723                        this._parent._parent._parent.redrawObject();
724                        _root.redopropertywindow=this._parent._parent._parent;
725                };
726        };
727
728
729        // KeyValue.getValueFromObject(key)
730        // for a given key, returns the value from the way, point or POI
731
732        KeyValue.prototype.getValueFromObject=function(k) {
733                var v;
734                switch (this._parent._parent.proptype) {
735                        case 'point':   v=_root.ws.path[_root.pointselected].attr[k]; break;
736                        case 'POI':             v=_root.map.pois[poiselected].attr[k]; break;
737                        case 'way':             v=_root.ws.attr[k]; break;
738                        case 'relation':v=_root.editingrelation.attr[k]; break;
739                }
740                if (v==undefined) { v='(type value here)'; }
741                return v;
742        };
743
744        // KeyValue.scrollToField()
745        // make sure this field is visible
746       
747        KeyValue.prototype.scrollToField=function() {
748                var pw=this._parent._parent;
749                if (this._x>=-(pw.attributes._x) &&
750                        this._x< -(pw.attributes._x)+190*(pw.xnumber-1)+5) {
751                        return;                 // In view
752                                                        // -(pw.attributes._x) is left x of the panel
753                }
754
755                // To get in view, we need our column on the right of the panel
756                var newcol=Math.floor(this._x/190);             // column we're in
757                newcol=Math.min(newcol,pw.cols-pw.xnumber);
758                newcol=Math.max(newcol,0);
759                pw.attributes._x=-newcol*190;
760                pw.scrollbar._x=newcol*190/pw.sscope*pw.mwidth;
761                // (inverse of calculation in pw.scrollbar.onPress)
762        };
763
764        Object.registerClass("keyvalue",KeyValue);
765
766        // =====================================================================================
767        // KeyValue support functions
768
769        // setValueFromTextfield(value textfield)
770        // setValueInObject(property type,key,value)
771        // - update the way, point or POI with the new value
772        //   (opposite of getValueFromObject)
773       
774        function setValueFromTextfield(tf) {
775                tf._parent._parent._parent.saveUndo();
776                setValueInObject(tf._parent._parent._parent.proptype,
777                                                 tf._parent.keyname.text,
778                                                 tf.text);
779        };
780       
781        function setValueInObject(proptype,k,v) {
782                switch (proptype) {
783                        case 'point':   var id=_root.ws.path[_root.pointselected].id;
784                                                        nodes[id].attr[k]=v;
785                                                        nodes[id].tagged=hasTags(nodes[id].attr);
786                                                        nodes[id].markDirty();
787                                                        _root.ws.clean=false; break;
788                        case 'POI':             _root.map.pois[poiselected].attr[k]=v;
789                                                        _root.map.pois[poiselected].clean=false; break;
790                        case 'way':             _root.ws.attr[k]=v;
791                                                        _root.ws.clean=false; break;
792                        case 'relation':_root.editingrelation.attr[k]=v;
793                                                        _root.editingrelation.clean=false; break;
794                }
795        };
796
797        // renameKey(key textfield)
798
799        function renameKey(tf) {
800                var k=tf.text;
801                tf._parent._parent._parent.saveUndo();
802                if (k!=tf._parent.lastkey) {
803                        // field has been renamed, so delete old one and set new one
804                        // (temporary references used to get around Ming delete bug)
805                        switch (tf._parent._parent._parent.proptype) {
806                                case 'point':   var noderef=_root.ws.path[_root.pointselected];
807                                                                delete noderef.attr[tf._parent.lastkey];
808                                                                _root.ws.clean=false; break;
809                                case 'POI':             var poiref=_root.map.pois[poiselected];
810                                                                delete poiref.attr[tf._parent.lastkey];
811                                                                _root.map.pois[poiselected].clean=false; break;
812                                case 'way':             delete _root.ws.attr[tf._parent.lastkey];
813                                                                _root.ws.clean=false; break;
814                                case 'relation':delete _root.editingrelation.attr[tf._parent.lastkey];
815                                                                _root.editingrelation.clean=false; break;
816                        }
817                        setValueFromTextfield(tf._parent.value);
818                        tf._parent.lastkey=k;
819                }
820        };
821
822        // =====================================================================================
823        // RelMember object
824
825        function RelMember() {};
826        RelMember.prototype=new MovieClip();
827
828        RelMember.prototype.init=function(rel_id) {
829                this.rel = _root.map.relations[rel_id];
830
831                // Grey background
832                this.createEmptyMovieClip('grey',1);
833                with (this.grey) {
834                        beginFill(0x909090,100);
835                        moveTo(0,0); lineTo(182,0);
836                        lineTo(182,17); lineTo(0,17);
837                        endFill();
838                        lineStyle(1,0xDDDDDD,100);
839                        moveTo(115,2); lineTo(115,15);
840                        moveTo(166,2); lineTo(166,15);
841                };
842
843                // Initialise key
844                this.createEmptyMovieClip('keynameclick', 2);
845                this.keynameclick.createTextField('keyname',1,0,-1,118,18);
846                var t=this.rel.getType(); var n=this.rel.getName();
847                with (this.keynameclick.keyname) {
848                        type='dynamic'; selectable=false;
849                        text=n; setTextFormat(plainWhite);
850                        setNewTextFormat(boldWhite); replaceSel(t+" ");
851                };
852                this.keynameclick.onPress=function() {
853                        this._parent.rel.editRelation(true);
854                };
855                this.keynameclick.onRollOver=function() { this._parent.rel.setHighlight(true); };
856                this.keynameclick.onRollOut=function() { this._parent.rel.setHighlight(false); };
857
858                // Remove icon
859                this.attachMovie("closecross", "i_remove", 4);
860                with (this.i_remove) { _x=174; _y=8; };
861                this.i_remove.onPress=function() { this._parent.removeRelation(); };
862
863                // Role (value)
864                this.createTextField('value',3,116,1,50,15);    // 3,92,-1,70,18
865                with (this.value) {
866                        backgroundColor=0xDDDDDD;
867                        background=true;
868                        type='input';
869                        setTextFormat(plainTiny);
870                        setNewTextFormat(plainTiny);
871                        restrict="^"+chr(0)+"-"+chr(31);
872                        maxChars=255;
873                };
874                this.value.text=this.getRole();
875                this.value.onSetFocus =function() { this._parent.scrollToField();
876                                                                                        _root.keytarget='value'; };
877                this.value.onKillFocus=function() { _root.keytarget=''; };
878                this.value.onChanged  =function(tf) { fixUTF8(); this._parent.setRole(tf); };
879        };
880
881        RelMember.prototype.getRole=function() {
882                var v;
883                switch (this._parent._parent.proptype) {
884                        case 'point':   v=this.rel.getNodeRole(_root.ws.path[_root.pointselected].id); break;
885                        case 'POI':             v=this.rel.getNodeRole(poiselected); break;
886                        case 'way':             v=this.rel.getWayRole(wayselected); break;
887                }
888                if (v==undefined) { v='(type value here)'; }
889                return v;               
890        };
891
892        RelMember.prototype.setRole=function(tf) {
893                var role = tf.text;
894                switch (this._parent._parent.proptype) {
895                        case 'point':   v=this.rel.setNodeRole(_root.ws.path[_root.pointselected].id, role); break;
896                        case 'POI':             v=this.rel.setNodeRole(poiselected, role); break;
897                        case 'way':             v=this.rel.setWayRole(wayselected, role); break;
898                }
899        };
900
901        RelMember.prototype.removeRelation=function() {
902                switch (this._parent._parent.proptype) {
903                        case 'point': this.rel.removeNode(_root.ws.path[_root.pointselected].id); break;
904                        case 'POI':   this.rel.removeNode(poiselected); break;
905                        case 'way':   this.rel.removeWay(wayselected); break;
906                }
907                _root.panel.properties.reinit();
908        };
909
910        RelMember.prototype.scrollToField=KeyValue.prototype.scrollToField;
911
912        Object.registerClass("relmember",RelMember);
913
914
915
916
917        // =====================================================================================
918        // General support functions
919
920        // setTypeText - set contents of type window
921       
922        function setTypeText(a,b) {
923                if (a=='') {
924                        _root.panel.scale._visible=true;
925                        _root.panel.t_type._visible=_root.panel.t_details._visible=_root.panel.padlock._visible=false;
926                        removeMovieClip(_root.panel.historylink);
927
928                        var thislat=coord2lat(_root.map._y);
929                        var latfactor=Math.cos(thislat/(180/Math.PI));
930                        var m=Math.floor((111200*latfactor)*90/masterscale/bscale);
931
932                        _root.panel.scale.dist.text=m+'m (z'+_root.scale+')';
933                        _root.panel.scale.dist.setTextFormat(plainSmall);
934                        _root.panel.scale.dist.selectable=false;
935                        _root.panel.scale.dist._x=(90-_root.panel.scale.dist.textWidth)/2;
936                } else {
937                        _root.panel.scale._visible=false;
938                        _root.panel.t_type._visible=_root.panel.t_details._visible=true;
939                        _root.panel.t_type.text=a;    _root.panel.t_type.setTextFormat(boldText);
940                        _root.panel.t_details.text=b; _root.panel.t_details.setTextFormat(plainText);
941                        if (_root.ws.locked ||
942                                _root.map.pois[_root.poiselected].locked) {
943                                _root.panel.padlock._visible=true;
944                                _root.panel.padlock._x=_root.panel.t_details.textWidth+15;
945                        } else {
946                                _root.panel.padlock._visible=false;
947                        }
948                        _root.panel.createEmptyMovieClip('historylink',25);
949                        with (_root.panel.historylink) {
950                                beginFill(0,0); moveTo(5,23);
951                                lineTo(7+_root.panel.t_details.textWidth,23);
952                                lineTo(7+_root.panel.t_details.textWidth,23+_root.panel.t_details.textHeight);
953                                lineTo(5,23+_root.panel.t_details.textHeight); lineTo(5,23);
954                        };
955                        _root.panel.historylink.onPress=getHistory;
956                        _root.panel.historylink.useHandCursor=true;
957                        _root.panel.historylink.onRollOver=function() {
958                                var v;
959                                if (_root.poiselected) { v=_root.map.pois[poiselected].version; }
960                                else if (_root.pointselected>-2) {
961                                        v=_root.ws.path[_root.pointselected].version+", in ways ";
962                                        var w=_root.ws.path[_root.pointselected].ways; for (var i in w) { v+=i+","; }
963                                        v=v.substr(0,v.length-1);
964                                }
965                                else { v=_root.ws.version; }
966                                setFloater("Version "+v);
967                        };
968                        _root.panel.historylink.onRollOut =function() { clearFloater(); };
969                }
970        }
971
972        // getPanelColumns - how many columns can fit into the panel?
973
974        function getPanelColumns() {
975                return Math.max(Math.floor((Stage.width-110-15)/190),1);
976        }
977
978        // getGlobalCoord - where on the screen is the textfield?
979
980        function getGlobalCoord(tf) {
981                var pt=new Object();
982                pt.x=tf._parent._x+72*(tf._name=='value');
983                pt.y=tf._parent._y-2;
984                tf._parent.localToGlobal(pt);
985                return new Array(pt.x-tf._parent._x,pt.y-tf._parent._y);
986        }
987
988        // updateButtons - set alpha for buttons
989       
990        function updateButtons() {
991                var pt=_root.panel.properties.proptype;
992                _root.panel.i_repeatattr._alpha=100-50*(pt=='' || _root.saved[pt]=='');
993                _root.panel.i_newattr._alpha   =100-50*(pt=='');
994                _root.panel.i_newrel._alpha    =100-50*(pt=='');
995               
996                var t=50;
997                if (_root.wayselected!=0) {
998                        if (_root.ws.path[0].id==_root.ws.path[_root.ws.path.length-1].id) {
999                                if (_root.ws.path.length>3) { t=100; }
1000                        } else if (_root.ws.path.length>2) { t=100; }
1001                }
1002                _root.panel.i_tidy._alpha=t;
1003        }
1004
1005        function updateScissors(v) {
1006                _root.panel.i_scissors._alpha=50+50*v;
1007        }
1008
1009        // hashLength
1010       
1011        function hashLength (a) {
1012                var l=0;
1013                for (var i in a) { l++; }
1014                return l;
1015        }
1016
1017        // fixUTF8 - bugfix for Flash Player Linux encoding
1018
1019        function fixUTF8() {
1020                if (System.capabilities.os.indexOf('Linux')==-1) { return; }
1021
1022                var s=eval(Selection.getFocus()); var t=s.text;
1023                var i=Selection.getCaretIndex()-1; var d=i;
1024                while (((t.charCodeAt(i)>=0x80 && t.charCodeAt(i)<=0xBF) || (cp1252[t.charCodeAt(i)])) && i>0) {
1025                        if (cp1252[t.charCodeAt(i)]) {
1026                                t=t.substr(0,i)+String.fromCharCode(cp1252[t.charCodeAt(i)])+t.substr(i+1);
1027                        }
1028                        i--;
1029                }
1030                if (i==d) { return; }
1031
1032                var u=0;
1033                if (t.charCodeAt(i)>=0xC2 && t.charCodeAt(i)<=0xDF && d-i==1) {
1034                        // two-byte sequence
1035                        u= (t.charCodeAt(i+1) & 0x3F)       +
1036                          ((t.charCodeAt(i  ) & 3   ) << 6) +
1037                          ((t.charCodeAt(i  ) & 0x1C) << 6);
1038
1039                } else if (t.charCodeAt(i)>=0xE0 && t.charCodeAt(i)<=0xEF && d-i==2) {
1040                        // three-byte sequence
1041                        // (Flash Player doesn't cope with any more obscure Unicode)
1042                        u= (t.charCodeAt(i+2) & 0x3F)        + 
1043                          ((t.charCodeAt(i+1) & 3   ) << 6 ) + 
1044                          ((t.charCodeAt(i+1) & 0x3C) << 6 ) +
1045                          ((t.charCodeAt(i  ) & 0x0F) << 12);
1046                }
1047               
1048                if (u!=0) {
1049                        s.text=t.slice(0,i)+String.fromCharCode(u)+t.slice(d+1);
1050                        s.text=s.text.split(String.fromCharCode(0x03)).join('');
1051                }
1052        }
Note: See TracBrowser for help on using the repository browser.