PageSourceSearch

https://altcourt.org/application/modules/Seaocore/externals/scripts/tagger/tagger.js?c=143

js altcourt.org collected 2026-10-01 13:13:05 UTC 39,656 bytes, 1,379 lines download raw bytes

1var SEAOLasso = new Class({
2
3  Implements : [Options, Events],
4
5  active : false,
6
7  options : {
8    autoHide: true,
9    cropMode : false,
10    globalTrigger : false,
11    min : false,
12    max : false,
13    ratio : false,
14    contain : false,
15    trigger : null,
16    border : '#999',
17    color : '#7389AE',
18    opacity : .3,
19    zindex : 10000,
20    bgimage : './blank.gif'
21  },
22	
23  binds : {},
24
25  initialize : function(options){
26    this.setOptions(options);
27		
28    this.box = new Element('div', { 
29      'styles' : {
30        'display' : 'none', 
31        'position' : 'absolute',  
32        'z-index' : this.options.zindex
33      } 
34    }).inject((this.container) ? this.container : document.body);
35		
36    this.overlay = new Element('div',{
37      'class' : 'lasso-overlay',
38      'styles' : {
39        'position' : 'relative', /*
40        'background' : 'url('+this.options.bgimage+')',*/ 'height' : '100%', 
41        'width' : '100%',   
42        'z-index' : this.options.zindex+1
43      }
44    }).inject(this.box);
45
46    this.mask = new Element('div',{
47      'styles' : {
48        'position' : 'absolute', 
49        'background-color' : this.options.color, 
50        'opacity' : this.options.opacity, 
51        'height' : '100%', 
52        'width' : '100%', 
53        'z-index' : this.options.zindex-1
54      }
55    });
56
57    if(this.options.cropMode){
58      this.mask.setStyle('z-index',this.options.zindex-2).inject(this.container);
59      this.options.trigger = this.mask; // override trigger since we are a crop
60    } else {
61      this.mask.inject(this.overlay);
62    }
63		
64    this.trigger = $(this.options.trigger);
65		
66    // Marching Ants
67    var antStyles = {
68      'position' : 'absolute', 
69      'width' : 1, 
70      'height' : 1, 
71      'overflow' : 'hidden', 
72      'z-index' : this.options.zindex+1
73    };
74
75    if( this.options.border.test(/\.(jpe?g|gif|png)/) ) antStyles.backgroundImage = 'url('+this.options.border+')';
76    else var antBorder = '1px dashed '+this.options.border;
77
78    this.marchingAnts = {};
79    ['left','right','top','bottom'].each(function(side,idx){
80      switch(side){
81        case 'left' :
82          style = $merge(antStyles,{
83          top : 0, 
84          left : -1, 
85          height : '100%'
86        });
87        break;
88        case 'right' :
89          style = $merge(antStyles,{
90          top : 0, 
91          right : -1, 
92          height : '100%'
93        });
94        break;
95        case 'top' :
96          style = $merge(antStyles,{
97          top : -1, 
98          left : 0, 
99          width : '100%'
100        });
101        break;
102        case 'bottom' :
103          style = $merge(antStyles,{
104          bottom : -1, 
105          left : 0, 
106          width : '100%'
107        });
108        break;
109      }
110      if(antBorder) style['border-'+side] = antBorder;
111      this.marchingAnts[side] = new Element('div',{
112        'styles' : style
113      }).inject(this.overlay);
114    },this);
115
116    this.binds.start = this.start.bindWithEvent(this);
117    this.binds.move = this.move.bindWithEvent(this);
118    this.binds.end = this.end.bindWithEvent(this);
119
120    this.attach();
121
122    document.body.onselectstart = function(e){
123      e = new Event(e).stop();
124      return false;
125    };
126
127    // better alternative?
128    this.removeDOMSelection = (document.selection && document.selection.empty) ? function(){
129      document.selection.empty();
130    } : 
131    (window.getSelection) ? function(){
132      var s=window.getSelection();
133      if(s && s.removeAllRanges) s.removeAllRanges();
134    } : $lambda(false);
135
136    this.resetCoords();		
137  },
138
139  attach : function(){
140    this.trigger.addEvent('mousedown', this.binds.start);
141  },
142
143  detach : function(){
144    if(this.active) this.end();
145    this.trigger.removeEvent('mousedown', this.binds.start);
146  },
147
148  start : function(event){
149    if((!this.options.autoHide && event.target == this.box) || (!this.options.globalTrigger && (this.trigger != event.target))) return false;
150    this.active = true;
151    document.addEvents({
152      'mousemove' : this.binds.move, 
153      'mouseup' : this.binds.end
154    });
155    this.resetCoords();
156    if(this.options.contain) this.getContainCoords();
157    if(this.container) this.getRelativeOffset();
158    this.setStartCoords(event.page);
159    this.fireEvent('start');
160    return true;
161  },
162
163  move : function(event){
164    if(!this.active) return false;
165		
166    this.removeDOMSelection(); // clear as fast as possible!
167		
168    // saving bytes s = start, m = move, c = container
169    var s = this.coords.start, m = event.page, box = this.coords.box = {}, c = this.coords.container;
170
171    if(this.container){
172      m.y -= this.offset.top;
173      m.x -= this.offset.left;
174    } 
175
176    var f = this.flip = {
177      y : (s.y > m.y), 
178      x : (s.x > m.x)
179    }; // flipping orgin? compare start to move
180    box.y = (f.y) ? [m.y,s.y] : [s.y, m.y]; // order y
181    box.x = (f.x) ? [m.x,s.x] : [s.x, m.x]; // order x
182
183    if(this.options.contain){
184      if(box.y[0] < c.y[0] ) box.y[0] = c.y[0]; // constrain top
185      if(box.y[1] > c.y[1] ) box.y[1] = c.y[1]; // constrain bottom
186      if(box.x[0] < c.x[0] ) box.x[0] = c.x[0]; // constrain left
187      if(box.x[1] > c.x[1] ) box.x[1] = c.x[1]; // constrain right
188    }
189		
190    if(this.options.max){ // max width & height
191      if( box.x[1] - box.x[0] > this.options.max[0]){ // width is larger then max, fix
192        if(f.x) box.x[0] = box.x[1] - this.options.max[0]; // if flipped
193        else box.x[1] = box.x[0] + this.options.max[0]; // if normal
194      }
195      if( box.y[1] - box.y[0] > this.options.max[1]){ // height is larger then max, fix
196        if(f.y) box.y[0] = box.y[1] - this.options.max[1]; // if flipped
197        else box.y[1] = box.y[0] + this.options.max[1];  // if normal
198      }
199    }
200	
201    // ratio constraints
202    if(this.options.ratio){ 
203      var ratio = this.options.ratio;
204      // get width/height divide by ratio
205      var r = {
206        x  : (box.x[1] - box.x[0]) / ratio[0],  
207        y  : (box.y[1] - box.y[0]) / ratio[1]
208      };
209      if(r.x > r.y){ // if width ratio is bigger fix width
210        if(f.x) box.x[0] =  box.x[1] - (r.y * ratio[0]); // if flipped width fix
211        else  	box.x[1] =  box.x[0] + (r.y * ratio[0]); // normal width fix
212      } else if( r.x < r.y){ // if height ratio is bigger fix height
213        if(f.y) box.y[0] =  box.y[1] - (r.x * ratio[1]); // if flipped height fix
214        else 	box.y[1] =  box.y[0] + (r.x * ratio[1]); // normal height fix
215      }
216    }
217
218    this.refresh();
219    return true;
220  },
221	
222  refresh : function(){
223    var c = this.coords, box = this.coords.box, cc = this.coords.container;
224    c.w = box.x[1] - box.x[0];
225    c.h = box.y[1] - box.y[0];
226    c.top = box.y[0];
227    c.left = box.x[0];
228    this.box.setStyles({
229      'display' : 'block',  
230      'top' : c.top, 
231      'left' : c.left, 
232      'width' : c.w, 
233      'height' : c.h
234    });
235    this.fireEvent('resize',this.getRelativeCoords());			
236  },
237
238  end : function(event){
239    if(!this.active) return false;
240    this.active = false;
241    document.removeEvents({
242      'mousemove' : this.binds.move, 
243      'mouseup' : this.binds.end
244    });
245    if(this.options.autoHide) this.resetCoords();
246    else if(this.options.min){
247      if(this.coords.w < this.options.min[0] || this.coords.h < this.options.min[1]) this.resetCoords();
248    }
249    var ret = (this.options.autoHide) ? null : this.getRelativeCoords();
250    this.fireEvent('complete',ret);
251    return true;
252  },
253
254  setStartCoords : function(coords){
255    if(this.container){
256      coords.y -= this.offset.top;
257      coords.x -= this.offset.left;
258    } 
259    this.coords.start = coords;
260    this.coords.w = 0;
261    this.coords.h = 0;
262    this.box.setStyles({
263      'display' : 'block', 
264      'top' : this.coords.start.y, 
265      'left' : this.coords.start.x
266    });
267  },
268
269  resetCoords : function(){
270    this.coords = {
271      start : {
272        x : 0, 
273        y : 0
274      }, 
275      move : {
276        x : 0, 
277        y : 0
278      }, 
279      end : {
280        x: 0, 
281        y: 0
282      }, 
283      w: 0, 
284      h: 0
285    };
286    this.box.setStyles({
287      'display' : 'none', 
288      'top' : 0, 
289      'left' : 0, 
290      'width' : 0, 
291      'height' : 0
292    });	
293    this.getContainCoords();
294  },
295	
296  getRelativeCoords : function(){
297    var box = this.coords.box, cc = $merge(this.coords.container), c = this.coords;
298    if(!this.options.contain) cc = {
299      x : [0,0], 
300      y : [0,0]
301      };
302    return {
303      x : (box.x[0] - cc.x[0]).toInt(), 
304      y : (box.y[0] - cc.y[0]).toInt(), 
305      w : (c.w).toInt(), 
306      h : (c.h).toInt()
307    };
308  },
309
310  getContainCoords : function(){
311    var tc = this.trigger.getCoordinates(this.container);
312    this.coords.container = {
313      y : [tc.top,tc.top+tc.height], 
314      x : [tc.left,tc.left+tc.width]
315    }; // FIXME
316  },
317	
318  getRelativeOffset : function(){
319    this.offset = this.container.getCoordinates();
320  },
321	
322  reset : function(){
323    this.detach();
324  },
325
326  destroy : function(){
327    this.detach();
328    this.mask.destroy();
329    this.overlay.destroy();
330    this.box.destroy();/*
331    $H(this.marchingAnts).each(function(el){
332      el.destroy();
333    });*/
334  }
335	
336});
337
338SEAOLasso.Crop = new Class({
339
340  Extends : SEAOLasso,
341	
342  options : {
343    autoHide : false,
344    cropMode : true,
345    contain : true,
346    handleSize : 8,
347    preset : false,
348    handleStyle : {
349      'border' : '1px solid #000',
350      'background-color' : '#ccc' ,
351      opacity : .75
352    },
353    handlePreventsDefault : true
354  },
355	
356  initialize : function(img,options){
357
358    this.img = $(img);
359    if( this.img.get('tag') != 'img' ) return false;
360		
361    var coords = this.img.getCoordinates();
362
363    // the getCoordinates adds 2 extra pixels
364    var widthFix = coords.width - 2;
365    var heightFix = coords.height - 2;
366                
367    this.container = new Element('div', {
368      'id' :'lassoMask',
369      'styles' : {
370        'position' : 'relative',
371        'width' : widthFix,
372        'height' : heightFix       
373      }
374    }).inject(this.img, 'after');
375		
376    this.img.setStyle('display', 'none');
377    
378    options.p = this.container;
379
380    
381    this.crop = new Element('img', {
382      'src' : this.img.get('src'),
383      styles : {
384        'position' : 'absolute',
385        'top' : 0,
386        'left' : 0,
387        'width' : widthFix +1,
388        'height' : heightFix +1,
389        'padding' : 0,
390        'margin' : 0,
391        'z-index' : this.options.zindex-1
392      }
393    }).inject(this.container);
394    
395	
396    this.parent(options);
397				
398    this.binds.handleMove = this.handleMove.bind(this);
399    this.binds.handleEnd = this.handleEnd.bind(this);
400    this.binds.handles = {};
401		
402    this.handles = {}; // stores resize handler elements
403    // important! this setup a matrix for each handler, patterns emerge when broken into 3x3 grid. Faster/easier processing.
404    this.handlesGrid = {
405      'NW':[0,0],
406      'N':[0,1],
407      'NE':[0,2],
408      'W':[1,0],
409      'E':[1,2],
410      'SW':[2,0],
411      'S':[2,1],
412      'SE':[2,2]
413    };
414    // this could be more elegant!
415    ['NW','N','NE','W','E','SW','S','SE'].each(function(handle){
416      var grid = this.handlesGrid[handle]; // grab location in matrix
417      this.binds.handles[handle] = this.handleStart.bindWithEvent(this,[handle,grid[0],grid[1]]); // bind
418      this.handles[handle] = new Element("div", {
419        'styles' : $merge({
420          'position' : 'absolute',
421          'display' : 'block',
422          'visibility' : 'hidden',
423          'width' : this.options.handleSize,
424          'height' : this.options.handleSize,
425          'overflow' : 'hidden',
426          'cursor' : (handle.toLowerCase()+'-resize'),
427          'z-index' : this.options.zindex+2
428        },this.options.handleStyle),
429        'events' : {
430          'mousedown' : this.binds.handles[handle]
431        }
432      }).inject(this.box,'bottom');
433      // start - Webligo Developments
434      // Seems to not let them be hidden for some reason
435      this.handles[handle].style.visibility = 'hidden';
436    // end - Webligo Developments
437    },this);
438		
439    this.binds.drag = this.handleStart.bindWithEvent(this,['DRAG',1,1]);
440    this.overlay.addEvent('mousedown', this.binds.drag);
441    
442    this.setDefault();
443  },
444	
445  setDefault : function(){
446    if(!this.options.preset) return this.resetCoords();
447    this.getContainCoords();
448    this.getRelativeOffset();
449    var c = this.coords.container, d = this.options.preset;
450    this.coords.start = {
451      x : d[0],
452      y : d[1]
453    };
454    this.active = true;
455    this.move({
456      page : {
457        x: d[2]+this.offset.left,
458        y: d[3]+this.offset.top
459      }
460    });
461    this.active = false;
462  },
463	
464  handleStart : function(event,handle,row,col){
465    this.currentHandle = {
466      'handle' : handle,
467      'row' : row,
468      'col' : col
469    }; // important! used for easy matrix transforms.
470    document.addEvents({
471      'mousemove' : this.binds.handleMove,
472      'mouseup' : this.binds.handleEnd
473    });
474    // had to merge because we don't want to effect the class instance of box. we want to record it
475    event.page.y -= this.offset.top;
476    event.page.x -= this.offset.left;
477    this.coords.hs = {
478      's' : event.page,
479      'b' : $merge(this.coords.box)
480    }; // handler start (used for 'DRAG')
481    this.active = true;
482
483    if( this.options.handlePreventsDefault ) {
484      event.stop();
485    }
486  },
487	
488  handleMove : function(event){
489    var box = this.coords.box, c = this.coords.container, m = event.page, cur = this.currentHandle, s = this.coords.start;
490    m.y -= this.offset.top;
491    m.x -= this.offset.left;
492    if(cur.handle == 'DRAG'){ // messy? could probably be optimized.
493      var hs = this.coords.hs, xm = m.x - hs.s.x, ym = m.y - hs.s.y, diff;
494      box.y[0] = hs.b.y[0] + ym;
495      box.y[1] = hs.b.y[1] + ym;
496      box.x[0] = hs.b.x[0] + xm;
497      box.x[1] = hs.b.x[1] + xm;
498      if((diff = box.y[0] - c.y[0]) < 0) {
499        box.y[0] -= diff;
500        box.y[1] -= diff;
501      } // constrains drag North
502      if((diff = box.y[1] - c.y[1]) > 0) {
503        box.y[0] -= diff;
504        box.y[1] -= diff;
505      } // constrains drag South
506      if((diff = box.x[0] - c.x[0]) < 0) {
507        box.x[0] -= diff;
508        box.x[1] -= diff;
509      } // constrains drag West
510      if((diff = box.x[1] - c.x[1]) > 0) {
511        box.x[0] -= diff;
512        box.x[1] -= diff;
513      } // constrains drag East
514      return this.refresh();
515    }
516
517    // handles flipping ( nw handle behaves like a se when past the orgin )
518    if(cur.row == 0 && box.y[1] < m.y){
519      cur.row = 2;
520    } 		// fixes North passing South
521    if(cur.row == 2 && box.y[0] > m.y){
522      cur.row = 0;
523    } 		// fixes South passing North
524    if(cur.col == 0 && box.x[1] < m.x){
525      cur.col = 2;
526    } 		// fixes West passing East
527    if(cur.col == 2 && box.x[0] > m.x){
528      cur.col = 0;
529    } 		// fixes East passing West
530
531    if(cur.row == 0 || cur.row == 2){ // if top or bottom row ( center e,w are special case)
532      s.y = (cur.row) ? box.y[0] : box.y[1]; 				// set start.y opposite of current direction ( anchor )
533      if(cur.col == 0){
534        s.x = box.x[1];
535      } 				// if West side anchor East
536      if(cur.col == 1){
537        s.x = box.x[0];
538        m.x = box.x[1];
539      } // if center lock width
540      if(cur.col == 2){
541        s.x = box.x[0];
542      } 				// if East side anchor West
543    }
544		
545    if(!this.options.ratio){ // these handles only apply when ratios are not in effect. center handles don't makes sense on ratio
546      if(cur.row == 1){ // sanity check make sure we are dealing with the right handler
547        if(cur.col == 0){
548          s.y = box.y[0];
549          m.y = box.y[1];
550          s.x = box.x[1];
551        }		// if West lock height anchor East
552        else if(cur.col == 2){
553          s.y = box.y[0];
554          m.y = box.y[1];
555          s.x = box.x[0];
556        }// if East lock height anchor West
557      }
558    }
559    m.y += this.offset.top;
560    m.x += this.offset.left;
561    this.move(event); // now that we manipulated event pass it to move to manage.
562
563    if( this.options.handlePreventsDefault ) {
564      event.stop();
565    }
566  },
567	
568  handleEnd : function(event){
569    document.removeEvents({
570      'mousemove' : this.binds.handleMove,
571      'mouseup' : this.binds.handleEnd
572    });
573    this.active = false;
574    this.currentHandle = false;
575    if(this.options.min && (this.coords.w < this.options.min[0] || this.coords.h < this.options.min[1])){
576      if(this.options.preset) this.setDefault();
577      else this.resetCoords();
578    }
579
580    if( this.options.handlePreventsDefault ) {
581      event.stop();
582    }
583  },
584	
585  end : function(event){
586    if(!this.parent(event)) return false;
587    if(this.options.min && (this.coords.w < this.options.min[0] || this.coords.h < this.options.min[1])){
588      this.setDefault();
589    }
590  },
591	
592  resetCoords : function(){
593    this.parent();
594    this.coords.box = {
595      x : [0,0],
596      y : [0,0]
597    };
598    this.hideHandlers();
599  //this.crop.setStyle('clip', 'rect(0px 0px 0px 0px)');
600  },	
601	
602  showHandlers : function(){
603    var box = this.coords.box;
604		
605    if(this.options.min && (this.coords.w < this.options.min[0] || this.coords.h < this.options.min[1])) this.hideHandlers();
606		
607    else {
608      var tops = [], lefts = [], pxdiff = (this.options.handleSize / 2)+1; // used to store location of handlers
609      for(var cell = 0, cells = 2; cell <= cells; cell++ ){  // using matrix again
610        tops[cell] = ( (cell == 0) ? 0 : ((cell == 2) ? box.y[1] - box.y[0] : (box.y[1] - box.y[0])/2  ) ) - pxdiff;
611        lefts[cell] = ( (cell == 0) ? 0 : ((cell == 2) ? box.x[1] - box.x[0] : (box.x[1] - box.x[0])/2 ) ) - pxdiff;
612      }
613
614      for(var handleID in this.handlesGrid){ // get each handler's matrix location
615        var grid = this.handlesGrid[handleID], handle = this.handles[handleID];
616        if(!this.options.ratio || (grid[0] != 1 && grid[1] != 1)
616){ // if no ratio or not N,E,S,W show
617          if(this.options.min && this.options.max){
618            if((this.options.min[0] == this.options.max[0]) && (grid[1] % 2) == 0) continue; // turns off W&E since width is set
619            if(this.options.min[1] == this.options.max[1] && (grid[0] % 2) == 0) continue;  // turns off N&S since height is set
620          }
621          handle.setStyles({
622            'visibility' : 'visible',
623            'top' : tops[grid[0]],
624            'left' : lefts[grid[1]]
625          }); // just grab from grid
626        }
627      }
628    }
629  },
630	
631  hideHandlers : function(){
632    for(handle in this.handles){
633      this.handles[handle].setStyle('visibility','hidden');
634    }
635  },
636	
637  refresh : function(){
638    this.parent();
639    var box = this.coords.box, cc = this.coords.container;
640
641    if(Browser.Engine.trident && Browser.Engine.version < 5 && this.currentHandle && this.currentHandle.col === 1)
642      this.overlay.setStyle('width' , '100.1%').setStyle('width','100%');
643
644    //  this.crop.setStyle('clip' , 'rect('+(box.y[0])+'px '+(box.x[1])+'px '+(box.y[1])+'px '+(box.x[0])+'px )' );
645    this.showHandlers();
646  },
647
648  destroy : function(){
649    this.parent();
650          
651    this.img.inject(this.container, 'after');
652    this.img.setStyle('display', '');
653    this.container.destroy();/*
654  $H(this.handles).each(function(el){
655    el.destroy();
656  });*/
657  }
658
659});
660
661
662
663var SEAOTagger = new Class({
664
665  Implements : [Events, Options],
666
667  options : {
668    // Local options
669    'title' : false,
670    'description' : false,
671    'transImage' : 'application/modules/Seaocore/externals/images/trans.gif',
672    'existingTags' : [],
673    'tagListElement' : false,
674    'linkElement' : false,
675    'noTextTagHref' : true,
676    'guid' : false,
677    'enableCreate' : false,
678    'enableDelete' : false,   
679    
680    // Create
681    'createRequestOptions' : {
682      'url' : '',
683      'data' : {
684        'format' : 'json'
685      }
686    },
687    'deleteRequestOptions' : {
688      'url' : '',
689      'data' : {
690        'format' : 'json'
691      }
692    },
693
694    // Cropper options
695    'cropOptions' : {
696      'preset' : [10,10,58,58],
697      'min' : [48,48],
698      'max' : [128,128],
699      'handleSize' : 8,
700      'opacity' : .6,
701      'color' : '#7389AE',
702      'border' : 'externals/moolasso/crop.gif'
703    },
704
705    // Autosuggest options
706    'suggestProto' : 'local',
707    'suggestParam' : [
708      
709    ],
710    'suggestOptions' : {
711      'minLength': 0,
712      'maxChoices' : 100,
713      'delay' : 250,
714      'selectMode': 'pick',
715      //'autocompleteType': 'message',
716      'multiple': false,
717      'className': 'message-autosuggest',
718      'filterSubset' : true,
719      'tokenFormat' : 'object',
720      'tokenValueKey' : 'label',
721      'injectChoice': $empty,
722      'onPush' : $empty,
723      
724      'prefetchOnInit' : true,
725      'alwaysOpen' : true,
726      'ignoreKeys' : true
727    },
728    
729    'enableShowToolTip':false,
730    // Show ToolTip
731    'showToolTipRequestOptions' : {
732      'url' : '',
733      'data' : {
734        'format' : 'json'
735      }
736    }
737  },
738
739  initialize : function(el, options) {
740    el = $(el);
741    if(!el)
742      return;
743    if( el.get('tag') != 'img' ) {
744      this.image = el.getElement('img');
745    } else {
746      this.image = el;
747    }
748
749    this.element = el;
750    this.count = 0;
751    
752    this.actualImage = new Image();
753    this.actualImage.src = this.image.get('src');    
754    this.setOptions(options);
755
756    //this.element.addEvent('')
757    this.options.existingTags.each(this.addTag.bind(this));
758    this.addToolTip();
759  },
760
761  begin : function() {
762    if( !this.options.enableCreate ) return;
763    this.getCrop();
764    this.getForm();
765    this.getSuggest();
766    this.fireEvent('onBegin');
767  },
768
769  end : function() {
770    if( this.crop ) {
771      this.crop.destroy();
772      delete this.crop;
773    }
774    if( this.form ) {
775      this.form.destroy();
776      delete this.form;
777    }
778    if( this.suggest ) {
779      delete this.suggest;
780    }
781    this.fireEvent('onEnd');
782  },
783
784  getCrop : function() {
785    if( !this.crop ) {
786      var options = $merge(this.options.cropOptions, {
787        
788        });
789      this.crop = new SEAOLasso.Crop(this.image, options);
790      this.crop.addEvent('resize', this.onMove.bind(this));
791      this.crop.refresh();
792    }
793
794    return this.crop;
795  },
796
797  getForm : function() {
798    if( !this.form ) {
799      this.form = new Element('div', {
800        'id' : 'tagger_form',
801        'class' : 'tagger_form',
802        'styles' : {
803          'position' : 'absolute',
804          'z-index' : '100000',
805          'width' : '150px'
806        //'height' : '300px'
807        }
808      }).inject(this.element, 'after');
809
810      // Title
811      if( this.options.title ) {
812        new Element('div', {
813          'class' : 'media_photo_tagform_titlebar',
814          'html' : this.options.title
815        }).inject(this.form);
816      }
817
818      // Container
819      this.formContainer = new Element('div', {
820        'class' : 'media_photo_tagform_container'
821      }).inject(this.form);
822
823      // Description
824      if( this.options.description ) {
825        new Element('div', {
826          'class' : 'media_photo_tagform_text',
827          'html' : this.options.description
828        }).inject(this.formContainer);
829      }
830
831      // Input
832      this.input = new Element('input', {
833        'id' : 'tagger_input',
834        'class' : 'tagger_input',
835        'type' : 'text',
836        'styles' : {
837          
838      }
839      }).inject(this.formContainer);
840
841      // Choices
842      this.choices = new Element('div', {
843        'class' : 'tagger_list'
844      }).inject(this.formContainer);
845
846      // Submit container
847      var submitContainer = new Element('div', {
848        'class' : 'media_photo_tagform_submits'
849      }).inject(this.formContainer);
850
851      var self = this;
852      new Element('a', {
853        'id' : 'tag_save',
854        'href' : 'javascript:void(0);',
855        'html' : en4.core.language.translate('Save'),
856        'events' : {
857          'click' : function() {
858            var data = {}; //JSON.decode(choice.getElement('input').value);
859            data.label = self.input.value;
860            if( $type(data.label) && data.label != '' ) {
861              data.extra = self.coords;
862              self.createTag(data);
863            }
864          }
865        }
866      }).inject(submitContainer);
867
868      new Element('a', {
869        'id' : 'tag_cancel',
870        'href' : 'javascript:void(0);',
871        'html' : en4.core.language.translate('Cancel'),
872        'events' : {
873          'click' : function() {
874            this.end();
875          }.bind(this)
876        }
877      }).inject(submitContainer);
878
879      this.input.focus();
880    }
881    
882    return this.form;
883  },
884
885  getSuggest : function() {
886    if( !this.suggest ) {
887      var self = this;
888      var options = $merge(this.options.suggestOptions, {
889        'overflow' : true,
890        'maxChoices' : 4,
891        'customChoices' : this.choices,
892        'injectChoice' : function(token) {
893          var choice = new Element('li', {
894            'class': 'autocompleter-choices',
895            //'value': token.id,
896            'html': token.photo || '',
897            'id': token.guid
898          });
899          new Element('div', {
900            'html' : this.markQueryValue(token.label),
901            'class' : 'autocompleter-choice'
902          }).inject(choice);
903          new Element('input', {
904            'type' : 'hidden',
905            'value' : JSON.encode(token)
906          }).inject(choice);
907          this.addChoiceEvents(choice).inject(this.choices);
908          choice.store('autocompleteChoice', token);
909        },
910        'onChoiceSelect' : function(choice) {
911          var data = JSON.decode(choice.getElement('input').value);
912          data.extra = self.coords;
913          self.createTag(data);
914        //alert(choice.getElement('input').value);
915        },
916        'emptyChoices' : function() {
917          this.fireEvent('onHide', [this.element, this.choices]);
918        },
919        'onCommand' : function(e) {
920          switch (e.key) {
921            case 'enter':
922              self.createTag({
923                label : self.input.value,
924                extra : self.coords
925              });
926              break;
927          }
928        }
929      });
930
931      if( this.options.suggestProto == 'local' ) {
932        this.suggest = new Autocompleter.Local(this.input, this.options.suggestParam, options);
933      } else if( this.options.suggestProto == 'request.json' ) {
934        this.suggest = new Autocompleter.Request.JSON(this.input, this.options.suggestParam, options);
935      }
936    }
937
938    return this.suggest;
939  },
940
941  getTagList : function() {
942    if( !this.tagList ) {
943      if( !this.options.tagListElement ) {
944        this.tagList = new Element('div', {
945          'class' : 'tag_list'
946        }).inject(this.element, 'after');
947      } else {
948        this.tagList = $(this.options.tagListElement);
949      }
950    }
951
952    return this.tagList;
953  },
954
955  onMove : function(coords) {
956    this.coords = coords;
957    var coords_y=coords.y;
958    var pos = {
959      x:0,
960      y:0
961    }; //this.element.getPosition();
962    var form = this.getForm();
963    var formParentHeight=this.getForm().getParent().getCoordinates().height - 2;
964    if(formParentHeight < (coords_y + 20 +form.getCoordinates().height - 2  )){
965      coords_y = coords_y - (form.getCoordinates().height - 2);    
966    }
967    form.setStyles({
968      'top' : pos.y + coords_y + 20,
969      'left' : pos.x + coords.x + coords.w + 20
970    });
971  },
972
973
974
975
976  // Tagging stuff
977
978  addTag : function(params) {
979    // Required: id, text, x, y, w, h
980
981    if ( 'object' != $type(params)  || !params.extra) {
982      //alert('This entry has already been tagged.');
983      return;
984    }
985
986    var baseX = 0, baseY = 0, baseW = 0, baseH = 0;
987    
988    ["x", "y", "w", "h"].each(function(key) {
989      params.extra[key] = parseInt(params.extra[key]);
990    });
991    
992    var actualImageCoords =this.getActualImageCoords();
993    var imageCoords =this.getImageCoords();
994    // Set Relative X Coords    
995    ["x", "w"].each(function(key) {
996      params.extra[key]= (params.extra[key]/ actualImageCoords.width * imageCoords.width).toInt();    
997    });
998    
999    // Set Relative Y Coords     
1000    ["y", "h"].each(function(key) {
1001      params.extra[key]= (params.extra[key] / actualImageCoords.height * imageCoords.height).toInt();
1002    });
1003
1004    if( this.options.noTextTagHref && params.tag_type == 'core_tag' ) {
1005      delete params.href;
1006    }
1007   
1008    // Make tag
1009    if($('tag_' + params.id))
1010      $('tag_' + params.id).destroy();
1011    var tag = new Element('div', {
1012      'id' : 'tag_' + params.id,
1013      'class' : 'tag_div',
1014      'html' : '<img src="'+this.options.transImage+'" width="100%" height="100%" />',
1015      'styles' : {
1016        'position' : 'absolute',
1017        'width' : params.extra.w,
1018        'height' : params.extra.h,
1019        'top' : baseY + params.extra.y,
1020        'left' : baseX + params.extra.x
1021      },
1022      'events' : {
1023        'mouseover' : function() {
1024          this.showTag(params.id);
1025        }.bind(this),
1026        'mouseout' : function() {
1027          this.hideTag(params.id);
1028        }.bind(this)
1029      }
1030    }).inject(this.element, 'after');
1031
1032    // Make label
1033    // Note: we need to use visibility hidden to position correctly in IE
1034    if($('tag_label_' + params.id))
1035      $('tag_label_' + params.id).destroy();
1036    var label = new Element("span", {
1037      'id' : 'tag_label_' + params.id,
1038      'class' : 'tag_label',
1039      'html' : params.text,
1040      'styles' : {
1041        'position' : 'absolute'
1042      }
1043    }).inject(this.element, 'after');
1044
1045    var labelPos = {};
1046    labelPos.top = ( baseY + params.extra.y + tag.getSize().y );
1047    labelPos.left = Math.round( ( baseX + params.extra.x ) + ( tag.getSize().x / 2 ) - (label.getSize().x / 2) );
1048
1049    if( this.element.getSize().y < labelPos.top.toInt() + 20 ){
1050      labelPos.top = baseY + params.extra.y - label.getSize().y;
1051    }
1052
1053    label.setStyles(labelPos);
1054
1055    this.hideTag(params.id);
1056
1057    var isFirst = ( !$type(this.count) || this.count == 0 );
1058    this.getTagList().setStyle('display', '');
1059
1060    // Make list
1061    if($('tag_comma_' + params.id))
1062      $('tag_comma_' + params.id).destroy();
1063    if( !isFirst ) new Element('span', {
1064      'id' : 'tag_comma_' + params.id,
1065      'class' : 'tag_comma',
1066      'html' : ','
1067    }).inject(this.getTagList());
1068
1069    // Make other thingy
1070    if($('tag_info_' + params.id))
1071      $('tag_info_' + params.id).destroy();
1072    var info = new Element('span', {
1073      'id' : 'tag_info_' + params.id,
1074      'class' : 'tag_info media_tag_listcontainer'
1075    }).inject(this.getTagList());
1076    
1077    if($('tag_activator_' + params.id))
1078      $('tag_activator_' + params.id).destroy();
1079    var activator = new Element('a', {
1080      'id' : 'tag_activator_' + params.id,
1081      'class' : 'tag_activator',
1082      'href' : params.href || null,
1083      'html' : params.text,
1084      'rel': params.id,
1085      'events' : {
1086        'mouseover' : function() {
1087          this.showTag(params.id);       
1088        }.bind(this),
1089        'mouseout' : function() {
1090          this.hideTag(params.id);
1091        }.bind(this)
1092      }
1093    }).inject(info);
1094   
1095    // Delete
1096    if(!this.options.enableShowToolTip  && this.checkCanRemove(params.id) )
1097    {
1098      info.appendText(' (');
1099      if($('tag_destroyer_' + params.id))
1100        $('tag_destroyer_' + params.id).destroy();
1101      var destroyer = new Element('a', {
1102        'id' : 'tag_destroyer_' + params.id,
1103        'class' : 'tag_destroyer albums_tag_delete',
1104        'href' : 'javascript:void(0);',
1105        'html' : en4.core.language.translate('delete'),
1106        'events' : {
1107          'click' : function() {
1108            this.removeTag(params.id);            
1109          }.bind(this)
1110        }
1111      }).inject(info);
1112      info.appendText(')');
1113    }
1114    
1115    this.count++;
1116  },
1117
1118  createTag : function(params) {
1119    if( !this.options.enableCreate ) return;
1120    
1121    params.extra = this.getSaveCoords(params.extra);
1122    // Send request
1123    var requestOptions = $merge(this.options.createRequestOptions, {
1124      'data' : $merge(params, {
1125        
1126        }),
1127      'onComplete' : function(responseJSON) {
1128        this.addTag(responseJSON);
1129        this.addToolTip();
1130        this.fireEvent('onCreateTag',responseJSON);
1131      }.bind(this)
1132    });
1133    var request = new Request.JSON(requestOptions);
1134    request.send();
1135
1136    // End tagging
1137    this.end();
1138  },
1139
1140  removeTag : function(id) {
1141
1142    if( !this.checkCanRemove(id) ) return;
1143
1144    // Remove from frontend
1145    var next = $('tag_info_' + id).getNext(); 
1146    if($('tag_comma_' + id))
1147      $('tag_comma_' + id).destroy();
1148    else if( next && next.get('html').trim() == ',' ) next.destroy();
1149    $('tag_' + id).destroy();
1150    $('tag_label_' + id).destroy();
1151    $('tag_info_' + id).destroy();
1152    this.count--;
1153    this.fireEvent('onRemoveTag',[id]);
1154    
1155    // Send request
1156    var requestOptions = $merge(this.options.deleteRequestOptions, {
1157      'data' : {
1158        'tagmap_id' : id
1159      },
1160      'onComplete' : function(responseJSON) {
1161        
1162      }.bind(this)
1163    });
1164    var request = new Request.JSON(requestOptions);
1165    request.send();    
1166  },
1167
1168  checkCanRemove : function(id) {
1169
1170    // Check if can remove
1171    var tagData;
1172    this.options.existingTags.each(function(datum) {
1173      if( datum.tagmap_id == id ) {
1174        tagData = datum;
1175      }
1176    });
1177
1178    if( this.options.enableDelete ) return true;
1179
1180    if( tagData ) {
1181      if( tagData.tag_type + '_' + tagData.tag_id == this.options.guid ) return true;
1182      if( tagData.tagger_type + '_' + tagData.tagger_id == this.options.guid ) return true;
1183    }
1184    
1185    return false;
1186  },
1187
1188  showTag : function(id) {
1189    $('tag_' + id)/*.addClass('tag_div')*/.removeClass('tag_div_hidden');
1190    $('tag_label_' + id)/*.addClass('tag_label')*/.removeClass('tag_label_hidden');
1191  },
1192
1193  hideTag : function(id) {
1194    $('tag_' + id).addClass('tag_div_hidden')/*.removeClass('tag_div')*/;
1195    $('tag_label_' + id).addClass('tag_label_hidden')/*.removeClass('tag_label')*/;
1196  },
1197  
1198  getActualImageCoords: function(){
1199    return {
1200      'width' : this.actualImage.width, 
1201      'height' : this.actualImage.height
1202    };
1203  },
1204  
1205  
1206  getImageCoords: function(){   
1207    var coords = this.image.getCoordinates();    
1208    // the getCoordinates adds 2 extra pixels
1209    return {
1210      'width' : (coords.width - 2), 
1211      'height' : (coords.height - 2)
1212    };
1213  },
1214  getCropCoords: function(){
1215    var coords =this.getCrop().crop.getCoordinates();
1216    // the getCoordinates adds 2 extra pixels
1217    return {
1218      'width' : (coords.width - 2), 
1219      'height' : (coords.height - 2)
1220    };
1221  },
1222  getSaveCoords: function(coods){
1223    var actualImageCoords =this.getActualImageCoords();
1224    var imageCoords =this.getCropCoords();
1225    // Set Relative X Coords    
1226    ["x", "w"].each(function(key) {      
1227      coods[key]= ((coods[key]/ imageCoords.width) * actualImageCoords.width).toInt();     
1228    });
1229    
1230    // Set Relative Y Coords     
1231    ["y", "h"].each(function(key) {
1232      coods[key]= ((coods[key] / imageCoords.height) * actualImageCoords.height).toInt();
1233    });
1234   
1235    return coods;
1236  },
1237
1238  setToolTip:function(){
1239    if(this.options.enableShowToolTip == false)
1240      return;
1241    // Add tooltips
1242    var window_size = window.getSize()
1243    return  new SEATips($$('.tag_activator'), {
1244      fixed : true,
1245      title:'',
1246      className : 'sea_add_tooltip_link_tips',
1247      hideDelay :200,
1248      showDelay :200,
1249      offset : {
1250        'x' : 0,
1251        'y' : 0
1252      },
1253      windowPadding: {
1254        'x':200, 
1255        'y':(window_size.y/2)
1256      },
1257      req_pendding:0
1258    }   
1259    ); 
1260  },
1261  getToolTipDefaultContent: function(){
1262    var toolTipDefault = new Element('div', {});
1263     
1264    var info_tip = new Element('div', {
1265     
1266      'class' : 'uiOverlay info_tip',    
1267      'styles' : {    
1268        'width' : 200,    
1269        'top' : 0        
1270      }      
1271    }).inject(toolTipDefault);
1272    
1273    var info_tip_content_wrapper = new Element('div', {
1274      'class' : 'info_tip_content_wrapper'
1275    }).inject(info_tip);
1276   
1277    var info_tip_content = new Element('div', {
1278      'class' : 'info_tip_content'
1279    }).inject(info_tip_content_wrapper);
1280   
1281    new Element('div', {     
1282      'class' : 'info_tip_content_loader',
1283      'html' : '<img src="application/modules/Seaocore/externals/images/core/loading.gif" alt="Loading" />'          
1284    }).inject(info_tip_content);
1285    
1286    
1287    return toolTipDefault;
1288  },
1289  addToolTip:function(){
1290    var self=this;
1291    if(this.options.enableShowToolTip){
1292      $$('.tag_activator').addEvent('mouseover', function(event) { 
1293        var el = $(event.target);   
1294        ItemTooltips.options.offset.y = el.offsetHeight;
1295        ItemTooltips.options.showDelay = 0; 
1296        ItemTooltips.options.showToolTip=true;
1297        if( !el.retrieve('tip-loaded', false) ) {
1298          ItemTooltips.options.req_pendding++;
1299          var id='';
1300          if(el.hasAttribute("rel"))
1301            id=el.rel;
1302          if(id =='')
1303            return;
1304
1305          el.store('tip-loaded', true);
1306          el.store('tip:title',self.getToolTipDefaultContent());
1307          el.store('tip:text', ''); 
1308
1309          el.addEvent('mouseleave',function(){
1310            ItemTooltips.options.showToolTip=false;  
1311          });       
1312
1313          var requestOptions = $merge(self.options.showToolTipRequestOptions, {
1314            'data' : {
1315              format : 'html',
1316              'tagmap_id' : id
1317            },
1318            evalScripts : true,
1319            onSuccess : function(responseTree, responseElements, responseHTML, responseJavaScript) {          
1320              el.store('tip:title', '');
1321              var responseHTMLContent = new Element('div',
1322              {
1323                html :responseHTML    
1324              });
1325
1326              if( self.checkCanRemove(id) )
1327              {
1328                var responseHTMLContentDelete = responseHTMLContent.getElement('.tagged_info_tip_content_delete');
1329                responseHTMLContentDelete.appendText(' (');
1330                if($('tag_destroyer_' + id))
1331                  $('tag_destroyer_' + id).destroy();
1332                new Element('a', {
1333                  'id' : 'tag_destroyer_' + id,
1334                  'class' : 'tag_destroyer albums_tag_delete',
1335                  'href' : 'javascript:void(0);',
1336                  'html' : en4.core.language.translate('remove tag'),
1337                  'events' : {
1338                    'click' : function() {
1339                      ItemTooltips.options.canHide = true;
1340                      ItemTooltips.hide(el);
1341                      self.removeTag(id);                                            
1342                    }.bind(this)
1343                  }
1344                }).inject(responseHTMLContentDelete);
1345                responseHTMLContentDelete.appendText(')');
1346              }
1347              
1348              el.store('tip:text', responseHTMLContent);
1349              ItemTooltips.options.showDelay=0;
1350              ItemTooltips.elementEnter(event, el); // Force it to update the text
1351              ItemTooltips.options.showDelay=200;
1352              ItemTooltips.options.req_pendding--;
1353              if(!ItemTooltips.options.showToolTip || ItemTooltips.options.req_pendding > 0){
1354                ItemTooltips.elementLeave(event,el);
1355              }           
1356              var tipEl=ItemTooltips.toElement();
1357              tipEl.addEvents({
1358                'mouseenter': function() {
1359                  ItemTooltips.options.canHide = false;
1360                  ItemTooltips.show(el);
1361                },
1362                'mouseleave': function() {                
1363                  ItemTooltips.options.canHide = true;
1364                  ItemTooltips.hide(el);                    
1365                }
1366              });
1367              Smoothbox.bind($$(".tag_activator"));
1368            }.bind(this)
1369          });
1370          
1371          new Request.HTML(requestOptions).send();
1372        }
1373
1374      });
1375      var ItemTooltips = self.setToolTip();
1376    }  
1377  }
1378
1379});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.