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

Last change on this file since 18175 was 18175, checked in by avar, 10 years ago

#2351: Make the preset hint translatable

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                                                   iText('preset_tip', 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=='' || el=='created_by' || p.substr(0,6)=='(type ' || !p) { _root.chat.text+=el+","; 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.