Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

aui-datatable-edit.js 31KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439
  1. AUI.add('aui-datatable-edit', function(A) {
  2. var Lang = A.Lang,
  3. AArray = A.Array,
  4. AEscape = A.Escape,
  5. isArray = Lang.isArray,
  6. isBoolean = Lang.isBoolean,
  7. isFunction = Lang.isFunction,
  8. isObject = Lang.isObject,
  9. isString = Lang.isString,
  10. LString = Lang.String,
  11. _toInitialCap = A.cached(function(str) {
  12. return str.substring(0, 1).toUpperCase() + str.substring(1);
  13. }),
  14. isBaseEditor = function(val) {
  15. return (val instanceof A.BaseCellEditor);
  16. },
  17. WidgetStdMod = A.WidgetStdMod,
  18. AgetClassName = A.getClassName,
  19. ADD = 'add',
  20. ADD_OPTION = 'addOption',
  21. BASE_CELL_EDITOR = 'baseCellEditor',
  22. BOUNDING_BOX = 'boundingBox',
  23. CALENDAR = 'calendar',
  24. CANCEL = 'cancel',
  25. CELL = 'cell',
  26. CELLEDITOR = 'celleditor',
  27. CHECKBOX_CELL_EDITOR = 'checkboxCellEditor',
  28. CHECKED = 'checked',
  29. CLICK = 'click',
  30. COLUMNSET = 'columnset',
  31. CONTENT_BOX = 'contentBox',
  32. DATA = 'data',
  33. DATATABLE = 'datatable',
  34. DATE_CELL_EDITOR = 'dateCellEditor',
  35. DD = 'dd',
  36. DELETE = 'delete',
  37. DISK = 'disk',
  38. DOTTED = 'dotted',
  39. DROP_DOWN_CELL_EDITOR = 'dropDownCellEditor',
  40. EDIT = 'edit',
  41. EDITABLE = 'editable',
  42. EDITOR = 'editor',
  43. EDIT_EVENT = 'editEvent',
  44. EDIT_OPTIONS = 'editOptions',
  45. ELEMENT = 'element',
  46. ELEMENT_NAME = 'elementName',
  47. FIELD = 'field',
  48. GRIP = 'grip',
  49. HANDLE = 'handle',
  50. HIDE = 'hide',
  51. HIDE_ON_SAVE = 'hideOnSave',
  52. ICON = 'icon',
  53. ID = 'id',
  54. INIT_EDIT = 'initEdit',
  55. INIT_TOOLBAR = 'initToolbar',
  56. INIT_VALIDATOR = 'initValidator',
  57. INPUT = 'input',
  58. INPUT_FORMATTER = 'inputFormatter',
  59. KEY = 'key',
  60. LABEL = 'label',
  61. LINK = 'link',
  62. MOUSEDOWN = 'mousedown',
  63. MULTIPLE = 'multiple',
  64. NAME = 'name',
  65. OPTION = 'option',
  66. OPTIONS = 'options',
  67. OPTIONS_CELL_EDITOR = 'optionsCellEditor',
  68. OUTPUT_FORMATTER = 'outputFormatter',
  69. PENCIL = 'pencil',
  70. RADIO_CELL_EDITOR = 'radioCellEditor',
  71. RECORDS = 'records',
  72. RECORDSET = 'recordset',
  73. REMOVE = 'remove',
  74. RENDERED = 'rendered',
  75. RETURN = 'return',
  76. ROW = 'row',
  77. SAVE = 'save',
  78. SELECTED = 'selected',
  79. SELECTED_ATTR_NAME = 'selectedAttrName',
  80. SHOW_TOOLBAR = 'showToolbar',
  81. SUBMIT = 'submit',
  82. TEXT_AREA_CELL_EDITOR = 'textAreaCellEditor',
  83. TEXT_CELL_EDITOR = 'textCellEditor',
  84. TOOLBAR = 'toolbar',
  85. UNESCAPE_VALUE = 'unescapeValue',
  86. VALIDATOR = 'validator',
  87. VALUE = 'value',
  88. VERTICAL = 'vertical',
  89. VISIBLE = 'visible',
  90. WRAPPER = 'wrapper',
  91. _COMMA = ',',
  92. _DOT = '.',
  93. _EMPTY_STR = '',
  94. _HASH = '#',
  95. _NL = '\n',
  96. _SPACE = ' ',
  97. REGEX_BR = /<br\s*\/?>/gi,
  98. REGEX_NL = /[\r\n]/g,
  99. CSS_CELLEDITOR_EDIT = AgetClassName(CELLEDITOR, EDIT),
  100. CSS_CELLEDITOR_EDIT_ADD_OPTION = AgetClassName(CELLEDITOR, EDIT, ADD, OPTION),
  101. CSS_CELLEDITOR_EDIT_DD_HANDLE = AgetClassName(CELLEDITOR, EDIT, DD, HANDLE),
  102. CSS_CELLEDITOR_EDIT_DELETE_OPTION = AgetClassName(CELLEDITOR, EDIT, DELETE, OPTION),
  103. CSS_CELLEDITOR_EDIT_HIDE_OPTION = AgetClassName(CELLEDITOR, EDIT, HIDE, OPTION),
  104. CSS_CELLEDITOR_EDIT_INPUT_NAME = AgetClassName(CELLEDITOR, EDIT, INPUT, NAME),
  105. CSS_CELLEDITOR_EDIT_INPUT_VALUE = AgetClassName(CELLEDITOR, EDIT, INPUT, VALUE),
  106. CSS_CELLEDITOR_EDIT_LABEL = AgetClassName(CELLEDITOR, EDIT, LABEL),
  107. CSS_CELLEDITOR_EDIT_LINK = AgetClassName(CELLEDITOR, EDIT, LINK),
  108. CSS_CELLEDITOR_EDIT_OPTION_ROW = AgetClassName(CELLEDITOR, EDIT, OPTION, ROW),
  109. CSS_CELLEDITOR_ELEMENT = AgetClassName(CELLEDITOR, ELEMENT),
  110. CSS_CELLEDITOR_LABEL = AgetClassName(CELLEDITOR, LABEL),
  111. CSS_CELLEDITOR_OPTION = AgetClassName(CELLEDITOR, OPTION),
  112. CSS_CELLEDITOR_WRAPPER = AgetClassName(CELLEDITOR, WRAPPER),
  113. CSS_DATATABLE_EDITABLE = AgetClassName(DATATABLE, EDITABLE),
  114. CSS_ICON = AgetClassName(ICON),
  115. CSS_ICON_GRIP_DOTTED_VERTICAL = AgetClassName(ICON, GRIP, DOTTED, VERTICAL),
  116. TPL_BR = '<br/>';
  117. /**
  118. * An extension for A.DataTable.Base to support Cell Editing:
  119. *
  120. * Check the list of <a href="CellEditorSupport.html#configattributes">Configuration Attributes</a> available for
  121. * CellEditorSupport.
  122. *
  123. * @param config {Object} Object literal specifying widget configuration properties.
  124. *
  125. * @class CellEditorSupport
  126. * @constructor
  127. * @extends Base
  128. */
  129. var CellEditorSupport = function() {};
  130. CellEditorSupport.NAME = 'dataTableCellEditorSupport';
  131. CellEditorSupport.ATTRS = {
  132. editEvent: {
  133. setter: '_setEditEvent',
  134. validator: isString,
  135. value: CLICK
  136. }
  137. };
  138. A.mix(CellEditorSupport.prototype, {
  139. initializer: function() {
  140. var instance = this;
  141. instance.after({
  142. render: instance._afterRenderEditor
  143. });
  144. instance.on(instance.get(EDIT_EVENT), instance._onCellEdit);
  145. instance.after(instance._afterUiSetRecordset, instance, '_uiSetRecordset');
  146. },
  147. getCellEditor: function(record, column) {
  148. var instance = this;
  149. var columnEditor = column.get(EDITOR);
  150. var recordEditor = record.get(DATA).editor;
  151. if (columnEditor === false || recordEditor === false) {
  152. return null;
  153. }
  154. return recordEditor || columnEditor;
  155. },
  156. getRecordColumnValue: function(record, column) {
  157. return record.getValue(column.get(FIELD));
  158. },
  159. syncEditableColumnsUI: function() {
  160. var instance = this;
  161. var columnset = instance.get(COLUMNSET);
  162. var recordset = instance.get(RECORDSET);
  163. A.each(columnset.idHash, function(column) {
  164. var editor = column.get(EDITOR);
  165. if (isBaseEditor(editor)) {
  166. A.all('[headers='+column.get(ID)+']').addClass(CSS_DATATABLE_EDITABLE);
  167. }
  168. });
  169. A.each(recordset.get(RECORDS), function(record) {
  170. var editor = record.get(DATA).editor;
  171. var isBaseEditorInstance = isBaseEditor(editor);
  172. A.all(_HASH + record.get("id") + '>td').each(function(td, index) {
  173. var column = columnset.getColumn(index);
  174. if (editor === false) {
  175. td.removeClass(CSS_DATATABLE_EDITABLE);
  176. }
  177. else if (isBaseEditorInstance || (column.get(EDITOR) !== false)) {
  178. td.addClass(CSS_DATATABLE_EDITABLE);
  179. }
  180. });
  181. });
  182. },
  183. _afterUiSetRecordset: function(event) {
  184. var instance = this;
  185. instance.syncEditableColumnsUI();
  186. },
  187. _afterRenderEditor: function(event) {
  188. var instance = this;
  189. if (!instance.events) {
  190. instance.plug(A.Plugin.DataTableEvents);
  191. }
  192. },
  193. _editCell: function(event) {
  194. var instance = this;
  195. var columnset = instance.get(COLUMNSET);
  196. var recordset = instance.get(RECORDSET);
  197. var column = event.column;
  198. var record = event.record;
  199. instance.activeColumnIndex = columnset.getColumnIndex(column);
  200. instance.activeRecordIndex = recordset.getRecordIndex(record);
  201. var alignNode = event.alignNode || event.cell;
  202. var editor = instance.getCellEditor(record, column);
  203. if (isBaseEditor(editor)) {
  204. if (!editor.get(RENDERED)) {
  205. editor.on({
  206. visibleChange: A.bind(instance._onEditorVisibleChange, instance),
  207. save: A.bind(instance._onEditorSave, instance)
  208. });
  209. editor.render();
  210. }
  211. editor.set(
  212. VALUE,
  213. instance.getRecordColumnValue(record, column)
  214. );
  215. editor.show().move(alignNode.getXY());
  216. }
  217. },
  218. _onCellEdit: function(event) {
  219. var instance = this;
  220. instance._editCell(event);
  221. },
  222. _onEditorVisibleChange: function(event) {
  223. var instance = this;
  224. var editor = event.currentTarget;
  225. var selection = instance.selection;
  226. if (selection) {
  227. var activeRecord = selection.getActiveRecord();
  228. var activeColumn = selection.getActiveColumn();
  229. var cell = instance.getCellNode(activeRecord, activeColumn);
  230. var row = instance.getRowNode(activeRecord);
  231. if (event.newVal) {
  232. editor._syncFocus();
  233. }
  234. else {
  235. selection.select(cell, row);
  236. }
  237. }
  238. },
  239. _onEditorSave: function(event) {
  240. var instance = this;
  241. var editor = event.currentTarget;
  242. var recordset = instance.get(RECORDSET);
  243. editor.set(VALUE, event.newVal);
  244. var selection = instance.selection;
  245. if (selection) {
  246. var newVal = A.Escape.html(event.newVal);
  247. recordset.updateRecordDataByKey(
  248. selection.getActiveRecord(),
  249. selection.getActiveColumn().get(KEY),
  250. newVal
  251. );
  252. }
  253. },
  254. _setEditEvent: function(val) {
  255. return CELL + _toInitialCap(val);
  256. }
  257. });
  258. A.DataTable.CellEditorSupport = CellEditorSupport;
  259. // Augment A.DataTable.Base with A.DataTable.CellEditorSupport
  260. A.DataTable.Base = A.Base.create('dataTable', A.DataTable.Base, [A.DataTable.CellEditorSupport]);
  261. /**
  262. * Abstract class BaseCellEditor.
  263. *
  264. * Check the list of <a href="BaseCellEditor.html#configattributes">Configuration Attributes</a> available for
  265. * BaseCellEditor.
  266. *
  267. * @param config {Object} Object literal specifying widget configuration properties.
  268. *
  269. * @class BaseCellEditor
  270. * @abstract
  271. * @extends A.Overlay
  272. */
  273. var BaseCellEditor = A.Component.create({
  274. NAME: BASE_CELL_EDITOR,
  275. ATTRS: {
  276. editable: {
  277. value: false,
  278. validator: isBoolean
  279. },
  280. elementName: {
  281. value: VALUE,
  282. validator: isString
  283. },
  284. footerContent: {
  285. value: _EMPTY_STR
  286. },
  287. hideOnSave: {
  288. value: true,
  289. validator: isBoolean
  290. },
  291. inputFormatter: {
  292. value: function(val) {
  293. if (isString(val)) {
  294. val = val.replace(REGEX_NL, TPL_BR);
  295. }
  296. return val;
  297. }
  298. },
  299. outputFormatter: {
  300. value: function(val) {
  301. var instance = this;
  302. if (isString(val)) {
  303. if (instance.get(UNESCAPE_VALUE)) {
  304. val = LString.unescapeEntities(val);
  305. }
  306. // console.log(val);
  307. val = val.replace(REGEX_BR, _NL);
  308. }
  309. return val;
  310. }
  311. },
  312. showToolbar: {
  313. value: true,
  314. validator: isBoolean
  315. },
  316. strings: {
  317. value: {
  318. edit: 'Edit',
  319. save: 'Save',
  320. cancel: 'Cancel'
  321. }
  322. },
  323. tabIndex: {
  324. value: 1
  325. },
  326. toolbar: {
  327. setter: '_setToolbar',
  328. validator: isObject,
  329. value: null
  330. },
  331. unescapeValue: {
  332. value: true,
  333. validator: isBoolean
  334. },
  335. validator: {
  336. setter: '_setValidator',
  337. validator: isObject,
  338. value: null
  339. },
  340. value: {
  341. value: _EMPTY_STR
  342. },
  343. visible: {
  344. value: false
  345. }
  346. },
  347. EXTENDS: A.Overlay,
  348. UI_ATTRS: [ EDITABLE, SHOW_TOOLBAR, VALUE ],
  349. prototype: {
  350. CONTENT_TEMPLATE: '<form></form>',
  351. ELEMENT_TEMPLATE: null,
  352. elements: null,
  353. validator: null,
  354. _hDocMouseDownEv: null,
  355. initializer: function(config) {
  356. var instance = this;
  357. instance._initEvents();
  358. },
  359. destructor: function() {
  360. var instance = this;
  361. var hDocMouseDown = instance._hDocMouseDownEv;
  362. var toolbar = instance.toolbar;
  363. var validator = instance.validator;
  364. if (hDocMouseDown) {
  365. hDocMouseDown.detach();
  366. }
  367. if (toolbar) {
  368. toolbar.destroy();
  369. }
  370. if (validator) {
  371. validator.destroy();
  372. }
  373. },
  374. bindUI: function() {
  375. var instance = this;
  376. instance.get(BOUNDING_BOX).on(KEY, A.bind(instance._onEscKey, instance), 'down:27');
  377. },
  378. formatValue: function(formatter, val) {
  379. var instance = this;
  380. if (isFunction(formatter)) {
  381. val = formatter.call(instance, val);
  382. }
  383. return val;
  384. },
  385. getValue: function() {
  386. var instance = this;
  387. return instance.formatValue(
  388. instance.get(INPUT_FORMATTER),
  389. instance.getElementsValue()
  390. );
  391. },
  392. _initEvents: function() {
  393. var instance = this;
  394. instance.publish({
  395. cancel: {
  396. defaultFn: instance._defCancelFn
  397. },
  398. initEdit: {
  399. defaultFn: instance._defInitEditFn,
  400. fireOnce: true
  401. },
  402. initValidator: {
  403. defaultFn: instance._defInitValidatorFn,
  404. fireOnce: true
  405. },
  406. initToolbar: {
  407. defaultFn: instance._defInitToolbarFn,
  408. fireOnce: true
  409. },
  410. save: {
  411. defaultFn: instance._defSaveFn
  412. }
  413. });
  414. instance.after({
  415. render: instance._afterRender,
  416. visibleChange: A.debounce(instance._debounceVisibleChange, 350, instance)
  417. });
  418. instance.on({
  419. 'form-validator:submit': A.bind(instance._onSubmit, instance)
  420. });
  421. },
  422. _afterRender: function() {
  423. var instance = this;
  424. instance._handleInitValidatorEvent();
  425. instance._handleInitToolbarEvent();
  426. },
  427. _defCancelFn: function(event) {
  428. var instance = this;
  429. instance.hide();
  430. },
  431. _defInitValidatorFn: function(event) {
  432. var instance = this;
  433. instance.validator = new A.FormValidator(
  434. instance.get(VALIDATOR)
  435. );
  436. },
  437. _defInitToolbarFn: function(event) {
  438. var instance = this;
  439. var editable = instance.get(EDITABLE);
  440. instance.toolbar = new A.Toolbar(
  441. instance.get(TOOLBAR)
  442. )
  443. .render(instance.footerNode);
  444. if (editable) {
  445. instance._uiSetEditable(editable);
  446. }
  447. },
  448. _defSaveFn: function(event) {
  449. var instance = this;
  450. if (instance.get(HIDE_ON_SAVE)) {
  451. instance.hide();
  452. }
  453. },
  454. _debounceVisibleChange: function(event) {
  455. var instance = this;
  456. var hDocMouseDown = instance._hDocMouseDownEv;
  457. if (event.newVal) {
  458. if (!hDocMouseDown) {
  459. instance._hDocMouseDownEv = A.getDoc().on(MOUSEDOWN, A.bind(instance._onDocMouseDownExt, instance));
  460. }
  461. }
  462. else if (hDocMouseDown) {
  463. hDocMouseDown.detach();
  464. instance._hDocMouseDownEv = null;
  465. }
  466. },
  467. _handleCancelEvent: function() {
  468. var instance = this;
  469. instance.fire(CANCEL);
  470. },
  471. _handleEditEvent: function() {
  472. var instance = this;
  473. instance.fire(EDIT);
  474. },
  475. _handleInitEditEvent: function() {
  476. var instance = this;
  477. if (instance.get(RENDERED)) {
  478. this.fire(INIT_EDIT);
  479. }
  480. },
  481. _handleInitValidatorEvent: function() {
  482. var instance = this;
  483. if (instance.get(RENDERED)) {
  484. this.fire(INIT_VALIDATOR);
  485. }
  486. },
  487. _handleInitToolbarEvent: function() {
  488. var instance = this;
  489. if (instance.get(RENDERED) && instance.get(SHOW_TOOLBAR)) {
  490. this.fire(INIT_TOOLBAR);
  491. }
  492. },
  493. _handleSaveEvent: function() {
  494. var instance = this;
  495. if (!instance.validator.hasErrors()) {
  496. instance.fire(SAVE, {
  497. newVal: instance.getValue(),
  498. prevVal: instance.get(VALUE)
  499. });
  500. }
  501. },
  502. _onDocMouseDownExt: function(event) {
  503. var instance = this;
  504. var boundingBox = instance.get(BOUNDING_BOX);
  505. if (!boundingBox.contains(event.target)) {
  506. instance.set(VISIBLE, false);
  507. }
  508. },
  509. _onEscKey: function(event) {
  510. var instance = this;
  511. instance.hide();
  512. },
  513. _onSubmit: function(event) {
  514. var instance = this;
  515. var validator = event.validator;
  516. instance._handleSaveEvent();
  517. if (validator) {
  518. validator.formEvent.halt();
  519. }
  520. },
  521. _setToolbar: function(val) {
  522. var instance = this;
  523. var strings = instance.getStrings();
  524. return A.merge(
  525. {
  526. activeState: false,
  527. children: [
  528. {
  529. label: strings[SAVE],
  530. icon: DISK,
  531. type: SUBMIT
  532. },
  533. {
  534. handler: A.bind(instance._handleCancelEvent, instance),
  535. label: strings[CANCEL]
  536. }
  537. ]
  538. },
  539. val
  540. );
  541. },
  542. _setValidator: function(val) {
  543. var instance = this;
  544. return A.merge(
  545. {
  546. boundingBox: instance.get(CONTENT_BOX),
  547. bubbleTargets: instance
  548. },
  549. val
  550. );
  551. },
  552. _uiSetShowToolbar: function(val) {
  553. var instance = this;
  554. var footerNode = instance.footerNode;
  555. if (val) {
  556. footerNode.show();
  557. }
  558. else {
  559. footerNode.hide();
  560. }
  561. instance._handleInitToolbarEvent();
  562. },
  563. /*
  564. * NOTE FOR DEVELOPERS:
  565. *
  566. * Yoy *may* want to replace the methods from this section on your implementation.
  567. */
  568. getElementsValue: function() {
  569. var instance = this;
  570. var elements = instance.elements;
  571. if (elements) {
  572. return elements.get(VALUE);
  573. }
  574. return _EMPTY_STR;
  575. },
  576. renderUI: function() {
  577. var instance = this;
  578. if (instance.ELEMENT_TEMPLATE) {
  579. instance.elements = A.Node.create(instance.ELEMENT_TEMPLATE);
  580. instance._syncElementsName();
  581. instance.setStdModContent(WidgetStdMod.BODY, instance.elements);
  582. }
  583. },
  584. _defInitEditFn: function(event) {
  585. },
  586. _syncElementsFocus: function() {
  587. var instance = this;
  588. instance.elements.selectText();
  589. },
  590. _syncElementsName: function() {
  591. var instance = this;
  592. instance.elements.setAttribute(
  593. NAME,
  594. instance.get(ELEMENT_NAME)
  595. );
  596. },
  597. _syncFocus: function() {
  598. var instance = this;
  599. A.later(0, instance, instance._syncElementsFocus);
  600. },
  601. _uiSetEditable: function(val) {
  602. var instance = this;
  603. var toolbar = instance.toolbar;
  604. if (instance.get(RENDERED) && toolbar) {
  605. if (val) {
  606. toolbar.add(
  607. {
  608. handler: A.bind(instance._handleEditEvent, instance),
  609. icon: PENCIL,
  610. label: instance.getString(EDIT)
  611. },
  612. 1
  613. );
  614. }
  615. else {
  616. toolbar.remove(1);
  617. }
  618. }
  619. },
  620. _uiSetValue: function(val) {
  621. var instance = this;
  622. var elements = instance.elements;
  623. if (elements) {
  624. elements.val(
  625. instance.formatValue(instance.get(OUTPUT_FORMATTER), val)
  626. );
  627. }
  628. }
  629. /*
  630. * End of replaceable methods.
  631. */
  632. }
  633. });
  634. A.BaseCellEditor = BaseCellEditor;
  635. /**
  636. * Abstract class BaseOptionsCellEditor for options attribute support.
  637. *
  638. * Check the list of <a href="BaseOptionsCellEditor.html#configattributes">Configuration Attributes</a> available for
  639. * BaseCellEditor.
  640. *
  641. * @param config {Object} Object literal specifying widget configuration properties.
  642. *
  643. * @class BaseOptionsCellEditor
  644. * @abstract
  645. * @extends A.BaseCellEditor
  646. */
  647. var BaseOptionsCellEditor = A.Component.create({
  648. NAME: OPTIONS_CELL_EDITOR,
  649. ATTRS: {
  650. inputFormatter: {
  651. value: null
  652. },
  653. options: {
  654. setter: '_setOptions',
  655. value: {},
  656. validator: isObject
  657. },
  658. outputFormatter: {
  659. value: null
  660. },
  661. selectedAttrName: {
  662. value: SELECTED,
  663. validator: isString
  664. },
  665. strings: {
  666. value: {
  667. add: 'Add',
  668. cancel: 'Cancel',
  669. addOption: 'Add option',
  670. edit: 'Edit options',
  671. editOptions: 'Edit option(s)',
  672. name: 'Name',
  673. remove: 'Remove',
  674. save: 'Save',
  675. stopEditing: 'Stop editing',
  676. value: 'Value'
  677. }
  678. }
  679. },
  680. EXTENDS: A.BaseCellEditor,
  681. UI_ATTRS: [OPTIONS],
  682. prototype: {
  683. EDIT_TEMPLATE: '<div class="' + CSS_CELLEDITOR_EDIT + '"></div>',
  684. EDIT_OPTION_ROW_TEMPLATE: '<div class="' + CSS_CELLEDITOR_EDIT_OPTION_ROW + '">' +
  685. '<span class="' + [ CSS_CELLEDITOR_EDIT_DD_HANDLE, CSS_ICON, CSS_ICON_GRIP_DOTTED_VERTICAL ].join(_SPACE) + '"></span>' +
  686. '<input class="' + CSS_CELLEDITOR_EDIT_INPUT_NAME + '" size="7" placeholder="{titleName}" title="{titleName}" type="text" value="{valueName}" /> ' +
  687. '<input class="' + CSS_CELLEDITOR_EDIT_INPUT_VALUE + '" size="7" placeholder="{titleValue}" title="{titleValue}" type="text" value="{valueValue}" /> ' +
  688. '<a class="' + [ CSS_CELLEDITOR_EDIT_LINK, CSS_CELLEDITOR_EDIT_DELETE_OPTION ].join(_SPACE) + '" href="javascript:void(0);">{remove}</a> ' +
  689. '</div>',
  690. EDIT_ADD_LINK_TEMPLATE: '<a class="' + [ CSS_CELLEDITOR_EDIT_LINK, CSS_CELLEDITOR_EDIT_ADD_OPTION ].join(_SPACE) + '" href="javascript:void(0);">{addOption}</a> ',
  691. EDIT_LABEL_TEMPLATE: '<div class="' + CSS_CELLEDITOR_EDIT_LABEL + '">{editOptions}</div>',
  692. editContainer: null,
  693. editSortable: null,
  694. options: null,
  695. initializer: function() {
  696. var instance = this;
  697. instance.on(EDIT, instance._onEditEvent);
  698. instance.on(SAVE, instance._onSave);
  699. instance.after(INIT_TOOLBAR, instance._afterInitToolbar);
  700. },
  701. addNewOption: function(name, value) {
  702. var instance = this;
  703. var addOptionLink = instance.editContainer.one(_DOT+CSS_CELLEDITOR_EDIT_ADD_OPTION);
  704. var newRow = A.Node.create(
  705. instance._createEditOption(
  706. name || _EMPTY_STR,
  707. value || _EMPTY_STR
  708. )
  709. );
  710. addOptionLink.placeBefore(newRow);
  711. newRow.one(INPUT).focus();
  712. },
  713. removeOption: function(optionRow) {
  714. optionRow.remove();
  715. },
  716. saveOptions: function() {
  717. var instance = this;
  718. var editContainer = instance.editContainer;
  719. if (editContainer) {
  720. var names = editContainer.all(_DOT+CSS_CELLEDITOR_EDIT_INPUT_NAME);
  721. var values = editContainer.all(_DOT+CSS_CELLEDITOR_EDIT_INPUT_VALUE);
  722. var options = {};
  723. names.each(function(inputName, index) {
  724. var name = inputName.val();
  725. var value = values.item(index).val();
  726. options[value] = name;
  727. });
  728. instance.set(OPTIONS, options);
  729. instance._uiSetValue(
  730. instance.get(VALUE)
  731. );
  732. instance.toggleEdit();
  733. }
  734. },
  735. toggleEdit: function() {
  736. var instance = this;
  737. instance.editContainer.toggle();
  738. },
  739. // TODO - rewrite this method
  740. _createOptions: function(val) {
  741. var instance = this;
  742. var elements = instance.elements;
  743. var optionsBuffer = [];
  744. var wrappersBuffer = [];
  745. var optionTpl = instance.OPTION_TEMPLATE;
  746. var optionWrapperTpl = instance.OPTION_WRAPPER;
  747. A.each(val, function(oLabel, oValue) {
  748. var values = {
  749. id: A.guid(),
  750. label: AEscape.html(oLabel),
  751. name: AEscape.html(oValue),
  752. value: AEscape.html(oValue)
  753. };
  754. if (optionTpl) {
  755. optionsBuffer.push(Lang.sub(optionTpl, values));
  756. }
  757. if (optionWrapperTpl) {
  758. wrappersBuffer.push(Lang.sub(optionWrapperTpl, values));
  759. }
  760. });
  761. var options = A.NodeList.create(optionsBuffer.join(_EMPTY_STR));
  762. var wrappers = A.NodeList.create(wrappersBuffer.join(_EMPTY_STR));
  763. if (wrappers.size()) {
  764. wrappers.each(function(wrapper, i) {
  765. wrapper.prepend(options.item(i));
  766. });
  767. elements.setContent(wrappers);
  768. }
  769. else {
  770. elements.setContent(options);
  771. }
  772. instance.options = options;
  773. },
  774. _createEditBuffer: function() {
  775. var instance = this;
  776. var strings = instance.getStrings();
  777. var buffer = [];
  778. buffer.push(
  779. Lang.sub(instance.EDIT_LABEL_TEMPLATE, {
  780. editOptions: strings[EDIT_OPTIONS]
  781. })
  782. );
  783. A.each(instance.get(OPTIONS), function(name, value) {
  784. buffer.push(instance._createEditOption(name, value));
  785. });
  786. buffer.push(
  787. Lang.sub(instance.EDIT_ADD_LINK_TEMPLATE, {
  788. addOption: strings[ADD_OPTION]
  789. })
  790. );
  791. return buffer.join(_EMPTY_STR);
  792. },
  793. _createEditOption: function(name, value) {
  794. var instance = this;
  795. var strings = instance.getStrings();
  796. return Lang.sub(
  797. instance.EDIT_OPTION_ROW_TEMPLATE,
  798. {
  799. remove: strings[REMOVE],
  800. titleName: AEscape.html(strings[NAME]),
  801. titleValue: AEscape.html(strings[VALUE]),
  802. valueName: AEscape.html(name),
  803. valueValue: AEscape.html(value)
  804. }
  805. );
  806. },
  807. _defInitEditFn: function(event) {
  808. var instance = this;
  809. var editContainer = A.Node.create(instance.EDIT_TEMPLATE);
  810. editContainer.delegate('click', A.bind(instance._onEditLinkClickEvent, instance), _DOT+CSS_CELLEDITOR_EDIT_LINK);
  811. editContainer.delegate('keydown', A.bind(instance._onEditKeyEvent, instance), INPUT);
  812. instance.editContainer = editContainer;
  813. instance.setStdModContent(
  814. WidgetStdMod.BODY,
  815. editContainer.hide(),
  816. WidgetStdMod.AFTER
  817. );
  818. instance.editSortable = new A.Sortable({
  819. container: editContainer,
  820. handles: [ _DOT+CSS_CELLEDITOR_EDIT_DD_HANDLE ],
  821. nodes: _DOT+CSS_CELLEDITOR_EDIT_OPTION_ROW,
  822. opacity: '.3'
  823. })
  824. .delegate.dd.plug(A.Plugin.DDConstrained, {
  825. constrain: editContainer,
  826. stickY: true
  827. });
  828. instance._syncEditOptionsUI();
  829. },
  830. _getSelectedOptions: function() {
  831. var instance = this;
  832. var options = [];
  833. instance.options.each(function(option) {
  834. if (option.get(instance.get(SELECTED_ATTR_NAME))) {
  835. options.push(option);
  836. }
  837. });
  838. return A.all(options);
  839. },
  840. _onEditEvent: function(event) {
  841. var instance = this;
  842. instance._handleInitEditEvent();
  843. instance.toggleEdit();
  844. instance._syncEditOptionsUI();
  845. },
  846. _onEditLinkClickEvent: function(event) {
  847. var instance = this;
  848. var currentTarget = event.currentTarget;
  849. if (currentTarget.test(_DOT+CSS_CELLEDITOR_EDIT_ADD_OPTION)) {
  850. instance.addNewOption();
  851. }
  852. else if (currentTarget.test(_DOT+CSS_CELLEDITOR_EDIT_HIDE_OPTION)) {
  853. instance.toggleEdit();
  854. }
  855. else if (currentTarget.test(_DOT+CSS_CELLEDITOR_EDIT_DELETE_OPTION)) {
  856. instance.removeOption(
  857. currentTarget.ancestor(_DOT+CSS_CELLEDITOR_EDIT_OPTION_ROW)
  858. );
  859. }
  860. event.halt();
  861. },
  862. _onEditKeyEvent: function(event) {
  863. var instance = this;
  864. var currentTarget = event.currentTarget;
  865. if (event.isKey(RETURN)) {
  866. var nextInput = currentTarget.next(INPUT);
  867. if (nextInput) {
  868. nextInput.selectText();
  869. }
  870. else {
  871. instance.addNewOption();
  872. }
  873. event.halt();
  874. }
  875. },
  876. _onSave: function(event) {
  877. var instance = this;
  878. instance.saveOptions();
  879. },
  880. _setOptions: function(val) {
  881. var options = {};
  882. if (isArray(val)) {
  883. AArray.each(val, function(value) {
  884. options[value] = value;
  885. });
  886. }
  887. else if (isObject(val)) {
  888. options = val;
  889. }
  890. return options;
  891. },
  892. _syncEditOptionsUI: function() {
  893. var instance = this;
  894. instance.editContainer.setContent(instance._createEditBuffer());
  895. },
  896. _uiSetOptions: function(val) {
  897. var instance = this;
  898. instance._uiSetValue(instance.get(VALUE));
  899. instance._createOptions(val);
  900. instance._syncElementsName();
  901. },
  902. _uiSetValue: function(val) {
  903. var instance = this;
  904. var options = instance.options;
  905. if (options && options.size()) {
  906. options.set(instance.get(SELECTED_ATTR_NAME), false);
  907. if (val) {
  908. if (!isArray(val)) {
  909. val = val.split(_COMMA);
  910. }
  911. AArray.each(val, function(value) {
  912. options.filter('[value="' + AEscape.html(Lang.trim(value)) + '"]').set(instance.get(SELECTED_ATTR_NAME), true);
  913. });
  914. }
  915. }
  916. return val;
  917. }
  918. }
  919. });
  920. A.BaseOptionsCellEditor = BaseOptionsCellEditor;
  921. /**
  922. * TextCellEditor class.
  923. *
  924. * Check the list of <a href="TextCellEditor.html#configattributes">Configuration Attributes</a> available for
  925. * TextCellEditor.
  926. *
  927. * @param config {Object} Object literal specifying widget configuration properties.
  928. *
  929. * @class TextCellEditor
  930. * @constructor
  931. * @extends A.BaseCellEditor
  932. */
  933. var TextCellEditor = A.Component.create({
  934. NAME: TEXT_CELL_EDITOR,
  935. EXTENDS: A.BaseCellEditor,
  936. prototype: {
  937. ELEMENT_TEMPLATE: '<input autocomplete="off" class="' + CSS_CELLEDITOR_ELEMENT + '" type="text" />'
  938. }
  939. });
  940. A.TextCellEditor = TextCellEditor;
  941. /**
  942. * TextAreaCellEditor class.
  943. *
  944. * Check the list of <a href="TextAreaCellEditor.html#configattributes">Configuration Attributes</a> available for
  945. * TextAreaCellEditor.
  946. *
  947. * @param config {Object} Object literal specifying widget configuration properties.
  948. *
  949. * @class TextAreaCellEditor
  950. * @constructor
  951. * @extends A.TextAreaCellEditor
  952. */
  953. var TextAreaCellEditor = A.Component.create({
  954. NAME: TEXT_AREA_CELL_EDITOR,
  955. EXTENDS: A.BaseCellEditor,
  956. prototype: {
  957. ELEMENT_TEMPLATE: '<textarea class="' + CSS_CELLEDITOR_ELEMENT + '"></textarea>'
  958. }
  959. });
  960. A.TextAreaCellEditor = TextAreaCellEditor;
  961. /**
  962. * DropDownCellEditor class.
  963. *
  964. * Check the list of <a href="DropDownCellEditor.html#configattributes">Configuration Attributes</a> available for
  965. * DropDownCellEditor.
  966. *
  967. * @param config {Object} Object literal specifying widget configuration properties.
  968. *
  969. * @class DropDownCellEditor
  970. * @constructor
  971. * @extends A.DropDownCellEditor
  972. */
  973. var DropDownCellEditor = A.Component.create({
  974. NAME: DROP_DOWN_CELL_EDITOR,
  975. ATTRS: {
  976. multiple: {
  977. value: false,
  978. validator: isBoolean
  979. }
  980. },
  981. EXTENDS: A.BaseOptionsCellEditor,
  982. UI_ATTRS: [MULTIPLE],
  983. prototype: {
  984. ELEMENT_TEMPLATE: '<select class="' + CSS_CELLEDITOR_ELEMENT + '"></select>',
  985. OPTION_TEMPLATE: '<option value="{value}">{label}</option>',
  986. getElementsValue: function() {
  987. var instance = this;
  988. if (instance.get(MULTIPLE)) {
  989. return instance._getSelectedOptions().get(VALUE);
  990. }
  991. return instance.elements.get(VALUE);
  992. },
  993. _syncElementsFocus: function() {
  994. var instance = this;
  995. instance.elements.focus();
  996. },
  997. _uiSetMultiple: function(val) {
  998. var instance = this;
  999. var elements = instance.elements;
  1000. if (val) {
  1001. elements.setAttribute(MULTIPLE, MULTIPLE);
  1002. }
  1003. else {
  1004. elements.removeAttribute(MULTIPLE);
  1005. }
  1006. }
  1007. }
  1008. });
  1009. A.DropDownCellEditor = DropDownCellEditor;
  1010. /**
  1011. * CheckboxCellEditor class.
  1012. *
  1013. * Check the list of <a href="DropDownCellEditor.html#configattributes">Configuration Attributes</a> available for
  1014. * CheckboxCellEditor.
  1015. *
  1016. * @param config {Object} Object literal specifying widget configuration properties.
  1017. *
  1018. * @class CheckboxCellEditor
  1019. * @constructor
  1020. * @extends A.CheckboxCellEditor
  1021. */
  1022. var CheckboxCellEditor = A.Component.create({
  1023. NAME: CHECKBOX_CELL_EDITOR,
  1024. ATTRS: {
  1025. selectedAttrName: {
  1026. value: CHECKED
  1027. }
  1028. },
  1029. EXTENDS: A.BaseOptionsCellEditor,
  1030. prototype: {
  1031. ELEMENT_TEMPLATE: '<div class="' + CSS_CELLEDITOR_ELEMENT + '"></div>',
  1032. OPTION_TEMPLATE: '<input class="' + CSS_CELLEDITOR_OPTION + '" id="{id}" name="{name}" type="checkbox" value="{value}"/>',
  1033. OPTION_WRAPPER: '<label class="' + CSS_CELLEDITOR_WRAPPER + '" for="{id}"><span class="' + CSS_CELLEDITOR_LABEL + '">{label}</span></label>',
  1034. getElementsValue: function() {
  1035. var instance = this;
  1036. return instance._getSelectedOptions().get(VALUE);
  1037. },
  1038. _syncElementsFocus: function() {
  1039. var instance = this;
  1040. var options = instance.options;
  1041. if (options && options.size()) {
  1042. options.item(0).focus();
  1043. }
  1044. },
  1045. _syncElementsName: function() {
  1046. var instance = this;
  1047. var options = instance.options;
  1048. if (options) {
  1049. options.setAttribute(NAME, instance.get(ELEMENT_NAME));
  1050. }
  1051. }
  1052. }
  1053. });
  1054. A.CheckboxCellEditor = CheckboxCellEditor;
  1055. /**
  1056. * RadioCellEditor class.
  1057. *
  1058. * Check the list of <a href="RadioCellEditor.html#configattributes">Configuration Attributes</a> available for
  1059. * RadioCellEditor.
  1060. *
  1061. * @param config {Object} Object literal specifying widget configuration properties.
  1062. *
  1063. * @class RadioCellEditor
  1064. * @constructor
  1065. * @extends A.RadioCellEditor
  1066. */
  1067. var RadioCellEditor = A.Component.create({
  1068. NAME: RADIO_CELL_EDITOR,
  1069. EXTENDS: A.CheckboxCellEditor,
  1070. prototype: {
  1071. OPTION_TEMPLATE: '<input class="aui-field-input-choice" id="{id}" name="{name}" type="radio" value="{value}"/>',
  1072. getElementsValue: function() {
  1073. var instance = this;
  1074. return instance._getSelectedOptions().get(VALUE)[0];
  1075. }
  1076. }
  1077. });
  1078. A.RadioCellEditor = RadioCellEditor;
  1079. /**
  1080. * DateCellEditor class.
  1081. *
  1082. * Check the list of <a href="DateCellEditor.html#configattributes">Configuration Attributes</a> available for
  1083. * DateCellEditor.
  1084. *
  1085. * @param config {Object} Object literal specifying widget configuration properties.
  1086. *
  1087. * @class DateCellEditor
  1088. * @constructor
  1089. * @extends A.DateCellEditor
  1090. */
  1091. var DateCellEditor = A.Component.create({
  1092. NAME: DATE_CELL_EDITOR,
  1093. EXTENDS: A.BaseCellEditor,
  1094. ATTRS: {
  1095. bodyContent: {
  1096. value: _EMPTY_STR
  1097. },
  1098. calendar: {
  1099. setter: '_setCalendar',
  1100. validator: isObject,
  1101. value: null
  1102. }
  1103. },
  1104. prototype: {
  1105. ELEMENT_TEMPLATE: '<input class="' + CSS_CELLEDITOR_ELEMENT + '" type="hidden" />',
  1106. initializer: function() {
  1107. var instance = this;
  1108. instance.on('calendar:select', A.bind(instance._onDateSelect, instance));
  1109. },
  1110. getElementsValue: function() {
  1111. var instance = this;
  1112. return instance.calendar.getFormattedSelectedDates().join(_COMMA);
  1113. },
  1114. _afterRender: function() {
  1115. var instance = this;
  1116. A.DateCellEditor.superclass._afterRender.apply(instance, arguments);
  1117. instance.calendar = new A.Calendar(
  1118. instance.get(CALENDAR)
  1119. )
  1120. .render(instance.bodyNode);
  1121. },
  1122. _onDateSelect: function(event) {
  1123. var instance = this;
  1124. instance.elements.val(
  1125. event.date.formatted.join(_COMMA)
  1126. );
  1127. },
  1128. _setCalendar: function(val) {
  1129. var instance = this;
  1130. return A.merge(
  1131. {
  1132. bubbleTargets: instance
  1133. },
  1134. val
  1135. );
  1136. },
  1137. _uiSetValue: function(val) {
  1138. var instance = this;
  1139. var calendar = instance.calendar;
  1140. if (calendar) {
  1141. if (val && isString(val)) {
  1142. val = val.split(_COMMA);
  1143. }
  1144. instance.calendar.set('dates', val);
  1145. }
  1146. }
  1147. }
  1148. });
  1149. A.DateCellEditor = DateCellEditor;
  1150. }, '@VERSION@' ,{requires:['aui-calendar','aui-datatable-events','aui-toolbar','aui-form-validator','escape','overlay','sortable'], skinnable:true});