utilities.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. Ext.namespace('MODx.util.Progress');
  2. /**
  3. * A JSON Reader specific to MODExt
  4. *
  5. * @class MODx.util.JSONReader
  6. * @extends Ext.util.JSONReader
  7. * @param {Object} config An object of configuration properties
  8. * @xtype modx-json-reader
  9. */
  10. MODx.util.JSONReader = function(config) {
  11. config = config || {};
  12. Ext.applyIf(config,{
  13. successProperty:'success'
  14. ,totalProperty: 'total'
  15. ,root: 'data'
  16. });
  17. MODx.util.JSONReader.superclass.constructor.call(this,config,['id','msg']);
  18. };
  19. Ext.extend(MODx.util.JSONReader,Ext.data.JsonReader);
  20. Ext.reg('modx-json-reader',MODx.util.JSONReader);
  21. /**
  22. * @class MODx.util.Progress
  23. */
  24. MODx.util.Progress = {
  25. id: 0
  26. ,time: function(v,id,msg) {
  27. msg = msg || _('saving');
  28. if (MODx.util.Progress.id === id && v < 11) {
  29. Ext.MessageBox.updateProgress(v/10,msg);
  30. }
  31. }
  32. ,reset: function() {
  33. MODx.util.Progress.id = MODx.util.Progress.id + 1;
  34. }
  35. };
  36. /** Adds a lock mask to an element */
  37. MODx.LockMask = function(config) {
  38. config = config || {};
  39. Ext.applyIf(config,{
  40. msg: _('locked')
  41. ,msgCls: 'modx-lockmask'
  42. });
  43. MODx.LockMask.superclass.constructor.call(this,config.el,config);
  44. };
  45. Ext.extend(MODx.LockMask,Ext.LoadMask,{
  46. locked: false
  47. ,toggle: function() {
  48. if (this.locked) {
  49. this.hide();
  50. this.locked = false;
  51. } else {
  52. this.show();
  53. this.locked = true;
  54. }
  55. }
  56. ,lock: function() { this.locked = true; this.show(); }
  57. ,unlock: function() { this.locked = false; this.hide(); }
  58. });
  59. Ext.reg('modx-lockmask',MODx.LockMask);
  60. /** add clearDirty to basicform */
  61. Ext.override(Ext.form.BasicForm,{
  62. clearDirty : function(nodeToRecurse){
  63. nodeToRecurse = nodeToRecurse || this;
  64. nodeToRecurse.items.each(function(f){
  65. if (!f.getValue) return;
  66. if(f.items){
  67. this.clearDirty(f);
  68. } else if(f.originalValue != f.getValue()){
  69. f.originalValue = f.getValue();
  70. }
  71. },this);
  72. }
  73. });
  74. /**
  75. * Static Textfield
  76. */
  77. MODx.StaticTextField = Ext.extend(Ext.form.TextField, {
  78. fieldClass: 'x-static-text-field',
  79. onRender: function() {
  80. this.readOnly = true;
  81. this.disabled = !this.initialConfig.submitValue;
  82. MODx.StaticTextField.superclass.onRender.apply(this, arguments);
  83. }
  84. });
  85. Ext.reg('statictextfield',MODx.StaticTextField);
  86. /**
  87. * Static Boolean
  88. */
  89. MODx.StaticBoolean = Ext.extend(Ext.form.TextField, {
  90. fieldClass: 'x-static-text-field',
  91. onRender: function(tf) {
  92. this.readOnly = true;
  93. this.disabled = !this.initialConfig.submitValue;
  94. MODx.StaticBoolean.superclass.onRender.apply(this, arguments);
  95. this.on('change',this.onChange,this);
  96. }
  97. ,setValue: function(v) {
  98. if (v === 1) {
  99. this.addClass('green');
  100. v = _('yes');
  101. } else {
  102. this.addClass('red');
  103. v = _('no');
  104. }
  105. MODx.StaticBoolean.superclass.setValue.apply(this, arguments);
  106. }
  107. });
  108. Ext.reg('staticboolean',MODx.StaticBoolean);
  109. // This method strips not allowed html tags/attributes, html comments and php tags,
  110. // replaces javascript invocation in a href attribute and masks html event attributes
  111. // in an input string - assuming the result is safe to be displayed by a browser
  112. MODx.util.safeHtml = function (input, allowedTags, allowedAttributes) {
  113. var strip = function(input, allowedTags, allowedAttributes) {
  114. return input.replace(tags, function ($0, $1) {
  115. return allowedTags.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
  116. }).replace(attributes, function ($0, $1) {
  117. return allowedAttributes.indexOf($1.toLowerCase() + ',') > -1 ? $0 : '';
  118. });
  119. };
  120. allowedTags = (((allowedTags || '<a><br><i><em><b><strong>') + '')
  121. .toLowerCase()
  122. .match(/<[a-z][a-z0-9]*>/g) || [])
  123. .join(''); // making sure the allowedTags arg is a string containing only tags in lowercase (<a><b><c>)
  124. allowedAttributes = (((allowedAttributes || 'href,class') + '')
  125. .toLowerCase()
  126. .match(/[a-z\-,]*/g) || [])
  127. .join('').concat(','); // making sure the allowedAttributes arg is a comma separated string containing only attributes in lowercase (a,b,c)
  128. var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
  129. attributes = /([a-z][a-z0-9]*)\s*=\s*".*?"/gi,
  130. eventAttributes = /on([a-z][a-z0-9]*\s*=)/gi,
  131. commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi,
  132. hrefJavascript = /href(\s*?=\s*?(["'])javascript:.*?\2|\s*?=\s*?javascript:.*?(?![^> ]))/gi,
  133. length;
  134. input = input.replace(commentsAndPhpTags, '').replace(hrefJavascript, 'href="javascript:void(0)"');
  135. do {
  136. length = input.length;
  137. input = strip(input, allowedTags, allowedAttributes);
  138. } while (length !== input.length);
  139. return input.replace(eventAttributes, 'on&#8203;$1');
  140. };
  141. /****************************************************************************
  142. * Ext-specific overrides/extensions *
  143. ****************************************************************************/
  144. /* add helper method to set checkbox boxLabel */
  145. Ext.override(Ext.form.Checkbox, {
  146. setBoxLabel: function(boxLabel){
  147. this.boxLabel = boxLabel;
  148. if(this.rendered){
  149. this.wrap.child('.x-form-cb-label').update(boxLabel);
  150. }
  151. }
  152. });
  153. Array.prototype.in_array = function(p_val) {
  154. for(var i=0,l=this.length;i<l;i=i+1) {
  155. if(this[i] === p_val) {
  156. return true;
  157. }
  158. }
  159. return false;
  160. };
  161. Ext.form.setCheckboxValues = function(form,id,mask) {
  162. var f, n=0;
  163. while ((f = form.findField(id+n)) !== null) {
  164. f.setValue((mask & (1<<n))?'true':'false');
  165. n=n+1;
  166. }
  167. };
  168. Ext.form.getCheckboxMask = function(cbgroup) {
  169. var mask='';
  170. if (typeof(cbgroup) !== 'undefined') {
  171. if ((typeof(cbgroup)==='string')) {
  172. mask = cbgroup+'';
  173. } else {
  174. for(var i=0,len=cbgroup.length;i<len;i=i+1) {
  175. mask += (mask !== '' ? ',' : '')+(cbgroup[i]-0);
  176. }
  177. }
  178. }
  179. return mask;
  180. };
  181. Ext.form.BasicForm.prototype.append = function() {
  182. var layout = new Ext.form.Layout();
  183. var fields = [];
  184. layout.stack.push.apply(layout.stack, arguments);
  185. for(var i = 0; i < arguments.length; i=i+1) {
  186. if(arguments[i].isFormField) {
  187. fields.push(arguments[i]);
  188. }
  189. }
  190. layout.render(this.el);
  191. if(fields.length > 0) {
  192. this.items.addAll(fields);
  193. for(var f=0;f<fields.length;f=f+1) {
  194. fields[f].render('x-form-el-' + fields[f].id);
  195. }
  196. }
  197. return this;
  198. };
  199. Ext.form.AMPMField = function(id,v) {
  200. return new Ext.form.ComboBox({
  201. store: new Ext.data.SimpleStore({
  202. fields: ['ampm']
  203. ,data: [['am'],['pm']]
  204. })
  205. ,displayField: 'ampm'
  206. ,hiddenName: id
  207. ,mode: 'local'
  208. ,editable: false
  209. ,forceSelection: true
  210. ,triggerAction: 'all'
  211. ,width: 60
  212. ,value: v || 'am'
  213. });
  214. };
  215. Ext.form.HourField = function(id,name,v){
  216. return new Ext.form.ComboBox({
  217. store: new Ext.data.SimpleStore({
  218. fields: ['hour']
  219. ,data: [[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12]]
  220. })
  221. ,displayField: 'hour'
  222. ,mode: 'local'
  223. ,triggerAction: 'all'
  224. ,width: 60
  225. ,forceSelection: true
  226. ,rowHeight: false
  227. ,editable: false
  228. ,value: v || 1
  229. ,transform: id
  230. });
  231. };
  232. Ext.override(Ext.tree.TreeNodeUI,{
  233. hasClass : function(className){
  234. var el = Ext.fly(this.elNode);
  235. if (!el) return '';
  236. return className && (' '+el.dom.className+' ').indexOf(' '+className+' ') !== -1;
  237. }
  238. ,renderElements : function(n, a, targetNode, bulkRender){
  239. this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
  240. var cb = Ext.isBoolean(a.checked),
  241. renderer = n.ownerTree && n.ownerTree.renderItemText ? n.ownerTree.renderItemText : this.renderItemText,
  242. nel,
  243. href = this.getHref(a.page),
  244. iconMarkup = '<i class="icon'+(a.icon ? " x-tree-node-inline-icon" : "")+(a.iconCls ? " "+a.iconCls : "")+'" unselectable="on"></i>',
  245. elbowMarkup = n.attributes.pseudoroot ?
  246. '<i class="icon-sort-down expanded-icon"></i>' :
  247. //'<img alt="" src="'+ this.emptyIcon+ '" class="x-tree-ec-icon x-tree-elbow" />',
  248. '<i class="x-tree-ec-icon x-tree-elbow"></i>',
  249. buf = ['<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf x-unselectable ', a.cls,'" unselectable="on">',
  250. '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
  251. elbowMarkup,
  252. iconMarkup,
  253. cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : '/>')) : '',
  254. '<a hidefocus="on" class="x-tree-node-anchor" href="',href,'" tabIndex="1" ',
  255. a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '><span unselectable="on">',renderer(a),"</span></a></div>",
  256. '<ul class="x-tree-node-ct" style="display:none;"></ul>',
  257. "</li>"].join('');
  258. if(bulkRender !== true && n.nextSibling && (nel = n.nextSibling.ui.getEl())){
  259. this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf);
  260. }else{
  261. this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf);
  262. }
  263. this.elNode = this.wrap.childNodes[0];
  264. this.ctNode = this.wrap.childNodes[1];
  265. var cs = this.elNode.childNodes;
  266. this.indentNode = cs[0];
  267. this.ecNode = cs[1];
  268. this.iconNode = cs[2];
  269. var index = 3;
  270. if(cb){
  271. this.checkbox = cs[3];
  272. this.checkbox.defaultChecked = this.checkbox.checked;
  273. index++;
  274. }
  275. this.anchor = cs[index];
  276. this.textNode = cs[index].firstChild;
  277. }
  278. /**
  279. * Renders the item text as a XSS-safe value. Can be overridden with a renderItemText method on the Tree.
  280. * @param text
  281. * @returns string
  282. */
  283. ,renderItemText: function(item) {
  284. return Ext.util.Format.htmlEncode(item.text)
  285. }
  286. ,getChildIndent : function(){
  287. if(!this.childIndent){
  288. var buf = [],
  289. p = this.node;
  290. while(p){
  291. if((!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)) && !p.attributes.pseudoroot){
  292. if(!p.isLast()) {
  293. buf.unshift('<img alt="" src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
  294. } else {
  295. buf.unshift('<img alt="" src="'+this.emptyIcon+'" class="x-tree-icon" />');
  296. }
  297. }
  298. p = p.parentNode;
  299. }
  300. this.childIndent = buf.join("");
  301. }
  302. return this.childIndent;
  303. }
  304. });
  305. /* allows for messages in JSON responses */
  306. Ext.override(Ext.form.Action.Submit,{
  307. handleResponse : function(response){
  308. var m = Ext.decode(response.responseText); /* shaun 7/11/07 */
  309. if (this.form.errorReader) {
  310. var rs = this.form.errorReader.read(response);
  311. var errors = [];
  312. if (rs.records) {
  313. for(var i = 0, len = rs.records.length; i < len; i=i+1) {
  314. var r = rs.records[i];
  315. errors[i] = r.data;
  316. }
  317. }
  318. if (errors.length < 1) { errors = null; }
  319. return {
  320. success : rs.success
  321. ,message : m.message /* shaun 7/11/07 */
  322. ,object : m.object /* shaun 7/18/07 */
  323. ,errors : errors
  324. };
  325. }
  326. return Ext.decode(response.responseText);
  327. }
  328. });
  329. /* QTips to form fields */
  330. Ext.form.Field.prototype.afterRender = Ext.form.Field.prototype.afterRender.createSequence(function() {
  331. if (this.description) {
  332. Ext.QuickTips.register({
  333. target: this.getEl()
  334. ,text: this.description
  335. ,enabled: true
  336. });
  337. var label = Ext.form.Field.findLabel(this);
  338. if(label){
  339. Ext.QuickTips.register({
  340. target: label
  341. ,text: this.description
  342. ,enabled: true
  343. });
  344. }
  345. }
  346. });
  347. Ext.applyIf(Ext.form.Field,{
  348. findLabel: function(field) {
  349. var wrapDiv = null;
  350. var label = null;
  351. wrapDiv = field.getEl().up('div.x-form-element');
  352. if(wrapDiv){
  353. label = wrapDiv.child('label');
  354. }
  355. if(label){
  356. return label;
  357. }
  358. wrapDiv = field.getEl().up('div.x-form-item');
  359. if(wrapDiv) {
  360. label = wrapDiv.child('label');
  361. }
  362. if(label){
  363. return label;
  364. }
  365. }
  366. });
  367. /* allow copying to clipboard */
  368. MODx.util.Clipboard = function() {
  369. return {
  370. escape: function(text){
  371. text = encodeURIComponent(text);
  372. return text.replace(/%0A/g, "%0D%0A");
  373. }
  374. ,copy: function(text){
  375. if (Ext.isIE) {
  376. window.clipboardData.setData("Text", text);
  377. } else {
  378. var flashcopier = 'flashcopier';
  379. if (!document.getElementById(flashcopier)) {
  380. var divholder = document.createElement('div');
  381. divholder.id = flashcopier;
  382. document.body.appendChild(divholder);
  383. }
  384. document.getElementById(flashcopier).innerHTML = '';
  385. var divinfo = '<embed src="' + MODx.config.manager_url
  386. + 'assets/modext/_clipboard.swf" FlashVars="clipboard='
  387. + MODx.util.Clipboard.escape(text)
  388. + '" width="0" height="0" type="application/x-shockwave-flash"></embed>';
  389. document.getElementById(flashcopier).innerHTML = divinfo;
  390. }
  391. }
  392. };
  393. }();
  394. Ext.util.Format.trimCommas = function(s) {
  395. s = s.replace(',,',',');
  396. var len = s.length;
  397. if (s.substr(len-1,1) == ",") {
  398. s = s.substring(0,len-1);
  399. }
  400. if (s.substr(0,1) == ",") {
  401. s = s.substring(1);
  402. }
  403. if (s == ',') { s = ''; }
  404. return s;
  405. };
  406. /* rowactions plugin */
  407. Ext.ns('Ext.ux.grid');if('function'!==typeof RegExp.escape){RegExp.escape=function(s){if('string'!==typeof s){return s}return s.replace(/([.*+?\^=!:${}()|\[\]\/\\])/g,'\\$1')}}Ext.ux.grid.RowActions=function(a){Ext.apply(this,a);this.addEvents('beforeaction','action','beforegroupaction','groupaction');Ext.ux.grid.RowActions.superclass.constructor.call(this)};Ext.extend(Ext.ux.grid.RowActions,Ext.util.Observable,{actionEvent:'click',autoWidth:true,dataIndex:'',editable:false,header:'',isColumn:true,keepSelection:false,menuDisabled:true,sortable:false,tplGroup:'<tpl for="actions">'+'<div class="ux-grow-action-item<tpl if="\'right\'===align"> ux-action-right</tpl> '+'{cls}" style="{style}" qtip="{qtip}">{text}</div>'+'</tpl>',tplRow:'<div class="ux-row-action">'+'<tpl for="actions">'+'<div class="ux-row-action-item {cls} <tpl if="text">'+'ux-row-action-text</tpl>" style="{hide}{style}" qtip="{qtip}">'+'<tpl if="text"><span qtip="{qtip}">{text}</span></tpl></div>'+'</tpl>'+'</div>',hideMode:'visibility',widthIntercept:4,widthSlope:21,init:function(g){this.grid=g;this.id=this.id||Ext.id();var h=g.getColumnModel().lookup;delete(h[undefined]);h[this.id]=this;if(!this.tpl){this.tpl=this.processActions(this.actions)}if(this.autoWidth){this.width=this.widthSlope*this.actions.length+this.widthIntercept;this.fixed=true}var i=g.getView();var j={scope:this};j[this.actionEvent]=this.onClick;g.afterRender=g.afterRender.createSequence(function(){i.mainBody.on(j);g.on('destroy',this.purgeListeners,this)},this);if(!this.renderer){this.renderer=function(a,b,c,d,e,f){b.css+=(b.css?' ':'')+'ux-row-action-cell';return this.tpl.apply(this.getData(a,b,c,d,e,f))}.createDelegate(this)}if(i.groupTextTpl&&this.groupActions){i.interceptMouse=i.interceptMouse.createInterceptor(function(e){if(e.getTarget('.ux-grow-action-item')){return false}});i.groupTextTpl='<div class="ux-grow-action-text">'+i.groupTextTpl+'</div>'+this.processActions(this.groupActions,this.tplGroup).apply()}if(true===this.keepSelection){g.processEvent=g.processEvent.createInterceptor(function(a,e){if('mousedown'===a){return!this.getAction(e)}},this)}},getData:function(a,b,c,d,e,f){return c.data||{}},processActions:function(b,c){var d=[];Ext.each(b,function(a,i){if(a.iconCls&&'function'===typeof(a.callback||a.cb)){this.callbacks=this.callbacks||{};this.callbacks[a.iconCls]=a.callback||a.cb}var o={cls:a.iconIndex?'{'+a.iconIndex+'}':(a.iconCls?a.iconCls:''),qtip:a.qtipIndex?'{'+a.qtipIndex+'}':(a.tooltip||a.qtip?a.tooltip||a.qtip:''),text:a.textIndex?'{'+a.textIndex+'}':(a.text?a.text:''),hide:a.hideIndex?'<tpl if="'+a.hideIndex+'">'+('display'===this.hideMode?'display:none':'visibility:hidden')+';</tpl>':(a.hide?('display'===this.hideMode?'display:none':'visibility:hidden;'):''),align:a.align||'right',style:a.style?a.style:''};d.push(o)},this);var e=new Ext.XTemplate(c||this.tplRow);return new Ext.XTemplate(e.apply({actions:d}))},getAction:function(e){var a=false;var t=e.getTarget('.ux-row-action-item');if(t){a=t.className.replace(/ux-row-action-item /,'');if(a){a=a.replace(/ ux-row-action-text/,'');a=a.trim()}}return a},onClick:function(e,a){var b=this.grid.getView();var c=e.getTarget('.x-grid3-row');var d=b.findCellIndex(a.parentNode.parentNode);var f=this.getAction(e);if(false!==c&&false!==d&&false!==f){var g=this.grid.store.getAt(c.rowIndex);if(this.callbacks&&'function'===typeof this.callbacks[f]){this.callbacks[f](this.grid,g,f,c.rowIndex,d)}if(true!==this.eventsSuspended&&false===this.fireEvent('beforeaction',this.grid,g,f,c.rowIndex,d)){return}else if(true!==this.eventsSuspended){this.fireEvent('action',this.grid,g,f,c.rowIndex,d)}}t=e.getTarget('.ux-grow-action-item');if(t){var h=b.findGroup(a);var i=h?h.id.replace(/ext-gen[0-9]+-gp-/,''):null;var j;if(i){var k=new RegExp(RegExp.escape(i));j=this.grid.store.queryBy(function(r){return r._groupId.match(k)});j=j?j.items:[]}f=t.className.replace(/ux-grow-action-item (ux-action-right )*/,'');if('function'===typeof this.callbacks[f]){this.callbacks[f](this.grid,j,f,i)}if(true!==this.eventsSuspended&&false===this.fireEvent('beforegroupaction',this.grid,j,f,i)){return false}this.fireEvent('groupaction',this.grid,j,f,i)}}});Ext.reg('rowactions',Ext.ux.grid.RowActions);
  408. /*
  409. * Ext JS Library 0.30
  410. * Copyright(c) 2006-2009, Ext JS, LLC.
  411. * licensing@extjs.com
  412. *
  413. * http://extjs.com/license
  414. */
  415. Ext.SwitchButton = Ext.extend(Ext.Component, {
  416. initComponent : function(){
  417. Ext.SwitchButton.superclass.initComponent.call(this);
  418. var mc = new Ext.util.MixedCollection();
  419. mc.addAll(this.items);
  420. this.items = mc;
  421. this.addEvents('change');
  422. if(this.handler){
  423. this.on('change', this.handler, this.scope || this);
  424. }
  425. },
  426. onRender : function(ct, position){
  427. var el = document.createElement('table');
  428. el.cellSpacing = 0;
  429. el.className = 'x-rbtn';
  430. el.id = this.id;
  431. var row = document.createElement('tr');
  432. el.appendChild(document.createElement('tbody')).appendChild(row);
  433. var count = this.items.length;
  434. var last = count - 1;
  435. this.activeItem = this.items.get(this.activeItem);
  436. for(var i = 0; i < count; i++){
  437. var item = this.items.itemAt(i);
  438. var cell = row.appendChild(document.createElement('td'));
  439. cell.id = this.id + '-rbi-' + i;
  440. var cls = i == 0 ? 'x-rbtn-first' : (i == last ? 'x-rbtn-last' : 'x-rbtn-item');
  441. item.baseCls = cls;
  442. if(this.activeItem == item){
  443. cls += '-active';
  444. }
  445. cell.className = cls;
  446. var button = document.createElement('button');
  447. button.innerHTML = '&#160;';
  448. button.className = item.iconCls;
  449. button.qtip = item.tooltip;
  450. cell.appendChild(button);
  451. item.cell = cell;
  452. }
  453. this.el = Ext.get(ct.dom.appendChild(el));
  454. this.el.on('click', this.onClick, this);
  455. },
  456. getActiveItem : function(){
  457. return this.activeItem;
  458. },
  459. setActiveItem : function(item){
  460. if(typeof item != 'object' && item !== null){
  461. item = this.items.get(item);
  462. }
  463. var current = this.getActiveItem();
  464. if(item != current){
  465. if(current){
  466. Ext.fly(current.cell).removeClass(current.baseCls + '-active');
  467. }
  468. if(item) {
  469. Ext.fly(item.cell).addClass(item.baseCls + '-active');
  470. }
  471. this.activeItem = item;
  472. this.fireEvent('change', this, item);
  473. }
  474. return item;
  475. },
  476. onClick : function(e){
  477. var target = e.getTarget('td', 2);
  478. if(!this.disabled && target){
  479. this.setActiveItem(parseInt(target.id.split('-rbi-')[1], 10));
  480. }
  481. }
  482. });
  483. Ext.reg('switch', Ext.SwitchButton);
  484. Ext.onReady(function() {
  485. MODx.util.JSONReader = MODx.load({ xtype: 'modx-json-reader' });
  486. MODx.form.Handler = MODx.load({ xtype: 'modx-form-handler' });
  487. MODx.msg = MODx.load({ xtype: 'modx-msg' });
  488. });
  489. /* always-submit checkboxes */
  490. Ext.form.XCheckbox=Ext.extend(Ext.form.Checkbox,{submitOffValue:0,submitOnValue:1,onRender:function(){this.inputValue=this.submitOnValue;Ext.form.XCheckbox.superclass.onRender.apply(this,arguments);this.hiddenField=this.wrap.insertFirst({tag:'input',type:'hidden'});if(this.tooltip){this.imageEl.set({qtip:this.tooltip})}this.updateHidden()},setValue:function(v){v=this.convertValue(v);this.updateHidden(v);Ext.form.XCheckbox.superclass.setValue.apply(this,arguments)},updateHidden:function(v){v=undefined!==v?v:this.checked;v=this.convertValue(v);if(this.hiddenField){this.hiddenField.dom.value=v?this.submitOnValue:this.submitOffValue;this.hiddenField.dom.name=v?'':this.el.dom.name}},convertValue:function(v){return(v===true||v==='true'||v===this.submitOnValue||String(v).toLowerCase()==='on')}});Ext.reg('xcheckbox',Ext.form.XCheckbox);
  491. /* drag/drop grids */
  492. Ext.namespace('Ext.ux.dd');Ext.ux.dd.GridDragDropRowOrder=Ext.extend(Ext.util.Observable,{copy:false,scrollable:false,constructor:function(config){if(config)Ext.apply(this,config);this.addEvents({beforerowmove:true,afterrowmove:true,beforerowcopy:true,afterrowcopy:true});Ext.ux.dd.GridDragDropRowOrder.superclass.constructor.call(this)},init:function(grid){this.grid=grid;grid.enableDragDrop=true;grid.on({render:{fn:this.onGridRender,scope:this,single:true}})},onGridRender:function(grid){var self=this;this.target=new Ext.dd.DropTarget(grid.getEl(),{ddGroup:grid.ddGroup||'GridDD',grid:grid,gridDropTarget:this,notifyDrop:function(dd,e,data){if(this.currentRowEl){this.currentRowEl.removeClass('grid-row-insert-below');this.currentRowEl.removeClass('grid-row-insert-above')}var t=Ext.lib.Event.getTarget(e);var rindex=this.grid.getView().findRowIndex(t);if(rindex===false||rindex==data.rowIndex){return false}if(this.gridDropTarget.fireEvent(self.copy?'beforerowcopy':'beforerowmove',this.gridDropTarget,data.rowIndex,rindex,data.selections,123)===false){return false}var ds=this.grid.getStore();var selections=new Array();var keys=ds.data.keys;for(var key in keys){for(var i=0;i<data.selections.length;i++){if(keys[key]==data.selections[i].id){if(rindex==key){return false}selections.push(data.selections[i])}}}if(rindex>data.rowIndex&&this.rowPosition<0){rindex--}if(rindex<data.rowIndex&&this.rowPosition>0){rindex++}if(rindex>data.rowIndex&&data.selections.length>1){rindex=rindex-(data.selections.length-1)}if(rindex==data.rowIndex){return false}if(!self.copy){for(var i=0;i<data.selections.length;i++){ds.remove(ds.getById(data.selections[i].id))}}for(var i=selections.length-1;i>=0;i--){var insertIndex=rindex;ds.insert(insertIndex,selections[i])}var sm=this.grid.getSelectionModel();if(sm){sm.selectRecords(data.selections)}this.gridDropTarget.fireEvent(self.copy?'afterrowcopy':'afterrowmove',this.gridDropTarget,data.rowIndex,rindex,data.selections);return true},notifyOver:function(dd,e,data){var t=Ext.lib.Event.getTarget(e);var rindex=this.grid.getView().findRowIndex(t);var ds=this.grid.getStore();var keys=ds.data.keys;for(var key in keys){for(var i=0;i<data.selections.length;i++){if(keys[key]==data.selections[i].id){if(rindex==key){if(this.currentRowEl){this.currentRowEl.removeClass('grid-row-insert-below');this.currentRowEl.removeClass('grid-row-insert-above')}return this.dropNotAllowed}}}}if(rindex<0||rindex===false){this.currentRowEl.removeClass('grid-row-insert-above');return this.dropNotAllowed}try{var currentRow=this.grid.getView().getRow(rindex);var resolvedRow=new Ext.Element(currentRow).getY()-this.grid.getView().scroller.dom.scrollTop;var rowHeight=currentRow.offsetHeight;this.rowPosition=e.getPageY()-resolvedRow-(rowHeight/2);if(this.currentRowEl){this.currentRowEl.removeClass('grid-row-insert-below');this.currentRowEl.removeClass('grid-row-insert-above')}if(this.rowPosition>0){this.currentRowEl=new Ext.Element(currentRow);this.currentRowEl.addClass('grid-row-insert-below')}else{if(rindex-1>=0){var previousRow=this.grid.getView().getRow(rindex-1);this.currentRowEl=new Ext.Element(previousRow);this.currentRowEl.addClass('grid-row-insert-below')}else{this.currentRowEl.addClass('grid-row-insert-above')}}}catch(err){console.warn(err);rindex=false}return(rindex===false)?this.dropNotAllowed:this.dropAllowed},notifyOut:function(dd,e,data){if(this.currentRowEl){this.currentRowEl.removeClass('grid-row-insert-above');this.currentRowEl.removeClass('grid-row-insert-below')}}});if(this.targetCfg){Ext.apply(this.target,this.targetCfg)}if(this.scrollable){Ext.dd.ScrollManager.register(grid.getView().getEditorParent());grid.on({beforedestroy:this.onBeforeDestroy,scope:this,single:true})}},getTarget:function(){return this.target},getGrid:function(){return this.grid},getCopy:function(){return this.copy?true:false},setCopy:function(b){this.copy=b?true:false},onBeforeDestroy:function(grid){Ext.dd.ScrollManager.unregister(grid.getView().getEditorParent())}});
  493. /** selectability in Ext grids */
  494. if (!Ext.grid.GridView.prototype.templates) {
  495. Ext.grid.GridView.prototype.templates = {};
  496. }
  497. Ext.grid.GridView.prototype.templates.cell = new Ext.Template(
  498. '<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} x-selectable {css}" style="{style}" tabIndex="0" {cellAttr}>',
  499. '<div class="x-grid3-cell-inner x-grid3-col-{id}" {attr}>{value}</div>',
  500. '</td>'
  501. );
  502. /* combocolumn */
  503. if (!MODx.grid) { MODx.grid = {}; }
  504. MODx.grid.ComboColumn = Ext.extend(Ext.grid.Column,{
  505. gridId: undefined
  506. ,constructor: function(cfg){
  507. MODx.grid.ComboColumn.superclass.constructor.call(this, cfg);
  508. this.renderer = (this.editor && this.editor.triggerAction) ? MODx.grid.ComboBoxRenderer(this.editor,this.gridId) : function(value) {return value;};
  509. }
  510. });
  511. Ext.grid.Column.types['combocolumn'] = MODx.grid.ComboColumn;
  512. MODx.grid.ComboBoxRenderer = function(combo, gridId) {
  513. var getValue = function(value) {
  514. var idx = combo.store.find(combo.valueField, value);
  515. var rec = combo.store.getAt(idx);
  516. if (rec) {
  517. return rec.get(combo.displayField);
  518. }
  519. return value;
  520. };
  521. return function(value) {
  522. if (combo.store.getCount() == 0 && gridId) {
  523. combo.store.on(
  524. 'load',
  525. function() {
  526. var grid = Ext.getCmp(gridId);
  527. if (grid) {
  528. grid.getView().refresh();
  529. }
  530. },{single: true}
  531. );
  532. return value;
  533. }
  534. return getValue(value);
  535. };
  536. };
  537. Ext.Button.buttonTemplate = new Ext.Template(
  538. '<span id="{4}" class="x-btn {1} {3}" unselectable="on"><em class="{2}"><button type="{0}"></button></em></span>'
  539. );
  540. Ext.Button.buttonTemplate.compile();
  541. Ext.TabPanel.prototype.itemTpl = new Ext.Template(
  542. '<li class="{cls}" id="{id}"><a class="x-tab-strip-close"></a>',
  543. '<span class="x-tab-strip-text {iconCls}">{text}</span></li>'
  544. );
  545. Ext.TabPanel.prototype.itemTpl.disableFormats = true;
  546. Ext.TabPanel.prototype.itemTpl.compile();