Project

General

Profile

Revision db6fbc92

IDdb6fbc9211c526c9ef3131ff61d490e02a50ffc7
Parent 70938860
Child aa6e5fe9

Added by Aurelien BOMPARD about 13 years ago

vigiboard: implémentation des traductions BabelJS

git-svn-id: https://vigilo-dev.si.c-s.fr/svn@6831 b22e2e97-25c9-44ff-b637-2e5ceca36478

View differences:

MANIFEST.in
13 13
graft vigiboard/public
14 14
include *.ini
15 15
include jsl.cfg
16
include babeljs.py
babeljs.py
1
# -*- coding: utf-8 -*-
2
"""
3
Provides a class derived from Babel's compile_catalog
4
which automatically creates JavaScript files compatible
5
with Babel's JavaScript frontend.
6

  
7
This code was taken from:
8
http://svn.python.org/projects/doctools/trunk/setup.py
9

  
10
And generates files for use with:
11
http://babel.edgewall.org/browser/trunk/contrib/babel.js
12
"""
13
try:
14
    from babel.messages.pofile import read_po
15
    from babel.messages.frontend import compile_catalog
16
    try:
17
        from simplejson import dump
18
    except ImportError:
19
        from json import dump
20
except ImportError:
21
    pass
22
else:
23
    import os
24
    from distutils import log
25

  
26
    class compile_catalog_plusjs(compile_catalog):
27
        """
28
        An extended command that writes all message strings that occur in
29
        JavaScript files to a JavaScript file along with the .mo file.
30

  
31
        Unfortunately, babel's setup command isn't built very extensible, so
32
        most of the run() code is duplicated here.
33
        """
34

  
35
        def run(self):
36
            compile_catalog.run(self)
37

  
38
            po_files = []
39
            js_files = []
40

  
41
            if not self.input_file:
42
                if self.locale:
43
                    po_files.append((self.locale,
44
                                     os.path.join(self.directory, self.locale,
45
                                                  'LC_MESSAGES',
46
                                                  self.domain + '.po')))
47
                    js_files.append(os.path.join(self.directory, self.locale,
48
                                                 'LC_MESSAGES',
49
                                                 self.domain + '.js'))
50
                else:
51
                    for locale in os.listdir(self.directory):
52
                        po_file = os.path.join(self.directory, locale,
53
                                               'LC_MESSAGES', self.domain + '.po')
54
                        if os.path.exists(po_file):
55
                            po_files.append((locale, po_file))
56
                            js_files.append(os.path.join(self.directory, locale,
57
                                                         'LC_MESSAGES',
58
                                                         self.domain + '.js'))
59
            else:
60
                po_files.append((self.locale, self.input_file))
61
                if self.output_file:
62
                    js_files.append(self.output_file)
63
                else:
64
                    js_files.append(os.path.join(self.directory, self.locale,
65
                                                 'LC_MESSAGES',
66
                                                 self.domain + '.js'))
67

  
68
            for js_file, (locale, po_file) in zip(js_files, po_files):
69
                infile = open(po_file, 'r')
70
                try:
71
                    catalog = read_po(infile, locale)
72
                finally:
73
                    infile.close()
74

  
75
                if catalog.fuzzy and not self.use_fuzzy:
76
                    continue
77

  
78
                log.info('writing JavaScript strings in catalog %r to %r',
79
                         po_file, js_file)
80

  
81
                jscatalog = {}
82
                for message in catalog:
83
                    # Si le message n'a pas encore été traduit,
84
                    # on ne l'ajoute pas. Le message d'origine
85
                    # (non traduit) sera renvoyé.
86
                    if not message.string:
87
                        continue
88

  
89
                    # On n'ajoute le message au fichier de traduction JS
90
                    # auto-généré que si le message est utilisé dans du
91
                    # code JavaScript.
92
                    if any(x[0].endswith('.js') for x in message.locations):
93
                        msgid = message.id
94
                        if isinstance(msgid, (list, tuple)):
95
                            msgid = msgid[0]
96
                        jscatalog[msgid] = message.string
97

  
98
                outfile = open(js_file, 'wb')
99
                try:
100
                    outfile.write('babel.Translations.load(');
101
                    dump(dict(
102
                        messages=jscatalog,
103
                        plural_expr=catalog.plural_expr,
104
                        locale=str(catalog.locale)
105
                        ), outfile)
106
                    outfile.write(').install();')
107
                finally:
108
                    outfile.close()
109

  
setup.py
20 20

  
21 21
sysconfdir = os.getenv("SYSCONFDIR", "/etc")
22 22

  
23
cmdclass = {}
24
try:
25
    from babeljs import compile_catalog_plusjs
26
except ImportError:
27
    pass
28
else:
29
    cmdclass['compile_catalog'] = compile_catalog_plusjs
30

  
23 31
setup(
24 32
    name='vigilo-vigiboard',
25 33
    version='2.0.0',
......
45 53
    package_data={
46 54
        'vigiboard': [
47 55
            'i18n/*/LC_MESSAGES/*.mo',
56
            'i18n/*/LC_MESSAGES/*.js',
57
            'templates/*/*',
58
            'public/js/*.js',
48 59
        ],
49 60
    },
50 61
    message_extractors={
51 62
        'vigiboard': [
52 63
            ('**.py', 'python', None),
64
            ('**/public/js/*.js', 'javascript', None),
53 65
        ],
54 66
    },
55 67

  
......
79 91
            'masked_events = vigiboard.controllers.plugins.masked_events:PluginMaskedEvents',
80 92
        ]
81 93
    },
94
    cmdclass=cmdclass,
