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

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

bunch of join/unjoin fixes

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