4f4f2648f7888768b6002548c8cc8109e5942b57.svn-base 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. Ext.BLANK_IMAGE_URL = 'resources/s.gif';
  2. Docs = {};
  3. ApiPanel = function() {
  4. ApiPanel.superclass.constructor.call(this, {
  5. id : 'api-tree',
  6. region : 'west',
  7. split : true,
  8. width : 280,
  9. minSize : 175,
  10. maxSize : 500,
  11. collapsible : true,
  12. margins : '0 0 5 5',
  13. cmargins : '0 0 0 0',
  14. rootVisible : false,
  15. lines : false,
  16. autoScroll : true,
  17. animCollapse : false,
  18. animate : false,
  19. collapseMode : 'mini',
  20. loader : new Ext.tree.TreeLoader({
  21. preloadChildren : true,
  22. clearOnLoad : false
  23. }),
  24. root : new Ext.tree.AsyncTreeNode({
  25. text : 'Ext JS',
  26. id : 'root',
  27. expanded : true,
  28. children : [Docs.classData]
  29. }),
  30. collapseFirst : false
  31. });
  32. // no longer needed!
  33. // new Ext.tree.TreeSorter(this, {folderSort:true,leafAttr:'isClass'});
  34. this.getSelectionModel().on('beforeselect', function(sm, node) {
  35. return node.isLeaf();
  36. });
  37. };
  38. Ext.extend(ApiPanel, Ext.tree.TreePanel, {
  39. selectClass : function(cls) {
  40. if (cls) {
  41. var parts = cls.split('.');
  42. var last = parts.length - 1;
  43. for (var i = 0; i < last; i++) { // things get nasty -
  44. // static classes can
  45. // have .
  46. var p = parts[i];
  47. var fc = p.charAt(0);
  48. var staticCls = fc.toUpperCase() == fc;
  49. if (p == 'Ext' || !staticCls) {
  50. parts[i] = 'pkg-' + p;
  51. } else if (staticCls) {
  52. --last;
  53. parts.splice(i, 1);
  54. }
  55. }
  56. parts[last] = cls;
  57. this.selectPath('/root/apidocs/' + parts.join('/'));
  58. }
  59. }
  60. });
  61. DocPanel = Ext.extend(Ext.Panel, {
  62. closable : true,
  63. autoScroll : true,
  64. initComponent : function() {
  65. var ps = this.cclass.split('.');
  66. this.title = ps[ps.length - 1];
  67. DocPanel.superclass.initComponent.call(this);
  68. },
  69. scrollToMember : function(member) {
  70. var el = Ext.fly(this.cclass + '-' + member);
  71. if (el) {
  72. var top = (el.getOffsetsTo(this.body)[1]) + this.body.dom.scrollTop;
  73. this.body.scrollTo('top', top - 25, {
  74. duration : .75,
  75. callback : this.hlMember.createDelegate(this, [member])
  76. });
  77. }
  78. },
  79. scrollToSection : function(id) {
  80. var el = Ext.getDom(id);
  81. if (el) {
  82. var top = (Ext.fly(el).getOffsetsTo(this.body)[1])
  83. + this.body.dom.scrollTop;
  84. this.body.scrollTo('top', top - 25, {
  85. duration : .5,
  86. callback : function() {
  87. Ext.fly(el).next('h2').pause(.2).highlight(
  88. '#8DB2E3', {
  89. attr : 'color'
  90. });
  91. }
  92. });
  93. }
  94. },
  95. hlMember : function(member) {
  96. var el = Ext.fly(this.cclass + '-' + member);
  97. if (el) {
  98. el.up('tr').highlight('#cadaf9');
  99. }
  100. }
  101. });
  102. MainPanel = function() {
  103. this.searchStore = new Ext.data.Store({
  104. proxy : new Ext.data.ScriptTagProxy({
  105. url : 'http://extjs.com/playpen/api.php'
  106. }),
  107. reader : new Ext.data.JsonReader({
  108. root : 'data'
  109. }, ['cls', 'member', 'type', 'doc']),
  110. baseParams : {},
  111. listeners : {
  112. 'beforeload' : function() {
  113. this.baseParams.qt = Ext.getCmp('search-type')
  114. .getValue();
  115. }
  116. }
  117. });
  118. MainPanel.superclass.constructor.call(this, {
  119. id : 'doc-body',
  120. region : 'center',
  121. margins : '0 5 5 0',
  122. resizeTabs : true,
  123. minTabWidth : 135,
  124. tabWidth : 135,
  125. plugins : new Ext.ux.TabCloseMenu(),
  126. enableTabScroll : true,
  127. activeTab : 0,
  128. items : {
  129. id : 'welcome-panel',
  130. title : 'API Home',
  131. autoLoad : {
  132. url : 'welcome.html',
  133. callback : this.initSearch,
  134. scope : this
  135. },
  136. iconCls : 'icon-docs',
  137. autoScroll : true,
  138. tbar : ['Search: ', ' ', new Ext.ux.SelectBox({
  139. listClass : 'x-combo-list-small',
  140. width : 90,
  141. value : 'Starts with',
  142. id : 'search-type',
  143. store : new Ext.data.SimpleStore({
  144. fields : ['text'],
  145. expandData : true,
  146. data : ['Starts with', 'Ends with',
  147. 'Any match']
  148. }),
  149. displayField : 'text'
  150. }), ' ', new Ext.app.SearchField({
  151. width : 240,
  152. store : this.searchStore,
  153. paramName : 'q'
  154. })]
  155. }
  156. });
  157. };
  158. Ext.extend(MainPanel, Ext.TabPanel, {
  159. initEvents : function() {
  160. MainPanel.superclass.initEvents.call(this);
  161. this.body.on('click', this.onClick, this);
  162. },
  163. onClick : function(e, target) {
  164. if (target = e.getTarget('a:not(.exi)', 3)) {
  165. var cls = Ext.fly(target).getAttributeNS('ext', 'cls');
  166. e.stopEvent();
  167. if (cls) {
  168. var member = Ext.fly(target).getAttributeNS('ext', 'member');
  169. this.loadClass(target.href, cls, member);
  170. } else if (target.className == 'inner-link') {
  171. this.getActiveTab().scrollToSection(target.href.split('#')[1]);
  172. } else {
  173. window.open(target.href);
  174. }
  175. } else if (target = e.getTarget('.micon', 2)) {
  176. e.stopEvent();
  177. var tr = Ext.fly(target.parentNode);
  178. if (tr.hasClass('expandable')) {
  179. tr.toggleClass('expanded');
  180. }
  181. }
  182. },
  183. loadClass : function(href, cls, member) {
  184. var id = 'docs-' + cls;
  185. var tab = this.getComponent(id);
  186. if (tab) {
  187. this.setActiveTab(tab);
  188. if (member) {
  189. tab.scrollToMember(member);
  190. }
  191. } else {
  192. var autoLoad = {
  193. url : href
  194. };
  195. if (member) {
  196. autoLoad.callback = function() {
  197. Ext.getCmp(id).scrollToMember(member);
  198. }
  199. }
  200. var p = this.add(new DocPanel({
  201. id : id,
  202. cclass : cls,
  203. autoLoad : autoLoad,
  204. iconCls : Docs.icons[cls]
  205. }));
  206. this.setActiveTab(p);
  207. }
  208. },
  209. initSearch : function() {
  210. // Custom rendering Template for the View
  211. var resultTpl = new Ext.XTemplate(
  212. '<tpl for=".">',
  213. '<div class="search-item">',
  214. '<a class="member" ext:cls="{cls}" ext:member="{member}" href="output/{cls}.html">',
  215. '<img src="../resources/images/default/s.gif" class="item-icon icon-{type}"/>{member}',
  216. '</a> ',
  217. '<a class="cls" ext:cls="{cls}" href="output/{cls}.html">{cls}</a>',
  218. '<p>{doc}</p>', '</div></tpl>');
  219. var p = new Ext.DataView({
  220. applyTo : 'search',
  221. tpl : resultTpl,
  222. loadingText : 'Searching...',
  223. store : this.searchStore,
  224. itemSelector : 'div.search-item',
  225. emptyText : '<h3>Use the search field above to search the Ext API for classes, properties, config options, methods and events.</h3>'
  226. });
  227. },
  228. doSearch : function(e) {
  229. var k = e.getKey();
  230. if (!e.isSpecialKey()) {
  231. var text = e.target.value;
  232. if (!text) {
  233. this.searchStore.baseParams.q = '';
  234. this.searchStore.removeAll();
  235. } else {
  236. this.searchStore.baseParams.q = text;
  237. this.searchStore.reload();
  238. }
  239. }
  240. }
  241. });
  242. Ext.onReady(function() {
  243. Ext.QuickTips.init();
  244. var api = new ApiPanel();
  245. var mainPanel = new MainPanel();
  246. api.on('click', function(node, e) {
  247. if (node.isLeaf()) {
  248. e.stopEvent();
  249. mainPanel.loadClass(node.attributes.href, node.id);
  250. }
  251. });
  252. mainPanel.on('tabchange', function(tp, tab) {
  253. api.selectClass(tab.cclass);
  254. });
  255. var hd = new Ext.Panel({
  256. border : false,
  257. layout : 'anchor',
  258. region : 'north',
  259. cls : 'docs-header',
  260. height : 60,
  261. items : [{
  262. xtype : 'box',
  263. el : 'header',
  264. border : false,
  265. anchor : 'none -25'
  266. }, new Ext.Toolbar({
  267. cls : 'top-toolbar',
  268. items : [' ', new Ext.form.TextField({
  269. width : 200,
  270. emptyText : 'Find a Class',
  271. listeners : {
  272. render : function(f) {
  273. f.el.on('keydown',
  274. filterTree, f,
  275. {
  276. buffer : 350
  277. });
  278. }
  279. }
  280. }), ' ', ' ', {
  281. iconCls : 'icon-expand-all',
  282. tooltip : 'Expand All',
  283. handler : function() {
  284. api.root.expand(true);
  285. }
  286. }, '-', {
  287. iconCls : 'icon-collapse-all',
  288. tooltip : 'Collapse All',
  289. handler : function() {
  290. api.root.collapse(true);
  291. }
  292. }, '->', {
  293. tooltip : 'Hide Inherited Members',
  294. iconCls : 'icon-hide-inherited',
  295. enableToggle : true,
  296. toggleHandler : function(b, pressed) {
  297. mainPanel[pressed
  298. ? 'addClass'
  299. : 'removeClass']('hide-inherited');
  300. }
  301. }, '-', {
  302. tooltip : 'Expand All Members',
  303. iconCls : 'icon-expand-members',
  304. enableToggle : true,
  305. toggleHandler : function(b, pressed) {
  306. mainPanel[pressed
  307. ? 'addClass'
  308. : 'removeClass']('full-details');
  309. }
  310. }]
  311. })]
  312. })
  313. var viewport = new Ext.Viewport({
  314. layout : 'border',
  315. items : [hd, api, mainPanel]
  316. });
  317. api.expandPath('/root/apidocs');
  318. // allow for link in
  319. var page = window.location.href.split('?')[1];
  320. if (page) {
  321. var ps = Ext.urlDecode(page);
  322. var cls = ps['class'];
  323. mainPanel.loadClass('output/' + cls + '.html', cls, ps.member);
  324. }
  325. viewport.doLayout();
  326. setTimeout(function() {
  327. Ext.get('loading').remove();
  328. Ext.get('loading-mask').fadeOut({
  329. remove : true
  330. });
  331. }, 250);
  332. var filter = new Ext.tree.TreeFilter(api, {
  333. clearBlank : true,
  334. autoClear : true
  335. });
  336. var hiddenPkgs = [];
  337. function filterTree(e) {
  338. var text = e.target.value;
  339. Ext.each(hiddenPkgs, function(n) {
  340. n.ui.show();
  341. });
  342. if (!text) {
  343. filter.clear();
  344. return;
  345. }
  346. api.expandAll();
  347. var re = new RegExp('^' + Ext.escapeRe(text), 'i');
  348. filter.filterBy(function(n) {
  349. return !n.attributes.isClass || re.test(n.text);
  350. });
  351. // hide empty packages that weren't filtered
  352. hiddenPkgs = [];
  353. api.root.cascade(function(n) {
  354. if (!n.attributes.isClass && n.ui.ctNode.offsetHeight < 3) {
  355. n.ui.hide();
  356. hiddenPkgs.push(n);
  357. }
  358. });
  359. }
  360. });
  361. Ext.app.SearchField = Ext.extend(Ext.form.TwinTriggerField, {
  362. initComponent : function() {
  363. if (!this.store.baseParams) {
  364. this.store.baseParams = {};
  365. }
  366. Ext.app.SearchField.superclass.initComponent.call(this);
  367. this.on('specialkey', function(f, e) {
  368. if (e.getKey() == e.ENTER) {
  369. this.onTrigger2Click();
  370. }
  371. }, this);
  372. },
  373. validationEvent : false,
  374. validateOnBlur : false,
  375. trigger1Class : 'x-form-clear-trigger',
  376. trigger2Class : 'x-form-search-trigger',
  377. hideTrigger1 : true,
  378. width : 180,
  379. hasSearch : false,
  380. paramName : 'query',
  381. onTrigger1Click : function() {
  382. if (this.hasSearch) {
  383. this.store.baseParams[this.paramName] = '';
  384. this.store.removeAll();
  385. this.el.dom.value = '';
  386. this.triggers[0].hide();
  387. this.hasSearch = false;
  388. this.focus();
  389. }
  390. },
  391. onTrigger2Click : function() {
  392. var v = this.getRawValue();
  393. if (v.length < 1) {
  394. this.onTrigger1Click();
  395. return;
  396. }
  397. if (v.length < 2) {
  398. Ext.Msg
  399. .alert('Invalid Search',
  400. 'You must enter a minimum of 2 characters to search the API');
  401. return;
  402. }
  403. this.store.baseParams[this.paramName] = v;
  404. var o = {
  405. start : 0
  406. };
  407. this.store.reload({
  408. params : o
  409. });
  410. this.hasSearch = true;
  411. this.triggers[0].show();
  412. this.focus();
  413. }
  414. });
  415. /**
  416. * Makes a ComboBox more closely mimic an HTML SELECT. Supports clicking and
  417. * dragging through the list, with item selection occurring when the mouse
  418. * button is released. When used will automatically set {@link #editable} to
  419. * false and call {@link Ext.Element#unselectable} on inner elements.
  420. * Re-enabling editable after calling this will NOT work.
  421. *
  422. * @author Corey Gilmore http://extjs.com/forum/showthread.php?t=6392
  423. *
  424. * @history 2007-07-08 jvs Slight mods for Ext 2.0
  425. */
  426. Ext.ux.SelectBox = function(config) {
  427. this.searchResetDelay = 1000;
  428. config = config || {};
  429. config = Ext.apply(config || {}, {
  430. editable : false,
  431. forceSelection : true,
  432. rowHeight : false,
  433. lastSearchTerm : false,
  434. triggerAction : 'all',
  435. mode : 'local'
  436. });
  437. Ext.ux.SelectBox.superclass.constructor.apply(this, arguments);
  438. this.lastSelectedIndex = this.selectedIndex || 0;
  439. };
  440. Ext.extend(Ext.ux.SelectBox, Ext.form.ComboBox, {
  441. lazyInit : false,
  442. initEvents : function() {
  443. Ext.ux.SelectBox.superclass.initEvents.apply(this, arguments);
  444. // you need to use keypress to capture upper/lower case and
  445. // shift+key, but it doesn't work in IE
  446. this.el.on('keydown', this.keySearch, this, true);
  447. this.cshTask = new Ext.util.DelayedTask(
  448. this.clearSearchHistory, this);
  449. },
  450. keySearch : function(e, target, options) {
  451. var raw = e.getKey();
  452. var key = String.fromCharCode(raw);
  453. var startIndex = 0;
  454. if (!this.store.getCount()) {
  455. return;
  456. }
  457. switch (raw) {
  458. case Ext.EventObject.HOME :
  459. e.stopEvent();
  460. this.selectFirst();
  461. return;
  462. case Ext.EventObject.END :
  463. e.stopEvent();
  464. this.selectLast();
  465. return;
  466. case Ext.EventObject.PAGEDOWN :
  467. this.selectNextPage();
  468. e.stopEvent();
  469. return;
  470. case Ext.EventObject.PAGEUP :
  471. this.selectPrevPage();
  472. e.stopEvent();
  473. return;
  474. }
  475. // skip special keys other than the shift key
  476. if ((e.hasModifier() && !e.shiftKey) || e.isNavKeyPress()
  477. || e.isSpecialKey()) {
  478. return;
  479. }
  480. if (this.lastSearchTerm == key) {
  481. startIndex = this.lastSelectedIndex;
  482. }
  483. this.search(this.displayField, key, startIndex);
  484. this.cshTask.delay(this.searchResetDelay);
  485. },
  486. onRender : function(ct, position) {
  487. this.store.on('load', this.calcRowsPerPage, this);
  488. Ext.ux.SelectBox.superclass.onRender.apply(this, arguments);
  489. if (this.mode == 'local') {
  490. this.calcRowsPerPage();
  491. }
  492. },
  493. onSelect : function(record, index, skipCollapse) {
  494. if (this.fireEvent('beforeselect', this, record, index) !== false) {
  495. this.setValue(record.data[this.valueField
  496. || this.displayField]);
  497. if (!skipCollapse) {
  498. this.collapse();
  499. }
  500. this.lastSelectedIndex = index + 1;
  501. this.fireEvent('select', this, record, index);
  502. }
  503. },
  504. render : function(ct) {
  505. Ext.ux.SelectBox.superclass.render.apply(this, arguments);
  506. if (Ext.isSafari) {
  507. this.el.swallowEvent('mousedown', true);
  508. }
  509. this.el.unselectable();
  510. this.innerList.unselectable();
  511. this.trigger.unselectable();
  512. this.innerList.on('mouseup', function(e, target, options) {
  513. if (target.id && target.id == this.innerList.id) {
  514. return;
  515. }
  516. this.onViewClick();
  517. }, this);
  518. this.innerList.on('mouseover', function(e, target, options) {
  519. if (target.id && target.id == this.innerList.id) {
  520. return;
  521. }
  522. this.lastSelectedIndex = this.view
  523. .getSelectedIndexes()[0]
  524. + 1;
  525. this.cshTask.delay(this.searchResetDelay);
  526. }, this);
  527. this.trigger.un('click', this.onTriggerClick, this);
  528. this.trigger.on('mousedown', function(e, target, options) {
  529. e.preventDefault();
  530. this.onTriggerClick();
  531. }, this);
  532. this.on('collapse', function(e, target, options) {
  533. Ext.getDoc().un('mouseup', this.collapseIf, this);
  534. }, this, true);
  535. this.on('expand', function(e, target, options) {
  536. Ext.getDoc().on('mouseup', this.collapseIf, this);
  537. }, this, true);
  538. },
  539. clearSearchHistory : function() {
  540. this.lastSelectedIndex = 0;
  541. this.lastSearchTerm = false;
  542. },
  543. selectFirst : function() {
  544. this.focusAndSelect(this.store.data.first());
  545. },
  546. selectLast : function() {
  547. this.focusAndSelect(this.store.data.last());
  548. },
  549. selectPrevPage : function() {
  550. if (!this.rowHeight) {
  551. return;
  552. }
  553. var index = Math.max(this.selectedIndex - this.rowsPerPage, 0);
  554. this.focusAndSelect(this.store.getAt(index));
  555. },
  556. selectNextPage : function() {
  557. if (!this.rowHeight) {
  558. return;
  559. }
  560. var index = Math.min(this.selectedIndex + this.rowsPerPage,
  561. this.store.getCount() - 1);
  562. this.focusAndSelect(this.store.getAt(index));
  563. },
  564. search : function(field, value, startIndex) {
  565. field = field || this.displayField;
  566. this.lastSearchTerm = value;
  567. var index = this.store.find.apply(this.store, arguments);
  568. if (index !== -1) {
  569. this.focusAndSelect(index);
  570. }
  571. },
  572. focusAndSelect : function(record) {
  573. var index = typeof record === 'number' ? record : this.store
  574. .indexOf(record);
  575. this.select(index, this.isExpanded());
  576. this.onSelect(this.store.getAt(record), index, this
  577. .isExpanded());
  578. },
  579. calcRowsPerPage : function() {
  580. if (this.store.getCount()) {
  581. this.rowHeight = Ext.fly(this.view.getNode(0)).getHeight();
  582. this.rowsPerPage = this.maxHeight / this.rowHeight;
  583. } else {
  584. this.rowHeight = false;
  585. }
  586. }
  587. });
  588. Ext.Ajax.on('requestcomplete', function(ajax, xhr, o) {
  589. if (typeof urchinTracker == 'function' && o && o.url) {
  590. urchinTracker(o.url);
  591. }
  592. });