' . $fn . '
', $html);
27 | }
28 |
29 | echo $html;
30 |
31 | function show_api_page($el) {
32 | $functionval = $el->getAttribute('name'); //preg_replace('/^jquery\./i', '$.', $el->getAttribute('name'));
33 | $params = $el->getElementsByTagName('params');
34 | $all_params = array();
35 | for ($i = 0; $i < $params->length; $i++) {
36 | array_push($all_params, trim($params->item($i)->getAttribute('name')));
37 | }
38 |
39 | if (count($all_params)) {
40 | $id = strtolower(trim($functionval) . '_' . join($all_params, '_'));
41 | $params_str = count($all_params) ? '(' . join($all_params, ', ') . ')' : '';
42 | } else {
43 | $id = strtolower(trim($functionval));
44 | $params_str = '';
45 | }
46 |
47 | $b = "\n ";
48 | $cat = $el->getAttribute('cat');
49 | $catkey = stripspace($cat);
50 | $subcat = $el->parentNode->getAttribute('value');
51 | $subcatkey = stripspace($subcat);
52 |
53 | $added = $el->getElementsByTagName('added')->item(0)->nodeValue;
54 | $desc = $el->getElementsByTagName('longdesc')->item(0)->nodeValue;
55 |
56 | if (!$desc) {
57 | $desc = $el->getElementsByTagName('desc')->item(0)->nodeValue;
58 | }
59 |
60 | $returns = htmlentities($el->getAttribute('return'));
61 |
62 | $examples = $el->getElementsByTagName('example');
63 |
64 | echo '
';
69 | echo $b;
70 |
71 | echo '
Category: ' . $cat . '/' . $subcat . ' (added ' . $added . ')
';
72 | echo $b;
73 |
74 |
75 | // TODO clean up markup quirks
76 | echo $desc;
77 | echo $b;
78 |
79 | // TODO detailed options
80 |
81 | echo '
Returns
';
82 | echo '
' . $returns . '
';
83 | echo $b;
84 |
85 | if ($params->length) {
86 | echo '
Parameters
';
87 | echo $b;
88 | echo '
';
89 | echo $b;
90 |
91 | for ($i = 0; $i < $params->length; $i++) {
92 | $p = $params->item($i);
93 | echo '- ' . $p->getAttribute('name') . ' ';
94 | echo '(' . $p->getAttribute('type') . ')';
95 |
96 | if ($p->getAttribute('optional')) {
97 | echo ' optional';
98 | }
99 |
100 | echo ': ' . $p->getElementsByTagName('desc')->item(0)->nodeValue . '
';
101 | echo $b;
102 | }
103 |
104 | echo '
';
105 | echo $b;
106 | }
107 |
108 | if (count($examples)) {
109 | for ($i = 0; $i < $examples->length; $i++) {
110 | $e = $examples->item($i);
111 | echo '
Example
';
112 | echo $b;
113 |
114 | echo '
' . $e->getElementsByTagName('desc')->item(0)->nodeValue . '
';
115 |
116 | $code = $e->getElementsByTagName('code');
117 | if ($code->length) {
118 | echo '
jQuery Code
';
119 | echo '
' . htmlentities($code->item(0)->nodeValue) . '
';
120 | echo $b;
121 | }
122 | }
123 | }
124 | }
125 |
126 | function getcategories($filename, $request) {
127 | $dom= new DOMDocument();
128 | $dom->load($filename);
129 | $cats = $dom->getElementsByTagName('cat');
130 |
131 | $html = "
\n";
132 |
133 | for ($i = 0; $i < $cats->length; $i++) {
134 | $cat = $cats->item($i);
135 | $catval = $cat->getAttribute('value');
136 | $catkey = stripspace($catval);
137 |
138 | $selected = $catkey == $request[0] ? ' active' : '';
139 |
140 | $html .= "\t" . '- \n";
141 | $html .= "\t" . '
' . "\n";
142 |
143 | $subcats = $cat->getElementsByTagName('subcat');
144 | for ($j = 0; $j < $subcats->length; $j++) {
145 | $subcat = $subcats->item($j);
146 | $subcatval = $subcat->getAttribute('value');
147 | $subcatkey = stripspace($subcatval);
148 |
149 | list($fn_html, $fn_selected) = getElements($catval, $subcat, $request, 'function');
150 | list($sel_html, $sel_selected) = getElements($catval, $subcat, $request, 'selector');
151 | list($prop_html, $prop_selected) = getElements($catval, $subcat, $request, 'property');
152 |
153 | $selected = ($subcatkey == $request[1] || $fn_selected || $sel_selected || $prop_selected) ? ' class="active"' : '';
154 |
155 | $html .= "\t\t" . '- ' . $subcatval . "\n";
156 |
157 | $html .= "\t\t" . '
' . "\n";
158 | $html .= $fn_html;
159 | $html .= $sel_html;
160 | $html .= $prop_html;
161 |
162 | $html .= "\t\t
\n";
163 | }
164 |
165 | $html .= "\t
\n";
166 | }
167 |
168 | return $html;
169 | }
170 |
171 | function getElements($catval, $subcat, $request, $tag) {
172 | global $requested_page;
173 | $html = '';
174 |
175 | $catkey = stripspace($catval);
176 | $subcatkey = stripspace($subcat->getAttribute('value'));
177 |
178 | $element_found = false;
179 |
180 | $functions = getOrderedElements($subcat, $tag);
181 | for ($k = 0; $k < count($functions); $k++) {
182 | $function = $functions[$k];
183 |
184 | $functionval = $function->getAttribute('name'); // preg_replace('/^jquery\./i', '$.',
185 |
186 | $params = $function->getElementsByTagName('params');
187 | $all_params = array();
188 | for ($l = 0; $l < $params->length; $l++) {
189 | array_push($all_params, trim($params->item($l)->getAttribute('name')));
190 | }
191 |
192 | if (count($all_params)) {
193 | $id = strtolower(trim($functionval) . '_' . join($all_params, '_'));
194 | $params_str = count($all_params) ? '(' . join($all_params, ', ') . ')' : '';
195 | } else {
196 | $id = strtolower(trim($functionval));
197 | $params_str = '';
198 | }
199 |
200 | $selected = '';
201 | if ($catkey == $request[0] && $subcatkey == $request[1] && $id == $request[2]) {
202 | $requested_page = $function;
203 | $element_found = true;
204 | $selected = ' class="active"';
205 | }
206 |
207 | $html .= "\t\t\t" . '- ' . $functionval . $params_str . '
' . "\n";
208 | }
209 |
210 | return array($html, $element_found);
211 | }
212 |
213 | function getOrderedElements($context, $tag) {
214 | $elements = $context->getElementsByTagName($tag);
215 | $ordered = array();
216 |
217 | for ($i = 0; $i < $elements->length; $i++) {
218 | array_push($ordered, $elements->item($i));
219 | }
220 |
221 | usort($ordered, 'elOrder');
222 | return $ordered;
223 | }
224 |
225 | function elOrder($a, $b) {
226 | return strcasecmp($a->getAttribute('name'), $b->getAttribute('name'));
227 | }
228 |
229 | function stripspace($s) {
230 | return preg_replace('/\s+/', '_', $s);
231 | }
232 |
233 | // source: http://uk2.php.net/manual/en/function.xml-parse.php#87920
234 | function xml2array($url, $get_attributes = 1, $priority = 'tag')
235 | {
236 | $contents = "";
237 | if (!function_exists('xml_parser_create'))
238 | {
239 | return array ();
240 | }
241 | $parser = xml_parser_create('');
242 | if (!($fp = @ fopen($url, 'rb')))
243 | {
244 | return array ();
245 | }
246 | while (!feof($fp))
247 | {
248 | $contents .= fread($fp, 8192);
249 | }
250 | fclose($fp);
251 | xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
252 | xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
253 | xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
254 | xml_parse_into_struct($parser, trim($contents), $xml_values);
255 | xml_parser_free($parser);
256 | if (!$xml_values)
257 | return; //Hmm...
258 | $xml_array = array ();
259 | $parents = array ();
260 | $opened_tags = array ();
261 | $arr = array ();
262 | $current = & $xml_array;
263 | $repeated_tag_index = array ();
264 | foreach ($xml_values as $data)
265 | {
266 | unset ($attributes, $value);
267 | extract($data);
268 | $result = array ();
269 | $attributes_data = array ();
270 | if (isset ($value))
271 | {
272 | if ($priority == 'tag')
273 | $result = $value;
274 | else
275 | $result['value'] = $value;
276 | }
277 | if (isset ($attributes) and $get_attributes)
278 | {
279 | foreach ($attributes as $attr => $val)
280 | {
281 | if ($priority == 'tag')
282 | $attributes_data[$attr] = $val;
283 | else
284 | $result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
285 | }
286 | }
287 | if ($type == "open")
288 | {
289 | $parent[$level -1] = & $current;
290 | if (!is_array($current) or (!in_array($tag, array_keys($current))))
291 | {
292 | $current[$tag] = $result;
293 | if ($attributes_data)
294 | $current[$tag . '_attr'] = $attributes_data;
295 | $repeated_tag_index[$tag . '_' . $level] = 1;
296 | $current = & $current[$tag];
297 | }
298 | else
299 | {
300 | if (isset ($current[$tag][0]))
301 | {
302 | $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
303 | $repeated_tag_index[$tag . '_' . $level]++;
304 | }
305 | else
306 | {
307 | $current[$tag] = array (
308 | $current[$tag],
309 | $result
310 | );
311 | $repeated_tag_index[$tag . '_' . $level] = 2;
312 | if (isset ($current[$tag . '_attr']))
313 | {
314 | $current[$tag]['0_attr'] = $current[$tag . '_attr'];
315 | unset ($current[$tag . '_attr']);
316 | }
317 | }
318 | $last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
319 | $current = & $current[$tag][$last_item_index];
320 | }
321 | }
322 | elseif ($type == "complete")
323 | {
324 | if (!isset ($current[$tag]))
325 | {
326 | $current[$tag] = $result;
327 | $repeated_tag_index[$tag . '_' . $level] = 1;
328 | if ($priority == 'tag' and $attributes_data)
329 | $current[$tag . '_attr'] = $attributes_data;
330 | }
331 | else
332 | {
333 | if (isset ($current[$tag][0]) and is_array($current[$tag]))
334 | {
335 | $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
336 | if ($priority == 'tag' and $get_attributes and $attributes_data)
337 | {
338 | $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
339 | }
340 | $repeated_tag_index[$tag . '_' . $level]++;
341 | }
342 | else
343 | {
344 | $current[$tag] = array (
345 | $current[$tag],
346 | $result
347 | );
348 | $repeated_tag_index[$tag . '_' . $level] = 1;
349 | if ($priority == 'tag' and $get_attributes)
350 | {
351 | if (isset ($current[$tag . '_attr']))
352 | {
353 | $current[$tag]['0_attr'] = $current[$tag . '_attr'];
354 | unset ($current[$tag . '_attr']);
355 | }
356 | if ($attributes_data)
357 | {
358 | $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
359 | }
360 | }
361 | $repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
362 | }
363 | }
364 | }
365 | elseif ($type == 'close')
366 | {
367 | $current = & $parent[$level -1];
368 | }
369 | }
370 | return ($xml_array);
371 | }
372 |
373 | ?>
--------------------------------------------------------------------------------
/lib/jqueryapi/api-browser.js:
--------------------------------------------------------------------------------
1 | // globals
2 | if (!window.runtime) {
3 | airapp = false;
4 | } else {
5 | airapp = true;
6 | }
7 |
8 | lastRoot = 'api';
9 |
10 | $.fn.textDropShadow = function() {
11 | return this.each(function () {
12 | var $text = $(this);
13 | $text.html(''+$text.html()+''+$text.html()+'');
14 | return $text;
15 | });
16 | };
17 |
18 | function apiBrowserMain() {
19 | $('#navigation a').textDropShadow();
20 | $('#navigation label').prepend('Filter');
21 |
22 | // handle external links
23 | window.favs = {};
24 |
25 | if (airapp) {
26 | $('#credit a').click(function () {
27 | window.runtime.flash.net.navigateToURL(new window.runtime.flash.net.URLRequest(this.href));
28 | return false;
29 | });
30 | }
31 |
32 | $(window).click(function (event) {
33 | var $elm = $(event.target);
34 | if (event.target.nodeName == 'SPAN' && $elm.is('.fav')) {
35 | $elm.toggleClass('on');
36 |
37 | // silly hack for last minute bug
38 | var key = $elm.attr('id').toLowerCase().replace(/^\$\./, '');
39 |
40 | if ($elm.is('.on')) {
41 | // bit dopy, and hacky, but will do for now
42 | jquerydocs.data[key].fav = 'true';
43 | favs[key] = 1;
44 | } else {
45 | jquerydocs.data[key].fav = 'false';
46 | delete favs[key];
47 | }
48 |
49 | if (!airapp) {
50 | // commit fav to cookie
51 | createCookie('favs', $.toJSON(favs), 365);
52 | } else {
53 | var FileSystem = window.runtime.flash.filesystem;
54 |
55 | var file = FileSystem.File.applicationStorageDirectory.resolvePath('favs.json');
56 | var fileStream = new FileSystem.FileStream();
57 | fileStream.open(file, FileSystem.FileMode.WRITE);
58 | fileStream.writeUTFBytes($.toJSON(favs));
59 | fileStream.close();
60 | }
61 |
62 | return false;
63 | }
64 | });
65 |
66 | var timer = null;
67 | var last = '';
68 | $('#query').keyup(function () {
69 | if (this.value != last) {
70 | if (timer) {
71 | clearTimeout(timer);
72 | }
73 | last = this.value;
74 | if (jquerydocs.find) {
75 | timer = setTimeout(queryDocs, 250);
76 | }
77 | }
78 | }).focus(function () {
79 | $(this).parent().addClass('selected');
80 | }).blur(function () {
81 | $(this).parent().removeClass('selected');
82 | });
83 |
84 | function queryDocs() {
85 | if (jquerydocs == null) {
86 | return;
87 | }
88 | jquerydocs = _jquerydocs; // reset
89 |
90 | // the query trimmed
91 | var q = $('#query').val().toLowerCase().replace( /^\s+|\s+$/g,"");
92 |
93 | if (q == '') {
94 | loadCategories();
95 | return;
96 | }
97 |
98 | var $wrapper = $('#browser > div');
99 | $wrapper.empty();
100 |
101 | var items = [];
102 |
103 | if (q.indexOf('=') !== -1) {
104 | q = q.split('=');
105 | items = jquerydocs.find(q[1], q[0]); // hidden feature to search by a specific field, i.e. added=1.3
106 | } else {
107 | items = jquerydocs.find(q);
108 | }
109 |
110 | showFunctions(items, $wrapper);
111 | if (items.length) {
112 | $('#functions').show();
113 | } else {
114 | $('#browser > div').html('No functions found.
');
115 | }
116 | }
117 |
118 | if (!window.jquerydocs.initialised) {
119 | loadDocs('lib/docs/api-docs.xml'); // from api-loader.js and triggers api-load-complete
120 | } else {
121 | init();
122 | }
123 | }
124 |
125 | $(document).bind('api-load-complete', function () {
126 | // cache the original
127 | window._jquerydocs = jquerydocs;
128 |
129 | // version notices
130 | $('#version').html(jquerydocs.version);
131 | document.title += ' v' + jquerydocs.version; // note - I have to manually insert the version since it's lacking :-(
132 |
133 | // now manually load the plugins API - I'm avoiding using loadDocs because it triggers a callback to api-load-complete
134 | // which causes our infinite loop :-(
135 | $.ajax({
136 | url: 'lib/docs/plugins.xml', // generated from jquery source: /tools/wikiapi2xml/createjQueryXMLDocs.py
137 | dataType: 'xml',
138 | async : false,
139 | success: parse
140 | });
141 |
142 | attachFind(jquerydocs);
143 |
144 | if (window.location.search) {
145 | $('#query').val(window.location.search.substr(1)).keyup();
146 | }
147 |
148 | init();
149 | });
150 |
151 | $.fn.stackSelect = function (fn) {
152 | return this.length ? this.animate({
153 | height: 0,
154 | opacity: 0,
155 | padding: 0
156 | }, 200, function () {
157 | $(this).hide();
158 | fn.call(this);
159 | }) : fn.call(this);
160 | };
161 |
162 | function loadFavs() {
163 | if (!airapp) {
164 | // read favs from cookie
165 | eval('favs = ' + readCookie('favs'));// need to change to Crockford's json parser
166 | } else {
167 | var FileSystem = window.runtime.flash.filesystem;
168 |
169 | var file = FileSystem.File.applicationStorageDirectory.resolvePath('favs.json');
170 | if (file.exists) {
171 | var fileStream = new FileSystem.FileStream();
172 | fileStream.open( file, FileSystem.FileMode.READ );
173 | var data = fileStream.readMultiByte( file.size, FileSystem.File.systemCharset );
174 | fileStream.close();
175 |
176 | favs = JSON.parse(data);
177 | }
178 | }
179 |
180 | if (favs == null) {
181 | favs = {};
182 | } else {
183 | for (var k in favs) {
184 | jquerydocs.data[k].fav = 'true';
185 | }
186 | }
187 | }
188 |
189 | function loadCategories(root) {
190 | var html = [];
191 | var categories = jquerydocs.categories;
192 | root = (root || "").toLowerCase();
193 |
194 | if (root) {
195 | lastRoot = root;
196 | } else {
197 | root = lastRoot;
198 | }
199 |
200 | for (var i = 0; i < categories.length; i++) {
201 | if (categories[i].root == root) {
202 | html.push('- ' + categories[i].name.replace(/^UI\//, '') + '
');
203 | }
204 | }
205 |
206 | if (html.length) {
207 | $('#browser > div').html('' + html.join('') + '
');
208 | } else {
209 | $('#browser > div').html('No functions found.
');
210 | }
211 | }
212 |
213 | // TODO find out why it's not in id order
214 | function showFunctions(items, $wrapper) {
215 | var argsA = [],
216 | args,
217 | html = [],
218 | i, j;
219 |
220 | $wrapper.find('> #functions, dd').remove();
221 |
222 | for (i = 0; i < items.length; i++) {
223 | argsA = [];
224 | args = '';
225 |
226 | if (items[i].params.length) {
227 | for (j = 0; j < items[i].params.length; j++) {
228 | argsA.push(items[i].params[j].name);
229 | }
230 | args = '(' + argsA.join(', ') + ')';
231 | } else if (items[i].type == 'function') {
232 | args = '()';
233 | }
234 |
235 | html.push('- ' + items[i].name + args + '
');
236 | }
237 |
238 | step = (200 * $wrapper.find('dl').length) + 10;
239 | var $html = $('' + html.join('') + '
').css('display', 'none');
240 | $wrapper.append($html);
241 | }
242 |
243 |
244 | function init() {
245 | var $wrapper = $('#browser > div'),
246 | $categories = $('#categories'),
247 | $detail = $('#detail > div'),
248 | blank_iframe = 'index-blank.html',
249 | title = document.title,
250 | html = [],
251 | categories = jquerydocs.categories;
252 |
253 | loadFavs();
254 | loadCategories();
255 |
256 | var $nav = $('#navigation a').click(function () {
257 | $nav.removeClass('selected');
258 | $(this).addClass('selected');
259 |
260 | $('#query').val('');
261 |
262 | if (this.hash.substr(1) == 'favs') {
263 | $wrapper.empty();
264 | var items = jquerydocs.find('true', 'fav');
265 | showFunctions(items, $wrapper);
266 | if (items.length) {
267 | $('#functions').show();
268 | } else {
269 | $('#browser > div').html('No functions found.
');
270 | }
271 | } else {
272 | loadCategories(this.hash.substr(1));
273 | }
274 |
275 | return false;
276 | });
277 |
278 | $wrapper.click(function (event) {
279 | categories = jquerydocs.categories;
280 | var dt = (event.target.nodeName == 'DT'),
281 | $selected = $(event.target),
282 | step = 210,
283 | i, j, // loop indices
284 | q = $selected.text(), // search term
285 | items, // matches
286 | item, // specific function
287 | argsA = [],
288 | args = '',
289 | html = [],
290 | deselect = false,
291 | category,
292 | subcategory,
293 | fns = [];
294 |
295 | if (dt) {
296 |
297 | var inId = $selected.parent().attr('id');
298 |
299 | if ($selected.is('.active') && $selected.parent('#functions').length == 0) {
300 | // go up a level
301 | deselect = true;
302 |
303 | if ($selected.parent('#subcategories').length) {
304 | $selected = $('#categories').find('.active');
305 | } else {
306 | $('#functions, #subcategories').slideUp(function () {
307 | $(this).remove();
308 | });
309 | $('#categories').find('dt').removeClass('active').css('padding', 5).animate({
310 | opacity : 1,
311 | height : '100%'
312 | });
313 | return;
314 | }
315 | } else {
316 | $selected.parent().find('dt').removeClass('active');
317 | $selected.addClass('active');
318 | }
319 |
320 | if ($selected.parents('#categories').length) { // category selected
321 | category = $selected.attr('id');
322 |
323 | $categories.find('dt').removeClass('active');
324 | $selected.addClass('active');
325 | $wrapper.find('> dl:not(#categories), dd').remove();
326 |
327 | if (jquerydocs.categories[category].subcategories && jquerydocs.categories[category].subcategories.length) {
328 | for (i = 0; i < categories[category].subcategories.length; i++) {
329 | html.push('- ' + categories[category].subcategories[i].name + '
');
330 | }
331 |
332 | var $html = $('' + html.join('') + '
');
333 | $html.css('display', 'none');
334 |
335 | $wrapper.append($html);
336 | $wrapper.find('#categories dt:not(.active)').stackSelect(function () {
337 | $wrapper.find('#subcategories').slideDown();
338 | });
339 | }
340 | } else if ($selected.parents('#subcategories').length) { // subcategory selected
341 | category = $('#categories .active').attr('id');
342 | subcategory = $selected.attr('id').replace(/subcategory/, '');
343 | fns = [];
344 | for (i = 0; i < jquerydocs.categories[category].subcategories[subcategory].functions.length; i++) {
345 | fns.push(jquerydocs.categories[category].subcategories[subcategory].functions[i]);
346 | }
347 |
348 | showFunctions(jquerydocs.find(fns), $wrapper); // function because we get reused.
349 |
350 | $wrapper.find('#subcategories dt:not(.active)').stackSelect(function () {
351 | $wrapper.find('#functions').slideDown();
352 | });
353 | } else if ($selected.parents('#functions').length) { // function selected
354 | item = jquerydocs.data[$selected.attr('id')];
355 |
356 | $detail.empty();
357 |
358 | document.title = q + ' :: ' + title;
359 |
360 | html.push('' + q + ' ' + item.type + '
');
361 | html.push('Category: ' + item.category + '/' + item.subcategory + (item.added ? ' (added ' + item.added + ')' : '') + '
');
362 | html.push(item.longdesc || '' + item.desc + '
'); // longdesc is usally HTML
363 | html.push('Returns
');
364 | html.push('' + (item['return'] || 'Nothing') + '
');
365 |
366 | if (item.params.length) {
367 | html.push('Parameters
');
368 | html.push('');
369 | for (i = 0; i < item.params.length; i++) {
370 | html.push('- ' + item.params[i].name + ' ');
371 | if (item.params[i].type) {
372 | html.push('(' + item.params[i].type + ')');
373 | }
374 | html.push(': ' + item.params[i].desc + '
');
375 | }
376 | html.push('
');
377 | }
378 |
379 | // detailed options
380 | if (item.options && item.options.length) {
381 | html.push('Options
');
382 | html.push('');
383 | for (i = 0; i < item.options.length; i++) {
384 | html.push('- ' + item.options[i].name + ' ');
385 | if (item.options[i].type) {
386 | html.push('(' + item.options[i].type + ')');
387 | }
388 | html.push(': ' + item.options[i].desc + '
');
389 | }
390 | html.push('
');
391 |
392 | }
393 |
394 | for (i = 0; i < item.examples.length; i++) {
395 | html.push('Example
');
396 | if (item.examples[i].desc) {
397 | html.push('' + item.examples[i].desc + '
');
398 | }
399 | html.push('jQuery Code
');
400 | html.push('
' + item.examples[i].htmlCode + '
');
401 |
402 | // this is special code that will convert in to a real running example once run through 'runExample(item)'
403 | if (item.examples[i].html) {
404 |
405 | // prepare for a JSBin link - currently point to live
406 | j = item.examples[i].runCode.replace("", function () {
407 | return "";
408 | });
409 |
410 | html.push('
');
411 | }
412 | }
413 |
414 | // step = (200 * $wrapper.find('dl').length) + 10;
415 | $detail.append('
' + html.join('') + '');
416 | $detail.parent().get(0).scrollTop = 0; // reset the overflow position
417 | fixLinks($detail.find('dd')); // makes links to more docs absolute rather than relative (should do in the api-docs.js)
418 |
419 | // in place of runExamples to allow AIR to run the iframe's contents
420 | if (airapp) {
421 | $('div.liveExample a.external').click(function () {
422 | window.runtime.flash.net.navigateToURL(new window.runtime.flash.net.URLRequest(this.href));
423 | return false;
424 | });
425 |
426 | for (i = 0; i < item.examples.length; i++) {
427 | win = document.getElementById(item.examples[i].id);
428 | if (win) { // some examples don't have code
429 | $(win).bind('load', { example: item.examples[i] }, function (event) {
430 | var example = event.data.example;
431 | this.contentWindow.childSandboxBridge.write(
432 | example.runCode.replace("", '
'));
433 | });
434 | }
435 | }
436 | } else {
437 | runExample(item);
438 | }
439 |
440 | // code highlight
441 | prettyPrint($detail.get(0));
442 | }
443 | }
444 | });
445 | }
446 |
--------------------------------------------------------------------------------
/lib/jqueryapi/json2.js:
--------------------------------------------------------------------------------
1 | /*
2 | http://www.JSON.org/json2.js
3 | 2008-11-19
4 |
5 | Public Domain.
6 |
7 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
8 |
9 | See http://www.JSON.org/js.html
10 |
11 | This file creates a global JSON object containing two methods: stringify
12 | and parse.
13 |
14 | JSON.stringify(value, replacer, space)
15 | value any JavaScript value, usually an object or array.
16 |
17 | replacer an optional parameter that determines how object
18 | values are stringified for objects. It can be a
19 | function or an array of strings.
20 |
21 | space an optional parameter that specifies the indentation
22 | of nested structures. If it is omitted, the text will
23 | be packed without extra whitespace. If it is a number,
24 | it will specify the number of spaces to indent at each
25 | level. If it is a string (such as '\t' or ' '),
26 | it contains the characters used to indent at each level.
27 |
28 | This method produces a JSON text from a JavaScript value.
29 |
30 | When an object value is found, if the object contains a toJSON
31 | method, its toJSON method will be called and the result will be
32 | stringified. A toJSON method does not serialize: it returns the
33 | value represented by the name/value pair that should be serialized,
34 | or undefined if nothing should be serialized. The toJSON method
35 | will be passed the key associated with the value, and this will be
36 | bound to the object holding the key.
37 |
38 | For example, this would serialize Dates as ISO strings.
39 |
40 | Date.prototype.toJSON = function (key) {
41 | function f(n) {
42 | // Format integers to have at least two digits.
43 | return n < 10 ? '0' + n : n;
44 | }
45 |
46 | return this.getUTCFullYear() + '-' +
47 | f(this.getUTCMonth() + 1) + '-' +
48 | f(this.getUTCDate()) + 'T' +
49 | f(this.getUTCHours()) + ':' +
50 | f(this.getUTCMinutes()) + ':' +
51 | f(this.getUTCSeconds()) + 'Z';
52 | };
53 |
54 | You can provide an optional replacer method. It will be passed the
55 | key and value of each member, with this bound to the containing
56 | object. The value that is returned from your method will be
57 | serialized. If your method returns undefined, then the member will
58 | be excluded from the serialization.
59 |
60 | If the replacer parameter is an array of strings, then it will be
61 | used to select the members to be serialized. It filters the results
62 | such that only members with keys listed in the replacer array are
63 | stringified.
64 |
65 | Values that do not have JSON representations, such as undefined or
66 | functions, will not be serialized. Such values in objects will be
67 | dropped; in arrays they will be replaced with null. You can use
68 | a replacer function to replace those with JSON values.
69 | JSON.stringify(undefined) returns undefined.
70 |
71 | The optional space parameter produces a stringification of the
72 | value that is filled with line breaks and indentation to make it
73 | easier to read.
74 |
75 | If the space parameter is a non-empty string, then that string will
76 | be used for indentation. If the space parameter is a number, then
77 | the indentation will be that many spaces.
78 |
79 | Example:
80 |
81 | text = JSON.stringify(['e', {pluribus: 'unum'}]);
82 | // text is '["e",{"pluribus":"unum"}]'
83 |
84 |
85 | text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
86 | // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
87 |
88 | text = JSON.stringify([new Date()], function (key, value) {
89 | return this[key] instanceof Date ?
90 | 'Date(' + this[key] + ')' : value;
91 | });
92 | // text is '["Date(---current time---)"]'
93 |
94 |
95 | JSON.parse(text, reviver)
96 | This method parses a JSON text to produce an object or array.
97 | It can throw a SyntaxError exception.
98 |
99 | The optional reviver parameter is a function that can filter and
100 | transform the results. It receives each of the keys and values,
101 | and its return value is used instead of the original value.
102 | If it returns what it received, then the structure is not modified.
103 | If it returns undefined then the member is deleted.
104 |
105 | Example:
106 |
107 | // Parse the text. Values that look like ISO date strings will
108 | // be converted to Date objects.
109 |
110 | myData = JSON.parse(text, function (key, value) {
111 | var a;
112 | if (typeof value === 'string') {
113 | a =
114 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
115 | if (a) {
116 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
117 | +a[5], +a[6]));
118 | }
119 | }
120 | return value;
121 | });
122 |
123 | myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
124 | var d;
125 | if (typeof value === 'string' &&
126 | value.slice(0, 5) === 'Date(' &&
127 | value.slice(-1) === ')') {
128 | d = new Date(value.slice(5, -1));
129 | if (d) {
130 | return d;
131 | }
132 | }
133 | return value;
134 | });
135 |
136 |
137 | This is a reference implementation. You are free to copy, modify, or
138 | redistribute.
139 |
140 | This code should be minified before deployment.
141 | See http://javascript.crockford.com/jsmin.html
142 |
143 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
144 | NOT CONTROL.
145 | */
146 |
147 | /*jslint evil: true */
148 |
149 | /*global JSON */
150 |
151 | /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
152 | call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
153 | getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
154 | lastIndex, length, parse, prototype, push, replace, slice, stringify,
155 | test, toJSON, toString, valueOf
156 | */
157 |
158 | // Create a JSON object only if one does not already exist. We create the
159 | // methods in a closure to avoid creating global variables.
160 |
161 | if (!this.JSON) {
162 | JSON = {};
163 | }
164 | (function () {
165 |
166 | function f(n) {
167 | // Format integers to have at least two digits.
168 | return n < 10 ? '0' + n : n;
169 | }
170 |
171 | if (typeof Date.prototype.toJSON !== 'function') {
172 |
173 | Date.prototype.toJSON = function (key) {
174 |
175 | return this.getUTCFullYear() + '-' +
176 | f(this.getUTCMonth() + 1) + '-' +
177 | f(this.getUTCDate()) + 'T' +
178 | f(this.getUTCHours()) + ':' +
179 | f(this.getUTCMinutes()) + ':' +
180 | f(this.getUTCSeconds()) + 'Z';
181 | };
182 |
183 | String.prototype.toJSON =
184 | Number.prototype.toJSON =
185 | Boolean.prototype.toJSON = function (key) {
186 | return this.valueOf();
187 | };
188 | }
189 |
190 | var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
191 | escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
192 | gap,
193 | indent,
194 | meta = { // table of character substitutions
195 | '\b': '\\b',
196 | '\t': '\\t',
197 | '\n': '\\n',
198 | '\f': '\\f',
199 | '\r': '\\r',
200 | '"' : '\\"',
201 | '\\': '\\\\'
202 | },
203 | rep;
204 |
205 |
206 | function quote(string) {
207 |
208 | // If the string contains no control characters, no quote characters, and no
209 | // backslash characters, then we can safely slap some quotes around it.
210 | // Otherwise we must also replace the offending characters with safe escape
211 | // sequences.
212 |
213 | escapable.lastIndex = 0;
214 | return escapable.test(string) ?
215 | '"' + string.replace(escapable, function (a) {
216 | var c = meta[a];
217 | return typeof c === 'string' ? c :
218 | '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
219 | }) + '"' :
220 | '"' + string + '"';
221 | }
222 |
223 |
224 | function str(key, holder) {
225 |
226 | // Produce a string from holder[key].
227 |
228 | var i, // The loop counter.
229 | k, // The member key.
230 | v, // The member value.
231 | length,
232 | mind = gap,
233 | partial,
234 | value = holder[key];
235 |
236 | // If the value has a toJSON method, call it to obtain a replacement value.
237 |
238 | if (value && typeof value === 'object' &&
239 | typeof value.toJSON === 'function') {
240 | value = value.toJSON(key);
241 | }
242 |
243 | // If we were called with a replacer function, then call the replacer to
244 | // obtain a replacement value.
245 |
246 | if (typeof rep === 'function') {
247 | value = rep.call(holder, key, value);
248 | }
249 |
250 | // What happens next depends on the value's type.
251 |
252 | switch (typeof value) {
253 | case 'string':
254 | return quote(value);
255 |
256 | case 'number':
257 |
258 | // JSON numbers must be finite. Encode non-finite numbers as null.
259 |
260 | return isFinite(value) ? String(value) : 'null';
261 |
262 | case 'boolean':
263 | case 'null':
264 |
265 | // If the value is a boolean or null, convert it to a string. Note:
266 | // typeof null does not produce 'null'. The case is included here in
267 | // the remote chance that this gets fixed someday.
268 |
269 | return String(value);
270 |
271 | // If the type is 'object', we might be dealing with an object or an array or
272 | // null.
273 |
274 | case 'object':
275 |
276 | // Due to a specification blunder in ECMAScript, typeof null is 'object',
277 | // so watch out for that case.
278 |
279 | if (!value) {
280 | return 'null';
281 | }
282 |
283 | // Make an array to hold the partial results of stringifying this object value.
284 |
285 | gap += indent;
286 | partial = [];
287 |
288 | // Is the value an array?
289 |
290 | if (Object.prototype.toString.apply(value) === '[object Array]') {
291 |
292 | // The value is an array. Stringify every element. Use null as a placeholder
293 | // for non-JSON values.
294 |
295 | length = value.length;
296 | for (i = 0; i < length; i += 1) {
297 | partial[i] = str(i, value) || 'null';
298 | }
299 |
300 | // Join all of the elements together, separated with commas, and wrap them in
301 | // brackets.
302 |
303 | v = partial.length === 0 ? '[]' :
304 | gap ? '[\n' + gap +
305 | partial.join(',\n' + gap) + '\n' +
306 | mind + ']' :
307 | '[' + partial.join(',') + ']';
308 | gap = mind;
309 | return v;
310 | }
311 |
312 | // If the replacer is an array, use it to select the members to be stringified.
313 |
314 | if (rep && typeof rep === 'object') {
315 | length = rep.length;
316 | for (i = 0; i < length; i += 1) {
317 | k = rep[i];
318 | if (typeof k === 'string') {
319 | v = str(k, value);
320 | if (v) {
321 | partial.push(quote(k) + (gap ? ': ' : ':') + v);
322 | }
323 | }
324 | }
325 | } else {
326 |
327 | // Otherwise, iterate through all of the keys in the object.
328 |
329 | for (k in value) {
330 | if (Object.hasOwnProperty.call(value, k)) {
331 | v = str(k, value);
332 | if (v) {
333 | partial.push(quote(k) + (gap ? ': ' : ':') + v);
334 | }
335 | }
336 | }
337 | }
338 |
339 | // Join all of the member texts together, separated with commas,
340 | // and wrap them in braces.
341 |
342 | v = partial.length === 0 ? '{}' :
343 | gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
344 | mind + '}' : '{' + partial.join(',') + '}';
345 | gap = mind;
346 | return v;
347 | }
348 | }
349 |
350 | // If the JSON object does not yet have a stringify method, give it one.
351 |
352 | if (typeof JSON.stringify !== 'function') {
353 | JSON.stringify = function (value, replacer, space) {
354 |
355 | // The stringify method takes a value and an optional replacer, and an optional
356 | // space parameter, and returns a JSON text. The replacer can be a function
357 | // that can replace values, or an array of strings that will select the keys.
358 | // A default replacer method can be provided. Use of the space parameter can
359 | // produce text that is more easily readable.
360 |
361 | var i;
362 | gap = '';
363 | indent = '';
364 |
365 | // If the space parameter is a number, make an indent string containing that
366 | // many spaces.
367 |
368 | if (typeof space === 'number') {
369 | for (i = 0; i < space; i += 1) {
370 | indent += ' ';
371 | }
372 |
373 | // If the space parameter is a string, it will be used as the indent string.
374 |
375 | } else if (typeof space === 'string') {
376 | indent = space;
377 | }
378 |
379 | // If there is a replacer, it must be a function or an array.
380 | // Otherwise, throw an error.
381 |
382 | rep = replacer;
383 | if (replacer && typeof replacer !== 'function' &&
384 | (typeof replacer !== 'object' ||
385 | typeof replacer.length !== 'number')) {
386 | throw new Error('JSON.stringify');
387 | }
388 |
389 | // Make a fake root object containing our value under the key of ''.
390 | // Return the result of stringifying the value.
391 |
392 | return str('', {'': value});
393 | };
394 | }
395 |
396 |
397 | // If the JSON object does not yet have a parse method, give it one.
398 |
399 | if (typeof JSON.parse !== 'function') {
400 | JSON.parse = function (text, reviver) {
401 |
402 | // The parse method takes a text and an optional reviver function, and returns
403 | // a JavaScript value if the text is a valid JSON text.
404 |
405 | var j;
406 |
407 | function walk(holder, key) {
408 |
409 | // The walk method is used to recursively walk the resulting structure so
410 | // that modifications can be made.
411 |
412 | var k, v, value = holder[key];
413 | if (value && typeof value === 'object') {
414 | for (k in value) {
415 | if (Object.hasOwnProperty.call(value, k)) {
416 | v = walk(value, k);
417 | if (v !== undefined) {
418 | value[k] = v;
419 | } else {
420 | delete value[k];
421 | }
422 | }
423 | }
424 | }
425 | return reviver.call(holder, key, value);
426 | }
427 |
428 |
429 | // Parsing happens in four stages. In the first stage, we replace certain
430 | // Unicode characters with escape sequences. JavaScript handles many characters
431 | // incorrectly, either silently deleting them, or treating them as line endings.
432 |
433 | cx.lastIndex = 0;
434 | if (cx.test(text)) {
435 | text = text.replace(cx, function (a) {
436 | return '\\u' +
437 | ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
438 | });
439 | }
440 |
441 | // In the second stage, we run the text against regular expressions that look
442 | // for non-JSON patterns. We are especially concerned with '()' and 'new'
443 | // because they can cause invocation, and '=' because it can cause mutation.
444 | // But just to be safe, we want to reject all unexpected forms.
445 |
446 | // We split the second stage into 4 regexp operations in order to work around
447 | // crippling inefficiencies in IE's and Safari's regexp engines. First we
448 | // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
449 | // replace all simple value tokens with ']' characters. Third, we delete all
450 | // open brackets that follow a colon or comma or that begin the text. Finally,
451 | // we look to see that the remaining characters are only whitespace or ']' or
452 | // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
453 |
454 | if (/^[\],:{}\s]*$/.
455 | test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
456 | replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
457 | replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
458 |
459 | // In the third stage we use the eval function to compile the text into a
460 | // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
461 | // in JavaScript: it can begin a block or an object literal. We wrap the text
462 | // in parens to eliminate the ambiguity.
463 |
464 | j = eval('(' + text + ')');
465 |
466 | // In the optional fourth stage, we recursively walk the new structure, passing
467 | // each name/value pair to a reviver function for possible transformation.
468 |
469 | return typeof reviver === 'function' ?
470 | walk({'': j}, '') : j;
471 | }
472 |
473 | // If the text is not JSON parseable, then a SyntaxError is thrown.
474 |
475 | throw new SyntaxError('JSON.parse');
476 | };
477 | }
478 | })();
--------------------------------------------------------------------------------
/lib/jqueryapi/api-loader.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | if (!window.jquerydocs) {
4 | window.jquerydocs = {};
5 | } else {
6 | // we've already been included, bomb out
7 | return;
8 | }
9 |
10 | window.apiloader = {};
11 |
12 | var msie = /*@cc_on!@*/0;
13 | apiloader.blank_iframe = msie ? 'index-blank-ie.html' : 'index-blank.html';
14 | apiloader.online = window.runtime ? false : true;
15 | apiloader.example_jquery = {
16 | 'online' : 'http://code.jquery.com/jquery-1.3.js',
17 | 'offline' : 'http://code.jquery.com/jquery-1.3.js' //app:/lib/jquery/jquery-1.3.js'
18 | };
19 |
20 | var guid = 0;
21 |
22 | var re_opt = /options/i;
23 |
24 | init();
25 |
26 | window.loadDocs = function(data, async) {
27 | $(document).trigger('api-loading');
28 |
29 | if (typeof async == 'undefined') {
30 | async = true;
31 | }
32 |
33 | if (typeof data != 'undefined' && typeof data != 'string') {
34 | jquerydocs = data;
35 | attachFind(jquerydocs);
36 | $(document).trigger('api-load-success');
37 | $(document).trigger('api-load-complete');
38 | } else {
39 | // parser
40 | $.ajax({
41 | url: data || 'jquery-docs.xml', // generated from jquery source: /tools/wikiapi2xml/createjQueryXMLDocs.py
42 | dataType: 'xml',
43 | success: parse,
44 | async: async,
45 | error: function () {
46 | attachFind(jquerydocs);
47 | $(document).trigger('api-load-error');
48 | },
49 | complete: function () {
50 | $(document).trigger('api-load-complete');
51 | }
52 | });
53 | }
54 | };
55 |
56 | function init() {
57 | jquerydocs.letters = [];
58 |
59 | jquerydocs.data = {};
60 | jquerydocs.searchNames = [];
61 | jquerydocs.categories = [];
62 | }
63 |
64 | window.parse = function(xml) {
65 | var docinfo = $('docs', xml);
66 |
67 | if (!jquerydocs.startdoc) { // only initialise this once
68 | jquerydocs.startdoc = docinfo.attr('startdoc');
69 | jquerydocs.version = docinfo.attr('version');
70 | jquerydocs.timestamp = docinfo.attr('timestamp');
71 | }
72 |
73 | var letters = jquerydocs.letters; // holder before sorting and inserting
74 |
75 | var dict = getDictionary();
76 | var root = docinfo.attr('startdoc').toLowerCase();
77 |
78 | // loop through all types collecting data
79 | $('cat', xml).each(function (i) {
80 | var catName = this.getAttribute('value');
81 | var category = {};
82 | category.name = catName;
83 | category.root = root;
84 | category.subcategories = [];
85 |
86 | $('subcat', this).each(function (i) {
87 | var subcatName = this.getAttribute('value');
88 | var subcategory = { name : subcatName, functions : [] };
89 |
90 | $('function,property,selector', this).each(function () {
91 | var data = {};
92 | guid++;
93 |
94 | // some function names have spaces around them - so trim
95 | var name = this.getAttribute('name').replace( /^\s+|\s+$/g, '');
96 |
97 | var searchName = name.toLowerCase().replace(/^jquery\./, '');
98 | letters.push(name.toLowerCase().substr(0,1));
99 |
100 | name = name.replace(/^jquery\./i, '$.');
101 |
102 | jquerydocs.searchNames.push(searchName + guid);
103 | subcategory.functions.push(searchName + guid);
104 |
105 | data['id'] = guid;
106 | data['searchname'] = searchName;
107 | data['name'] = name;
108 | data['type'] = this.nodeName.toLowerCase();
109 | data['category'] = this.getAttribute('cat');
110 | data['subcategory'] = subcatName;
111 | data['return'] = escapeHTML(this.getAttribute('return'));
112 | data['added'] = $('added', this).text();
113 | data['sample'] = $('> sample', this).text();
114 | data['desc'] = $('> desc', this).text();
115 | data['longdesc'] = deWikify($('> longdesc', this).text());
116 |
117 | // silly hack because of conversion issue from wiki to text (the .ready function
118 | // has HTML in the description), but also includes HTML that should be printed,
119 | // in particular the body tag :-(
120 | data.longdesc = data.longdesc.replace(//, '<body>');
121 |
122 | // some descs are in HTML format, some aren't
123 | if (!(/
/).test(data.longdesc)) {
124 | data.longdesc = '
' + data.longdesc.split(/\n\n/).join('
') + '
';
125 | }
126 |
127 | // strip our empty p tag if there was no description
128 | if (data.longdesc == '
') {
129 | data.longdesc = '';
130 | }
131 |
132 | /** params - we'll also search for Options to decide whether we need to parse */
133 | var readOptions = false;
134 | data.params = [];
135 | $('params', this).each(function (i) {
136 | var type = escapeHTML(this.getAttribute('type'));
137 | var name = this.getAttribute('name');
138 | var opt = this.getAttribute('optional') || "";
139 | var desc = $('desc', this).text();
140 |
141 | if (re_opt.test(type)) {
142 | readOptions = true;
143 | }
144 |
145 | data.params.push({
146 | optional : (/true/i).test(opt), // bool
147 | name : name,
148 | type : type,
149 | desc : desc
150 | });
151 | });
152 |
153 | if (readOptions) {
154 | data.options = [];
155 | $('option', this).each(function () {
156 | var option = {};
157 | option['name'] = this.getAttribute('name');
158 | option['default'] = this.getAttribute('default') || '';
159 | option['type'] = escapeHTML(this.getAttribute('type'));
160 | option['desc'] = deWikify($('desc', this).text());
161 |
162 | data.options.push(option);
163 | });
164 | }
165 |
166 | data.examples = [];
167 | /** examples */
168 | $('example', this).each(function (i) {
169 | var iframe = '', exampleId = '';
170 | var example = {};
171 |
172 | example['code'] = $('code', this).text();
173 | example['htmlCode'] = escapeHTML(example.code);
174 | example['desc'] = deWikify(escapeHTML($('desc', this).text()));
175 | example['css'] = $('css', this).text() || '';
176 | example['inhead'] = $('inhead', this).text() || '';
177 | example['html'] = $('html', this).text() || '';
178 |
179 | exampleId = guid + 'iframeExample' + i;
180 | example['id'] = exampleId;
181 |
182 | if (example.html) {
183 |
184 | iframe = '
';
185 |
186 | // we're storing the example iframe source to insert in to
187 | // the iframe only once it's inserted in to the DOM.
188 | example['runCode'] = iframeTemplate().replace(/%([a-z]*)%/ig, function (m, l) {
189 | return example[l] || "";
190 | });
191 | } else {
192 | example.runCode = '';
193 | }
194 |
195 | data.examples.push(example);
196 | });
197 |
198 | jquerydocs.data[searchName + data.id] = data;
199 | });
200 |
201 | category.subcategories.push(subcategory);
202 | });
203 |
204 | jquerydocs.categories.push(category); // FIXME should I warn if this exists?
205 | });
206 |
207 | jquerydocs.letters = unique($.map(letters.sort(), function (i) {
208 | return i.substr(0,1);
209 | }));
210 |
211 | // attachFind(jquerydocs);
212 |
213 | $(document).trigger('api-load-success');
214 | };
215 |
216 | // helpers
217 |
218 | window.attachFind = function(o) {
219 | var categoryRootLookup = {};
220 | var i = jquerydocs.categories.length;
221 | while (i--) {
222 | categoryRootLookup[jquerydocs.categories[i].name] = jquerydocs.categories[i].root;
223 | }
224 |
225 | o.find = function (s, by) {
226 | var found = [],
227 | tmp = {},
228 | tmpNames = [],
229 | lettersLK = {},
230 | letters = [],
231 | catsLK = {},
232 | cats = [],
233 | catPointer = 0,
234 | subLK = {},
235 | sub = [],
236 | subcatPointer = 0;
237 | data = {}; // reusing i from above
238 |
239 | function add(data, i) {
240 | mapFields(data);
241 |
242 | tmp[jquerydocs.searchNames[i]] = data;
243 | tmpNames.push(jquerydocs.searchNames[i]);
244 |
245 | if (!lettersLK[jquerydocs.searchNames[i].substr(0, 1)]) {
246 | lettersLK[jquerydocs.searchNames[i].substr(0, 1)] = true;
247 | letters.push(jquerydocs.searchNames[i].substr(0, 1));
248 | }
249 |
250 | if (typeof catsLK[data.category] == 'undefined') {
251 | catsLK[data.category] = catPointer;
252 | cats.push({ name : data.category, subcategories : [], root : categoryRootLookup[data.category] });
253 |
254 | subLK[data.category] = {};
255 |
256 | subcatPointer = 0;
257 | catPointer++;
258 | }
259 |
260 | if (typeof subLK[data.category][data.subcategory] == 'undefined') {
261 | subLK[data.category][data.subcategory] = subcatPointer;
262 | cats[catsLK[data.category]].subcategories.push({ name : data.subcategory, functions : [] });
263 |
264 | subcatPointer++;
265 | }
266 |
267 | // bug here...
268 | cats[catsLK[data.category]].subcategories[subLK[data.category][data.subcategory]].functions.push(jquerydocs.searchNames[i]);
269 | }
270 |
271 | if (typeof s == 'string') {
272 | s = s.toLowerCase();
273 | by = (by || 'searchname').toLowerCase();
274 |
275 | if (by == 'name') by = 'searchname'; // search without the $.
276 |
277 | for (i = 0; i < jquerydocs.searchNames.length; i++) {
278 | if (jquerydocs.data[jquerydocs.searchNames[i]][by] && jquerydocs.data[jquerydocs.searchNames[i]][by].toLowerCase().indexOf(s) == 0) {
279 | add(jquerydocs.data[jquerydocs.searchNames[i]], i);
280 | }
281 | }
282 | } else if (s instanceof Array) {
283 | for (i = 0; i < s.length; i++) {
284 | if (jquerydocs.data[s[i]]) {
285 | add(jquerydocs.data[s[i]], i);
286 | }
287 | }
288 | }
289 |
290 | tmpNames = tmpNames.sort().reverse(); // never sure if this is faster with the reverse
291 | i = tmpNames.length;
292 | while (i--) {
293 | found.push(tmp[tmpNames[i]]);
294 | }
295 |
296 | // this is kind of noddy, but returns the same object as we queried - which is cool!
297 | found.letters = letters;
298 | found.categories = cats;
299 | found.data = tmp;
300 | found.searchNames = tmpNames;
301 | attachFind(found);
302 |
303 | return found;
304 | };
305 | };
306 |
307 | function mapFields(data, dict) {
308 | if (data.fieldsMapped) {
309 | return;
310 | }
311 |
312 | var key, type;
313 |
314 | if (!dict) {
315 | dict = getDictionary();
316 | }
317 |
318 | for (key in dict) {
319 | type = typeof data[key];
320 | if (type != 'undefined') {
321 | if (type == 'object') {
322 | mapFields(data[key], dict);
323 | }
324 |
325 | data[dict[key]] = data[key];
326 | }
327 | }
328 | }
329 |
330 | function unique(a) {
331 | var ret = [], done = {};
332 |
333 | try {
334 | for ( var i = 0, length = a.length; i < length; i++ ) {
335 | var id = a[ i ] ;
336 |
337 | if ( !done[ id ] ) {
338 | done[ id ] = true;
339 | ret.push( a[ i ] );
340 | }
341 | }
342 |
343 | } catch( e ) {
344 | ret = a;
345 | }
346 |
347 | return ret;
348 | }
349 |
350 | function iframeTemplate() {
351 | // array so that we maintain some formatting
352 | return [
353 | '',
355 | '<' + 'html>',
356 | '<' + 'head>',
357 | '
',
358 | '<' + 'script src="' + apiloader.example_jquery[apiloader.online ? 'online' : 'offline'] + '"><' + '/script>',
359 | '%inhead%',
360 | '<' + 'style>',
361 | '%css%',
362 | '<' + '/style>',
363 | '<' + '/head>',
364 | '<' + 'body>',
365 | '%html%',
366 | '<' + 'script>',
367 | '$(document).ready(function(){', '%code%', ' });',
368 | '<' + '/script>',
369 | '<' + '/body>',
370 | '<' + '/html>'
371 | ].join("\n");
372 | }
373 |
374 | function getDictionary() {
375 | return {
376 | 'a' : 'id',
377 | 'b' : 'searchname',
378 | 'c' : 'name',
379 | 'd' : 'type',
380 | 'e' : 'category',
381 | 'f' : 'subcategory',
382 | 'g' : 'return',
383 | 'h' : 'added',
384 | 'i' : 'sample',
385 | 'j' : 'desc',
386 | 'k' : 'longdesc',
387 | 'l' : 'params',
388 | 'm' : 'optional',
389 | 'n' : 'options',
390 | 'o' : 'default',
391 | 'p' : 'examples',
392 | 'q' : 'code',
393 | 'r' : 'htmlCode',
394 | 's' : 'css',
395 | 't' : 'inhead',
396 | 'u' : 'html',
397 | 'v' : 'runCode'
398 | };
399 | }
400 |
401 | /** public utility functions */
402 |
403 | window.escapeHTML = function (s) {
404 | // converts null to string
405 | return (s+"").replace(/[<>]/g, function (m) {
406 | if (m == '<') return '<';
407 | else if (m == '>') return '>';
408 | });
409 | };
410 |
411 | window.cleanSelector = function(s) {
412 | return (s+"").replace(/[\$\.]/g, function (m) {
413 | // handle escaping characters that break the selector engine
414 | if (m == '$') {
415 | return '\\$';
416 | } else if (m == '.') {
417 | return '\\.';
418 | }
419 | });
420 | };
421 |
422 | window.linkifyTypes = function(type) {
423 | // cheeky way to avoid doing a massive if (m == x || m == y || m == etc) - we just do an .indexOf()
424 | var nodocs = '|jQuery|XMLHttpRequest|Plugins|Validator|Validation|undefined|or|Any|DOM|Map|top|left|lt|gt|\(s\)||'; // note we purposely include an empty match
425 |
426 | return type ? $.map(type.replace(/DOMElement/g, 'DOM Element').split(/, /), function (n) {
427 | // match words and linkify, then italic to the optionals
428 | return n.replace(/boolean/, 'Boolean').replace(/\b[a-z]*\b/gi, function (m, l) {
429 | // special case
430 | if (m == 'Elements') {
431 | return '
Elements';
432 | // no specific documentation for these types
433 | } else if (nodocs.indexOf('|' + m + '|') !== -1) {
434 | return m;
435 | } else {
436 | return '
' + m + '';
437 | }
438 | });
439 | }).join(', ') : "";
440 | };
441 |
442 | window.deWikify = function (s) {
443 | return (""+s).replace(/'''.*?'''/g, function (m) {
444 | return '
' + m.replace(/'''/g, '') + '';
445 | }).replace(/''.*?''/g, function (m) {
446 | return '
' + m.replace(/''/g, '') + '';
447 | }).replace(/\[http.*?\]/, function (m) {
448 | var p = m.replace(/^\[/, '').replace(/\]$/, '').split(/ /);
449 | return '
' + (p.length == 2 ? p[1] : p[0]) + '';
450 | }).replace(/(((^|\n)(\*|[0-9]+.).*)+)/g, function (m) {
451 | var type = 'ol';
452 | // strip leading new line
453 | m = m.replace( /^\s+|\s+$/g, "" );
454 | if (m.match(/^\*/)) type = 'ul';
455 | return '<' + type + '>
' + m.replace(/\*?/g, '').split(/\n/).join("") + '' + type + '>';
456 | });
457 | };
458 |
459 | window.runExample = function(data) {
460 | if (!data.examples || data.examples.length == 0) return;
461 |
462 | var i, win, example;
463 |
464 | for (i = 0; i < data.examples.length; i++) {
465 | example = data.examples[i];
466 |
467 | win = $('#' + cleanSelector(example.id)).get(0);
468 | if (win) {
469 | win = win.contentDocument || win.contentWindow.document;
470 | if (msie) {
471 |
472 | }
473 | // from docs.jquery.com
474 | win.write(example.runCode
475 | .replace("$(document).ready(function(){", "window.onload = (function(){try{")
476 | .replace(/}\);\s*<\/sc/, "}catch(e){}});", ""));
478 |
479 | win.close();
480 | }
481 | }
482 | };
483 |
484 | window.fixLinks = function (context) {
485 | // since the source comes from the wiki, we need to adjust some of the links
486 | $('a', context).each(function () {
487 | var href = this.getAttribute('href');
488 | if (href && !href.match(/http/) && !href.match(/^#/) && this.className != 'fnName') {
489 | this.host = 'docs.jquery.com';
490 | this.pathname = this.pathname.replace(window.location.pathname, '');
491 | }
492 | });
493 | };
494 |
495 | })();
496 |
--------------------------------------------------------------------------------
/lib/air/AIRMenuBuilder.js:
--------------------------------------------------------------------------------
1 | /* AIRMenuBuilder.js - Revision: 1.5 */
2 |
3 | /*
4 | ADOBE SYSTEMS INCORPORATED
5 | Copyright 2007-2008 Adobe Systems Incorporated. All Rights Reserved.
6 |
7 | NOTICE: Adobe permits you to modify and distribute this file only in accordance with
8 | the terms of Adobe AIR SDK license agreement. You may have received this file from a
9 | source other than Adobe. Nonetheless, you may modify or
10 | distribute this file only in accordance with such agreement.
11 | */
12 |
13 | (function AIRMenuBuilder () {
14 |
15 | function constructor ( ) {
16 | window ['air'] = window ['air'] || {};
17 | window.air['ui'] = window.air['ui'] || {};
18 | window.air.ui['Menu'] = new Menu();
19 | registry = new FieldsRegistry();
20 | currentOS = runtime.flash.system.Capabilities.os;
21 | }
22 |
23 | var currentOS = null;
24 | var registry = null;
25 |
26 | var File = runtime.flash.filesystem.File;
27 | var FileStream = runtime.flash.filesystem.FileStream;
28 | var FileMode = runtime.flash.filesystem.FileMode;
29 | var NativeMenu = runtime.flash.display.NativeMenu;
30 | var NativeMenuItem = runtime.flash.display.NativeMenuItem;
31 | var SELECT = runtime.flash.events.Event.SELECT;
32 | var KEYBOARD = runtime.flash.ui.Keyboard;
33 | var COMPLETE = runtime.flash.events.Event.COMPLETE;
34 | var IO_ERROR = runtime.flash.events.IOErrorEvent.IO_ERROR;
35 | var NativeApplication = runtime.flash.desktop.NativeApplication;
36 | var NativeWindow = runtime.flash.display.NativeWindow;
37 | var Loader = runtime.flash.display.Loader;
38 | var URLRequest = runtime.flash.net.URLRequest;
39 | var BitmapData = runtime.flash.display.BitmapData;
40 |
41 | /**
42 | * CLASS FieldsRegistry
43 | * @class
44 | * @private
45 | */
46 | function FieldsRegistry () {
47 |
48 | this.proof = function (name, value) {
49 | if (!validateName(name)) { return null };
50 | switch (name) {
51 | case FieldsRegistry.ENABLED:
52 | case FieldsRegistry.ALT_KEY:
53 | case FieldsRegistry.SHIFT_KEY:
54 | case FieldsRegistry.CMD_KEY:
55 | case FieldsRegistry.CTRL_KEY:
56 | case FieldsRegistry.TOGGLED:
57 | case FieldsRegistry.DEFAULT_KEY:
58 | return (typeof value == 'boolean')?
59 | value: (typeof value == 'string')?
60 | (value.toLowerCase() == 'false')? false :
61 | true : getDefault (name);
62 | case FieldsRegistry.KEY_EQUIVALENT:
63 | var d;
64 | return (typeof value == 'string')?
65 | (value.length == 1)? value :
66 | getDefault (name) : getDefault (name);
67 | case FieldsRegistry.LABEL:
68 | return (typeof value == 'string')?
69 | (value.length != 0)? value:
70 | getDefault (name) : getDefault (name);
71 | case FieldsRegistry.MNEMONIC_INDEX:
72 | var n;
73 | return (typeof value == 'number')?
74 | value: (typeof value == 'string')?
75 | (!isNaN ( n = parseInt(value) ))? n :
76 | getDefault (name) : getDefault (name);
77 | case FieldsRegistry.TYPE:
78 | return (typeof value == 'string') ?
79 | (validateType(value))? value :
80 | getDefault (name) : getDefault (name);
81 | case FieldsRegistry.ON_SELECT:
82 | var f;
83 | return (typeof value == 'function')?
84 | value : (typeof value == 'string')?
85 | (typeof (f = window[value]) == 'function')?
86 | f : getDefault (name) : getDefault (name);
87 | }
88 | }
89 |
90 | this.iterateFields = function (callback, scope) {
91 | var f, n, fr = FieldsRegistry;
92 | for (f in fr) {
93 | n = fr [f] !== fr.prototype? fr [f] : null;
94 | if (n && !validateType(n)) {
95 | callback.call ( scope || window, n )
96 | };
97 | }
98 | }
99 |
100 | var validateType = function (type) {
101 | return type == FieldsRegistry.REGULAR ||
102 | type == FieldsRegistry.SEPARATOR ||
103 | type == FieldsRegistry.CHECK;
104 | }
105 |
106 | var validateName = function (fieldName) {
107 | for (var f in FieldsRegistry) {
108 | if (FieldsRegistry[f] == fieldName) { return true };
109 | }
110 | return false;
111 | }
112 |
113 |
114 | var getDefault = function (fieldName) {
115 | switch (fieldName) {
116 | case FieldsRegistry.ALT_KEY:
117 | case FieldsRegistry.SHIFT_KEY:
118 | case FieldsRegistry.TOGGLED:
119 | return false;
120 | case FieldsRegistry.ENABLED:
121 | case FieldsRegistry.DEFAULT_KEY:
122 | return true;
123 | case FieldsRegistry.KEY_EQUIVALENT:
124 | case FieldsRegistry.ON_SELECT:
125 | return null;
126 | case FieldsRegistry.LABEL:
127 | return ' ';
128 | case FieldsRegistry.MNEMONIC_INDEX:
129 | return -1;
130 | case FieldsRegistry.TYPE:
131 | return FieldsRegistry.REGULAR;
132 | case FieldsRegistry.CMD_KEY:
133 | case FieldsRegistry.CTRL_KEY:
134 | default:
135 | return null;
136 | }
137 | }
138 |
139 | }
140 | FieldsRegistry.ALT_KEY = 'altKey';
141 | FieldsRegistry.CMD_KEY = 'cmdKey';
142 | FieldsRegistry.CTRL_KEY = 'ctrlKey';
143 | FieldsRegistry.ENABLED = 'enabled';
144 | FieldsRegistry.KEY_EQUIVALENT = 'keyEquivalent';
145 | FieldsRegistry.LABEL = 'label';
146 | FieldsRegistry.MNEMONIC_INDEX = 'mnemonicIndex';
147 | FieldsRegistry.SHIFT_KEY = 'shiftKey';
148 | FieldsRegistry.TOGGLED = 'toggled';
149 | FieldsRegistry.TYPE = 'type';
150 | FieldsRegistry.ON_SELECT = 'onSelect';
151 | FieldsRegistry.DEFAULT_KEY = 'defaultKeyEquivalentModifiers';
152 | FieldsRegistry.SEPARATOR = 'separator';
153 | FieldsRegistry.CHECK = 'check';
154 | FieldsRegistry.REGULAR = 'regular';
155 |
156 | /**
157 | * CLASS Menu
158 | * Description
159 | * Loads a user menu defined as XML or JSON, and sets it as one of the
160 | * supported menu types.
161 | * @class
162 | * @author ciacob
163 | */
164 | function Menu() {
165 |
166 | var buildMenu = function (source, type) {
167 | var b = new Builder();
168 | b.loadData (source, type);
169 | return b.build();
170 | }
171 |
172 | var attachMenu = function (menu, type, target, icons) {
173 | var s = new Shell();
174 | s.link(menu, type, target, icons);
175 | }
176 |
177 | /**
178 | * Load a menu defined in XML format.
179 | * @param source
180 | * An object containing XML menu(s) to be loaded for various OS-es.
181 | * @return
182 | * A NativeMenu object built from the given XML source.
183 | */
184 | this.createFromXML = function ( source ) {
185 | return buildMenu ( source, Builder.XML );
186 | }
187 |
188 | /**
189 | * Same as air.ui.Menu.fromXML, except it handles JSON data.
190 | */
191 | this.createFromJSON = function ( source ) {
192 | return buildMenu ( source, Builder.JSON );
193 | }
194 |
195 | /**
196 | * - on Windows: sets the given nativeMenu object as the NativeWindow's
197 | * menu;
198 | * - on Mac: inserts the items of the given nativeMenu object between
199 | * the 'Edit' and 'Window' default menus;
200 | * @param nativeMenu
201 | * A NativeMenu returned by one of the air.ui.Menu.from...
202 | * functions.
203 | * @param overwrite
204 | * A boolean that will change the behavior on Mac. If true, the
205 | * default menus will be replaced entirely by the given nativeMenu
206 | */
207 | this.setAsMenu = function ( nativeMenu, overwrite ) {
208 | if (!arguments.length) {
209 | throw (new Error(
210 | "No argument given for the 'setAsMenu()' method."
211 | ));
212 | }
213 | var style = overwrite? Shell.MENU | Shell.OVERWRITE : Shell.MENU;
214 | attachMenu (nativeMenu, style);
215 | }
216 |
217 | /**
218 | * Displays the given menu as a contextual menu when the user right
219 | * clicks a certain DOM element.
220 | * @param nativeMenu
221 | * A NativeMenu returned by one of the air.ui.Menu.from...
222 | * functions.
223 | * @param domElement
224 | * The DOM Element to link with the given nativeMenu. The
225 | * contextual menu will only show when the user right clicks over
226 | * domElement. This attribute is optional. If missing, the context
227 | * menu will display on every right-click over the application.
228 | */
229 | this.setAsContextMenu = function ( nativeMenu, domElement ) {
230 | if (!arguments.length) {
231 | throw (new Error(
232 | "No argument given for the 'setAsContextMenu()' method."
233 | ));
234 | }
235 | if (arguments.length < 2) { domElement = Shell.UNSPECIFIED };
236 | attachMenu (nativeMenu, Shell.CONTEXT, domElement);
237 | }
238 |
239 | /**
240 | * Sets the given nativeMenu as the
241 | * ''NativeApplication.nativeApplication.icon.menu'' property.
242 | * @param nativeMenu
243 | * A NativeMenu returned by one of the air.ui.Menu.from...
244 | * functions.
245 | * @param icons
246 | * An array holding icon file paths or bitmap data objects.
247 | * If specified, these will be used as the application's
248 | * tray/dock icons.
249 | * @throws
250 | * If no bitmap data was set for the ''icon'' object and no default
251 | * icons are specified in the application descriptor.
252 | */
253 | this.setAsIconMenu = function ( nativeMenu, icons ) {
254 | if (!arguments.length) {
255 | throw (new Error(
256 | "No argument given for the 'setAsIconMenu()' method."
257 | ));
258 | }
259 | attachMenu (nativeMenu, Shell.ICON, null, icons);
260 | }
261 |
262 | }
263 |
264 | /**
265 | * CLASS DataSource
266 | * @public
267 | * @abstract
268 | */
269 | function DataSource() {
270 | var _this = this;
271 |
272 | var legalExtensions = ['xml', 'js'];
273 |
274 | var rSeed = null;
275 |
276 | var DATA_OBJECT = 1;
277 | var INLINE_STRING = 2;
278 | var FILE_PATH = 3;
279 | var FILE_OBJECT = 4;
280 | var ILLEGAL_TYPE = 5;
281 |
282 | function getFileContent (file) {
283 | var ret = '';
284 | var fileStream = new FileStream();
285 | fileStream.open(file, FileMode.READ);
286 | try {
287 | ret = fileStream.readUTFBytes(file.size);
288 | } catch(e) {
289 | throw(
290 | new Error(["Error\n", "ID: ", e.errorID, "\n", "Message: ",
291 | e.message, "\n"].join(''))
292 | );
293 | }
294 | fileStream.close();
295 | return ret;
296 | }
297 |
298 | function checkExtension (url, whiteList) {
299 | var match = url.match(/\.([^\.]*)$/);
300 | var extension = match? match[1] : null;
301 | for(var i=0; i
0);
467 | if (isError) {
468 | var errText = doc.getElementsByTagName(err)[0].innerText;
469 | var msg = errText.split(':');
470 | msg.length -= 1;
471 | msg = msg.join(':\n');
472 | throw (new Error ([
473 | 'Could not parse data: malformed XML file.', msg
474 | ].join('\n')));
475 | }
476 | that.document = doc;
477 | }
478 | }
479 |
480 | that.getRoot = function() {
481 | return that.document.documentElement;
482 | }
483 |
484 | that.getChildren = function (node) {
485 | var ret = [];
486 | if(node) {
487 | if(node.hasChildNodes && node.hasChildNodes()){
488 | var children = node.childNodes;
489 | for(var i=0; i 0) {
693 | var prev = iterable[i-1];
694 | prev['nextSibling'] = child;
695 | }
696 | }
697 | }
698 | }
699 | return ret;
700 | }
701 |
702 | that.getNextSibling = function (node) {
703 | if (node) {
704 | if(node !== that.getRoot()) {
705 | if (node['nextSibling']) { return node['nextSibling'] };
706 | }
707 | }
708 | return null;
709 | }
710 |
711 | that.getParent = function (node) {
712 | if (node) {
713 | if(node !== that.getRoot()) {
714 | if (node['parent']) { return node['parent'] };
715 | }
716 | }
717 | return null;
718 | }
719 |
720 | that.hasChildren = function (node) {
721 | if (node) {
722 | var iterable = (node === that.getRoot())? node:
723 | (node ['items'])? node ['items']: null;
724 | if (iterable) {
725 | return iterable.length && iterable.length > 0;
726 | }
727 | return false;
728 | }
729 | return false;
730 | }
731 |
732 | that.addChildAt = function (node, newChild, index) {
733 | if (node && newChild) {
734 | var children = that.getChildren (node) || (function() {
735 | node['items'] = [];
736 | return node['items'];
737 | })();
738 | index = Math.min(Math.max(0, index), children.length);
739 | children.splice (index, 0, newChild);
740 | if (index > 0) {
741 | children [index-1]['nextSibling'] = children [index]
742 | };
743 | if (index < children.length-1) {
744 | children[index]['nextSibling'] = children [index]+1
745 | };
746 | node['items'] = children;
747 | }
748 | }
749 |
750 | that.removeChildAt = function (node, index) {
751 | if (node) {
752 | var children = that.getChildren (node) || (function() {
753 | node['items'] = [];
754 | return node['items'];
755 | })();
756 | index = Math.min(Math.max(0, index), children.length);
757 | var removed = children [index];
758 | children.splice (index, 1);
759 | if(index > 0 && index < children.length) {
760 | children [index-1]['nextSibling'] = children [index];
761 | }
762 | node['items'] = children;
763 | return removed;
764 | }
765 | return null;
766 | }
767 |
768 | that.createNode = function (properties) {
769 | var node = {};
770 | for (var p in properties) {
771 | that.setProperty (node, p, properties[p])
772 | };
773 | if (that.getProperty (node, 'id') == null) {
774 | that.setProperty (node, 'id', that.generateUID());
775 | }
776 | return node;
777 | }
778 |
779 | that.getProperty = function (node, propName) {
780 | if (node) { return registry.proof(propName, node[propName]) };
781 | return null;
782 | }
783 |
784 | that.setProperty = function (node, propName, propValue) {
785 | if (node) {
786 | node[propName] = registry.proof(propName, propValue);
787 | }
788 | }
789 |
790 | this.$JSONDataSource.apply (this, arguments);
791 | }
792 |
793 | /**
794 | * CLASS Builder
795 | * @private
796 | * @class
797 | */
798 | function Builder() {
799 |
800 | var ds, root = null;
801 |
802 | function createDataSource (source, type) {
803 | var ret = null;
804 | if (type == Builder.XML) { ret = new XMLDataSource ( source ) };
805 | if (type == Builder.JSON) { ret = new JSONDataSource( source )};
806 | return ret;
807 | }
808 |
809 | function buildMenu() {
810 | var w = new Walker(ds, buildItem);
811 | w.walk ();
812 | }
813 |
814 | function buildItem (item) {
815 |
816 | // Get & parse info about the item to be built:
817 | var summary = ds.getSummary (item);
818 | var isFirstLevel = (!ds.getParent(item));
819 | var isItemDisabled = (!summary[FieldsRegistry.ENABLED]);
820 | var hasChildren = ds.hasChildren(item);
821 | var isItemSeparator = (summary [FieldsRegistry.TYPE] ==
822 | FieldsRegistry.SEPARATOR);
823 | var isItemAToggle = (summary [FieldsRegistry.TYPE] ==
824 | FieldsRegistry.CHECK);
825 |
826 | // Build the NativeMenuItem to represent this item:
827 | var ret = parseLabelForMnemonic (summary [FieldsRegistry.LABEL]);
828 | var nmi = new NativeMenuItem ( ret[0], isItemSeparator );
829 |
830 |
831 | // Attach features for this item:
832 | var parsedMnemonicIndex = ret[1];
833 | if (parsedMnemonicIndex >= 0) {
834 | summary [FieldsRegistry.MNEMONIC_INDEX] = parsedMnemonicIndex;
835 | };
836 | var mnemonicIndex = summary [FieldsRegistry.MNEMONIC_INDEX];
837 | if (mnemonicIndex != -1) { nmi.mnemonicIndex = mnemonicIndex };
838 | if (isItemAToggle) {
839 | var toggler = function (event) {
840 | var val = !ds.getProperty (item,
841 | FieldsRegistry.TOGGLED);
842 | ds.setProperty (item, FieldsRegistry.TOGGLED, val);
843 | nmi.checked = val;
844 | }
845 | nmi.addEventListener (SELECT, toggler);
846 | nmi.checked = summary [FieldsRegistry.TOGGLED];
847 | }
848 | if (summary [FieldsRegistry.ON_SELECT]) {
849 | var f = function (event) {
850 | var target = event.target;
851 | summary [FieldsRegistry.ON_SELECT].call (
852 | window, event, summary
853 | );
854 | }
855 | nmi.addEventListener (SELECT, f);
856 | }
857 | attachKeyEquivalentHandler (nmi, summary);
858 | if ( isItemDisabled ) { nmi.enabled = false };
859 |
860 | // Attach our item within the menu structure:
861 | item['_widget_'] = nmi;
862 | if (hasChildren) { nmi.submenu = new NativeMenu() };
863 | var data = nmi.data || (nmi.data = {});
864 | data['item'] = item;
865 | var parMnu = null;
866 | var parItem = ds.getParent(item);
867 | if (parItem) {
868 | var parWidget = parItem['_widget_'];
869 | parMnu = parWidget.submenu;
870 | if (!parMnu) { return };
871 | } else {
872 | parMnu = root || ( root = new NativeMenu() );
873 | }
874 | parMnu.addItem(nmi);
875 | }
876 |
877 | function qReplace (tStr, searchStr , replaceStr) {
878 | var index;
879 | while ((index = tStr.indexOf (searchStr)) >= 0) {
880 | var arr = tStr.split('');
881 | arr.splice (index, searchStr.length,
882 | replaceStr);
883 | tStr = arr.join('');
884 | }
885 | return tStr;
886 | }
887 |
888 | function parseLabelForMnemonic (label) {
889 | var l = label;
890 | if (l) {
891 | l = qReplace(l, '__', '[UNDERSCORE]');
892 | l = qReplace(l, '_', '[MNEMONIC]');
893 | l = qReplace(l, '[UNDERSCORE]', '_');
894 | var mi = l.indexOf ('[MNEMONIC]');
895 | l = qReplace(l, '[MNEMONIC]', '');
896 | if (mi >= 0) { return [l, mi] };
897 | }
898 | return [l, -1];
899 | }
900 |
901 | function attachKeyEquivalentHandler (nativeItem, summary) {
902 | if (summary[FieldsRegistry.DEFAULT_KEY]) {
903 | // Linux implementation needs this check:
904 | var def = nativeItem.keyEquivalentModifiers &&
905 | nativeItem.keyEquivalentModifiers[0]?
906 | nativeItem.keyEquivalentModifiers[0] : null;
907 | if (def && typeof def != "undefined") {
908 | if (summary[FieldsRegistry.CTRL_KEY] === false) {
909 | if (def == KEYBOARD.CONTROL) { def = null };
910 | }
911 | if (summary[FieldsRegistry.CMD_KEY] === false) {
912 | if (def == KEYBOARD.COMMAND) { def = null };
913 | }
914 | }
915 | }
916 | var key;
917 | if (key = summary[FieldsRegistry.KEY_EQUIVALENT]) {
918 | var mods = [];
919 | if (def) { mods.push(def) };
920 | if (summary[FieldsRegistry.CTRL_KEY]) {
921 | mods.push (KEYBOARD.CONTROL);
922 | }
923 | if (summary[FieldsRegistry.CMD_KEY]) {
924 | mods.push (KEYBOARD.COMMAND);
925 | }
926 | if (summary[FieldsRegistry.ALT_KEY]) {
927 | mods.push (KEYBOARD.ALTERNATE);
928 | }
929 | key = (summary[FieldsRegistry.SHIFT_KEY])?
930 | key.toUpperCase() : key.toLowerCase();
931 | nativeItem.keyEquivalent = key;
932 | nativeItem.keyEquivalentModifiers = mods;
933 | }
934 | }
935 |
936 | this.loadData = function (source, type) {
937 | if (source) { ds = createDataSource (source, type) }
938 | else { throw new Error([
939 | "Cannot create menu. ",
940 | "Provided data source is null"
941 | ].join('')) }
942 | }
943 |
944 | this.build = function() {
945 | if(ds) {buildMenu()};
946 | return root;
947 | }
948 | }
949 | Builder.XML = 0x10;
950 | Builder.JSON = 0x20;
951 |
952 | /**
953 | * CLASS NIConnector
954 | * @private
955 | * @class
956 | */
957 | function NIConnector () {
958 |
959 | var that = this;
960 |
961 | var LAST = 0x1;
962 | var BEFORE_LAST = 0x2;
963 |
964 | var ni;
965 | var nativeMenu;
966 | var overwrite;
967 | var allSet;
968 | var isMac;
969 |
970 | function $NIConnector (oNi, oNewNativeMenu, bOverwriteExisting) {
971 | if (oNi && oNewNativeMenu) {
972 | allSet = true;
973 | ni = oNi;
974 | nativeMenu = oNewNativeMenu;
975 | overwrite = bOverwriteExisting;
976 | isMac = currentOS.indexOf('Mac') >= 0;
977 | if (typeof NIConnector.defaultMenu == "undefined") {
978 | var app = NativeApplication.nativeApplication;
979 | NIConnector.defaultMenu = app.menu;
980 | }
981 | }
982 | }
983 |
984 |
985 | function isDefaultApplicationMenu () {
986 | var app = NativeApplication.nativeApplication;
987 | return (app.menu == NIConnector.defaultMenu);
988 | }
989 |
990 | function purge () {
991 | while (ni.menu.numItems) { ni.menu.removeItemAt (0) }
992 | }
993 |
994 | function add ( style ) {
995 | if (!ni.menu) {
996 | replace();
997 | return;
998 | }
999 | var addFunction = (style == LAST)?
1000 | ni.menu.addItem : function (item) {
1001 | ni.menu.addItemAt (item, ni.menu.numItems-1);
1002 | }
1003 | var item;
1004 | while (nativeMenu.numItems && (item = nativeMenu.removeItemAt(0))) {
1005 | if(isMac && !item.submenu) { continue };
1006 | addFunction.call (that, item);
1007 | }
1008 | }
1009 |
1010 | function replace () {
1011 | ni.menu = nativeMenu;
1012 | }
1013 |
1014 | this.doConnect = function () {
1015 | if (allSet) {
1016 | if (overwrite) {
1017 | if (isMac) {
1018 | purge ();
1019 | add (LAST);
1020 | }
1021 | else { replace() };
1022 | }
1023 | else {
1024 | if (isMac) {
1025 | if (isDefaultApplicationMenu()) { add (BEFORE_LAST) }
1026 | else { add (LAST) };
1027 | } else { add (LAST) };
1028 | }
1029 | }
1030 | }
1031 |
1032 | $NIConnector.apply (this, arguments);
1033 | }
1034 | NIConnector.defaultMenu;
1035 |
1036 |
1037 | /**
1038 | * CLASS Shell
1039 | * @private
1040 | * @class
1041 | */
1042 | function Shell() {
1043 |
1044 | function $Shell(){}
1045 |
1046 | var that = this;
1047 |
1048 | var CONTEXT_MENU = 'contextmenu';
1049 | var app = NativeApplication.nativeApplication;
1050 |
1051 | var uidSeed = 0;
1052 | var DEFAULT_ID = "DEFAULT_ID";
1053 |
1054 | var isMac = currentOS.indexOf('Mac') >= 0;
1055 |
1056 | var isBitmapData = function(obj) {
1057 | return obj &&
1058 | obj.constructor &&
1059 | obj.constructor === (new BitmapData (1, 1));
1060 | }
1061 |
1062 | var resolveDomEl = function (obj) {
1063 | var ret = null;
1064 | if (obj) {
1065 | if (typeof obj == 'object' && obj.nodeType == 1) { ret = obj };
1066 | if (typeof obj == 'string') {
1067 | var el;
1068 | if (el = document.getElementById(obj)) { ret = el };
1069 | }
1070 | }
1071 | return ret;
1072 | }
1073 |
1074 | var checkUserIcon = function (obj) {
1075 | var icon = app.icon;
1076 | return icon.bitmaps.length > 0;
1077 | }
1078 |
1079 | var getIcons = function (userIcons) {
1080 | var ret = [];
1081 | var entries = [];
1082 | if (userIcons && userIcons.length) {
1083 | entries = userIcons;
1084 | } else {
1085 | var p = new DOMParser();
1086 | var descr = String(app.applicationDescriptor);
1087 | var descrDoc = p.parseFromString(descr, "text/xml");
1088 | var appEl = descrDoc.getElementsByTagName('application')[0];
1089 | var iconEl = appEl.getElementsByTagName('icon')[0];
1090 | if (iconEl) {
1091 | var iconEntries = iconEl.getElementsByTagName('*');
1092 | for (var i=0; i 0;
1188 | if (!haveDefaultIcons) {
1189 | if (!isMac) {
1190 | throw (new Error([
1191 | "Cannot set the icon menu.",
1192 | "On operating systems that do not provide a default",
1193 | "tray icon, you must specify one before calling",
1194 | "setAsIconMenu().",
1195 | "Alternativelly, you can specify default icons in the",
1196 | "application's XML descriptor."
1197 | ].join('\n')));
1198 | }
1199 | }
1200 | var doAttach = function(bitmaps){
1201 | setBitmaps (bitmaps);
1202 | app.icon.menu = menu;
1203 | }
1204 | if (defaultIcons) {
1205 | loadDefaultBitmaps(defaultIcons, doAttach);
1206 | }
1207 | }
1208 | }
1209 |
1210 | this.link = function (oMenu, style, target, icons) {
1211 | if (Shell.MENU & style) {
1212 | var bOverwrite = style & Shell.OVERWRITE;
1213 | return linkMenu(oMenu, bOverwrite);
1214 | }
1215 | if (Shell.CONTEXT & style) {return linkContextMenu(oMenu, target)};
1216 | if (Shell.ICON & style) { return linkIconMenu(oMenu, icons) };
1217 | }
1218 |
1219 | $Shell.apply (this, arguments);
1220 | }
1221 | Shell.UNSPECIFIED = -1;
1222 | Shell.MENU = 1;
1223 | Shell.CONTEXT = 2;
1224 | Shell.ICON = 4;
1225 | Shell.OVERWRITE = 8;
1226 |
1227 | Shell.resolve = function (pathOrFile) {
1228 | var file = null;
1229 | try {
1230 | file = File(pathOrFile);
1231 | } catch(e) {
1232 | file = File.applicationDirectory.resolvePath (pathOrFile);
1233 | if (!file.exists) {
1234 | try {
1235 | file = new File (pathOrFile);
1236 | } catch(e) {
1237 | // must be a path, both 'relative' AND 'non-existing'.
1238 | }
1239 | }
1240 | }
1241 | return file;
1242 | }
1243 |
1244 | /**
1245 | * CLASS Walker
1246 | * @class
1247 | * @private
1248 | */
1249 | function Walker() {
1250 | var t, c, currentItem, allSet, item;
1251 |
1252 | function $Walker (target, callback) {
1253 | if (target && target instanceof DataSource) {
1254 | t = target;
1255 | }
1256 | if (callback && typeof callback == "function") {
1257 | c = callback;
1258 | }
1259 | if (t && c) { allSet = true };
1260 | }
1261 |
1262 | function getNearestAncestorSibling(node) {
1263 | while (node) {
1264 | node = t.getParent(node);
1265 | if(node) {
1266 | var s = t.getNextSibling(node);
1267 | if (s) { return s };
1268 | }
1269 | }
1270 | return null;
1271 | }
1272 |
1273 | function getFirstChildOfRoot() {
1274 | return t.getChildren(t.getRoot())[0] || null;
1275 | }
1276 |
1277 | function doTraverse() {
1278 | if (allSet) {
1279 | while (item = getNext()) { c.call (window, item) };
1280 |
1281 | } else {
1282 | throw (new Error([
1283 | 'Cannot traverse data tree.',
1284 | 'Please check the arguments you provided to the Walker class.',
1285 | ].join('\n')));
1286 | }
1287 | }
1288 |
1289 | function getNext() {
1290 | if (currentItem === null) { return null };
1291 |
1292 | if (typeof currentItem == 'undefined') {
1293 | currentItem = getFirstChildOfRoot();
1294 | }
1295 |
1296 | if (t.hasChildren(currentItem)) {
1297 | var parentNode = currentItem;
1298 | currentItem = t.getChildren(currentItem)[0];
1299 | return parentNode;
1300 | }
1301 |
1302 | if(t.getNextSibling(currentItem)) {
1303 | var current = currentItem;
1304 | currentItem = t.getNextSibling(currentItem);
1305 | return current;
1306 | }
1307 |
1308 | var ci = currentItem;
1309 | currentItem = getNearestAncestorSibling(currentItem);
1310 | return ci;
1311 | }
1312 |
1313 | this.walk = function (callback) {
1314 | doTraverse();
1315 | if (typeof callback == "function") { callback.call (this) };
1316 | }
1317 |
1318 | $Walker.apply (this, arguments);
1319 | }
1320 |
1321 | constructor.apply (this, arguments);
1322 | })();
--------------------------------------------------------------------------------