82 95
    data_files=[
83 96
        (os.path.join(sysconfdir, 'vigilo/vigiboard/'), [
84 97
            'deployment/vigiboard.conf',
vigiboard/controllers/root.py
23 23
from datetime import datetime
24 24
from time import mktime
25 25

  
26
from pkg_resources import resource_filename
27

  
26 28
from tg.exceptions import HTTPNotFound
27 29
from tg import expose, validate, require, flash, url, \
28 30
    tmpl_context, request, config, session, redirect
29 31
from webhelpers import paginate
30 32
from tw.forms import validators
31
from pylons.i18n import ugettext as _, lazy_ugettext as l_
33
from pylons.i18n import ugettext as _, lazy_ugettext as l_, get_lang
32 34
from sqlalchemy import asc
33 35
from sqlalchemy.sql import func
34 36
from sqlalchemy.orm import aliased
......
208 210
        )
209 211

  
210 212

  
213
    @expose()
214
    def i18n(self):
215
        import gettext
216
        import pylons
217
        import os.path
218

  
219
        # Repris de pylons.i18n.translation:_get_translator.
220
        conf = pylons.config.current_conf()
221
        try:
222
            rootdir = conf['pylons.paths']['root']
223
        except KeyError:
224
            rootdir = conf['pylons.paths'].get('root_path')
225
        localedir = os.path.join(rootdir, 'i18n')
226

  
227
        lang = get_lang()
228

  
229
        # Localise le fichier *.mo actuellement chargé
230
        # et génère le chemin jusqu'au *.js correspondant.
231
        filename = gettext.find(conf['pylons.package'], localedir,
232
            languages=lang)
233
        js = filename[:-3] + '.js'
234

  
235
        themes_filename = gettext.find(
236
            'vigilo-themes',
237
            resource_filename('vigilo.themes.i18n', ''),
238
            languages=lang)
239
        themes_js = themes_filename[:-3] + '.js'
240

  
241
        # Récupère et envoie le contenu du fichier de traduction *.js.
242
        fhandle = open(js, 'r')
243
        translations = fhandle.read()
244
        fhandle.close()
245

  
246
        fhandle = open(themes_js, 'r')
247
        translations += fhandle.read()
248
        fhandle.close()
249
        return translations
250

  
251

  
211 252
    class MaskedEventsSchema(schema.Schema):
212 253
        """Schéma de validation de la méthode masked_events."""
213 254
        idcorrevent = validators.Int(not_empty=True)
vigiboard/public/js/Autocompleter/Autocompleter.Local.js
1
/**
2
 * Autocompleter.Local
3
 *
4
 * http://digitarald.de/project/autocompleter/
5
 *
6
 * @version		1.1.2
7
 *
8
 * @license		MIT-style license
9
 * @author		Harald Kirschner <mail [at] digitarald.de>
10
 * @copyright	Author
11
 */
12

  
13
Autocompleter.Local = new Class({
14

  
15
	Extends: Autocompleter,
16

  
17
	options: {
18
		minLength: 0,
19
		delay: 200
20
	},
21

  
22
	initialize: function(element, tokens, options) {
23
		this.parent(element, options);
24
		this.tokens = tokens;
25
	},
26

  
27
	query: function() {
28
		this.update(this.filter());
29
	}
30

  
31
});
vigiboard/public/js/Autocompleter/Autocompleter.Request.js
1
/**
2
 * Autocompleter.Request
3
 *
4
 * http://digitarald.de/project/autocompleter/
5
 *
6
 * @version		1.1.2
7
 *
8
 * @license		MIT-style license
9
 * @author		Harald Kirschner <mail [at] digitarald.de>
10
 * @copyright	Author
11
 */
12

  
13
Autocompleter.Request = new Class({
14

  
15
	Extends: Autocompleter,
16

  
17
	options: {/*
18
		indicator: null,
19
		indicatorClass: null,
20
		onRequest: $empty,
21
		onComplete: $empty,*/
22
		postData: {},
23
		ajaxOptions: {},
24
		postVar: 'value'
25

  
26
	},
27

  
28
	query: function(){
29
		var data = $unlink(this.options.postData) || {};
30
		data[this.options.postVar] = this.queryValue;
31
		var indicator = $(this.options.indicator);
32
		if (indicator) indicator.setStyle('display', '');
33
		var cls = this.options.indicatorClass;
34
		if (cls) this.element.addClass(cls);
35
		this.fireEvent('onRequest', [this.element, this.request, data, this.queryValue]);
36
		this.request.send({'data': data});
37
	},
38

  
39
	/**
40
	 * queryResponse - abstract
41
	 *
42
	 * Inherated classes have to extend this function and use this.parent()
43
	 */
44
	queryResponse: function() {
45
		var indicator = $(this.options.indicator);
46
		if (indicator) indicator.setStyle('display', 'none');
47
		var cls = this.options.indicatorClass;
48
		if (cls) this.element.removeClass(cls);
49
		return this.fireEvent('onComplete', [this.element, this.request]);
50
	}
51

  
52
});
53

  
54
Autocompleter.Request.JSON = new Class({
55

  
56
	Extends: Autocompleter.Request,
57

  
58
	initialize: function(el, url, options) {
59
		this.parent(el, options);
60
		this.request = new Request.JSON($merge({
61
			'url': url,
62
			'link': 'cancel'
63
		}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
64
	},
65

  
66
	queryResponse: function(response) {
67
		this.parent();
68
		this.update(response);
69
	}
70

  
71
});
72

  
73
Autocompleter.Request.HTML = new Class({
74

  
75
	Extends: Autocompleter.Request,
76

  
77
	initialize: function(el, url, options) {
78
		this.parent(el, options);
79
		this.request = new Request.HTML($merge({
80
			'url': url,
81
			'link': 'cancel',
82
			'update': this.choices
83
		}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
84
	},
85

  
86
	queryResponse: function(tree, elements) {
87
		this.parent();
88
		if (!elements || !elements.length) {
89
			this.hideChoices();
90
		} else {
91
			this.choices.getChildren(this.options.choicesMatch).each(this.options.injectChoice || function(choice) {
92
				var value = choice.innerHTML;
93
				choice.inputValue = value;
94
				this.addChoiceEvents(choice.set('html', this.markQueryValue(value)));
95
			}, this);
96
			this.showChoices();
97
		}
98

  
99
	}
100

  
101
});
102

  
103
/* compatibility */
104

  
105
Autocompleter.Ajax = {
106
	Base: Autocompleter.Request,
107
	Json: Autocompleter.Request.JSON,
108
	Xhtml: Autocompleter.Request.HTML
109
};
vigiboard/public/js/Autocompleter/Autocompleter.js
1
/**
2
 * Autocompleter
3
 *
4
 * http://digitarald.de/project/autocompleter/
5
 *
6
 * @version		1.1.2
7
 *
8
 * @license		MIT-style license
9
 * @author		Harald Kirschner <mail [at] digitarald.de>
10
 * @copyright	Author
11
 */
12

  
13
var Autocompleter = new Class({
14

  
15
	Implements: [Options, Events],
16

  
17
	options: {/*
18
		onOver: $empty,
19
		onSelect: $empty,
20
		onSelection: $empty,
21
		onShow: $empty,
22
		onHide: $empty,
23
		onBlur: $empty,
24
		onFocus: $empty,*/
25
		minLength: 1,
26
		markQuery: true,
27
		width: 'inherit',
28
		maxChoices: 10,
29
		injectChoice: null,
30
		customChoices: null,
31
		emptyChoices: null,
32
		visibleChoices: true,
33
		className: 'autocompleter-choices',
34
		zIndex: 42,
35
		delay: 400,
36
		observerOptions: {},
37
		fxOptions: {},
38

  
39
		autoSubmit: false,
40
		overflow: false,
41
		overflowMargin: 25,
42
		selectFirst: false,
43
		filter: null,
44
		filterCase: false,
45
		filterSubset: false,
46
		forceSelect: false,
47
		selectMode: true,
48
		choicesMatch: null,
49

  
50
		multiple: false,
51
		separator: ', ',
52
		separatorSplit: /\s*[,;]\s*/,
53
		autoTrim: false,
54
		allowDupes: false,
55

  
56
		cache: true,
57
		relative: false
58
	},
59

  
60
	initialize: function(element, options) {
61
		this.element = $(element);
62
		this.setOptions(options);
63
		this.build();
64
		this.observer = new Observer(this.element, this.prefetch.bind(this), $merge({
65
			'delay': this.options.delay
66
		}, this.options.observerOptions));
67
		this.queryValue = null;
68
		if (this.options.filter) this.filter = this.options.filter.bind(this);
69
		var mode = this.options.selectMode;
70
		this.typeAhead = (mode == 'type-ahead');
71
		this.selectMode = (mode === true) ? 'selection' : mode;
72
		this.cached = [];
73
	},
74

  
75
	/**
76
	 * build - Initialize DOM
77
	 *
78
	 * Builds the html structure for choices and appends the events to the element.
79
	 * Override this function to modify the html generation.
80
	 */
81
	build: function() {
82
		if ($(this.options.customChoices)) {
83
			this.choices = this.options.customChoices;
84
		} else {
85
			this.choices = new Element('ul', {
86
				'class': this.options.className,
87
				'styles': {
88
					'zIndex': this.options.zIndex
89
				}
90
			}).inject(document.body);
91
			this.relative = false;
92
			if (this.options.relative) {
93
				this.choices.inject(this.element, 'after');
94
				this.relative = this.element.getOffsetParent();
95
			}
96
			this.fix = new OverlayFix(this.choices);
97
		}
98
		if (!this.options.separator.test(this.options.separatorSplit)) {
99
			this.options.separatorSplit = this.options.separator;
100
		}
101
		this.fx = (!this.options.fxOptions) ? null : new Fx.Tween(this.choices, $merge({
102
			'property': 'opacity',
103
			'link': 'cancel',
104
			'duration': 200
105
		}, this.options.fxOptions)).addEvent('onStart', Chain.prototype.clearChain).set(0);
106
		this.element.setProperty('autocomplete', 'off')
107
			.addEvent((Browser.Engine.trident || Browser.Engine.webkit) ? 'keydown' : 'keypress', this.onCommand.bind(this))
108
			.addEvent('click', this.onCommand.bind(this, [false]))
109
			.addEvent('focus', this.toggleFocus.create({bind: this, arguments: true, delay: 100}))
110
			.addEvent('blur', this.toggleFocus.create({bind: this, arguments: false, delay: 100}));
111
	},
112

  
113
	destroy: function() {
114
		if (this.fix) this.fix.destroy();
115
		this.choices = this.selected = this.choices.destroy();
116
	},
117

  
118
	toggleFocus: function(state) {
119
		this.focussed = state;
120
		if (!state) this.hideChoices(true);
121
		this.fireEvent((state) ? 'onFocus' : 'onBlur', [this.element]);
122
	},
123

  
124
	onCommand: function(e) {
125
		if (!e && this.focussed) return this.prefetch();
126
		if (e && e.key && !e.shift) {
127
			switch (e.key) {
128
				case 'enter':
129
					if (this.element.value != this.opted) return true;
130
					if (this.selected && this.visible) {
131
						this.choiceSelect(this.selected);
132
						return !!(this.options.autoSubmit);
133
					}
134
					break;
135
				case 'up': case 'down':
136
					if (!this.prefetch() && this.queryValue !== null) {
137
						var up = (e.key == 'up');
138
						this.choiceOver((this.selected || this.choices)[
139
							(this.selected) ? ((up) ? 'getPrevious' : 'getNext') : ((up) ? 'getLast' : 'getFirst')
140
						](this.options.choicesMatch), true);
141
					}
142
					return false;
143
				case 'esc': case 'tab':
144
					this.hideChoices(true);
145
					break;
146
			}
147
		}
148
		return true;
149
	},
150

  
151
	setSelection: function(finish) {
152
		var input = this.selected.inputValue, value = input;
153
		var start = this.queryValue.length, end = input.length;
154
		if (input.substr(0, start).toLowerCase() != this.queryValue.toLowerCase()) start = 0;
155
		if (this.options.multiple) {
156
			var split = this.options.separatorSplit;
157
			value = this.element.value;
158
			start += this.queryIndex;
159
			end += this.queryIndex;
160
			var old = value.substr(this.queryIndex).split(split, 1)[0];
161
			value = value.substr(0, this.queryIndex) + input + value.substr(this.queryIndex + old.length);
162
			if (finish) {
163
				var tokens = value.split(this.options.separatorSplit).filter(function(entry) {
164
					return this.test(entry);
165
				}, /[^\s,]+/);
166
				if (!this.options.allowDupes) tokens = [].combine(tokens);
167
				var sep = this.options.separator;
168
				value = tokens.join(sep) + sep;
169
				end = value.length;
170
			}
171
		}
172
		this.observer.setValue(value);
173
		this.opted = value;
174
		if (finish || this.selectMode == 'pick') start = end;
175
		this.element.selectRange(start, end);
176
		this.fireEvent('onSelection', [this.element, this.selected, value, input]);
177
	},
178

  
179
	showChoices: function() {
180
		var match = this.options.choicesMatch, first = this.choices.getFirst(match);
181
		this.selected = this.selectedValue = null;
182
		if (this.fix) {
183
			var pos = this.element.getCoordinates(this.relative), width = this.options.width || 'auto';
184
			this.choices.setStyles({
185
				'left': pos.left,
186
				'top': pos.bottom,
187
				'width': (width === true || width == 'inherit') ? pos.width : width
188
			});
189
		}
190
		if (!first) return;
191
		if (!this.visible) {
192
			this.visible = true;
193
			this.choices.setStyle('display', '');
194
			if (this.fx) this.fx.start(1);
195
			this.fireEvent('onShow', [this.element, this.choices]);
196
		}
197
		if (this.options.selectFirst || this.typeAhead || first.inputValue == this.queryValue) this.choiceOver(first, this.typeAhead);
198
		var items = this.choices.getChildren(match), max = this.options.maxChoices;
199
		var styles = {'overflowY': 'hidden', 'height': ''};
200
		this.overflown = false;
201
		if (items.length > max) {
202
			var item = items[max - 1];
203
			styles.overflowY = 'scroll';
204
			styles.height = item.getCoordinates(this.choices).bottom;
205
			this.overflown = true;
206
		};
207
		this.choices.setStyles(styles);
208
		this.fix.show();
209
		if (this.options.visibleChoices) {
210
			var scroll = document.getScroll(),
211
			size = document.getSize(),
212
			coords = this.choices.getCoordinates();
213
			if (coords.right > scroll.x + size.x) scroll.x = coords.right - size.x;
214
			if (coords.bottom > scroll.y + size.y) scroll.y = coords.bottom - size.y;
215
			window.scrollTo(Math.min(scroll.x, coords.left), Math.min(scroll.y, coords.top));
216
		}
217
	},
218

  
219
	hideChoices: function(clear) {
220
		if (clear) {
221
			var value = this.element.value;
222
			if (this.options.forceSelect) value = this.opted;
223
			if (this.options.autoTrim) {
224
				value = value.split(this.options.separatorSplit).filter($arguments(0)).join(this.options.separator);
225
			}
226
			this.observer.setValue(value);
227
		}
228
		if (!this.visible) return;
229
		this.visible = false;
230
		if (this.selected) this.selected.removeClass('autocompleter-selected');
231
		this.observer.clear();
232
		var hide = function(){
233
			this.choices.setStyle('display', 'none');
234
			this.fix.hide();
235
		}.bind(this);
236
		if (this.fx) this.fx.start(0).chain(hide);
237
		else hide();
238
		this.fireEvent('onHide', [this.element, this.choices]);
239
	},
240

  
241
	prefetch: function() {
242
		var value = this.element.value, query = value;
243
		if (this.options.multiple) {
244
			var split = this.options.separatorSplit;
245
			var values = value.split(split);
246
			var index = this.element.getSelectedRange().start;
247
			var toIndex = value.substr(0, index).split(split);
248
			var last = toIndex.length - 1;
249
			index -= toIndex[last].length;
250
			query = values[last];
251
		}
252
		if (query.length < this.options.minLength) {
253
			this.hideChoices();
254
		} else {
255
			if (query === this.queryValue || (this.visible && query == this.selectedValue)) {
256
				if (this.visible) return false;
257
				this.showChoices();
258
			} else {
259
				this.queryValue = query;
260
				this.queryIndex = index;
261
				if (!this.fetchCached()) this.query();
262
			}
263
		}
264
		return true;
265
	},
266

  
267
	fetchCached: function() {
268
		return false;
269
		if (!this.options.cache
270
			|| !this.cached
271
			|| !this.cached.length
272
			|| this.cached.length >= this.options.maxChoices
273
			|| this.queryValue) return false;
274
		this.update(this.filter(this.cached));
275
		return true;
276
	},
277

  
278
	update: function(tokens) {
279
		this.choices.empty();
280
		this.cached = tokens;
281
		var type = tokens && $type(tokens);
282
		if (!type || (type == 'array' && !tokens.length) || (type == 'hash' && !tokens.getLength())) {
283
			(this.options.emptyChoices || this.hideChoices).call(this);
284
		} else {
285
			if (this.options.maxChoices < tokens.length && !this.options.overflow) tokens.length = this.options.maxChoices;
286
			tokens.each(this.options.injectChoice || function(token){
287
				var choice = new Element('li', {'html': this.markQueryValue(token)});
288
				choice.inputValue = token;
289
				this.addChoiceEvents(choice).inject(this.choices);
290
			}, this);
291
			this.showChoices();
292
		}
293
	},
294

  
295
	choiceOver: function(choice, selection) {
296
		if (!choice || choice == this.selected) return;
297
		if (this.selected) this.selected.removeClass('autocompleter-selected');
298
		this.selected = choice.addClass('autocompleter-selected');
299
		this.fireEvent('onSelect', [this.element, this.selected, selection]);
300
		if (!this.selectMode) this.opted = this.element.value;
301
		if (!selection) return;
302
		this.selectedValue = this.selected.inputValue;
303
		if (this.overflown) {
304
			var coords = this.selected.getCoordinates(this.choices), margin = this.options.overflowMargin,
305
				top = this.choices.scrollTop, height = this.choices.offsetHeight, bottom = top + height;
306
			if (coords.top - margin < top && top) this.choices.scrollTop = Math.max(coords.top - margin, 0);
307
			else if (coords.bottom + margin > bottom) this.choices.scrollTop = Math.min(coords.bottom - height + margin, bottom);
308
		}
309
		if (this.selectMode) this.setSelection();
310
	},
311

  
312
	choiceSelect: function(choice) {
313
		if (choice) this.choiceOver(choice);
314
		this.setSelection(true);
315
		this.queryValue = false;
316
		this.hideChoices();
317
	},
318

  
319
	filter: function(tokens) {
320
		return (tokens || this.tokens).filter(function(token) {
321
			return this.test(token);
322
		}, new RegExp(((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp(), (this.options.filterCase) ? '' : 'i'));
323
	},
324

  
325
	/**
326
	 * markQueryValue
327
	 *
328
	 * Marks the queried word in the given string with <span class="autocompleter-queried">*</span>
329
	 * Call this i.e. from your custom parseChoices, same for addChoiceEvents
330
	 *
331
	 * @param		{String} Text
332
	 * @return		{String} Text
333
	 */
334
	markQueryValue: function(str) {
335
		return (!this.options.markQuery || !this.queryValue) ? str
336
			: str.replace(new RegExp('(' + ((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp() + ')', (this.options.filterCase) ? '' : 'i'), '<span class="autocompleter-queried">$1</span>');
337
	},
338

  
339
	/**
340
	 * addChoiceEvents
341
	 *
342
	 * Appends the needed event handlers for a choice-entry to the given element.
343
	 *
344
	 * @param		{Element} Choice entry
345
	 * @return		{Element} Choice entry
346
	 */
347
	addChoiceEvents: function(el) {
348
		return el.addEvents({
349
			'mouseover': this.choiceOver.bind(this, [el]),
350
			'click': this.choiceSelect.bind(this, [el])
351
		});
352
	}
353
});
354

  
355
var OverlayFix = new Class({
356

  
357
	initialize: function(el) {
358
		if (Browser.Engine.trident) {
359
			this.element = $(el);
360
			this.relative = this.element.getOffsetParent();
361
			this.fix = new Element('iframe', {
362
				'frameborder': '0',
363
				'scrolling': 'no',
364
				'src': 'javascript:false;',
365
				'styles': {
366
					'position': 'absolute',
367
					'border': 'none',
368
					'display': 'none',
369
					'filter': 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)'
370
				}
371
			}).inject(this.element, 'after');
372
		}
373
	},
374

  
375
	show: function() {
376
		if (this.fix) {
377
			var coords = this.element.getCoordinates(this.relative);
378
			delete coords.right;
379
			delete coords.bottom;
380
			this.fix.setStyles($extend(coords, {
381
				'display': '',
382
				'zIndex': (this.element.getStyle('zIndex') || 1) - 1
383
			}));
384
		}
385
		return this;
386
	},
387

  
388
	hide: function() {
389
		if (this.fix) this.fix.setStyle('display', 'none');
390
		return this;
391
	},
392

  
393
	destroy: function() {
394
		if (this.fix) this.fix = this.fix.destroy();
395
	}
396

  
397
});
398

  
399
Element.implement({
400

  
401
	getSelectedRange: function() {
402
		if (!Browser.Engine.trident) return {start: this.selectionStart, end: this.selectionEnd};
403
		var pos = {start: 0, end: 0};
404
		var range = this.getDocument().selection.createRange();
405
		if (!range || range.parentElement() != this) return pos;
406
		var dup = range.duplicate();
407
		if (this.type == 'text') {
408
			pos.start = 0 - dup.moveStart('character', -100000);
409
			pos.end = pos.start + range.text.length;
410
		} else {
411
			var value = this.value;
412
			var offset = value.length - value.match(/[\n\r]*$/)[0].length;
413
			dup.moveToElementText(this);
414
			dup.setEndPoint('StartToEnd', range);
415
			pos.end = offset - dup.text.length;
416
			dup.setEndPoint('StartToStart', range);
417
			pos.start = offset - dup.text.length;
418
		}
419
		return pos;
420
	},
421

  
422
	selectRange: function(start, end) {
423
		if (Browser.Engine.trident) {
424
			var diff = this.value.substr(start, end - start).replace(/\r/g, '').length;
425
			start = this.value.substr(0, start).replace(/\r/g, '').length;
426
			var range = this.createTextRange();
427
			range.collapse(true);
428
			range.moveEnd('character', start + diff);
429
			range.moveStart('character', start);
430
			range.select();
431
		} else {
432
			this.focus();
433
			this.setSelectionRange(start, end);
434
		}
435
		return this;
436
	}
437

  
438
});
439

  
440
/* compatibility */
441

  
442
Autocompleter.Base = Autocompleter;
vigiboard/public/js/Autocompleter/Observer.js
1
/**
2
 * Observer - Observe formelements for changes
3
 *
4
 * - Additional code from clientside.cnet.com
5
 *
6
 * @version		1.1
7
 *
8
 * @license		MIT-style license
9
 * @author		Harald Kirschner <mail [at] digitarald.de>
10
 * @copyright	Author
11
 */
12
var Observer = new Class({
13

  
14
	Implements: [Options, Events],
15

  
16
	options: {
17
		periodical: false,
18
		delay: 1000
19
	},
20

  
21
	initialize: function(el, onFired, options){
22
		this.element = $(el) || $$(el);
23
		this.addEvent('onFired', onFired);
24
		this.setOptions(options);
25
		this.bound = this.changed.bind(this);
26
		this.resume();
27
	},
28

  
29
	changed: function() {
30
		var value = this.element.get('value');
31
		if ($equals(this.value, value)) return;
32
		this.clear();
33
		this.value = value;
34
		this.timeout = this.onFired.delay(this.options.delay, this);
35
	},
36

  
37
	setValue: function(value) {
38
		this.value = value;
39
		this.element.set('value', value);
40
		return this.clear();
41
	},
42

  
43
	onFired: function() {
44
		this.fireEvent('onFired', [this.value, this.element]);
45
	},
46

  
47
	clear: function() {
48
		$clear(this.timeout || null);
49
		return this;
50
	},
51

  
52
	pause: function(){
53
		if (this.timer) $clear(this.timer);
54
		else this.element.removeEvent('keyup', this.bound);
55
		return this.clear();
56
	},
57

  
58
	resume: function(){
59
		this.value = this.element.get('value');
60
		if (this.options.periodical) this.timer = this.changed.periodical(this.options.periodical, this);
61
		else this.element.addEvent('keyup', this.bound);
62
		return this;
63
	}
64

  
65
});
66

  
67
var $equals = function(obj1, obj2) {
68
	return (obj1 == obj2 || JSON.encode(obj1) == JSON.encode(obj2));
69
};
vigiboard/public/js/Autocompleter/vigilo.js
1
Autocompleter.Request.VigiloJSON = new Class({
2

  
3
    Extends: Autocompleter.Request,
4

  
5
    options: {
6
        resVar: 'results'
7
    },
8

  
9
    initialize: function(el, url, options) {
10
        this.parent(el, options);
11
        this.request = new Request.JSON($merge({
12
            'url': url,
13
            'link': 'cancel'
14
        }, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
15
    },
16

  
17
    queryResponse: function(response) {
18
        this.parent();
19
        this.update(response[this.options.resVar]);
20
    }
21

  
22
});
vigiboard/public/js/autocompleter-vigilo.js
1
/**
2
 * Autocompleter.Request.VigiloJSON
3
 *
4
 */
5
Autocompleter.Request.VigiloJSON = new Class({
6

  
7
    Extends: Autocompleter.Request,
8

  
9
    options: {
10
        resVar: 'results'
11
    },
12

  
13
    initialize: function(el, url, options) {
14
        this.parent(el, options);
15
        this.request = new Request.JSON($merge({
16
            'url': url,
17
            'link': 'cancel'
18
        }, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
19
    },
20

  
21
    queryResponse: function(response) {
22
        this.parent();
23
        this.update(response[this.options.resVar]);
24
    }
25

  
26
});
vigiboard/public/js/jxlib.js
1
/******************************************************************************
2
 * MooTools 1.2.2
3
 * Copyright (c) 2006-2007 [Valerio Proietti](http://mad4milk.net/).
4
 * MooTools is distributed under an MIT-style license.
5
 ******************************************************************************
6
 * reset.css - Copyright (c) 2006, Yahoo! Inc. All rights reserved.
7
 * Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt
8
 ******************************************************************************
9
 * Jx UI Library, 2.0.1
10
 * Copyright (c) 2006-2008, DM Solutions Group Inc. All rights reserved.
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a
13
 * copy of this software and associated documentation files (the "Software"),
14
 * to deal in the Software without restriction, including without limitation
15
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16
 * and/or sell copies of the Software, and to permit persons to whom the
17
 * Software is furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included
20
 * in all copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
25
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28
 * DEALINGS IN THE SOFTWARE.
29
 *****************************************************************************/
30
// $Id: common.js 423 2009-05-12 12:37:56Z pagameba $
31
/**
32
 * Class: Jx
33
 * Jx is a global singleton object that contains the entire Jx library
34
 * within it.  All Jx functions, attributes and classes are accessed
35
 * through the global Jx object.  Jx should not create any other
36
 * global variables, if you discover that it does then please report
37
 * it as a bug
38
 *
39
 * License: 
40
 * Copyright (c) 2008, DM Solutions Group Inc.
41
 * 
42
 * This file is licensed under an MIT style license
43
 */
44
 
45
/* firebug console supressor for IE/Safari/Opera */
46
window.addEvent('load', function() {
47
    if (!("console" in window) || !("firebug" in window.console)) {
48
        var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
49
        "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
50

  
51
        window.console = {};
52
        for (var i = 0; i < names.length; ++i) {
53
            window.console[names[i]] = function() {};
54
        }
55
    }
56
});
57
/* inspired by extjs, apparently removes css image flicker and related problems in IE 6 */
58
/* This is already done in mootools Source/Core/Browser.js  KASI*/
59
/*
60
(function() {
61
    var ua = navigator.userAgent.toLowerCase();
62
    var isIE = ua.indexOf("msie") > -1,
63
        isIE7 = ua.indexOf("msie 7") > -1;
64
    if(isIE && !isIE7) {
65
        try {
66
            document.execCommand("BackgroundImageCache", false, true);
67
        } catch(e) {}
68
    }    
69
})();
70
*/
71
Class.Mutators.Family = function(self,name) {
72
    if ($defined(name)){
73
        self.$family = {'name': name};
74
        $[name] = $.object;
75
        return self;
76
    }
77
    else {
78
        this.implement('$family',{'name':self});
79
    }
80
};
81

  
82
/* Setup global namespace
83
 * If jxcore is loaded by jx.js, then the namespace and baseURL are
84
 * already established
85
 */
86
if (typeof Jx == 'undefined') {
87
    var Jx = {};
88
    (function() {
89
        var aScripts = document.getElementsByTagName('SCRIPT');
90
        for (var i=0; i<aScripts.length; i++) {
91
            var s = aScripts[i].src;
92
            var matches = /(.*[jx|js|lib])\/jxlib(.*)/.exec(s);
93
            if (matches && matches[0]) {
94
                /**
95
                 * Property: {String} baseURL
96
                 * This is the URL that Jx was loaded from, it is 
97
                 * automatically calculated from the script tag
98
                 * src property that included Jx.
99
                 *
100
                 * Note that this assumes that you are loading Jx
101
                 * from a js/ or lib/ folder in parallel to the
102
                 * images/ folder that contains the various images
103
                 * needed by Jx components.  If you have a different
104
                 * folder structure, you can define Jx's base
105
                 * by including the following before including
106
                 * the jxlib javascript file:
107
                 *
108
                 * (code)
109
                 * Jx = {
110
                 *    baseURL: 'some/path'
111
                 * }
112
                 * (end)
113
                 */ 
114
                 Jx.aPixel = document.createElement('img', {alt:'',title:''});
115
                 Jx.aPixel.src = matches[1]+'/a_pixel.png';
116
                 Jx.baseURL = Jx.aPixel.src.substring(0,
117
                     Jx.aPixel.src.indexOf('a_pixel.png'));
118
                
119
            }
120
        }
121
       /**
122
        * Determine if we're running in Adobe AIR. If so, determine which sandbox we're in
123
        */
124
        var src = aScripts[0].src;
125
        if (src.contains('app:')){
126
            Jx.isAir = true;
127
        } else {
128
            Jx.isAir = false;
129
        }
130
    })();
131
} 
132

  
133
/**
134
 * Method: applyPNGFilter
135
 *
136
 * Static method that applies the PNG Filter Hack for IE browsers
137
 * when showing 24bit PNG's.  Used automatically for img tags with
138
 * a class of png24.
139
 *
140
 * The filter is applied using a nifty feature of IE that allows javascript to
141
 * be executed as part of a CSS style rule - this ensures that the hack only
142
 * gets applied on IE browsers.
143
 *
144
 * The CSS that triggers this hack is only in the ie6.css files of the various
145
 * themes.
146
 *
147
 * Parameters:
148
 * object {Object} the object (img) to which the filter needs to be applied.
149
 */
150
Jx.applyPNGFilter = function(o)  {
151
   var t=Jx.aPixel.src;
152
   if( o.src != t ) {
153
       var s=o.src;
154
       o.src = t;
155
       o.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+s+"',sizingMethod='scale')";
156
   }
157
};
158

  
159
Jx.imgQueue = [];   //The queue of images to be loaded
160
Jx.imgLoaded = {};  //a hash table of images that have been loaded and cached
161
Jx.imagesLoading = 0; //counter for number of concurrent image loads 
162

  
163
/**
164
 * Method: addToImgQueue
165
 * Request that an image be set to a DOM IMG element src attribute.  This puts 
166
 * the image into a queue and there are private methods to manage that queue
167
 * and limit image loading to 2 at a time.
168
 *
169
 * Parameters:
170
 * obj - {Object} an object containing an element and src
171
 * property, where element is the element to update and src
172
 * is the url to the image.
173
 */
174
Jx.addToImgQueue = function(obj) {
175
    if (Jx.imgLoaded[obj.src]) {
176
        //if this image was already requested (i.e. it's in cache) just set it directly
177
        obj.element.src = obj.src;
178
    } else {
179
        //otherwise stick it in the queue
180
        Jx.imgQueue.push(obj);
181
        Jx.imgLoaded[obj.src] = true;
182
    }
183
    //start the queue management process
184
    Jx.checkImgQueue();
185
};
186

  
187
/**
188
 * Method: checkImgQueue
189
 *
190
 * An internal method that ensures no more than 2 images are loading at a time.
191
 */
192
Jx.checkImgQueue = function() {
193
    while (Jx.imagesLoading < 2 && Jx.imgQueue.length > 0) {
194
        Jx.loadNextImg();
195
    }
196
};
197

  
198
/**
199
 * Method: loadNextImg
200
 *
201
 * An internal method actually populate the DOM element with the image source.
202
 */
203
Jx.loadNextImg = function() {
204
    var obj = Jx.imgQueue.shift();
205
    if (obj) {
206
        ++Jx.imagesLoading;
207
        obj.element.onload = function(){--Jx.imagesLoading; Jx.checkImgQueue();};
208
        obj.element.onerror = function(){--Jx.imagesLoading; Jx.checkImgQueue();};
209
        obj.element.src = obj.src;
210
    }
211
};
212

  
213
/**
214
 * Method: createIframeShim
215
 * Creates a new iframe element that is intended to fill a container
216
 * to mask out other operating system controls (scrollbars, inputs, 
217
 * buttons, etc) when HTML elements are supposed to be above them.
218
 *
219
 * Returns:
220
 * an HTML iframe element that can be inserted into the DOM.
221
 */
222
Jx.createIframeShim = function() {
223
    return new Element('iframe', {
224
        'class':'jxIframeShim',
225
        'scrolling':'no',
226
        'frameborder':0
227
    });
228
};
229
/**
230
 * Method: getNumber
231
 * safely parse a number and return its integer value.  A NaN value 
232
 * returns 0.  CSS size values are also parsed correctly.
233
 *
234
 * Parameters: 
235
 * n - {Mixed} the string or object to parse.
236
 *
237
 * Returns:
238
 * {Integer} the integer value that the parameter represents
239
 */
240
Jx.getNumber = function(n, def) {
241
  var result = n===null||isNaN(parseInt(n,10))?(def||0):parseInt(n,10);
242
  return result;
243
}
244

  
245
/**
246
 * Method: getPageDimensions
247
 * return the dimensions of the browser client area.
248
 *
249
 * Returns:
250
 * {Object} an object containing a width and height property 
251
 * that represent the width and height of the browser client area.
252
 */
253
Jx.getPageDimensions = function() {
254
    return {width: window.getWidth(), height: window.getHeight()};
255
}
256

  
257
/**
258
 * Class: Element
259
 *
260
 * Element is a global object provided by the mootools library.  The
261
 * functions documented here are extensions to the Element object provided
262
 * by Jx to make cross-browser compatibility easier to achieve.  Most of the
263
 * methods are measurement related.
264
 *
265
 * While the code in these methods has been converted to use MooTools methods,
266
 * there may be better MooTools methods to use to accomplish these things.
267
 * Ultimately, it would be nice to eliminate most or all of these and find the
268
 * MooTools equivalent or convince MooTools to add them.
269
 */
270
Element.implement({
271
    /**
272
     * Method: getBoxSizing
273
     * return the box sizing of an element, one of 'content-box' or 
274
     *'border-box'.
275
     *
276
     * Parameters: 
277
     * elem - {Object} the element to get the box sizing of.
278
     *
279
     * Returns:
280
     * {String} the box sizing of the element.
281
     */
282
    getBoxSizing : function() {
283
      var result = 'content-box';
284
      if (Browser.Engine.trident || Browser.Engine.presto) { 
285
          var cm = document["compatMode"];
286
          if (cm == "BackCompat" || cm == "QuirksMode") { 
287
              result = 'border-box'; 
288
          } else {
289
              result = 'content-box'; 
290
        }
291
      } else {
292
          if (arguments.length === 0) {
293
              node = document.documentElement; 
294
          }
295
          var sizing = this.getStyle("-moz-box-sizing");
296
          if (!sizing) { 
297
              sizing = this.getStyle("box-sizing"); 
298
          }
299
          result = (sizing ? sizing : 'content-box');
300
      }
301
      return result;
302
    },
303
    /**
304
     * Method: getContentBoxSize
305
     * return the size of the content area of an element.  This is the size of
306
     * the element less margins, padding, and borders.
307
     *
308
     * Parameters: 
309
     * elem - {Object} the element to get the content size of.
310
     *
311
     * Returns:
312
     * {Object} an object with two properties, width and height, that
313
     * are the size of the content area of the measured element.
314
     */
315
    getContentBoxSize : function() {
316
      var w = this.offsetWidth;
317
      var h = this.offsetHeight;
318
      var padding = this.getPaddingSize();
319
      var border = this.getBorderSize();
320
      w = w - padding.left - padding.right - border.left - border.right;
321
      h = h - padding.bottom - padding.top - border.bottom - border.top;
322
      return {width: w, height: h};
323
    },
324
    /**
325
     * Method: getBorderBoxSize
326
     * return the size of the border area of an element.  This is the size of
327
     * the element less margins.
328
     *
329
     * Parameters: 
330
     * elem - {Object} the element to get the border sizing of.
331
     *
332
     * Returns:
333
     * {Object} an object with two properties, width and height, that
334
     * are the size of the border area of the measured element.
335
     */
336
    getBorderBoxSize: function() {
337
      var w = this.offsetWidth;
338
      var h = this.offsetHeight;
339
      return {width: w, height: h}; 
340
    },
341
    
342
    /**
343
     * Method: getMarginBoxSize
344
     * return the size of the margin area of an element.  This is the size of
345
     * the element plus margins.
346
     *
347
     * Parameters: 
348
     * elem - {Object} the element to get the margin sizing of.
349
     *
350
     * Returns:
351
     * {Object} an object with two properties, width and height, that
352
     * are the size of the margin area of the measured element.
353
     */
354
    getMarginBoxSize: function() {
355
        var margins = this.getMarginSize();
356
        var w = this.offsetWidth + margins.left + margins.right;
357
        var h = this.offsetHeight + margins.top + margins.bottom;
358
        return {width: w, height: h};
359
    },
360
    
361
    /**
362
     * Method: setContentBoxSize
363
     * set either or both of the width and height of an element to
364
     * the provided size.  This function ensures that the content
365
     * area of the element is the requested size and the resulting
366
     * size of the element may be larger depending on padding and
367
     * borders.
368
     *
369
     * Parameters: 
370
     * elem - {Object} the element to set the content area of.
371
     * size - {Object} an object with a width and/or height property that is the size to set
372
     * the content area of the element to.
373
     */
374
    setContentBoxSize : function(size) {
375
        if (this.getBoxSizing() == 'border-box') {
376
            var padding = this.getPaddingSize();
377
            var border = this.getBorderSize();
378
            if (typeof size.width != 'undefined') {
379
                var width = (size.width + padding.left + padding.right + border.left + border.right);
380
                if (width < 0) {
381
                    width = 0;
382
                }
383
                this.style.width = width + 'px';
384
            }
385
            if (typeof size.height != 'undefined') {
386
                var height = (size.height + padding.top + padding.bottom + border.top + border.bottom);
387
                if (height < 0) {
388
                    height = 0;
389
                }
390
                this.style.height = height + 'px';
391
            }
392
        } else {
393
            if (typeof size.width != 'undefined') {
394
                this.style.width = size.width + 'px';
395
            }
396
            if (typeof size.height != 'undefined') {
397
                this.style.height = size.height + 'px';
398
            }
399
        }
400
    },
401
    /**
402
     * Method: setBorderBoxSize
403
     * set either or both of the width and height of an element to
404
     * the provided size.  This function ensures that the border
405
     * size of the element is the requested size and the resulting
406
     * content areaof the element may be larger depending on padding and
407
     * borders.
408
     *
409
     * Parameters: 
410
     * elem - {Object} the element to set the border size of.
411
     * size - {Object} an object with a width and/or height property that is the size to set
412
     * the content area of the element to.
413
     */
414
    setBorderBoxSize : function(size) {
415
      if (this.getBoxSizing() == 'content-box') {
416
        var padding = this.getPaddingSize();
417
        var border = this.getBorderSize();
418
        var margin = this.getMarginSize();
419
        if (typeof size.width != 'undefined') {
420
          var width = (size.width - padding.left - padding.right - border.left - border.right - margin.left - margin.right);
421
          if (width < 0) {
422
            width = 0;
423
          }
424
          this.style.width = width + 'px';
425
        }
426
        if (typeof size.height != 'undefined') {
427
          var height = (size.height - padding.top - padding.bottom - border.top - border.bottom - margin.top - margin.bottom);
428
          if (height < 0) {
429
            height = 0;
430
          }
431
          this.style.height = height + 'px';
432
        }
433
      } else {
434
        if (typeof size.width != 'undefined' && size.width >= 0) {
435
          this.style.width = size.width + 'px';
436
        }
437
        if (typeof size.height != 'undefined' && size.height >= 0) {
438
          this.style.height = size.height + 'px';
439
        }
440
      }
441
    },
442
    /**
443
     * Method: getPaddingSize
444
     * returns the padding for each edge of an element
445
     *
446
     * Parameters: 
447
     * elem - {Object} The element to get the padding for.
448
     *
449
     * Returns:
450
     * {Object} an object with properties left, top, right and bottom
451
     * that contain the associated padding values.
452
     */
453
    getPaddingSize : function () {
454
      var l = Jx.getNumber(this.getStyle('padding-left'));
455
      var t = Jx.getNumber(this.getStyle('padding-top'));
456
      var r = Jx.getNumber(this.getStyle('padding-right'));
457
      var b = Jx.getNumber(this.getStyle('padding-bottom'));
458
      return {left:l, top:t, right: r, bottom: b};
459
    },
460
    /**
461
     * Method: getBorderSize
462
     * returns the border size for each edge of an element
463
     *
464
     * Parameters: 
465
     * elem - {Object} The element to get the borders for.
466
     *
467
     * Returns:
468
     * {Object} an object with properties left, top, right and bottom
469
     * that contain the associated border values.
470
     */
471
    getBorderSize : function() {
472
      var l = Jx.getNumber(this.getStyle('border-left-width'));
473
      var t = Jx.getNumber(this.getStyle('border-top-width'));
474
      var r = Jx.getNumber(this.getStyle('border-right-width'));
475
      var b = Jx.getNumber(this.getStyle('border-bottom-width'));
476
      return {left:l, top:t, right: r, bottom: b};
477
    },
478
    /**
479
     * Method: getMarginSize
480
     * returns the margin size for each edge of an element
481
     *
482
     * Parameters: 
483
     * elem - {Object} The element to get the margins for.
484
     *
485
     * Returns:
486
     *: {Object} an object with properties left, top, right and bottom
487
     * that contain the associated margin values.
488
     */
489
    getMarginSize : function() {
490
      var l = Jx.getNumber(this.getStyle('margin-left'));
491
      var t = Jx.getNumber(this.getStyle('margin-top'));
492
      var r = Jx.getNumber(this.getStyle('margin-right'));
493
      var b = Jx.getNumber(this.getStyle('margin-bottom'));
494
      return {left:l, top:t, right: r, bottom: b};
495
    },
496
    
497
    /**
498
     * Method: descendantOf
499
     * determines if the element is a descendent of the reference node.
500
     *
501
     * Parameters:
502
     * node - {HTMLElement} the reference node
503
     *
504
     * Returns:
505
     * {Boolean} true if the element is a descendent, false otherwise.
506
     */
507
    descendantOf: function(node) {
508
        var parent = $(this.parentNode);
509
        while (parent != node && parent && parent.parentNode && parent.parentNode != parent) {
510
            parent = $(parent.parentNode);
511
        }
512
        return parent == node;
513
    },
514
    
515
    /**
516
     * Method: findElement
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff