modx.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056
  1. Ext.namespace('MODx');
  2. Ext.apply(Ext,{
  3. isFirebug: (window.console && window.console.firebug)
  4. });
  5. /* work around IE9 createContextualFragment bug
  6. http://www.sencha.com/forum/showthread.php?125869-Menu-shadow-probolem-in-IE9
  7. */
  8. if ((typeof Range !== "undefined") && !Range.prototype.createContextualFragment)
  9. {
  10. Range.prototype.createContextualFragment = function(html)
  11. {
  12. var frag = document.createDocumentFragment(),
  13. div = document.createElement("div");
  14. frag.appendChild(div);
  15. div.outerHTML = html;
  16. return frag;
  17. };
  18. }
  19. /**
  20. * @class MODx
  21. * @extends Ext.Component
  22. * @param {Object} config An object of config properties
  23. * @xtype modx
  24. */
  25. MODx = function(config) {
  26. config = config || {};
  27. MODx.superclass.constructor.call(this,config);
  28. this.config = config;
  29. this.startup();
  30. };
  31. Ext.extend(MODx,Ext.Component,{
  32. config: {}
  33. ,util:{},window:{},panel:{},tree:{},form:{},grid:{},combo:{},toolbar:{},page:{},msg:{}
  34. ,expandHelp: true
  35. ,defaultState: []
  36. ,startup: function() {
  37. this.initQuickTips();
  38. this.request = this.getURLParameters();
  39. this.Ajax = this.load({ xtype: 'modx-ajax' });
  40. Ext.override(Ext.form.Field,{
  41. defaultAutoCreate: {tag: "input", type: "text", size: "20", autocomplete: "on", msgTarget: 'under' }
  42. });
  43. Ext.Ajax.on('requestexception',this.onAjaxException,this);
  44. Ext.menu.Menu.prototype.enableScrolling = false;
  45. this.addEvents({
  46. beforeClearCache: true
  47. ,beforeLogout: true
  48. ,beforeReleaseLocks: true
  49. ,beforeLoadPage: true
  50. ,afterClearCache: true
  51. ,afterLogout: true
  52. ,afterReleaseLocks: true
  53. ,ready: true
  54. });
  55. }
  56. /**
  57. * Add the given component to the modx-content container
  58. *
  59. * @param {String|Object} cmp Either a component xtype (string) or an object/configuration
  60. *
  61. * @return void
  62. */
  63. ,add: function(cmp) {
  64. if (typeof cmp === 'string') {
  65. cmp = { xtype: cmp }
  66. }
  67. var ctr = Ext.getCmp('modx-content');
  68. if (ctr) {
  69. ctr.removeAll();
  70. ctr.add(cmp);
  71. ctr.doLayout();
  72. }
  73. }
  74. ,load: function() {
  75. var a = arguments, l = a.length;
  76. var os = [];
  77. for(var i=0;i<l;i=i+1) {
  78. if (!a[i].xtype || a[i].xtype === '') {
  79. return false;
  80. }
  81. os.push(Ext.ComponentMgr.create(a[i]));
  82. }
  83. return (os.length === 1) ? os[0] : os;
  84. }
  85. ,initQuickTips: function() {
  86. Ext.QuickTips.init();
  87. Ext.apply(Ext.QuickTips.getQuickTip(), {
  88. dismissDelay: 2300
  89. ,interceptTitles: true
  90. });
  91. }
  92. ,getURLParameters: function() {
  93. var arg = {};
  94. var href = window.location.search;
  95. if (href.indexOf('?') !== -1) {
  96. var params = href.split('?')[1];
  97. var param = params.split('&');
  98. for (var i=0; i<param.length;i=i+1) {
  99. arg[param[i].split('=')[0]] = param[i].split('=')[1];
  100. }
  101. }
  102. return arg;
  103. }
  104. ,onAjaxException: function(conn,r,opt,e) {
  105. try {
  106. r = Ext.decode(r.responseText);
  107. } catch (e) {
  108. var text, matched = r.responseText.match(/<body[^>]*>([\w|\W]*)<\/body>/im);
  109. if (typeof(matched[1] !== 'undefined')) {
  110. text = '<p>'+e.message+':</p>'+matched[1];
  111. } else {
  112. text = e.message+': '+ r.responseText;
  113. }
  114. Ext.MessageBox.show({
  115. title: _('error')
  116. ,msg: text
  117. ,buttons: Ext.MessageBox.OK
  118. ,cls: 'modx-js-parse-error'
  119. ,minWidth: 600
  120. ,maxWidth: 750
  121. ,modal: false
  122. ,width: 600
  123. });
  124. }
  125. if (r && (r.code == 401 || (r.object && r.object.code == 401))) {
  126. if (!MODx.loginWindow) {
  127. MODx.loginWindow = MODx.load({
  128. xtype: 'modx-window-login'
  129. ,username: MODx.user.username
  130. });
  131. }
  132. MODx.loginWindow.show();
  133. }
  134. }
  135. ,loadAccordionPanels: function() { return []; }
  136. ,clearCache: function() {
  137. if (!this.fireEvent('beforeClearCache')) { return false; }
  138. var topic = '/clearcache/';
  139. this.console = MODx.load({
  140. xtype: 'modx-console'
  141. ,register: 'mgr'
  142. ,topic: topic
  143. ,clear: true
  144. ,show_filename: 0
  145. ,listeners: {
  146. 'shutdown': {fn:function() {
  147. if (this.fireEvent('afterClearCache')) {
  148. if (MODx.config.clear_cache_refresh_trees == 1) {
  149. Ext.getCmp('modx-layout').refreshTrees();
  150. }
  151. }
  152. },scope:this}
  153. }
  154. });
  155. this.console.show(Ext.getBody());
  156. MODx.Ajax.request({
  157. url: MODx.config.connector_url
  158. ,params: {
  159. action: 'system/clearcache'
  160. ,register: 'mgr'
  161. ,topic: topic
  162. ,media_sources: true
  163. ,menu: true
  164. ,action_map: true
  165. }
  166. ,listeners: {
  167. 'success':{fn:function() {
  168. this.console.fireEvent('complete');
  169. },scope:this}
  170. }
  171. });
  172. return true;
  173. }
  174. ,refreshURIs: function() {
  175. var topic = '/refreshuris/';
  176. MODx.msg.status({
  177. title: _('please_wait'),
  178. message: _('refreshuris_desc'),
  179. dontHide: true
  180. });
  181. MODx.Ajax.request({
  182. url: MODx.config.connector_url
  183. ,params: {
  184. action: 'system/refreshuris'
  185. ,register: 'mgr'
  186. ,topic: topic
  187. ,menu: true
  188. }
  189. ,listeners: {
  190. 'success':{fn:function(r) {
  191. MODx.msg.status({
  192. title: _('success')
  193. ,message: r.message || _('refresh_success')
  194. ,dontHide: false
  195. });
  196. this.clearCache();
  197. },scope:this}
  198. }
  199. });
  200. return true;
  201. }
  202. ,releaseLock: function(id) {
  203. if (this.fireEvent('beforeReleaseLocks')) {
  204. MODx.Ajax.request({
  205. url: MODx.config.connector_url
  206. ,params: {
  207. action: 'resource/locks/release'
  208. ,id: id
  209. }
  210. ,listeners: {
  211. 'success':{fn:function(r) { this.fireEvent('afterReleaseLocks',r); },scope:this}
  212. }
  213. });
  214. }
  215. }
  216. ,removeLocks: function(id) {
  217. MODx.msg.confirm({
  218. title: _('remove_locks')
  219. ,text: _('confirm_remove_locks')
  220. ,url: MODx.config.connectors_url
  221. ,params: {
  222. action: 'system/remove_locks'
  223. }
  224. ,listeners: {
  225. 'success': {
  226. fn:function() {
  227. var tree = Ext.getCmp("modx-resource-tree");
  228. if (tree && tree.rendered) {
  229. tree.refresh();
  230. }
  231. var cmp = Ext.getCmp("modx-panel-resource");
  232. if (cmp) {
  233. Ext.getCmp('modx-abtn-locked').hide();
  234. Ext.getCmp('modx-abtn-save').show();
  235. }
  236. },
  237. scope:this
  238. }
  239. }
  240. });
  241. }
  242. ,sleep: function(ms) {
  243. var s = new Date().getTime();
  244. for (var i=0;i < 1e7;i++) {
  245. if ((new Date().getTime() - s) > ms){
  246. break;
  247. }
  248. }
  249. }
  250. ,logout: function() {
  251. if (this.fireEvent('beforeLogout')) {
  252. MODx.msg.confirm({
  253. title: _('logout')
  254. ,text: _('logout_confirm')
  255. ,url: MODx.config.connector_url
  256. ,params: {
  257. action: 'security/logout'
  258. ,login_context: 'mgr'
  259. }
  260. ,listeners: {
  261. 'success': {fn:function(r) {
  262. if (this.fireEvent('afterLogout',r)) {
  263. location.href = './';
  264. }
  265. },scope:this}
  266. }
  267. });
  268. }
  269. }
  270. ,getPageStructure: function(v,c) {
  271. c = c || {};
  272. Ext.applyIf(c,{
  273. xtype: 'modx-tabs'
  274. ,itemId: 'tabs'
  275. ,items: v
  276. ,cls: 'structure-tabs'
  277. });
  278. return c;
  279. }
  280. ,setStaticElementPath: function(type) {
  281. var category = '',
  282. path = '',
  283. name = '',
  284. nameField = 'name',
  285. typePlural = type + "s";
  286. if (type === "template") {
  287. nameField = 'templatename';
  288. }
  289. if (MODx.config["static_elements_automate_" + typePlural] == 1) {
  290. if (Ext.getCmp("modx-" + type + "-category").getValue() > 0) {
  291. category = Ext.getCmp("modx-" + type + "-category").lastSelectionText;
  292. }
  293. name = Ext.getCmp("modx-" + type + "-" + nameField).getValue();
  294. path = MODx.getStaticElementsPath(name, category, typePlural);
  295. Ext.getCmp("modx-" + type + "-static-file").setValue(path);
  296. }
  297. }
  298. ,setStaticElementsConfig: function (config, type) {
  299. var typePlural = type + 's';
  300. if (MODx.request.a === 'element/' + type + '/create' && MODx.config['static_elements_automate_' + typePlural] == 1) {
  301. config.record['static'] = 1;
  302. config.record['static_file'] = MODx.config.static_elements_basepath + typePlural + '/';
  303. config.record['category'] = MODx.config.static_elements_default_category;
  304. if (MODx.config.static_elements_default_mediasource) {
  305. config.record['source'] = MODx.config.static_elements_default_mediasource;
  306. }
  307. }
  308. return config;
  309. }
  310. ,getStaticElementsPath: function(name, category, type) {
  311. var path = MODx.config.static_elements_basepath,
  312. ext = '';
  313. if (category.length > 0) {
  314. category = category.replace(/[^\w\s-]/gi, "");
  315. category = category.replace(/\s/g, '-').toLowerCase();
  316. // Convert nested elements to nested directory structure.
  317. category = category.replace(/--/gi, '/');
  318. category = "/" + category + "/";
  319. } else {
  320. category = "/";
  321. }
  322. // Remove trailing slash.
  323. path = path.replace(/\/$/, "");
  324. switch(type) {
  325. case "templates":
  326. ext = ".template.tpl";
  327. break;
  328. case "tvs":
  329. ext = ".tv.tpl";
  330. break;
  331. case "chunks":
  332. ext = ".chunk.tpl";
  333. break;
  334. case "snippets":
  335. ext = ".snippet.php";
  336. break;
  337. case "plugins":
  338. ext = ".plugin.php";
  339. break;
  340. }
  341. // Remove special characters and spaces.
  342. name = name.replace(/[^\w\s-]/gi, '');
  343. name = name.replace(/\s/g, '-').toLowerCase();
  344. if (name.length > 0) {
  345. path += "/" + type + category + name + ext;
  346. } else {
  347. path += "/" + type + category;
  348. }
  349. return path;
  350. }
  351. ,helpUrl: false
  352. ,loadHelpPane: function(b) {
  353. var url = MODx.helpUrl || MODx.config.help_url || '';
  354. if (!url || !url.length) { return false; }
  355. if (url.substring(0, 4) !== 'http') {
  356. url = MODx.config.base_help_url + url;
  357. }
  358. MODx.helpWindow = new Ext.Window({
  359. title: _('help')
  360. ,width: 850
  361. ,height: 500
  362. ,resizable: true
  363. ,maximizable: true
  364. ,modal: false
  365. ,layout: 'fit'
  366. ,bodyStyle : 'padding: 0;'
  367. ,items: [{
  368. xtype : 'container',
  369. layout : {
  370. type : 'vbox',
  371. align : 'stretch'
  372. },
  373. width : '100%',
  374. height : '100%',
  375. items :[{
  376. autoEl : {
  377. tag : 'iframe',
  378. src : url,
  379. width : '100%',
  380. height : '100%',
  381. frameBorder : 0
  382. }
  383. }]
  384. }]
  385. //,html: '<iframe src="' + url + '" width="100%" height="100%" frameborder="0"></iframe>'
  386. });
  387. MODx.helpWindow.show(b);
  388. return true;
  389. }
  390. ,addTab: function(tbp,opt) {
  391. var tabs = Ext.getCmp(tbp);
  392. if (tabs) {
  393. Ext.applyIf(opt,{
  394. id: 'modx-'+Ext.id()+'-tab'
  395. ,layout: 'form'
  396. ,labelAlign: 'top'
  397. ,cls: 'modx-resource-tab'
  398. ,bodyStyle: 'padding: 15px;'
  399. ,autoHeight: true
  400. ,defaults: {
  401. border: false
  402. ,msgTarget: 'side'
  403. ,width: 400
  404. }
  405. });
  406. tabs.add(opt);
  407. tabs.doLayout();
  408. tabs.setActiveTab(0);
  409. }
  410. }
  411. ,hiddenTabs: []
  412. ,hideTab: function(ct,tab) {this.hideRegion(ct,tab);}
  413. ,hideRegion: function(ct,tab) {
  414. var tp = Ext.getCmp(ct);
  415. if (tp) {
  416. var tabObj = tp.getItem(tab);
  417. if (tabObj) {
  418. var z = tp.hideTabStripItem(tab);
  419. MODx.hiddenTabs.push(tab);
  420. var idx = this._getNextActiveTab(tp,tab);
  421. tp.setActiveTab(idx);
  422. } else {
  423. var region = Ext.getCmp(tab);
  424. if (region) {
  425. region.hide();
  426. }
  427. }
  428. }
  429. }
  430. ,_getNextActiveTab: function(tp,tab) {
  431. if (MODx.hiddenTabs.indexOf(tab) != -1) {
  432. var id;
  433. for (var i=0;i<tp.items.items.length;i++) {
  434. id = tp.items.items[i].id;
  435. if (MODx.hiddenTabs.indexOf(id) == -1) { break; }
  436. }
  437. } else { id = tab; }
  438. return id;
  439. }
  440. ,moveTV: function(tvs,tab) {
  441. if (!Ext.isArray(tvs)) { tvs = [tvs]; }
  442. var tvp = Ext.getCmp('modx-panel-resource-tv');
  443. if (!tvp) { return; }
  444. for (var i=0;i<tvs.length;i++) {
  445. var tr = Ext.get(tvs[i]+'-tr');
  446. if (!tr) { return; }
  447. var fp = Ext.getCmp(tab);
  448. if (!fp) { return; }
  449. fp.add({
  450. html: ''
  451. ,width: '100%'
  452. ,id: 'tv-tr-out-'+tvs[i]
  453. ,cls: 'modx-tv-out'
  454. });
  455. fp.doLayout();
  456. var o = Ext.get('tv-tr-out-'+tvs[i]);
  457. o.replaceWith(tr);
  458. }
  459. }
  460. ,hideTV: function(tvs) {
  461. if (!Ext.isArray(tvs)) { tvs = [tvs]; }
  462. this.hideTVs(tvs);
  463. }
  464. ,hideTVs: function(tvs) {
  465. if (!Ext.isArray(tvs)) { tvs = [tvs]; }
  466. var el;
  467. for (var i=0;i<tvs.length;i++) {
  468. el = Ext.get(tvs[i]+'-tr');
  469. if (el) {
  470. el.setVisibilityMode(Ext.Element.DISPLAY);
  471. el.hide();
  472. }
  473. }
  474. }
  475. ,renameLabel: function(ct,flds,vals) {
  476. var cto;
  477. if (ct == 'modx-panel-resource' && flds.indexOf('modx-resource-content') != -1) {
  478. cto = Ext.getCmp('modx-resource-content');
  479. if (cto) {
  480. if (cto.setTitle) {
  481. cto.setTitle(vals[0]);
  482. } else if (cto.setLabel) {
  483. cto.setLabel(flds,vals);
  484. } else {
  485. cto.label.update(vals[0]);
  486. }
  487. }
  488. } else {
  489. cto = Ext.getCmp(ct);
  490. if (cto) {
  491. cto.setLabel(flds,vals);
  492. }
  493. }
  494. }
  495. ,renameTab: function(tb,title) {
  496. var tab = Ext.getCmp(tb);
  497. if (tab) {
  498. tab.setTitle(title);
  499. }
  500. }
  501. ,hideField: function(ct,flds) {
  502. ct = Ext.getCmp(ct);
  503. if (ct) {
  504. ct.hideField(flds);
  505. }
  506. }
  507. ,preview: function() {
  508. var url = MODx.config.site_url;
  509. if (MODx.config.default_site_url) {
  510. url = MODx.config.default_site_url;
  511. }
  512. window.open(url);
  513. }
  514. ,makeDroppable: function(fld,h,p) {
  515. if (!fld) return false;
  516. h = h || Ext.emptyFn;
  517. if (fld.getEl) {
  518. var el = fld.getEl();
  519. } else if (fld) {
  520. el = fld;
  521. }
  522. if (el) {
  523. new MODx.load({
  524. xtype: 'modx-treedrop'
  525. ,target: fld
  526. ,targetEl: el.dom
  527. ,onInsert: h
  528. ,panel: p || 'modx-panel-resource'
  529. });
  530. }
  531. return true;
  532. }
  533. ,debug: function(msg) {
  534. if (MODx.config.ui_debug_mode == 1) {
  535. console.log(msg);
  536. }
  537. }
  538. ,isEmpty: function(v) {
  539. return Ext.isEmpty(v) || v === false || v === 'false' || v === 'FALSE' || v === '0' || v === 0;
  540. }
  541. });
  542. Ext.reg('modx',MODx);
  543. /**
  544. * An override class for Ext.Ajax, which adds success/failure events.
  545. *
  546. * @class MODx.Ajax
  547. * @extends Ext.Component
  548. * @param {Object} config An object of config properties
  549. * @xtype modx-ajax
  550. */
  551. MODx.Ajax = function(config) {
  552. config = config || {};
  553. MODx.Ajax.superclass.constructor.call(this, config);
  554. };
  555. Ext.extend(MODx.Ajax,Ext.Component,{
  556. request: function(config) {
  557. Ext.apply(config,{
  558. success: function(r,o) {
  559. r = Ext.decode(r.responseText);
  560. if (!r) {
  561. return false;
  562. }
  563. r.options = o;
  564. if (r.success) {
  565. if (config.listeners.success && config.listeners.success.fn) {
  566. this._runCallback(config.listeners.success, [r]);
  567. }
  568. } else if (config.listeners.failure && config.listeners.failure.fn) {
  569. this._runCallback(config.listeners.failure, [r]);
  570. MODx.form.Handler.errorJSON(r);
  571. }
  572. return true;
  573. }
  574. ,failure: function(r, o) {
  575. r = Ext.decode(r.responseText);
  576. if (!r) {
  577. return false;
  578. }
  579. r.options = o;
  580. if (config.listeners.failure && config.listeners.failure.fn) {
  581. this._runCallback(config.listeners.failure, [r]);
  582. MODx.form.Handler.errorJSON(r);
  583. }
  584. return true;
  585. }
  586. ,scope: this
  587. ,headers: {
  588. 'Powered-By': 'MODx'
  589. ,'modAuth': config.auth
  590. }
  591. });
  592. Ext.Ajax.request(config);
  593. }
  594. /**
  595. * Execute the listener callback
  596. *
  597. * @param {Object} config - The listener configuration (ie.failure/success)
  598. * @param {Array} args - An array of arguments to pass to the callback
  599. */
  600. ,_runCallback: function(config, args) {
  601. var scope = window
  602. ,fn = config.fn;
  603. if (config.scope) {
  604. scope = config.scope;
  605. }
  606. fn.apply(scope || window, args);
  607. }
  608. });
  609. Ext.reg('modx-ajax',MODx.Ajax);
  610. MODx = new MODx();
  611. MODx.form.Handler = function(config) {
  612. config = config || {};
  613. MODx.form.Handler.superclass.constructor.call(this,config);
  614. };
  615. Ext.extend(MODx.form.Handler,Ext.Component,{
  616. fields: []
  617. ,handle: function(o,s,r) {
  618. r = Ext.decode(r.responseText);
  619. if (!r.success) {
  620. this.showError(r.message);
  621. return false;
  622. }
  623. return true;
  624. }
  625. ,highlightField: function(f) {
  626. if (f.id !== undefined && f.id !== 'forEach' && f.id !== '') {
  627. var fld = Ext.get(f.id);
  628. if (fld && fld.dom) {
  629. fld.dom.style.border = '1px solid red';
  630. }
  631. var ef = Ext.get(f.id+'_error');
  632. if (ef) { ef.innerHTML = f.msg; }
  633. this.fields.push(f.id);
  634. }
  635. }
  636. ,unhighlightFields: function() {
  637. for (var i=0;i<this.fields.length;i=i+1) {
  638. Ext.get(this.fields[i]).dom.style.border = '';
  639. var ef = Ext.get(this.fields[i]+'_error');
  640. if (ef) { ef.innerHTML = ''; }
  641. }
  642. this.fields = [];
  643. }
  644. ,errorJSON: function(e) {
  645. if (e === '') { return this.showError(e); }
  646. if (e.data && e.data !== null) {
  647. for (var p=0;p<e.data.length;p=p+1) {
  648. this.highlightField(e.data[p]);
  649. }
  650. }
  651. this.showError(e.message);
  652. return false;
  653. }
  654. ,errorExt: function(r,frm) {
  655. this.unhighlightFields();
  656. if (r && r.errors !== null && frm) {
  657. frm.markInvalid(r.errors);
  658. }
  659. if (r && r.message !== undefined && r.message !== '') {
  660. this.showError(r.message);
  661. } else {
  662. MODx.msg.hide();
  663. }
  664. return false;
  665. }
  666. ,showError: function(e) {
  667. if (e === '') {
  668. MODx.msg.hide();
  669. } else {
  670. MODx.msg.alert(_('error'),e,Ext.emptyFn);
  671. }
  672. }
  673. ,closeError: function() { MODx.msg.hide(); }
  674. });
  675. Ext.reg('modx-form-handler',MODx.form.Handler);
  676. MODx.Msg = function(config) {
  677. config = config || {};
  678. MODx.Msg.superclass.constructor.call(this,config);
  679. this.addEvents({
  680. 'success': true
  681. ,'failure': true
  682. ,'cancel': true
  683. });
  684. Ext.MessageBox.minWidth = 200;
  685. };
  686. Ext.extend(MODx.Msg,Ext.Component,{
  687. confirm: function(config) {
  688. this.purgeListeners();
  689. if (config.listeners) {
  690. for (var i in config.listeners) {
  691. var l = config.listeners[i];
  692. this.addListener(i,l.fn,l.scope || this,l.options || {});
  693. }
  694. }
  695. Ext.Msg.confirm(config.title || _('warning'),config.text,function(e) {
  696. if (e == 'yes') {
  697. MODx.Ajax.request({
  698. url: config.url
  699. ,params: config.params || {}
  700. ,method: 'post'
  701. ,scope: this
  702. ,listeners: {
  703. 'success':{fn:function(r) {
  704. this.fireEvent('success',r);
  705. },scope:this}
  706. ,'failure':{fn:function(r) {
  707. return this.fireEvent('failure',r);
  708. },scope:this}
  709. }
  710. });
  711. } else {
  712. this.fireEvent('cancel',config);
  713. }
  714. },this);
  715. }
  716. ,getWindow: function() {
  717. return Ext.Msg.getDialog();
  718. }
  719. ,alert: function(title,text,fn,scope) {
  720. fn = fn || Ext.emptyFn;
  721. scope = scope || this;
  722. Ext.Msg.alert(title,text,fn,scope);
  723. }
  724. ,status: function(opt) {
  725. if (!MODx.stMsgCt) {
  726. MODx.stMsgCt = Ext.DomHelper.insertFirst(document.body, {id:'modx-status-message-ct'}, true);
  727. }
  728. MODx.stMsgCt.alignTo(document, 't-t');
  729. var markup = this.getStatusMarkup(opt);
  730. var m = Ext.DomHelper.overwrite(MODx.stMsgCt, {html:markup}, true);
  731. var fadeOpts = {remove:true,useDisplay:true};
  732. if (!opt.dontHide) {
  733. if(!Ext.isIE8) {
  734. m.pause(opt.delay || 1.5).ghost("t",fadeOpts);
  735. } else {
  736. fadeOpts.duration = (opt.delay || 1.5);
  737. m.ghost("t",fadeOpts);
  738. }
  739. } else {
  740. m.on('click',function() {
  741. m.ghost('t',fadeOpts);
  742. });
  743. }
  744. }
  745. ,getStatusMarkup: function(opt) {
  746. var mk = '<div class="modx-status-msg">';
  747. if (opt.title) { mk += '<h3>'+opt.title+'</h3>'; }
  748. if (opt.message) { mk += '<span class="modx-smsg-message">'+opt.message+'</span>'; }
  749. return mk+'</div>';
  750. }
  751. });
  752. Ext.reg('modx-msg',MODx.Msg);
  753. /**
  754. * Server-side state provider for MODx
  755. *
  756. * @class MODx.state.HttpProvider
  757. * @extends Ext.state.Provider
  758. * @constructor
  759. * @param {Object} config Configuration object.
  760. */
  761. MODx.HttpProvider = function(config) {
  762. config = config || {};
  763. this.addEvents(
  764. 'readsuccess'
  765. ,'readfailure'
  766. ,'writesuccess'
  767. ,'writefailure'
  768. );
  769. MODx.HttpProvider.superclass.constructor.call(this,config);
  770. Ext.apply(this, config, {
  771. delay: 500
  772. ,dirty: false
  773. ,started: false
  774. ,autoStart: true
  775. ,autoRead: true
  776. ,queue: {}
  777. ,readUrl: MODx.config.connector_url
  778. ,writeUrl: MODx.config.connector_url
  779. ,method: 'post'
  780. ,baseParams: {
  781. register: 'state'
  782. ,topic: ''
  783. }
  784. ,writeBaseParams: {
  785. action: 'system/registry/register/send'
  786. ,message: ''
  787. ,message_key: ''
  788. ,message_format: 'json'
  789. ,delay: 0
  790. ,ttl: 0
  791. ,kill: 0
  792. }
  793. ,readBaseParams: {
  794. action: 'system/registry/register/read'
  795. ,format: 'json'
  796. ,poll_limit: 1
  797. ,poll_interval: 1
  798. ,time_limit: 10
  799. ,message_limit: 1000
  800. ,remove_read: 0
  801. ,show_filename: 0
  802. ,include_keys: 1
  803. }
  804. ,paramNames: {
  805. topic: 'topic'
  806. ,name: 'name'
  807. ,value: 'value'
  808. ,message: 'message'
  809. ,message_key: 'message_key'
  810. }
  811. });
  812. this.config = config;
  813. if (this.autoRead) {
  814. this.readState();
  815. }
  816. this.dt = new Ext.util.DelayedTask(this.submitState, this);
  817. if (this.autoStart) {
  818. this.start();
  819. }
  820. };
  821. Ext.extend(MODx.HttpProvider, Ext.state.Provider, {
  822. initState: function(state) {
  823. if (state instanceof Object) {
  824. Ext.iterate(state, function(name, value, o) {
  825. this.state[name] = value;//this.decodeValue(value);
  826. }, this)
  827. } else {
  828. this.state = {};
  829. }
  830. }
  831. ,set: function(name, value) {
  832. if (!name) {
  833. return;
  834. }
  835. this.queueChange(name, value);
  836. }
  837. ,get : function(name, defaultValue){
  838. return typeof this.state[name] == "undefined" ?
  839. defaultValue : this.state[name];
  840. }
  841. ,start: function() {
  842. this.dt.delay(this.delay);
  843. this.started = true;
  844. }
  845. ,stop: function() {
  846. this.dt.cancel();
  847. this.started = false;
  848. }
  849. ,queueChange:function(name, value) {
  850. var lastValue = this.state[name];
  851. var found = this.queue[name] !== undefined;
  852. if (found) {
  853. lastValue = this.queue[name];
  854. }
  855. var changed = undefined === lastValue || lastValue !== value;
  856. if (changed) {
  857. this.queue[name] = value;
  858. this.dirty = true;
  859. }
  860. if (this.started) {
  861. this.start();
  862. }
  863. return changed;
  864. }
  865. ,submitState: function() {
  866. if (!this.dirty) {
  867. this.dt.delay(this.delay);
  868. return;
  869. }
  870. this.dt.cancel();
  871. var o = {
  872. url: this.writeUrl
  873. ,method: this.method
  874. ,scope: this
  875. ,success: this.onWriteSuccess
  876. ,failure: this.onWriteFailure
  877. ,queue: Ext.apply({}, this.queue)
  878. ,params: {}
  879. };
  880. var params = Ext.apply({}, this.baseParams, this.writeBaseParams);
  881. params[this.paramNames.topic] = '/ys/user-' + MODx.user.id + '/';
  882. params[this.paramNames.message] = Ext.encode(this.queue);
  883. Ext.apply(o.params, params);
  884. // be optimistic
  885. this.dirty = false;
  886. Ext.Ajax.request(o);
  887. }
  888. ,clear: function(name) {
  889. this.set(name, undefined);
  890. }
  891. ,onWriteSuccess: function(r,o) {
  892. r = Ext.decode(r.responseText);
  893. if (true !== r.success) {
  894. this.dirty = true;
  895. } else {
  896. Ext.iterate(o.queue, function(name, value) {
  897. if(!name) {
  898. return;
  899. }
  900. if (undefined === value || null === value) {
  901. MODx.HttpProvider.superclass.clear.call(this, name);
  902. } else {
  903. // parent sets value and fires event
  904. MODx.HttpProvider.superclass.set.call(this, name, value);
  905. }
  906. }, this);
  907. if (false === this.dirty) {
  908. this.queue = {};
  909. } else {
  910. Ext.iterate(o.queue, function(name, value) {
  911. var found = this.queue[name] !== undefined;
  912. if (true === found && value === this.queue[name]) {
  913. delete this.queue[name];
  914. }
  915. }, this);
  916. }
  917. this.fireEvent('writesuccess', this);
  918. }
  919. }
  920. ,onWriteFailure: function(r) {
  921. r = Ext.decode(r.responseText);
  922. this.dirty = true;
  923. this.fireEvent('writefailure', this);
  924. }
  925. ,onReadFailure: function(r) {
  926. r = Ext.decode(r.responseText);
  927. this.fireEvent('readfailure', this);
  928. }
  929. ,onReadSuccess: function(r) {
  930. r = Ext.decode(r.responseText);
  931. var state;
  932. if (true === r.success && r.message) {
  933. state = Ext.decode(r.message);
  934. if (!(state instanceof Object)) {
  935. return;
  936. }
  937. Ext.iterate(state, function(name, value, o) {
  938. this.state[name] = value;
  939. }, this);
  940. this.queue = {};
  941. this.dirty = false;
  942. this.fireEvent('readsuccess', this);
  943. }
  944. }
  945. ,readState: function() {
  946. var o = {
  947. url: this.readUrl
  948. ,method: this.method
  949. ,scope: this
  950. ,success: this.onReadSuccess
  951. ,failure: this.onReadFailure
  952. ,params: {}
  953. };
  954. var params = Ext.apply({}, this.baseParams, this.readBaseParams);
  955. params[this.paramNames.topic] = '/ys/user-' + MODx.user.id + '/';
  956. Ext.apply(o.params, params);
  957. Ext.Ajax.request(o);
  958. }
  959. });
  960. MODx.Header = function(config) {
  961. config = config || {};
  962. Ext.applyIf(config, {
  963. cls: 'modx-page-header'
  964. ,autoEl: {
  965. tag: 'h2'
  966. }
  967. ,itemId: 'header'
  968. });
  969. MODx.Header.superclass.constructor.call(this, config);
  970. };
  971. Ext.extend(MODx.Header, Ext.BoxComponent, {});
  972. Ext.reg('modx-header', MODx.Header);
  973. MODx.Description = function(config) {
  974. config = config || {};
  975. Ext.applyIf(config, {
  976. cls: 'panel-desc'
  977. ,itemId: 'description'
  978. });
  979. MODx.Description.superclass.constructor.call(this, config);
  980. };
  981. Ext.extend(MODx.Description, Ext.BoxComponent, {});
  982. Ext.reg('modx-description', MODx.Description);