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-tree-debug.js 85KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012
  1. AUI.add('aui-tree-data', function(A) {
  2. /**
  3. * The TreeData Utility
  4. *
  5. * @module aui-tree
  6. * @submodule aui-tree-data
  7. */
  8. var L = A.Lang,
  9. isArray = L.isArray,
  10. isBoolean = L.isBoolean,
  11. isObject = L.isObject,
  12. isUndefined = L.isUndefined,
  13. BOUNDING_BOX = 'boundingBox',
  14. CHILDREN = 'children',
  15. CONTAINER = 'container',
  16. DOT = '.',
  17. ID = 'id',
  18. INDEX = 'index',
  19. LAZY_LOAD = 'lazyLoad',
  20. LEAF = 'leaf',
  21. NEXT_SIBLING = 'nextSibling',
  22. NODE = 'node',
  23. OWNER_TREE = 'ownerTree',
  24. PARENT_NODE = 'parentNode',
  25. PREV_SIBLING = 'prevSibling',
  26. PREVIOUS_SIBLING = 'previousSibling',
  27. TREE = 'tree',
  28. TREE_NODE = 'tree-node',
  29. TREE_DATA = 'tree-data',
  30. isTreeNode = function(v) {
  31. return ( A.instanceOf(v, A.TreeNode) );
  32. },
  33. isTreeView = function(v) {
  34. return ( A.instanceOf(v, A.TreeView) );
  35. },
  36. getCN = A.getClassName,
  37. CSS_TREE_NODE = getCN(TREE, NODE);
  38. /**
  39. * A base class for TreeData, providing:
  40. * <ul>
  41. * <li>Widget Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)</li>
  42. * <li>Handle the data of the tree</li>
  43. * <li>Basic DOM implementation (append/remove/insert)</li>
  44. * <li>Indexing management to handle the children nodes</li>
  45. * </ul>
  46. *
  47. * Check the list of <a href="TreeData.html#configattributes">Configuration Attributes</a> available for
  48. * TreeData.
  49. *
  50. * @param config {Object} Object literal specifying widget configuration properties.
  51. *
  52. * @class TreeData
  53. * @constructor
  54. * @extends Base
  55. */
  56. var TreeData = function () {};
  57. TreeData.ATTRS = {
  58. /**
  59. * Container to nest children nodes. If has cntainer it's not a leaf.
  60. *
  61. * @attribute container
  62. * @default null
  63. * @type Node | String
  64. */
  65. container: {
  66. setter: A.one
  67. },
  68. /**
  69. * Array of children (i.e. could be a JSON metadata object or a TreeNode instance).
  70. *
  71. * @attribute children
  72. * @default []
  73. * @type Array
  74. */
  75. children: {
  76. value: [],
  77. validator: isArray,
  78. setter: '_setChildren'
  79. },
  80. /**
  81. * Index the nodes.
  82. *
  83. * @attribute index
  84. * @default {}
  85. * @type Object
  86. */
  87. index: {
  88. value: {}
  89. }
  90. };
  91. A.mix(TreeData.prototype, {
  92. _indexPrimed: false,
  93. childrenLength: 0,
  94. /**
  95. * Construction logic executed during TreeData instantiation. Lifecycle.
  96. *
  97. * @method initializer
  98. * @protected
  99. */
  100. initTreeData: function() {
  101. var instance = this;
  102. // binding on initializer, needed before .render() phase
  103. instance.publish('move');
  104. instance.publish('append', { defaultFn: instance._appendChild });
  105. instance.publish('remove', { defaultFn: instance._removeChild });
  106. },
  107. /**
  108. * Descructor lifecycle implementation for the TreeData class.
  109. * Purges events attached to the node (and all child nodes).
  110. *
  111. * @method destructor
  112. * @protected
  113. */
  114. destructor: function() {
  115. var instance = this;
  116. instance.eachChildren(function(node) {
  117. node.destroy();
  118. }, true);
  119. },
  120. /**
  121. * Get a TreeNode by id.
  122. *
  123. * @method getNodeById
  124. * @param {String} uid
  125. * @return {TreeNode}
  126. */
  127. getNodeById: function(uid) {
  128. var instance = this;
  129. if (!instance._indexPrimed) {
  130. instance.refreshIndex();
  131. }
  132. return instance.get(INDEX)[uid];
  133. },
  134. /**
  135. * Whether the TreeNode is registered on this TreeData.
  136. *
  137. * @method isRegistered
  138. * @param {TreeNode} node
  139. * @return {boolean}
  140. */
  141. isRegistered: function(node) {
  142. var instance = this;
  143. return !!(instance.get(INDEX)[ node.get(ID) ]);
  144. },
  145. /**
  146. * Update the references of the passed TreeNode.
  147. *
  148. * @method updateReferences
  149. * @param {node} TreeNode
  150. * @param {parentNode} TreeNode
  151. * @param {ownerTree} TreeView
  152. */
  153. updateReferences: function(node, parentNode, ownerTree) {
  154. var instance = this;
  155. var oldParent = node.get(PARENT_NODE);
  156. var oldOwnerTree = node.get(OWNER_TREE);
  157. var moved = oldParent && (oldParent !== parentNode);
  158. if (oldParent) {
  159. if (moved) {
  160. // when moved update the oldParent children
  161. var children = oldParent.get(CHILDREN);
  162. A.Array.removeItem(children, node);
  163. oldParent.set(CHILDREN, children);
  164. }
  165. oldParent.unregisterNode(node);
  166. }
  167. if (oldOwnerTree) {
  168. oldOwnerTree.unregisterNode(node);
  169. }
  170. // update parent reference when registered
  171. node.set(PARENT_NODE, parentNode);
  172. // update the ownerTree of the node
  173. node.set(OWNER_TREE, ownerTree);
  174. if (parentNode) {
  175. // register the new node on the parentNode index
  176. parentNode.registerNode(node);
  177. }
  178. if (ownerTree) {
  179. // register the new node to the ownerTree index
  180. ownerTree.registerNode(node);
  181. }
  182. if (oldOwnerTree != ownerTree) {
  183. // when change the OWNER_TREE update the children references also
  184. node.eachChildren(function(child) {
  185. instance.updateReferences(child, child.get(PARENT_NODE), ownerTree);
  186. });
  187. }
  188. // trigger move event
  189. if (moved) {
  190. var output = instance.getEventOutputMap(node);
  191. if (!oldParent.get(CHILDREN).length) {
  192. oldParent.collapse();
  193. oldParent.hideHitArea();
  194. }
  195. output.tree.oldParent = oldParent;
  196. output.tree.oldOwnerTree = oldOwnerTree;
  197. instance.bubbleEvent('move', output);
  198. }
  199. },
  200. /**
  201. * Refresh the index (i.e. re-index all nodes).
  202. *
  203. * @method refreshIndex
  204. */
  205. refreshIndex: function() {
  206. var instance = this;
  207. // reset index
  208. instance.updateIndex({});
  209. // get all descendent children - deep
  210. instance.eachChildren(function(node) {
  211. instance.registerNode(node);
  212. }, true);
  213. },
  214. /**
  215. * Register the passed TreeNode on this TreeData.
  216. *
  217. * @method registerNode
  218. * @param {TreeNode} node
  219. */
  220. registerNode: function(node) {
  221. var instance = this;
  222. var uid = node.get(ID);
  223. var index = instance.get(INDEX);
  224. if (uid) {
  225. index[uid] = node;
  226. }
  227. if (isTreeView(instance)) {
  228. node.addTarget(instance);
  229. // when the node is appended to the TreeView set the OWNER_TREE
  230. node.set(OWNER_TREE, instance);
  231. }
  232. node._inheritOwnerTreeAttrs();
  233. instance.updateIndex(index);
  234. },
  235. /**
  236. * Update the <a href="TreeData.html#config_index">index</a> attribute value.
  237. *
  238. * @method updateIndex
  239. * @param {Object} index
  240. */
  241. updateIndex: function(index) {
  242. var instance = this;
  243. if (index) {
  244. instance._indexPrimed = true;
  245. instance.set(INDEX, index);
  246. }
  247. },
  248. /**
  249. * Unregister the passed TreeNode from this TreeData.
  250. *
  251. * @method unregisterNode
  252. * @param {TreeNode} node
  253. */
  254. unregisterNode: function(node) {
  255. var instance = this;
  256. var index = instance.get(INDEX);
  257. delete index[ node.get(ID) ];
  258. if (isTreeView(instance)) {
  259. node.removeTarget(instance);
  260. }
  261. instance.updateIndex(index);
  262. },
  263. /**
  264. * Collapse all children of the TreeData.
  265. *
  266. * @method collapseAll
  267. */
  268. collapseAll: function() {
  269. var instance = this;
  270. instance.eachChildren(function(node) {
  271. node.collapse();
  272. }, true);
  273. },
  274. /**
  275. * Expand all children of the TreeData.
  276. *
  277. * @method expandAll
  278. */
  279. expandAll: function() {
  280. var instance = this;
  281. instance.eachChildren(function(node) {
  282. node.expand();
  283. }, true);
  284. },
  285. /**
  286. * Select all children of the TreeData.
  287. *
  288. * @method selectAll
  289. */
  290. selectAll: function() {
  291. var instance = this;
  292. instance.eachChildren(function(child) {
  293. child.select();
  294. }, true);
  295. },
  296. /**
  297. * Unselect all children of the TreeData.
  298. *
  299. * @method unselectAll
  300. */
  301. unselectAll: function() {
  302. var instance = this;
  303. instance.eachChildren(function(child) {
  304. child.unselect();
  305. }, true);
  306. },
  307. /**
  308. * Loop each children and execute the <code>fn</code> callback.
  309. *
  310. * @method eachChildren
  311. * @param {function} fn callback
  312. * @param {boolean} fn recursive
  313. */
  314. eachChildren: function(fn, deep) {
  315. var instance = this;
  316. var children = instance.getChildren(deep);
  317. A.Array.each(children, function(node) {
  318. if (node) {
  319. fn.apply(instance, arguments);
  320. }
  321. });
  322. },
  323. /**
  324. * Loop each parent node and execute the <code>fn</code> callback.
  325. *
  326. * @method eachParent
  327. * @param {function} fn callback
  328. */
  329. eachParent: function(fn) {
  330. var instance = this;
  331. var parentNode = instance.get(PARENT_NODE);
  332. while (parentNode) {
  333. if (parentNode) {
  334. fn.call(instance, parentNode);
  335. }
  336. parentNode = parentNode.get(PARENT_NODE);
  337. }
  338. },
  339. /**
  340. * Bubble event to all parent nodes.
  341. *
  342. * @method bubbleEvent
  343. * @param {String} eventType
  344. * @param {Array} args
  345. * @param {boolean} cancelBubbling
  346. * @param {boolean} stopActionPropagation
  347. */
  348. bubbleEvent: function(eventType, args, cancelBubbling, stopActionPropagation) {
  349. var instance = this;
  350. // event.stopActionPropagation === undefined, invoke the event native action
  351. instance.fire(eventType, args);
  352. if (!cancelBubbling) {
  353. var parentNode = instance.get(PARENT_NODE);
  354. // Avoid execution of the native action (private methods) while propagate
  355. // for example: private _appendChild() is invoked only on the first level of the bubbling
  356. // the intention is only invoke the user callback on parent nodes.
  357. args = args || {};
  358. if (isUndefined(stopActionPropagation)) {
  359. stopActionPropagation = true;
  360. }
  361. args.stopActionPropagation = stopActionPropagation;
  362. while(parentNode) {
  363. parentNode.fire(eventType, args);
  364. parentNode = parentNode.get(PARENT_NODE);
  365. }
  366. }
  367. },
  368. /**
  369. * Create a TreeNode instance.
  370. *
  371. * @method createNode
  372. * @param {Object} options
  373. * @return {TreeNode}
  374. */
  375. createNode: function(options) {
  376. var instance = this;
  377. var classType = A.TreeNode.nodeTypes[ isObject(options) ? options.type : options ] || A.TreeNode;
  378. return new classType(
  379. isObject(options) ? options : {}
  380. );
  381. },
  382. /**
  383. * Append a child node to the TreeData.
  384. *
  385. * @method appendChild
  386. * @param {TreeNode} node
  387. * @param {boolean} cancelBubbling
  388. */
  389. appendChild: function(node, cancelBubbling) {
  390. var instance = this;
  391. var output = instance.getEventOutputMap(node);
  392. instance.bubbleEvent('append', output, cancelBubbling);
  393. },
  394. /**
  395. * Append a child node to the TreeData.
  396. *
  397. * @method _appendChild
  398. * @param {TreeNode} node
  399. * @param {boolean} cancelBubbling
  400. * @protected
  401. */
  402. _appendChild: function(event) {
  403. // stopActionPropagation while bubbling
  404. if (event.stopActionPropagation) {
  405. return false;
  406. }
  407. var instance = this;
  408. var node = event.tree.node;
  409. var ownerTree = instance.get(OWNER_TREE);
  410. var children = instance.get(CHILDREN);
  411. // updateReferences first
  412. instance.updateReferences(node, instance, ownerTree);
  413. // and then set the children, to have the appendChild propagation
  414. // the PARENT_NODE references should be updated
  415. var length = children.push(node);
  416. instance.childrenLength = children.length;
  417. // updating prev/nextSibling attributes
  418. var prevIndex = length - 2;
  419. var prevSibling = instance.item(prevIndex);
  420. node._nextSibling = null;
  421. node._prevSibling = prevSibling;
  422. // render node
  423. node.render(instance.get(CONTAINER));
  424. },
  425. /**
  426. * Get a TreeNode children by index.
  427. *
  428. * @method item
  429. * @param {Number} index
  430. * @return {TreeNode}
  431. */
  432. item: function(index) {
  433. var instance = this;
  434. return instance.get(CHILDREN)[index];
  435. },
  436. /**
  437. * Index of the passed TreeNode on the <a
  438. * href="TreeData.html#config_children">children</a> attribute.
  439. *
  440. * @method indexOf
  441. * @param {TreeNode} node
  442. * @return {Number}
  443. */
  444. indexOf: function(node) {
  445. var instance = this;
  446. return A.Array.indexOf( instance.get(CHILDREN), node );
  447. },
  448. /**
  449. * Whether the TreeData contains children or not.
  450. *
  451. * @method hasChildNodes
  452. * @return {boolean}
  453. */
  454. hasChildNodes: function() {
  455. var instance = this;
  456. return (instance.getChildrenLength() > 0);
  457. },
  458. /**
  459. * Get an Array of the children nodes of the current TreeData.
  460. *
  461. * @method getChildren
  462. * @param {boolean} deep
  463. * @return {Array}
  464. */
  465. getChildren: function(deep) {
  466. var instance = this;
  467. var cNodes = [];
  468. var children = instance.get(CHILDREN);
  469. cNodes = cNodes.concat(children);
  470. if (deep) {
  471. instance.eachChildren(function(child) {
  472. cNodes = cNodes.concat( child.getChildren(deep) );
  473. });
  474. }
  475. return cNodes;
  476. },
  477. getChildrenLength: function() {
  478. var instance = this;
  479. return (instance.childrenLength || instance.get(CHILDREN).length);
  480. },
  481. /**
  482. * Get an object containing metadata for the custom events.
  483. *
  484. * @method getEventOutputMap
  485. * @param {TreeData} node
  486. * @return {Object}
  487. */
  488. getEventOutputMap: function(node) {
  489. var instance = this;
  490. return {
  491. tree: {
  492. instance: instance,
  493. node: node || instance
  494. }
  495. };
  496. },
  497. /**
  498. * Remove the passed <code>node</code> from the current TreeData.
  499. *
  500. * @method removeChild
  501. * @param {TreeData} node
  502. */
  503. removeChild: function(node) {
  504. var instance = this;
  505. var output = instance.getEventOutputMap(node);
  506. instance.bubbleEvent('remove', output);
  507. },
  508. /**
  509. * Remove the passed <code>node</code> from the current TreeData.
  510. *
  511. * @method _removeChild
  512. * @param {TreeData} node
  513. */
  514. _removeChild: function(event) {
  515. // stopActionPropagation while bubbling
  516. if (event.stopActionPropagation) {
  517. return false;
  518. }
  519. var instance = this;
  520. var node = event.tree.node;
  521. var ownerTree = instance.get(OWNER_TREE);
  522. if (instance.isRegistered(node)) {
  523. // update parent reference when removed
  524. node.set(PARENT_NODE, null);
  525. // unregister the node
  526. instance.unregisterNode(node);
  527. // no parent, no ownerTree
  528. node.set(OWNER_TREE, null);
  529. if (ownerTree) {
  530. // unregister the removed node from the tree index
  531. ownerTree.unregisterNode(node);
  532. }
  533. // remove child from the container
  534. node.get(BOUNDING_BOX).remove();
  535. var children = instance.get(CHILDREN);
  536. A.Array.removeItem(children, node);
  537. instance.set(CHILDREN, children);
  538. }
  539. },
  540. /**
  541. * Delete all children of the current TreeData.
  542. *
  543. * @method empty
  544. */
  545. empty: function() {
  546. var instance = this;
  547. instance.eachChildren(function(node) {
  548. var parentNode = node.get(PARENT_NODE);
  549. if (parentNode) {
  550. parentNode.removeChild(node);
  551. }
  552. });
  553. },
  554. /**
  555. * Insert <code>treeNode</code> before or after the <code>refTreeNode</code>.
  556. *
  557. * @method insert
  558. * @param {TreeNode} treeNode
  559. * @param {TreeNode} refTreeNode
  560. * @param {TreeNode} where 'before' or 'after'
  561. */
  562. insert: function(treeNode, refTreeNode, where) {
  563. var instance = this;
  564. refTreeNode = refTreeNode || this;
  565. if (refTreeNode === treeNode) {
  566. return false; // NOTE: return
  567. }
  568. var refParentTreeNode = refTreeNode.get(PARENT_NODE);
  569. if (treeNode && refParentTreeNode) {
  570. var nodeBoundingBox = treeNode.get(BOUNDING_BOX);
  571. var refBoundingBox = refTreeNode.get(BOUNDING_BOX);
  572. var ownerTree = refTreeNode.get(OWNER_TREE);
  573. if (where === 'before') {
  574. refBoundingBox.placeBefore(nodeBoundingBox);
  575. }
  576. else if (where === 'after') {
  577. refBoundingBox.placeAfter(nodeBoundingBox);
  578. }
  579. var refSiblings = [];
  580. // using the YUI selector to regenerate the index based on the real dom
  581. // this avoid misscalculations on the nodes index number
  582. var DOMChildren = refParentTreeNode.get(BOUNDING_BOX).all('> ul > li');
  583. DOMChildren.each(function(child) {
  584. refSiblings.push( child.getData(TREE_NODE) );
  585. });
  586. // updating prev/nextSibling attributes
  587. var nextSiblingNode = nodeBoundingBox.get(NEXT_SIBLING);
  588. treeNode.set(NEXT_SIBLING, nextSiblingNode && nextSiblingNode.getData(TREE_NODE));
  589. var prevSiblingNode = nodeBoundingBox.get(PREVIOUS_SIBLING);
  590. treeNode.set(PREV_SIBLING, prevSiblingNode && prevSiblingNode.getData(TREE_NODE));
  591. // update all references
  592. refTreeNode.updateReferences(treeNode, refParentTreeNode, ownerTree);
  593. // updating refParentTreeNode childTreeNodes
  594. refParentTreeNode.set(CHILDREN, refSiblings);
  595. }
  596. // render treeNode after it's inserted
  597. treeNode.render();
  598. // invoking insert event
  599. var output = refTreeNode.getEventOutputMap(treeNode);
  600. output.tree.refTreeNode = refTreeNode;
  601. refTreeNode.bubbleEvent('insert', output);
  602. },
  603. /**
  604. * Insert <code>treeNode</code> after the <code>refTreeNode</code>.
  605. *
  606. * @method insertAfter
  607. * @param {TreeNode} treeNode
  608. * @param {TreeNode} refTreeNode
  609. */
  610. insertAfter: function(treeNode, refTreeNode) {
  611. var instance = this;
  612. instance.insert(treeNode, refTreeNode, 'after');
  613. },
  614. /**
  615. * Insert <code>treeNode</code> before the <code>refTreeNode</code>.
  616. *
  617. * @method insertBefore
  618. * @param {TreeNode} treeNode
  619. * @param {TreeNode} refTreeNode
  620. */
  621. insertBefore: function(treeNode, refTreeNode) {
  622. var instance = this;
  623. instance.insert(treeNode, refTreeNode, 'before');
  624. },
  625. /**
  626. * Get a TreeNode instance by a child DOM Node.
  627. *
  628. * @method getNodeByChild
  629. * @param {Node} child
  630. * @return {TreeNode}
  631. */
  632. getNodeByChild: function(child) {
  633. var instance = this;
  634. var treeNodeEl = child.ancestor(DOT+CSS_TREE_NODE);
  635. if (treeNodeEl) {
  636. return treeNodeEl.getData(TREE_NODE);
  637. }
  638. return null;
  639. },
  640. _inheritOwnerTreeAttrs: L.emptyFn,
  641. /**
  642. * Setter for <a href="TreeData.html#config_children">children</a>.
  643. *
  644. * @method _setChildren
  645. * @protected
  646. * @param {Array} v
  647. * @return {Array}
  648. */
  649. _setChildren: function(v) {
  650. var instance = this;
  651. var childNodes = [];
  652. var container = instance.get(CONTAINER);
  653. if (!container) {
  654. container = instance._createNodeContainer();
  655. }
  656. instance.childrenLength = v.length;
  657. // before render the node, make sure the PARENT_NODE and OWNER_TREE references are updated
  658. // this is required on the render phase of the TreeNode (_createNodeContainer)
  659. // to propagate the events callback (appendChild/expand)
  660. var ownerTree = instance;
  661. if (isTreeNode(instance)) {
  662. ownerTree = instance.get(OWNER_TREE);
  663. }
  664. var hasOwnerTree = isTreeView(ownerTree);
  665. var lazyLoad = true;
  666. if (hasOwnerTree) {
  667. lazyLoad = ownerTree.get(LAZY_LOAD);
  668. }
  669. instance.updateIndex({});
  670. if (instance.childrenLength > 0) {
  671. instance.set(LEAF, false);
  672. }
  673. A.Array.each(v, function(node, index) {
  674. if (node) {
  675. if (!isTreeNode(node) && isObject(node)) {
  676. // cache and remove children to lazy add them later for
  677. // performance reasons
  678. var children = node[CHILDREN];
  679. var hasChildren = children && children.length;
  680. node[OWNER_TREE] = ownerTree;
  681. node[PARENT_NODE] = instance;
  682. if (hasChildren && lazyLoad) {
  683. delete node[CHILDREN];
  684. }
  685. // creating node from json
  686. var jsonNode = node;
  687. node = instance.createNode(node);
  688. if (hasChildren && lazyLoad) {
  689. jsonNode.children = children;
  690. node.childrenLength = children.length;
  691. A.setTimeout(function() {
  692. node.set(CHILDREN, children);
  693. }, 50);
  694. }
  695. }
  696. instance.registerNode(node);
  697. if (hasOwnerTree) {
  698. ownerTree.registerNode(node);
  699. }
  700. node.render(container);
  701. // avoid duplicated children on the childNodes list
  702. if (A.Array.indexOf(childNodes, node) === -1) {
  703. childNodes.push(node);
  704. }
  705. }
  706. });
  707. return childNodes;
  708. }
  709. });
  710. A.TreeData = TreeData;
  711. }, '@VERSION@' ,{requires:['aui-base','aui-task-manager'], skinnable:false});
  712. AUI.add('aui-tree-node', function(A) {
  713. /**
  714. * The TreeNode Utility
  715. *
  716. * @module aui-tree
  717. * @submodule aui-tree-node
  718. */
  719. var Lang = A.Lang,
  720. isString = Lang.isString,
  721. isBoolean = Lang.isBoolean,
  722. ALWAYS_SHOW_HITAREA = 'alwaysShowHitArea',
  723. BLANK = '',
  724. BOUNDING_BOX = 'boundingBox',
  725. CHILDREN = 'children',
  726. CLEARFIX = 'clearfix',
  727. COLLAPSED = 'collapsed',
  728. CONTAINER = 'container',
  729. CONTENT = 'content',
  730. CONTENT_BOX = 'contentBox',
  731. DRAGGABLE = 'draggable',
  732. EXPANDED = 'expanded',
  733. HELPER = 'helper',
  734. HIDDEN = 'hidden',
  735. HIT_AREA_EL = 'hitAreaEl',
  736. HITAREA = 'hitarea',
  737. ICON = 'icon',
  738. ICON_EL = 'iconEl',
  739. INVALID = 'invalid',
  740. ID = 'id',
  741. LABEL = 'label',
  742. LABEL_EL = 'labelEl',
  743. LAST_SELECTED = 'lastSelected',
  744. LEAF = 'leaf',
  745. NODE = 'node',
  746. OVER = 'over',
  747. OWNER_TREE = 'ownerTree',
  748. PARENT_NODE = 'parentNode',
  749. RADIO = 'radio',
  750. RENDERED = 'rendered',
  751. SELECTED = 'selected',
  752. SPACE = ' ',
  753. TREE = 'tree',
  754. TREE_NODE = 'tree-node',
  755. concat = function() {
  756. return Array.prototype.slice.call(arguments).join(SPACE);
  757. },
  758. isTreeNode = function(v) {
  759. return (v instanceof A.TreeNode);
  760. },
  761. isTreeView = function(v) {
  762. return (v instanceof A.TreeView);
  763. },
  764. getCN = A.getClassName,
  765. CSS_HELPER_CLEARFIX = getCN(HELPER, CLEARFIX),
  766. CSS_TREE_COLLAPSED = getCN(TREE, COLLAPSED),
  767. CSS_TREE_CONTAINER = getCN(TREE, CONTAINER),
  768. CSS_TREE_CONTENT_BOX = getCN(TREE, CONTENT_BOX),
  769. CSS_TREE_EXPANDED = getCN(TREE, EXPANDED),
  770. CSS_TREE_HIDDEN = getCN(TREE, HIDDEN),
  771. CSS_TREE_HITAREA = getCN(TREE, HITAREA),
  772. CSS_TREE_ICON = getCN(TREE, ICON),
  773. CSS_TREE_LABEL = getCN(TREE, LABEL),
  774. CSS_TREE_NODE = getCN(TREE, NODE),
  775. CSS_TREE_NODE_CONTENT = getCN(TREE, NODE, CONTENT),
  776. CSS_TREE_NODE_CONTENT_INVALID = getCN(TREE, NODE, CONTENT, INVALID),
  777. CSS_TREE_NODE_HIDDEN_HITAREA = getCN(TREE, NODE, HIDDEN, HITAREA),
  778. CSS_TREE_NODE_LEAF = getCN(TREE, NODE, LEAF),
  779. CSS_TREE_NODE_OVER = getCN(TREE, NODE, OVER),
  780. CSS_TREE_NODE_SELECTED = getCN(TREE, NODE, SELECTED),
  781. HIT_AREA_TPL = '<div class="' + CSS_TREE_HITAREA + '"></div>',
  782. ICON_TPL = '<div class="' + CSS_TREE_ICON + '"></div>',
  783. LABEL_TPL = '<div class="' + CSS_TREE_LABEL + '"></div>',
  784. NODE_CONTAINER_TPL = '<ul></ul>',
  785. NODE_BOUNDING_TEMPLATE = '<li class="' + CSS_TREE_NODE + '"></li>',
  786. NODE_CONTENT_TEMPLATE = '<div class="' + concat(CSS_HELPER_CLEARFIX, CSS_TREE_NODE_CONTENT) + '"></div>';
  787. /**
  788. * A base class for TreeNode, providing:
  789. * <ul>
  790. * <li>Widget Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)</li>
  791. * <li>The node for the TreeView component</li>
  792. * </ul>
  793. *
  794. * Quick Example:<br/>
  795. *
  796. * <pre><code>var instance = new A.TreeNode({
  797. boundingBox: ''
  798. }).render();
  799. * </code></pre>
  800. *
  801. * Check the list of <a href="TreeNode.html#configattributes">Configuration Attributes</a> available for
  802. * TreeNode.
  803. *
  804. * @param config {Object} Object literal specifying widget configuration properties.
  805. *
  806. * @class TreeNode
  807. * @constructor
  808. * @extends TreeData
  809. */
  810. var TreeNode = A.Component.create(
  811. {
  812. /**
  813. * Static property provides a string to identify the class.
  814. *
  815. * @property TreeNode.NAME
  816. * @type String
  817. * @static
  818. */
  819. NAME: TREE_NODE,
  820. /**
  821. * Static property used to define the default attribute
  822. * configuration for the TreeNode.
  823. *
  824. * @property TreeNode.ATTRS
  825. * @type Object
  826. * @static
  827. */
  828. ATTRS: {
  829. /**
  830. * Always show the hitarea icon.
  831. *
  832. * @attribute alwaysShowHitArea
  833. * @default true
  834. * @type boolean
  835. */
  836. alwaysShowHitArea: {
  837. validator: isBoolean,
  838. value: true
  839. },
  840. boundingBox: {
  841. valueFn: function() {
  842. return A.Node.create(NODE_BOUNDING_TEMPLATE);
  843. }
  844. },
  845. contentBox: {
  846. valueFn: function() {
  847. return A.Node.create(NODE_CONTENT_TEMPLATE);
  848. }
  849. },
  850. /**
  851. * If true the TreeNode is draggable.
  852. *
  853. * @attribute draggable
  854. * @default true
  855. * @type boolean
  856. */
  857. draggable: {
  858. validator: isBoolean,
  859. value: true
  860. },
  861. /**
  862. * Whether the TreeNode is expanded by default.
  863. *
  864. * @attribute expanded
  865. * @default false
  866. * @type boolean
  867. */
  868. expanded: {
  869. validator: isBoolean,
  870. value: false
  871. },
  872. /**
  873. * Hitarea element.
  874. *
  875. * @attribute hitAreaEl
  876. * @default Generated DOM element.
  877. * @type Node | String
  878. */
  879. hitAreaEl: {
  880. setter: A.one,
  881. valueFn: function() {
  882. return A.Node.create(HIT_AREA_TPL);
  883. }
  884. },
  885. /**
  886. * Icon element.
  887. *
  888. * @attribute iconEl
  889. * @type Node | String
  890. */
  891. iconEl: {
  892. setter: A.one,
  893. valueFn: function() {
  894. return A.Node.create(ICON_TPL);
  895. }
  896. },
  897. /**
  898. * Id of the TreeNode.
  899. *
  900. * @attribute id
  901. * @default null
  902. * @type String
  903. */
  904. id: {
  905. validator: isString,
  906. valueFn: function() {
  907. return A.guid();
  908. }
  909. },
  910. /**
  911. * Label of the TreeNode.
  912. *
  913. * @attribute label
  914. * @default ''
  915. * @type String
  916. */
  917. label: {
  918. validator: isString,
  919. value: BLANK
  920. },
  921. /**
  922. * Label element to house the <code>label</code> attribute.
  923. *
  924. * @attribute labelEl
  925. * @default Generated DOM element.
  926. * @type Node | String
  927. */
  928. labelEl: {
  929. setter: A.one,
  930. valueFn: function() {
  931. var instance = this;
  932. var label = instance.get(LABEL);
  933. return A.Node.create(LABEL_TPL).html(label).unselectable();
  934. }
  935. },
  936. /**
  937. * Whether the TreeNode could have children or not (i.e. if any
  938. * children is present the TreeNode is a leaf).
  939. *
  940. * @attribute leaf
  941. * @default true
  942. * @type boolean
  943. */
  944. leaf: {
  945. setter: function(v) {
  946. var instance = this;
  947. // if has children it's not a leaf
  948. if (v && instance.get(CHILDREN).length) {
  949. return false;
  950. }
  951. return v;
  952. },
  953. validator: isBoolean,
  954. value: true
  955. },
  956. /**
  957. * Next sibling of the current TreeNode.
  958. *
  959. * @attribute nextSibling
  960. * @default null
  961. * @type TreeNode
  962. */
  963. nextSibling: {
  964. getter: '_getSibling',
  965. validator: isTreeNode,
  966. value: null
  967. },
  968. /**
  969. * TreeView which contains the current TreeNode.
  970. *
  971. * @attribute ownerTree
  972. * @default null
  973. * @type TreeView
  974. */
  975. ownerTree: {
  976. value: null
  977. },
  978. /**
  979. * Parent node of the current TreeNode.
  980. *
  981. * @attribute parentNode
  982. * @default null
  983. * @type TreeNode
  984. */
  985. parentNode: {
  986. validator: function(val) {
  987. return isTreeNode(val) || isTreeView(val);
  988. },
  989. value: null
  990. },
  991. /**
  992. * Previous sibling of the current TreeNode.
  993. *
  994. * @attribute prevSibling
  995. * @default null
  996. * @type TreeNode
  997. */
  998. prevSibling: {
  999. getter: '_getSibling',
  1000. validator: isTreeNode,
  1001. value: null
  1002. },
  1003. rendered: {
  1004. validator: isBoolean,
  1005. value: false
  1006. },
  1007. tabIndex: {
  1008. value: null
  1009. }
  1010. },
  1011. AUGMENTS: [A.TreeData],
  1012. EXTENDS: A.Base,
  1013. prototype: {
  1014. /**
  1015. * Replaced BOUNDING_TEMPLATE with NODE_BOUNDING_TEMPLATE.
  1016. *
  1017. * @property BOUNDING_TEMPLATE
  1018. * @type String
  1019. * @protected
  1020. */
  1021. BOUNDING_TEMPLATE: NODE_BOUNDING_TEMPLATE,
  1022. /**
  1023. * Replaced CONTENT_TEMPLATE with NODE_CONTENT_TEMPLATE.
  1024. *
  1025. * @property CONTENT_TEMPLATE
  1026. * @type String
  1027. * @protected
  1028. */
  1029. CONTENT_TEMPLATE: NODE_CONTENT_TEMPLATE,
  1030. /**
  1031. * Construction logic executed during TreeNode instantiation. Lifecycle.
  1032. *
  1033. * @method initializer
  1034. * @protected
  1035. */
  1036. initializer: function() {
  1037. var instance = this;
  1038. instance.get(BOUNDING_BOX).setData(TREE_NODE, instance);
  1039. // Sync the Widget TreeNode id with the BOUNDING_BOX id
  1040. instance._syncTreeNodeBBId();
  1041. instance._uiSetDraggable(instance.get(DRAGGABLE));
  1042. instance._uiSetExpanded(instance.get(EXPANDED));
  1043. instance._uiSetLeaf(instance.get(LEAF));
  1044. instance.initTreeData();
  1045. },
  1046. /**
  1047. * Bind the events on the TreeNode UI. Lifecycle.
  1048. *
  1049. * @method bindUI
  1050. * @protected
  1051. */
  1052. bindUI: function() {
  1053. var instance = this;
  1054. instance.after('childrenChange', A.bind(instance._afterSetChildren, instance));
  1055. instance.after('draggableChange', A.bind(instance._afterDraggableChange, instance));
  1056. instance.after('expandedChange', A.bind(instance._afterExpandedChange, instance));
  1057. instance.after('idChange', instance._afterSetId, instance);
  1058. instance.after('leafChange', A.bind(instance._afterLeafChange, instance));
  1059. },
  1060. render: function(container) {
  1061. var instance = this;
  1062. if (!instance.get(RENDERED)) {
  1063. instance.renderUI();
  1064. instance.bindUI();
  1065. instance.syncUI();
  1066. instance.set(RENDERED, true);
  1067. }
  1068. if (container) {
  1069. var boundingBox = instance.get(BOUNDING_BOX);
  1070. var parentNode = instance.get(PARENT_NODE);
  1071. boundingBox.appendTo(container);
  1072. if (parentNode) {
  1073. var paginator = parentNode.get(PAGINATOR);
  1074. if (paginator) {
  1075. boundingBox.insertBefore(paginator.element, null);
  1076. }
  1077. }
  1078. }
  1079. },
  1080. /**
  1081. * Create the DOM structure for the TreeNode. Lifecycle.
  1082. *
  1083. * @method renderUI
  1084. * @protected
  1085. */
  1086. renderUI: function() {
  1087. var instance = this;
  1088. instance._renderBoundingBox();
  1089. instance._renderContentBox();
  1090. },
  1091. /**
  1092. * Sync the TreeNode UI. Lifecycle.
  1093. *
  1094. * @method syncUI
  1095. * @protected
  1096. */
  1097. syncUI: function() {
  1098. var instance = this;
  1099. instance._syncIconUI();
  1100. },
  1101. /*
  1102. * Methods
  1103. */
  1104. append: function(node) {
  1105. var instance = this;
  1106. instance.appendChild(node);
  1107. },
  1108. /*
  1109. * Methods
  1110. */
  1111. appendChild: function() {
  1112. var instance = this;
  1113. if (!instance.isLeaf()) {
  1114. A.TreeNode.superclass.appendChild.apply(instance, arguments);
  1115. }
  1116. },
  1117. /**
  1118. * Collapse the current TreeNode.
  1119. *
  1120. * @method collapse
  1121. */
  1122. collapse: function() {
  1123. var instance = this;
  1124. instance.set(EXPANDED, false);
  1125. },
  1126. collapseAll: function() {
  1127. var instance = this;
  1128. A.TreeNode.superclass.collapseAll.apply(instance, arguments);
  1129. // instance is also a node, so collapse itself
  1130. instance.collapse();
  1131. },
  1132. /**
  1133. * Check if the current TreeNode contains the passed <code>node</code>.
  1134. *
  1135. * @method contains
  1136. * @param {TreeNode} node
  1137. * @return {boolean}
  1138. */
  1139. contains: function(node) {
  1140. var instance = this;
  1141. return node.isAncestor(instance);
  1142. },
  1143. /**
  1144. * Expand the current TreeNode.
  1145. *
  1146. * @method expand
  1147. */
  1148. expand: function() {
  1149. var instance = this;
  1150. instance.set(EXPANDED, true);
  1151. },
  1152. expandAll: function() {
  1153. var instance = this;
  1154. A.TreeNode.superclass.expandAll.apply(instance, arguments);
  1155. // instance is also a node, so expand itself
  1156. instance.expand();
  1157. },
  1158. /**
  1159. * Get the depth of the current TreeNode.
  1160. *
  1161. * @method getDepth
  1162. * @return {Number}
  1163. */
  1164. getDepth: function() {
  1165. var instance = this;
  1166. var depth = 0;
  1167. var parentNode = instance.get(PARENT_NODE);
  1168. while (parentNode) {
  1169. ++depth;
  1170. parentNode = parentNode.get(PARENT_NODE);
  1171. }
  1172. return depth;
  1173. },
  1174. hasChildNodes: function() {
  1175. var instance = this;
  1176. return (!instance.isLeaf() && A.TreeNode.superclass.hasChildNodes.apply(instance, arguments));
  1177. },
  1178. /*
  1179. * Hide hitarea icon.
  1180. *
  1181. * @method hideHitArea
  1182. */
  1183. hideHitArea: function() {
  1184. var instance = this;
  1185. instance.get(HIT_AREA_EL).addClass(CSS_TREE_NODE_HIDDEN_HITAREA);
  1186. },
  1187. /**
  1188. * Whether the current TreeNode is ancestor of the passed <code>node</code> or not.
  1189. *
  1190. * @method isLeaf
  1191. * @return {boolean}
  1192. */
  1193. isAncestor: function(node) {
  1194. var instance = this;
  1195. var parentNode = instance.get(PARENT_NODE);
  1196. while (parentNode) {
  1197. if (parentNode === node) {
  1198. return true;
  1199. }
  1200. parentNode = parentNode.get(PARENT_NODE);
  1201. }
  1202. return false;
  1203. },
  1204. /**
  1205. * Whether the current TreeNode is a leaf or not.
  1206. *
  1207. * @method isLeaf
  1208. * @return {boolean}
  1209. */
  1210. isLeaf: function() {
  1211. var instance = this;
  1212. return instance.get(LEAF);
  1213. },
  1214. /**
  1215. * Whether the current TreeNode is selected or not.
  1216. *
  1217. * @method isSelected
  1218. * @return {boolean}
  1219. */
  1220. isSelected: function() {
  1221. var instance = this;
  1222. return instance.get(CONTENT_BOX).hasClass(CSS_TREE_NODE_SELECTED);
  1223. },
  1224. /*
  1225. * Fires when <code>mouseout</code> the current TreeNode.
  1226. *
  1227. * @method over
  1228. */
  1229. out: function() {
  1230. var instance = this;
  1231. instance.get(CONTENT_BOX).removeClass(CSS_TREE_NODE_OVER);
  1232. },
  1233. /*
  1234. * Fires when <code>mouseover</code> the current TreeNode.
  1235. *
  1236. * @method over
  1237. */
  1238. over: function() {
  1239. var instance = this;
  1240. instance.get(CONTENT_BOX).addClass(CSS_TREE_NODE_OVER);
  1241. },
  1242. /*
  1243. * Select the current TreeNode.
  1244. *
  1245. * @method select
  1246. */
  1247. select: function() {
  1248. var instance = this;
  1249. var ownerTree = instance.get(OWNER_TREE);
  1250. if (ownerTree) {
  1251. ownerTree.set(LAST_SELECTED, instance);
  1252. }
  1253. instance.get(CONTENT_BOX).addClass(CSS_TREE_NODE_SELECTED);
  1254. instance.fire('select');
  1255. },
  1256. /*
  1257. * Show hitarea icon.
  1258. *
  1259. * @method showHitArea
  1260. */
  1261. showHitArea: function() {
  1262. var instance = this;
  1263. instance.get(HIT_AREA_EL).removeClass(CSS_TREE_NODE_HIDDEN_HITAREA);
  1264. },
  1265. /**
  1266. * Toggle the current TreeNode, <code>collapsed</code> or <code>expanded</code>.
  1267. *
  1268. * @method toggle
  1269. */
  1270. toggle: function() {
  1271. var instance = this;
  1272. if (instance.get(EXPANDED)) {
  1273. instance.collapse();
  1274. }
  1275. else {
  1276. instance.expand();
  1277. }
  1278. },
  1279. /*
  1280. * Unselect the current TreeNode.
  1281. *
  1282. * @method unselect
  1283. */
  1284. unselect: function() {
  1285. var instance = this;
  1286. instance.get(CONTENT_BOX).removeClass(CSS_TREE_NODE_SELECTED);
  1287. instance.fire('unselect');
  1288. },
  1289. /**
  1290. * Fire after draggable change.
  1291. *
  1292. * @method _afterDraggableChange
  1293. * @param {EventFacade} event
  1294. * @protected
  1295. */
  1296. _afterDraggableChange: function(event) {
  1297. var instance = this;
  1298. instance._uiSetDraggable(event.newVal);
  1299. instance._syncIconUI();
  1300. },
  1301. /**
  1302. * Fire after expanded change.
  1303. *
  1304. * @method _afterExpandedChange
  1305. * @param {EventFacade} event
  1306. * @protected
  1307. */
  1308. _afterExpandedChange: function(event) {
  1309. var instance = this;
  1310. instance._uiSetExpanded(event.newVal);
  1311. instance._syncIconUI();
  1312. },
  1313. /**
  1314. * Fire after leaf change.
  1315. *
  1316. * @method _afterLeafChange
  1317. * @param {EventFacade} event
  1318. * @protected
  1319. */
  1320. _afterLeafChange: function(event) {
  1321. var instance = this;
  1322. instance._uiSetLeaf(event.newVal);
  1323. instance._syncIconUI();
  1324. },
  1325. /**
  1326. * Fire after loading change.
  1327. *
  1328. * @method _afterLoadingChange
  1329. * @param {EventFacade} event
  1330. * @protected
  1331. */
  1332. _afterLoadingChange: function(event) {
  1333. var instance = this;
  1334. instance._syncIconUI();
  1335. },
  1336. /**
  1337. * Fire after set children.
  1338. *
  1339. * @method _afterSetChildren
  1340. * @param {EventFacade} event
  1341. * @protected
  1342. */
  1343. _afterSetChildren: function(event) {
  1344. var instance = this;
  1345. instance._syncIconUI();
  1346. },
  1347. /**
  1348. * Render the node container.
  1349. *
  1350. * @method _createNodeContainer
  1351. * @protected
  1352. * @return {Node}
  1353. */
  1354. _createNodeContainer: function() {
  1355. var instance = this;
  1356. // creating <ul class="aui-tree-container">
  1357. var nodeContainer = instance.get(CONTAINER) || A.Node.create(NODE_CONTAINER_TPL);
  1358. nodeContainer.addClass(CSS_TREE_CONTAINER);
  1359. // when it's not a leaf it has a <ul> container
  1360. instance.set(CONTAINER, nodeContainer);
  1361. return nodeContainer;
  1362. },
  1363. _getSibling: function(value, attrName) {
  1364. var instance = this;
  1365. var propName = '_' + attrName;
  1366. var sibling = instance[propName];
  1367. if (sibling !== null && !isTreeNode(sibling)) {
  1368. sibling = null;
  1369. instance[propName] = sibling;
  1370. }
  1371. return sibling;
  1372. },
  1373. /**
  1374. * Render the <code>boundingBox</code> node.
  1375. *
  1376. * @method _renderBoundingBox
  1377. * @protected
  1378. * @return {Node}
  1379. */
  1380. _renderBoundingBox: function() {
  1381. var instance = this;
  1382. var boundingBox = instance.get(BOUNDING_BOX);
  1383. var contentBox = instance.get(CONTENT_BOX);
  1384. contentBox.append(instance.get(ICON_EL));
  1385. contentBox.append(instance.get(LABEL_EL));
  1386. boundingBox.append(contentBox);
  1387. var nodeContainer = instance.get(CONTAINER);
  1388. if (nodeContainer) {
  1389. if (!instance.get(EXPANDED)) {
  1390. nodeContainer.addClass(CSS_TREE_HIDDEN);
  1391. }
  1392. boundingBox.append(nodeContainer);
  1393. }
  1394. return boundingBox;
  1395. },
  1396. /**
  1397. * Render the <code>contentBox</code> node.
  1398. *
  1399. * @method _renderContentBox
  1400. * @protected
  1401. * @return {Node}
  1402. */
  1403. _renderContentBox: function(v) {
  1404. var instance = this;
  1405. var contentBox = instance.get(CONTENT_BOX);
  1406. if (!instance.isLeaf()) {
  1407. var expanded = instance.get(EXPANDED);
  1408. // add folder css classes state
  1409. contentBox.addClass(
  1410. expanded ? CSS_TREE_EXPANDED : CSS_TREE_COLLAPSED
  1411. );
  1412. if (expanded) {
  1413. instance.expand();
  1414. }
  1415. }
  1416. return contentBox;
  1417. },
  1418. /**
  1419. * Sync the hitarea UI.
  1420. *
  1421. * @method _syncHitArea
  1422. * @protected
  1423. */
  1424. _syncHitArea: function() {
  1425. var instance = this;
  1426. if (instance.get(ALWAYS_SHOW_HITAREA) || instance.getChildrenLength()) {
  1427. instance.showHitArea();
  1428. }
  1429. else {
  1430. instance.hideHitArea();
  1431. instance.collapse();
  1432. }
  1433. },
  1434. /**
  1435. * Sync the hitarea UI.
  1436. *
  1437. * @method _syncIconUI
  1438. * @param {Array} children
  1439. * @protected
  1440. */
  1441. _syncIconUI: function() {
  1442. var instance = this;
  1443. instance._syncHitArea();
  1444. },
  1445. /**
  1446. * Set the <code>boundingBox</code> id.
  1447. *
  1448. * @method _syncTreeNodeBBId
  1449. * @param {String} id
  1450. * @protected
  1451. */
  1452. _syncTreeNodeBBId: function(id) {
  1453. var instance = this;
  1454. instance.get(BOUNDING_BOX).attr(
  1455. ID,
  1456. instance.get(ID)
  1457. );
  1458. },
  1459. _uiSetDraggable: function(val) {
  1460. var instance = this;
  1461. var contentBox = instance.get(CONTENT_BOX);
  1462. contentBox.toggleClass(CSS_TREE_NODE_CONTENT_INVALID, !val);
  1463. },
  1464. _uiSetExpanded: function(val) {
  1465. var instance = this;
  1466. if (!instance.isLeaf()) {
  1467. var container = instance.get(CONTAINER);
  1468. var contentBox = instance.get(CONTENT_BOX);
  1469. if (val) {
  1470. contentBox.replaceClass(CSS_TREE_COLLAPSED, CSS_TREE_EXPANDED);
  1471. if (container) {
  1472. container.removeClass(CSS_TREE_HIDDEN);
  1473. }
  1474. }
  1475. else {
  1476. contentBox.replaceClass(CSS_TREE_EXPANDED, CSS_TREE_COLLAPSED);
  1477. if (container) {
  1478. container.addClass(CSS_TREE_HIDDEN);
  1479. }
  1480. }
  1481. }
  1482. },
  1483. _uiSetLeaf: function(val) {
  1484. var instance = this;
  1485. var contentBox = instance.get(CONTENT_BOX);
  1486. if (val) {
  1487. instance.get(CONTAINER).remove();
  1488. instance.get(HIT_AREA_EL).remove();
  1489. }
  1490. else {
  1491. // append hitarea element
  1492. contentBox.prepend( instance.get(HIT_AREA_EL) );
  1493. // if has children append them to this model
  1494. instance._createNodeContainer();
  1495. instance._uiSetExpanded(instance.get(EXPANDED));
  1496. }
  1497. // add leaf css classes
  1498. contentBox.toggleClass(CSS_TREE_NODE_LEAF, val);
  1499. }
  1500. }
  1501. }
  1502. );
  1503. A.TreeNode = TreeNode;
  1504. /*
  1505. * TreeNodeIO
  1506. */
  1507. var isFunction = Lang.isFunction,
  1508. CACHE = 'cache',
  1509. IO = 'io',
  1510. LOADED = 'loaded',
  1511. LOADING = 'loading',
  1512. PAGINATOR = 'paginator',
  1513. TREE_NODE_IO = 'tree-node-io',
  1514. CSS_TREE_NODE_IO_LOADING = getCN(TREE, NODE, IO, LOADING);
  1515. /**
  1516. * A base class for TreeNodeIO, providing:
  1517. * <ul>
  1518. * <li>Widget Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)</li>
  1519. * <li>Ajax support to load the children of the current TreeNode</li>
  1520. * </ul>
  1521. *
  1522. * Quick Example:<br/>
  1523. *
  1524. * <pre><code>var treeNodeIO = new A.TreeNodeIO({
  1525. * label: 'TreeNodeIO',
  1526. * cache: false,
  1527. * io: {
  1528. * url: 'assets/content.html'
  1529. * }
  1530. * });
  1531. * </code></pre>
  1532. *
  1533. * Check the list of <a href="TreeNodeIO.html#configattributes">Configuration Attributes</a> available for
  1534. * TreeNodeIO.
  1535. *
  1536. * @param config {Object} Object literal specifying widget configuration properties.
  1537. *
  1538. * @class TreeNodeIO
  1539. * @constructor
  1540. * @extends TreeNode
  1541. */
  1542. var TreeNodeIO = A.Component.create(
  1543. {
  1544. /**
  1545. * Static property provides a string to identify the class.
  1546. *
  1547. * @property TreeNode.NAME
  1548. * @type String
  1549. * @static
  1550. */
  1551. NAME: TREE_NODE_IO,
  1552. /**
  1553. * Static property used to define the default attribute
  1554. * configuration for the TreeNode.
  1555. *
  1556. * @property TreeNode.ATTRS
  1557. * @type Object
  1558. * @static
  1559. */
  1560. ATTRS: {
  1561. /**
  1562. * Whether the current TreeNode should cache the loaded content or not.
  1563. *
  1564. * @attribute cache
  1565. * @default true
  1566. * @type boolean
  1567. */
  1568. cache: {
  1569. validator: isBoolean,
  1570. value: true
  1571. },
  1572. leaf: {
  1573. validator: isBoolean,
  1574. value: false
  1575. },
  1576. /**
  1577. * Whether the current TreeNode has loaded the content.
  1578. *
  1579. * @attribute loaded
  1580. * @default false
  1581. * @type boolean
  1582. */
  1583. loaded: {
  1584. validator: isBoolean,
  1585. value: false
  1586. },
  1587. /**
  1588. * Whether the current TreeNode IO transaction is loading.
  1589. *
  1590. * @attribute loading
  1591. * @default false
  1592. * @type boolean
  1593. */
  1594. loading: {
  1595. validator: isBoolean,
  1596. value: false
  1597. }
  1598. },
  1599. AUGMENTS: [A.TreeViewPaginator, A.TreeViewIO],
  1600. EXTENDS: A.TreeNode,
  1601. prototype: {
  1602. /**
  1603. * Bind the events on the TreeNodeIO UI. Lifecycle.
  1604. *
  1605. * @method bindUI
  1606. * @protected
  1607. */
  1608. bindUI: function() {
  1609. var instance = this;
  1610. A.TreeNodeIO.superclass.bindUI.apply(instance, arguments);
  1611. instance.on('ioRequestSuccess', instance._onIOSuccess, instance);
  1612. },
  1613. syncUI: function() {
  1614. var instance = this;
  1615. A.TreeNodeIO.superclass.syncUI.apply(instance, arguments);
  1616. },
  1617. /*
  1618. * Methods
  1619. */
  1620. expand: function() {
  1621. var instance = this;
  1622. var cache = instance.get(CACHE);
  1623. var io = instance.get(IO);
  1624. var loaded = instance.get(LOADED);
  1625. var loading = instance.get(LOADING);
  1626. if (!cache) {
  1627. // if cache is false on expand, always set LOADED to false
  1628. instance.set(LOADED, false);
  1629. }
  1630. if (io && !loaded && !loading && !instance.hasChildNodes()) {
  1631. if (!cache) {
  1632. // remove all children to reload
  1633. instance.empty();
  1634. }
  1635. instance.initIO();
  1636. }
  1637. else {
  1638. A.TreeNodeIO.superclass.expand.apply(instance, arguments);
  1639. }
  1640. },
  1641. /**
  1642. * If not specified on the TreeNode some attributes are inherited from the
  1643. * ownerTree by this method.
  1644. *
  1645. * @method _inheritOwnerTreeAttrs
  1646. * @protected
  1647. */
  1648. _inheritOwnerTreeAttrs: function() {
  1649. var instance = this;
  1650. var ownerTree = instance.get(OWNER_TREE);
  1651. if (ownerTree) {
  1652. if (!instance.get(IO)) {
  1653. var io = A.clone(
  1654. ownerTree.get(IO),
  1655. true,
  1656. function(value, key) {
  1657. if (isFunction(value) && (value.defaultFn || value.wrappedFn)) {
  1658. return false;
  1659. }
  1660. return true;
  1661. }
  1662. );
  1663. instance.set(IO, io);
  1664. }
  1665. if (!instance.get(PAGINATOR)) {
  1666. var ownerTreePaginator = ownerTree.get(PAGINATOR);
  1667. var paginator = A.clone(ownerTreePaginator);
  1668. // make sure we are not using the same element passed to the ownerTree on the TreeNode
  1669. if (paginator && paginator.element) {
  1670. paginator.element = ownerTreePaginator.element.clone();
  1671. }
  1672. instance.set(PAGINATOR, paginator);
  1673. }
  1674. }
  1675. },
  1676. _onIOSuccess: function(event) {
  1677. var instance = this;
  1678. instance.expand();
  1679. }
  1680. }
  1681. }
  1682. );
  1683. A.TreeNodeIO = TreeNodeIO;
  1684. /*
  1685. * TreeNodeCheck
  1686. */
  1687. var CHECKBOX = 'checkbox',
  1688. CHECKED = 'checked',
  1689. CHECK_CONTAINER_EL = 'checkContainerEl',
  1690. CHECK_EL = 'checkEl',
  1691. CHECK_NAME = 'checkName',
  1692. DOT = '.',
  1693. NAME = 'name',
  1694. TREE_NODE_CHECK = 'tree-node-check',
  1695. CSS_TREE_NODE_CHECKBOX = getCN(TREE, NODE, CHECKBOX),
  1696. CSS_TREE_NODE_CHECKBOX_CONTAINER = getCN(TREE, NODE, CHECKBOX, CONTAINER),
  1697. CSS_TREE_NODE_CHECKED = getCN(TREE, NODE, CHECKED),
  1698. CHECKBOX_CONTAINER_TPL = '<div class="' + CSS_TREE_NODE_CHECKBOX_CONTAINER + '"></div>',
  1699. CHECKBOX_TPL = '<input class="' + CSS_TREE_NODE_CHECKBOX + '" type="checkbox" />';
  1700. /**
  1701. * <p><img src="assets/images/aui-tree-nod-check/main.png"/></p>
  1702. *
  1703. * A base class for TreeNodeCheck, providing:
  1704. * <ul>
  1705. * <li>Widget Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)</li>
  1706. * <li>Checkbox support for the TreeNode</li>
  1707. * </ul>
  1708. *
  1709. * Check the list of <a href="TreeNodeCheck.html#configattributes">Configuration Attributes</a> available for
  1710. * TreeNodeCheck.
  1711. *
  1712. * @param config {Object} Object literal specifying widget configuration properties.
  1713. *
  1714. * @class TreeNodeCheck
  1715. * @constructor
  1716. * @extends TreeNodeIO
  1717. */
  1718. var TreeNodeCheck = A.Component.create(
  1719. {
  1720. /**
  1721. * Static property provides a string to identify the class.
  1722. *
  1723. * @property TreeNode.NAME
  1724. * @type String
  1725. * @static
  1726. */
  1727. NAME: TREE_NODE_CHECK,
  1728. /**
  1729. * Static property used to define the default attribute
  1730. * configuration for the TreeNode.
  1731. *
  1732. * @property TreeNode.ATTRS
  1733. * @type Object
  1734. * @static
  1735. */
  1736. ATTRS: {
  1737. /**
  1738. * Whether the TreeNode is checked or not.
  1739. *
  1740. * @attribute checked
  1741. * @default false
  1742. * @type boolean
  1743. */
  1744. checked: {
  1745. validator: isBoolean,
  1746. value: false
  1747. },
  1748. /**
  1749. * Container element for the checkbox.
  1750. *
  1751. * @attribute checkContainerEl
  1752. * @default Generated DOM element.
  1753. * @type Node | String
  1754. */
  1755. checkContainerEl: {
  1756. setter: A.one,
  1757. valueFn: function() {
  1758. return A.Node.create(CHECKBOX_CONTAINER_TPL);
  1759. }
  1760. },
  1761. /**
  1762. * Checkbox element.
  1763. *
  1764. * @attribute checkEl
  1765. * @default Generated DOM element.
  1766. * @type Node | String
  1767. */
  1768. checkEl: {
  1769. setter: A.one,
  1770. valueFn: function() {
  1771. var instance = this;
  1772. var checkBoxId = instance.get(ID) + 'Checkbox';
  1773. var attributes = {
  1774. ID: checkBoxId,
  1775. NAME: instance.get(CHECK_NAME)
  1776. };
  1777. return A.Node.create(CHECKBOX_TPL).attr(attributes);
  1778. }
  1779. },
  1780. /**
  1781. * Name of the checkbox element used on the current TreeNode.
  1782. *
  1783. * @attribute checkName
  1784. * @default 'tree-node-check'
  1785. * @type String
  1786. */
  1787. checkName: {
  1788. value: TREE_NODE_CHECK,
  1789. validator: isString
  1790. }
  1791. },
  1792. EXTENDS: A.TreeNodeIO,
  1793. prototype: {
  1794. initializer: function() {
  1795. var instance = this;
  1796. instance._uiSetChecked(instance.get(CHECKED));
  1797. },
  1798. /*
  1799. * Lifecycle
  1800. */
  1801. renderUI: function() {
  1802. var instance = this;
  1803. A.TreeNodeCheck.superclass.renderUI.apply(instance, arguments);
  1804. var checkEl = instance.get(CHECK_EL);
  1805. var checkContainerEl = instance.get(CHECK_CONTAINER_EL);
  1806. checkEl.hide();
  1807. checkContainerEl.append(checkEl);
  1808. instance.get(LABEL_EL).placeBefore(checkContainerEl);
  1809. if (instance.isChecked()) {
  1810. instance.check();
  1811. }
  1812. },
  1813. bindUI: function() {
  1814. var instance = this;
  1815. var contentBox = instance.get(CONTENT_BOX);
  1816. A.TreeNodeCheck.superclass.bindUI.apply(instance, arguments);
  1817. instance.after('checkedChange', A.bind(instance._afterCheckedChange, instance));
  1818. contentBox.delegate('click', A.bind(instance.toggleCheck, instance), DOT + CSS_TREE_NODE_CHECKBOX_CONTAINER);
  1819. contentBox.delegate('click', A.bind(instance.toggleCheck, instance), DOT + CSS_TREE_LABEL);
  1820. // cancel dblclick because of the check
  1821. instance.get(LABEL_EL).swallowEvent('dblclick');
  1822. },
  1823. /**
  1824. * Check the current TreeNode.
  1825. *
  1826. * @method check
  1827. */
  1828. check: function(originalTarget) {
  1829. var instance = this;
  1830. instance.set(
  1831. CHECKED,
  1832. true,
  1833. {
  1834. originalTarget: originalTarget
  1835. }
  1836. );
  1837. },
  1838. /*
  1839. * Whether the current TreeNodeCheck is checked.
  1840. *
  1841. * @method isChecked
  1842. * @return boolean
  1843. */
  1844. isChecked: function() {
  1845. var instance = this;
  1846. return instance.get(CHECKED);
  1847. },
  1848. /**
  1849. * Toggle the check status of the current TreeNode.
  1850. *
  1851. * @method toggleCheck
  1852. */
  1853. toggleCheck: function() {
  1854. var instance = this;
  1855. var checkEl = instance.get(CHECK_EL);
  1856. var checked = checkEl.attr(CHECKED);
  1857. if (!checked) {
  1858. instance.check();
  1859. }
  1860. else {
  1861. instance.uncheck();
  1862. }
  1863. },
  1864. /**
  1865. * Uncheck the current TreeNode.
  1866. *
  1867. * @method uncheck
  1868. */
  1869. uncheck: function(originalTarget) {
  1870. var instance = this;
  1871. instance.set(
  1872. CHECKED,
  1873. false,
  1874. {
  1875. originalTarget: originalTarget
  1876. }
  1877. );
  1878. },
  1879. _afterCheckedChange: function(event) {
  1880. var instance = this;
  1881. instance._uiSetChecked(event.newVal);
  1882. },
  1883. _uiSetChecked: function(val) {
  1884. var instance = this;
  1885. var checkEl = instance.get(CHECK_EL);
  1886. var contentBox = instance.get(CONTENT_BOX);
  1887. if (val) {
  1888. contentBox.addClass(CSS_TREE_NODE_CHECKED);
  1889. checkEl.attr(CHECKED, CHECKED);
  1890. }
  1891. else {
  1892. contentBox.removeClass(CSS_TREE_NODE_CHECKED);
  1893. checkEl.attr(CHECKED, BLANK);
  1894. }
  1895. }
  1896. }
  1897. }
  1898. );
  1899. A.TreeNodeCheck = TreeNodeCheck;
  1900. /*
  1901. * TreeNodeTask
  1902. */
  1903. var CHILD = 'child',
  1904. TREE_NODE_TASK = 'tree-node-task',
  1905. UNCHECKED = 'unchecked',
  1906. isTreeNodeTask = function(node) {
  1907. return node instanceof A.TreeNodeCheck;
  1908. },
  1909. CSS_TREE_NODE_CHILD_UNCHECKED = getCN(TREE, NODE, CHILD, UNCHECKED);
  1910. /**
  1911. * <p><img src="assets/images/aui-treeNodeTask/main.png"/></p>
  1912. *
  1913. * A base class for TreeNodeTask, providing:
  1914. * <ul>
  1915. * <li>Widget Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)</li>
  1916. * <li>3 states checkbox support</li>
  1917. * <li>Automatic check/uncheck the parent status based on the children checked status</li>
  1918. * </ul>
  1919. *
  1920. * Check the list of <a href="TreeNodeTask.html#configattributes">Configuration Attributes</a> available for
  1921. * TreeNodeTask.
  1922. *
  1923. * @param config {Object} Object literal specifying widget configuration properties.
  1924. *
  1925. * @class TreeNodeTask
  1926. * @constructor
  1927. * @extends TreeNodeCheck
  1928. */
  1929. var TreeNodeTask = A.Component.create(
  1930. {
  1931. /**
  1932. * Static property provides a string to identify the class.
  1933. *
  1934. * @property TreeNode.NAME
  1935. * @type String
  1936. * @static
  1937. */
  1938. NAME: TREE_NODE_TASK,
  1939. EXTENDS: A.TreeNodeCheck,
  1940. prototype: {
  1941. /*
  1942. * Methods
  1943. */
  1944. check: function(originalTarget) {
  1945. var instance = this;
  1946. originalTarget = originalTarget || instance;
  1947. if (!instance.isLeaf()) {
  1948. instance.eachChildren(
  1949. function(child) {
  1950. if (isTreeNodeTask(child)) {
  1951. child.check(originalTarget);
  1952. }
  1953. }
  1954. );
  1955. }
  1956. instance.eachParent(
  1957. function(parentNode) {
  1958. if (isTreeNodeTask(parentNode)) {
  1959. var parentHasUncheckedDescendants = false;
  1960. parentNode.eachChildren(function(child) {
  1961. if ((child !== instance) && !child.isChecked()) {
  1962. parentHasUncheckedDescendants = true;
  1963. }
  1964. else {
  1965. var childHasUncheckedChild = child.get(CONTENT_BOX).hasClass(CSS_TREE_NODE_CHILD_UNCHECKED);
  1966. if (childHasUncheckedChild) {
  1967. parentHasUncheckedDescendants = true;
  1968. }
  1969. }
  1970. });
  1971. if (!parentHasUncheckedDescendants) {
  1972. parentNode.get(CONTENT_BOX).removeClass(CSS_TREE_NODE_CHILD_UNCHECKED);
  1973. }
  1974. }
  1975. }
  1976. );
  1977. instance.get(CONTENT_BOX).removeClass(CSS_TREE_NODE_CHILD_UNCHECKED);
  1978. // invoke default check logic
  1979. A.TreeNodeTask.superclass.check.call(instance, originalTarget);
  1980. },
  1981. uncheck: function(originalTarget) {
  1982. var instance = this;
  1983. originalTarget = originalTarget || instance;
  1984. if (!instance.isLeaf()) {
  1985. instance.eachChildren(
  1986. function(child) {
  1987. if (child instanceof A.TreeNodeCheck) {
  1988. child.uncheck(originalTarget);
  1989. }
  1990. }
  1991. );
  1992. }
  1993. instance.eachParent(
  1994. function(parentNode) {
  1995. if (isTreeNodeTask(parentNode) && parentNode.isChecked()) {
  1996. parentNode.get(CONTENT_BOX).addClass(CSS_TREE_NODE_CHILD_UNCHECKED);
  1997. }
  1998. }
  1999. );
  2000. instance.get(CONTENT_BOX).removeClass(CSS_TREE_NODE_CHILD_UNCHECKED);
  2001. // invoke default uncheck logic
  2002. A.TreeNodeTask.superclass.uncheck.call(instance, originalTarget);
  2003. }
  2004. }
  2005. }
  2006. );
  2007. A.TreeNodeTask = TreeNodeTask;
  2008. /*
  2009. * TreeNodeRadio
  2010. */
  2011. var TREE_NODE_RADIO = 'tree-node-radio',
  2012. isTreeNodeRadio = function(node) {
  2013. return node instanceof A.TreeNodeRadio;
  2014. },
  2015. CSS_NODE_RADIO = getCN(TREE, NODE, RADIO),
  2016. CSS_NODE_RADIO_CHECKED = getCN(TREE, NODE, RADIO, CHECKED);
  2017. /**
  2018. * <p><img src="assets/images/aui-treeNodeRadio/main.png"/></p>
  2019. *
  2020. * A base class for TreeNodeRadio, providing:
  2021. * <ul>
  2022. * <li>Widget Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)</li>
  2023. * <li>3 states checkbox support</li>
  2024. * <li>Automatic check/uncheck the parent status based on the children checked status</li>
  2025. * </ul>
  2026. *
  2027. * Check the list of <a href="TreeNodeRadio.html#configattributes">Configuration Attributes</a> available for
  2028. * TreeNodeRadio.
  2029. *
  2030. * @param config {Object} Object literal specifying widget configuration properties.
  2031. *
  2032. * @class TreeNodeRadio
  2033. * @constructor
  2034. * @extends TreeNodeTask
  2035. */
  2036. var TreeNodeRadio = A.Component.create(
  2037. {
  2038. /**
  2039. * Static property provides a string to identify the class.
  2040. *
  2041. * @property TreeNode.NAME
  2042. * @type String
  2043. * @static
  2044. */
  2045. NAME: TREE_NODE_RADIO,
  2046. EXTENDS: A.TreeNodeCheck,
  2047. prototype: {
  2048. /*
  2049. * Methods
  2050. */
  2051. renderUI: function() {
  2052. var instance = this;
  2053. A.TreeNodeRadio.superclass.renderUI.apply(instance, arguments);
  2054. instance.get(CONTENT_BOX).addClass(CSS_NODE_RADIO);
  2055. },
  2056. _uncheckNodesRadio: function(node) {
  2057. var instance = this;
  2058. var children;
  2059. if (node) {
  2060. children = node.get(CHILDREN);
  2061. }
  2062. else {
  2063. var ownerTree = instance.get(OWNER_TREE);
  2064. if (ownerTree) {
  2065. children = ownerTree.get(CHILDREN);
  2066. }
  2067. else {
  2068. return;
  2069. }
  2070. }
  2071. A.Array.each(
  2072. children,
  2073. function(value, index, collection) {
  2074. if (!value.isLeaf()) {
  2075. instance._uncheckNodesRadio(value);
  2076. }
  2077. if (isTreeNodeRadio(value)) {
  2078. value.uncheck();
  2079. }
  2080. }
  2081. );
  2082. },
  2083. _uiSetChecked: function(val) {
  2084. var instance = this;
  2085. if (val) {
  2086. instance.get(CONTENT_BOX).addClass(CSS_NODE_RADIO_CHECKED);
  2087. instance.get(CHECK_EL).attr(CHECKED, CHECKED);
  2088. }
  2089. else {
  2090. instance.get(CONTENT_BOX).removeClass(CSS_NODE_RADIO_CHECKED);
  2091. instance.get(CHECK_EL).attr(CHECKED, BLANK);
  2092. }
  2093. },
  2094. check: function() {
  2095. var instance = this;
  2096. instance._uncheckNodesRadio();
  2097. A.TreeNodeRadio.superclass.check.apply(instance, arguments);
  2098. }
  2099. }
  2100. }
  2101. );
  2102. A.TreeNodeRadio = TreeNodeRadio;
  2103. /**
  2104. * TreeNode types hash map.
  2105. *
  2106. * <pre><code>A.TreeNode.nodeTypes = {
  2107. * check: A.TreeNodeCheck,
  2108. * io: A.TreeNodeIO,
  2109. * node: A.TreeNode,
  2110. * radio: A.TreeNodeRadio,
  2111. * task: A.TreeNodeTask
  2112. *};</code></pre>
  2113. *
  2114. * @for TreeNode
  2115. * @property A.TreeNode.nodeTypes
  2116. * @type Object
  2117. */
  2118. A.TreeNode.nodeTypes = {
  2119. check: A.TreeNodeCheck,
  2120. io: A.TreeNodeIO,
  2121. node: A.TreeNode,
  2122. radio: A.TreeNodeRadio,
  2123. task: A.TreeNodeTask
  2124. };
  2125. }, '@VERSION@' ,{requires:['aui-tree-data','aui-tree-io','aui-tree-paginator','json','querystring-stringify'], skinnable:false});
  2126. AUI.add('aui-tree-paginator', function(A) {
  2127. var Lang = A.Lang,
  2128. isObject = Lang.isObject,
  2129. isValue = Lang.isValue,
  2130. getCN = A.getClassName,
  2131. CHILDREN = 'children',
  2132. CONTAINER = 'container',
  2133. END = 'end',
  2134. IO = 'io',
  2135. LIMIT = 'limit',
  2136. MORE_RESULTS_LABEL = 'Load more results',
  2137. NODE = 'node',
  2138. OWNER_TREE = 'ownerTree',
  2139. PAGINATOR = 'paginator',
  2140. START = 'start',
  2141. TREE = 'tree',
  2142. TREE_NODE_IO = 'tree-node-io',
  2143. EV_TREE_NODE_PAGINATOR_CLICK = 'paginatorClick',
  2144. CSS_TREE_NODE_PAGINATOR = getCN(TREE, NODE, PAGINATOR),
  2145. TPL_PAGINATOR = '<a class="' + CSS_TREE_NODE_PAGINATOR + '" href="javascript:void(0);">{moreResultsLabel}</a>';
  2146. function TreeViewPaginator(config) {
  2147. var instance = this;
  2148. A.after(instance._bindPaginatorUI, this, 'bindUI');
  2149. A.after(instance._syncPaginatorUI, this, 'syncUI');
  2150. }
  2151. TreeViewPaginator.ATTRS = {
  2152. paginator: {
  2153. setter: function(value) {
  2154. var instance = this;
  2155. var paginatorNode = A.Node.create(
  2156. Lang.sub(
  2157. TPL_PAGINATOR,
  2158. {
  2159. moreResultsLabel: value.moreResultsLabel || MORE_RESULTS_LABEL
  2160. }
  2161. )
  2162. );
  2163. return A.merge(
  2164. {
  2165. alwaysVisible: false,
  2166. autoFocus: true,
  2167. element: paginatorNode,
  2168. endParam: END,
  2169. limitParam: LIMIT,
  2170. start: 0,
  2171. startParam: START
  2172. },
  2173. value
  2174. );
  2175. },
  2176. validator: isObject
  2177. }
  2178. };
  2179. TreeViewPaginator.prototype = {
  2180. /**
  2181. * Bind events to the paginator "show more" link.
  2182. *
  2183. * @method _bindPaginatorUI
  2184. * @protected
  2185. */
  2186. _bindPaginatorUI: function() {
  2187. var instance = this;
  2188. var paginator = instance.get(PAGINATOR);
  2189. if (paginator) {
  2190. paginator.element.on('click', A.bind(instance._handlePaginatorClickEvent, instance));
  2191. }
  2192. instance._createEvents();
  2193. },
  2194. /**
  2195. * Create custom events.
  2196. *
  2197. * @method _createEvents
  2198. * @private
  2199. */
  2200. _createEvents: function() {
  2201. var instance = this;
  2202. instance.publish(
  2203. EV_TREE_NODE_PAGINATOR_CLICK,
  2204. {
  2205. defaultFn: instance._defPaginatorClickFn,
  2206. prefix: TREE_NODE_IO
  2207. }
  2208. );
  2209. },
  2210. /**
  2211. * Default paginatorClick event handler. Increment the
  2212. * <code>paginator.start</code> to the next <code>paginator.limit</code>.
  2213. *
  2214. * @method _defPaginatorClickFn
  2215. * @param {EventFacade} event The Event object
  2216. * @protected
  2217. */
  2218. _defPaginatorClickFn: function(event) {
  2219. var instance = this;
  2220. var paginator = instance.get(PAGINATOR);
  2221. if (isValue(paginator.limit)) {
  2222. paginator.start = instance.getChildrenLength();
  2223. }
  2224. if (instance.get(IO)) {
  2225. instance.initIO();
  2226. }
  2227. },
  2228. /**
  2229. * Fires the paginatorClick event.
  2230. *
  2231. * @method _handlePaginatorClickEvent
  2232. * @param {EventFacade} event paginatorClick event facade
  2233. * @protected
  2234. */
  2235. _handlePaginatorClickEvent: function(event) {
  2236. var instance = this;
  2237. var output = instance.getEventOutputMap(instance);
  2238. instance.fire(EV_TREE_NODE_PAGINATOR_CLICK, output);
  2239. event.halt();
  2240. },
  2241. /**
  2242. * Adds two extra IO data parameter to the request to handle the
  2243. * paginator. By default these parameters are <code>limit</code> and
  2244. * <code>start</code>.
  2245. *
  2246. * @method _syncPaginatorIOData
  2247. * @protected
  2248. */
  2249. _syncPaginatorIOData: function(io) {
  2250. var instance = this;
  2251. var paginator = instance.get(PAGINATOR);
  2252. if (paginator && isValue(paginator.limit)) {
  2253. var data = io.cfg.data || {};
  2254. data[ paginator.limitParam ] = paginator.limit;
  2255. data[ paginator.startParam ] = paginator.start;
  2256. data[ paginator.endParam ] = (paginator.start + paginator.limit);
  2257. io.cfg.data = data;
  2258. }
  2259. },
  2260. /**
  2261. * Sync the paginator link UI.
  2262. *
  2263. * @method _syncPaginatorUI
  2264. * @protected
  2265. */
  2266. _syncPaginatorUI: function(newNodes) {
  2267. var instance = this;
  2268. var paginator = instance.get(PAGINATOR);
  2269. if (paginator) {
  2270. var hasMoreData = true;
  2271. if (newNodes) {
  2272. hasMoreData = (newNodes.length > 0);
  2273. }
  2274. var childrenLength = instance.getChildrenLength();
  2275. var start = paginator.start;
  2276. var total = paginator.total || childrenLength;
  2277. var showPaginator = childrenLength && hasMoreData && (total > childrenLength);
  2278. if (paginator.alwaysVisible || showPaginator) {
  2279. instance.get(CONTAINER).append(
  2280. paginator.element.show()
  2281. );
  2282. if (paginator.autoFocus) {
  2283. try {
  2284. paginator.element.focus();
  2285. }
  2286. catch(e) {}
  2287. }
  2288. }
  2289. else {
  2290. paginator.element.hide();
  2291. }
  2292. }
  2293. }
  2294. };
  2295. A.TreeViewPaginator = TreeViewPaginator;
  2296. }, '@VERSION@' ,{requires:['aui-base'], skinnable:false});
  2297. AUI.add('aui-tree-view', function(A) {
  2298. /**
  2299. * The TreeView Utility
  2300. *
  2301. * @module aui-tree
  2302. * @submodule aui-tree-view
  2303. */
  2304. var L = A.Lang,
  2305. isBoolean = L.isBoolean,
  2306. isString = L.isString,
  2307. UA = A.UA,
  2308. BOUNDING_BOX = 'boundingBox',
  2309. CHILDREN = 'children',
  2310. CONTAINER = 'container',
  2311. CONTENT = 'content',
  2312. CONTENT_BOX = 'contentBox',
  2313. DOT = '.',
  2314. FILE = 'file',
  2315. HITAREA = 'hitarea',
  2316. ICON = 'icon',
  2317. INVALID = 'invalid',
  2318. LABEL = 'label',
  2319. LAST_SELECTED = 'lastSelected',
  2320. LEAF = 'leaf',
  2321. NODE = 'node',
  2322. OWNER_TREE = 'ownerTree',
  2323. ROOT = 'root',
  2324. SELECT_ON_TOGGLE = 'selectOnToggle',
  2325. SPACE = ' ',
  2326. TREE = 'tree',
  2327. TREE_NODE = 'tree-node',
  2328. TREE_VIEW = 'tree-view',
  2329. TYPE = 'type',
  2330. VIEW = 'view',
  2331. concat = function() {
  2332. return Array.prototype.slice.call(arguments).join(SPACE);
  2333. },
  2334. isTreeNode = function(v) {
  2335. return ( v instanceof A.TreeNode );
  2336. },
  2337. getCN = A.getClassName,
  2338. CSS_TREE_HITAREA = getCN(TREE, HITAREA),
  2339. CSS_TREE_ICON = getCN(TREE, ICON),
  2340. CSS_TREE_LABEL = getCN(TREE, LABEL),
  2341. CSS_TREE_NODE_CONTENT = getCN(TREE, NODE, CONTENT),
  2342. CSS_TREE_NODE_CONTENT_INVALID = getCN(TREE, NODE, CONTENT, INVALID),
  2343. CSS_TREE_ROOT_CONTAINER = getCN(TREE, ROOT, CONTAINER),
  2344. CSS_TREE_VIEW_CONTENT = getCN(TREE, VIEW, CONTENT);
  2345. /**
  2346. * <p><img src="assets/images/aui-tree-view/main.png"/></p>
  2347. *
  2348. * A base class for TreeView, providing:
  2349. * <ul>
  2350. * <li>Widget Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)</li>
  2351. * </ul>
  2352. *
  2353. * Quick Example:<br/>
  2354. *
  2355. * <pre><code>var tree2 = new A.TreeView({
  2356. * width: 200,
  2357. * type: 'normal',
  2358. * boundingBox: '#tree',
  2359. * children: [
  2360. * { label: 'Folder 1', children: [ { label: 'file' }, { label: 'file' }, { label: 'file' } ] },
  2361. * { label: 'Folder 2', expanded: true, children: [ { label: 'file' }, { label: 'file' } ] },
  2362. * { label: 'Folder 3', children: [ { label: 'file' } ] },
  2363. * { label: 'Folder 4', expanded: true, children: [ { label: 'Folder 4-1', expanded: true, children: [ { label: 'file' } ] } ] }
  2364. * ]
  2365. * })
  2366. * .render();
  2367. * </code></pre>
  2368. *
  2369. * Check the list of <a href="TreeView.html#configattributes">Configuration Attributes</a> available for
  2370. * TreeView.
  2371. *
  2372. * @param config {Object} Object literal specifying widget configuration properties.
  2373. *
  2374. * @class TreeView
  2375. * @constructor
  2376. * @extends TreeData
  2377. */
  2378. var TreeView = A.Component.create(
  2379. {
  2380. /**
  2381. * Static property provides a string to identify the class.
  2382. *
  2383. * @property TreeView.NAME
  2384. * @type String
  2385. * @static
  2386. */
  2387. NAME: TREE_VIEW,
  2388. /**
  2389. * Static property used to define the default attribute
  2390. * configuration for the TreeView.
  2391. *
  2392. * @property TreeView.ATTRS
  2393. * @type Object
  2394. * @static
  2395. */
  2396. ATTRS: {
  2397. /**
  2398. * Type of the treeview (i.e. could be 'file' or 'normal').
  2399. *
  2400. * @attribute type
  2401. * @default 'file'
  2402. * @type String
  2403. */
  2404. type: {
  2405. value: FILE,
  2406. validator: isString
  2407. },
  2408. /**
  2409. * Last selected TreeNode.
  2410. *
  2411. * @attribute lastSelected
  2412. * @default null
  2413. * @type TreeNode
  2414. */
  2415. lastSelected: {
  2416. value: null,
  2417. validator: isTreeNode
  2418. },
  2419. lazyLoad: {
  2420. validator: isBoolean,
  2421. value: true
  2422. },
  2423. selectOnToggle: {
  2424. validator: isBoolean,
  2425. value: false
  2426. }
  2427. },
  2428. AUGMENTS: [A.TreeData, A.TreeViewPaginator, A.TreeViewIO],
  2429. prototype: {
  2430. CONTENT_TEMPLATE: '<ul></ul>',
  2431. initializer: function() {
  2432. var instance = this;
  2433. var boundingBox = instance.get(BOUNDING_BOX);
  2434. boundingBox.setData(TREE_VIEW, instance);
  2435. instance.initTreeData();
  2436. },
  2437. /**
  2438. * Bind the events on the TreeView UI. Lifecycle.
  2439. *
  2440. * @method bindUI
  2441. * @protected
  2442. */
  2443. bindUI: function() {
  2444. var instance = this;
  2445. instance.after('childrenChange', A.bind(instance._afterSetChildren, instance));
  2446. instance._delegateDOM();
  2447. },
  2448. /**
  2449. * Create the DOM structure for the TreeView. Lifecycle.
  2450. *
  2451. * @method renderUI
  2452. * @protected
  2453. */
  2454. renderUI: function() {
  2455. var instance = this;
  2456. instance._renderElements();
  2457. },
  2458. /**
  2459. * Fires after set children.
  2460. *
  2461. * @method _afterSetChildren
  2462. * @param {EventFacade} event
  2463. * @protected
  2464. */
  2465. _afterSetChildren: function(event) {
  2466. var instance = this;
  2467. var paginator = instance.get('paginator');
  2468. if (paginator && paginator.total) {
  2469. var increment = -1;
  2470. if (event.newVal.length > event.prevVal.length) {
  2471. increment = 1;
  2472. }
  2473. paginator.total += increment;
  2474. }
  2475. instance._syncPaginatorUI();
  2476. },
  2477. /**
  2478. * Create TreeNode from HTML markup.
  2479. *
  2480. * @method _createFromHTMLMarkup
  2481. * @param {Node} container
  2482. * @protected
  2483. */
  2484. _createFromHTMLMarkup: function(container) {
  2485. var instance = this;
  2486. container.all('> li').each(function(node) {
  2487. // use firstChild as label
  2488. var labelEl = node.one('> *').remove();
  2489. var label = labelEl.outerHTML();
  2490. var deepContainer = node.one('> ul');
  2491. var treeNode = new A.TreeNode({
  2492. boundingBox: node,
  2493. container: deepContainer,
  2494. label: label,
  2495. leaf: !deepContainer,
  2496. ownerTree: instance
  2497. });
  2498. if (instance.get('lazyLoad')) {
  2499. A.setTimeout(function() {
  2500. treeNode.render();
  2501. }, 50);
  2502. }
  2503. else {
  2504. treeNode.render();
  2505. }
  2506. // find the parent TreeNode...
  2507. var parentNode = node.get(PARENT_NODE).get(PARENT_NODE);
  2508. var parentInstance = parentNode.getData(TREE_NODE);
  2509. if (!A.instanceOf(parentInstance, A.TreeNode)) {
  2510. parentInstance = parentNode.getData(TREE_VIEW);
  2511. }
  2512. // and simulate the appendChild.
  2513. parentInstance.appendChild(treeNode);
  2514. if (deepContainer) {
  2515. // propgating markup recursion
  2516. instance._createFromHTMLMarkup(deepContainer);
  2517. }
  2518. });
  2519. },
  2520. _createNodeContainer: function() {
  2521. var instance = this;
  2522. var contentBox = instance.get(CONTENT_BOX);
  2523. instance.set(CONTAINER, contentBox);
  2524. return contentBox;
  2525. },
  2526. /**
  2527. * Render elements.
  2528. *
  2529. * @method _renderElements
  2530. * @protected
  2531. */
  2532. _renderElements: function() {
  2533. var instance = this;
  2534. var contentBox = instance.get(CONTENT_BOX);
  2535. var children = instance.get(CHILDREN);
  2536. var type = instance.get(TYPE);
  2537. var CSS_TREE_TYPE = getCN(TREE, type);
  2538. contentBox.addClass(CSS_TREE_VIEW_CONTENT);
  2539. contentBox.addClass(
  2540. concat(CSS_TREE_TYPE, CSS_TREE_ROOT_CONTAINER)
  2541. );
  2542. if (!children.length) {
  2543. // if children not specified try to create from markup
  2544. instance._createFromHTMLMarkup(contentBox);
  2545. }
  2546. },
  2547. /**
  2548. * Delegate events.
  2549. *
  2550. * @method _delegateDOM
  2551. * @protected
  2552. */
  2553. _delegateDOM: function() {
  2554. var instance = this;
  2555. var boundingBox = instance.get(BOUNDING_BOX);
  2556. // expand/collapse delegations
  2557. boundingBox.delegate('click', A.bind(instance._onClickNodeEl, instance), DOT+CSS_TREE_NODE_CONTENT);
  2558. boundingBox.delegate('dblclick', A.bind(instance._onClickHitArea, instance), DOT+CSS_TREE_ICON);
  2559. boundingBox.delegate('dblclick', A.bind(instance._onClickHitArea, instance), DOT+CSS_TREE_LABEL);
  2560. // other delegations
  2561. boundingBox.delegate('mouseenter', A.bind(instance._onMouseEnterNodeEl, instance), DOT+CSS_TREE_NODE_CONTENT);
  2562. boundingBox.delegate('mouseleave', A.bind(instance._onMouseLeaveNodeEl, instance), DOT+CSS_TREE_NODE_CONTENT);
  2563. },
  2564. /**
  2565. * Fires on click the TreeView (i.e. set the select/unselect state).
  2566. *
  2567. * @method _onClickNodeEl
  2568. * @param {EventFacade} event
  2569. * @protected
  2570. */
  2571. _onClickNodeEl: function(event) {
  2572. var instance = this;
  2573. var treeNode = instance.getNodeByChild( event.currentTarget );
  2574. if (treeNode) {
  2575. if (event.target.test(DOT+CSS_TREE_HITAREA)) {
  2576. treeNode.toggle();
  2577. if (!instance.get(SELECT_ON_TOGGLE)) {
  2578. return;
  2579. }
  2580. }
  2581. if (!treeNode.isSelected()) {
  2582. var lastSelected = instance.get(LAST_SELECTED);
  2583. // select drag node
  2584. if (lastSelected) {
  2585. lastSelected.unselect();
  2586. }
  2587. treeNode.select();
  2588. }
  2589. }
  2590. },
  2591. /**
  2592. * Fires on <code>mouseeneter</code> the TreeNode.
  2593. *
  2594. * @method _onMouseEnterNodeEl
  2595. * @param {EventFacade} event
  2596. * @protected
  2597. */
  2598. _onMouseEnterNodeEl: function(event) {
  2599. var instance = this;
  2600. var treeNode = instance.getNodeByChild( event.currentTarget );
  2601. if (treeNode) {
  2602. treeNode.over();
  2603. }
  2604. },
  2605. /**
  2606. * Fires on <code>mouseleave</code> the TreeNode.
  2607. *
  2608. * @method _onMouseLeaveNodeEl
  2609. * @param {EventFacade} event
  2610. * @protected
  2611. */
  2612. _onMouseLeaveNodeEl: function(event) {
  2613. var instance = this;
  2614. var treeNode = instance.getNodeByChild( event.currentTarget );
  2615. if (treeNode) {
  2616. treeNode.out();
  2617. }
  2618. },
  2619. /**
  2620. * Fires on <code>click</code> the TreeNode hitarea.
  2621. *
  2622. * @method _onClickHitArea
  2623. * @param {EventFacade} event
  2624. * @protected
  2625. */
  2626. _onClickHitArea: function(event) {
  2627. var instance = this;
  2628. var treeNode = instance.getNodeByChild( event.currentTarget );
  2629. if (treeNode) {
  2630. treeNode.toggle();
  2631. }
  2632. }
  2633. }
  2634. }
  2635. );
  2636. A.TreeView = TreeView;
  2637. /*
  2638. * TreeViewDD - Drag & Drop
  2639. */
  2640. var isNumber = L.isNumber,
  2641. ABOVE = 'above',
  2642. APPEND = 'append',
  2643. BELOW = 'below',
  2644. BLOCK = 'block',
  2645. BODY = 'body',
  2646. CLEARFIX = 'clearfix',
  2647. DEFAULT = 'default',
  2648. DISPLAY = 'display',
  2649. DOWN = 'down',
  2650. DRAG = 'drag',
  2651. DRAGGABLE = 'draggable',
  2652. DRAG_CURSOR = 'dragCursor',
  2653. DRAG_NODE = 'dragNode',
  2654. EXPANDED = 'expanded',
  2655. HELPER = 'helper',
  2656. INSERT = 'insert',
  2657. OFFSET_HEIGHT = 'offsetHeight',
  2658. PARENT_NODE = 'parentNode',
  2659. SCROLL_DELAY = 'scrollDelay',
  2660. STATE = 'state',
  2661. TREE_DRAG_DROP = 'tree-drag-drop',
  2662. UP = 'up',
  2663. DDM = A.DD.DDM,
  2664. CSS_HELPER_CLEARFIX = getCN(HELPER, CLEARFIX),
  2665. CSS_ICON = getCN(ICON),
  2666. CSS_TREE_DRAG_HELPER = getCN(TREE, DRAG, HELPER),
  2667. CSS_TREE_DRAG_HELPER_CONTENT = getCN(TREE, DRAG, HELPER, CONTENT),
  2668. CSS_TREE_DRAG_HELPER_LABEL = getCN(TREE, DRAG, HELPER, LABEL),
  2669. CSS_TREE_DRAG_INSERT_ABOVE = getCN(TREE, DRAG, INSERT, ABOVE),
  2670. CSS_TREE_DRAG_INSERT_APPEND = getCN(TREE, DRAG, INSERT, APPEND),
  2671. CSS_TREE_DRAG_INSERT_BELOW = getCN(TREE, DRAG, INSERT, BELOW),
  2672. CSS_TREE_DRAG_STATE_APPEND = getCN(TREE, DRAG, STATE, APPEND),
  2673. CSS_TREE_DRAG_STATE_INSERT_ABOVE = getCN(TREE, DRAG, STATE, INSERT, ABOVE),
  2674. CSS_TREE_DRAG_STATE_INSERT_BELOW = getCN(TREE, DRAG, STATE, INSERT, BELOW),
  2675. HELPER_TPL = '<div class="'+CSS_TREE_DRAG_HELPER+'">'+
  2676. '<div class="'+[CSS_TREE_DRAG_HELPER_CONTENT, CSS_HELPER_CLEARFIX].join(SPACE)+'">'+
  2677. '<span class="'+CSS_ICON+'"></span>'+
  2678. '<span class="'+CSS_TREE_DRAG_HELPER_LABEL+'"></span>'+
  2679. '</div>'+
  2680. '</div>';
  2681. /**
  2682. * A base class for TreeViewDD, providing:
  2683. * <ul>
  2684. * <li>Widget Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)</li>
  2685. * <li>DragDrop support for the TreeNodes</li>
  2686. * </ul>
  2687. *
  2688. * Quick Example:<br/>
  2689. *
  2690. * Check the list of <a href="TreeViewDD.html#configattributes">Configuration Attributes</a> available for
  2691. * TreeViewDD.
  2692. *
  2693. * @param config {Object} Object literal specifying widget configuration properties.
  2694. *
  2695. * @class TreeViewDD
  2696. * @constructor
  2697. * @extends TreeView
  2698. */
  2699. var TreeViewDD = A.Component.create(
  2700. {
  2701. /**
  2702. * Static property provides a string to identify the class.
  2703. *
  2704. * @property TreeViewDD.NAME
  2705. * @type String
  2706. * @static
  2707. */
  2708. NAME: TREE_DRAG_DROP,
  2709. /**
  2710. * Static property used to define the default attribute
  2711. * configuration for the TreeViewDD.
  2712. *
  2713. * @property TreeViewDD.ATTRS
  2714. * @type Object
  2715. * @static
  2716. */
  2717. ATTRS: {
  2718. /**
  2719. * Dragdrop helper element.
  2720. *
  2721. * @attribute helper
  2722. * @default null
  2723. * @type Node | String
  2724. */
  2725. helper: {
  2726. value: null
  2727. },
  2728. /**
  2729. * Delay of the scroll while dragging the TreeNodes.
  2730. *
  2731. * @attribute scrollDelay
  2732. * @default 100
  2733. * @type Number
  2734. */
  2735. scrollDelay: {
  2736. value: 100,
  2737. validator: isNumber
  2738. }
  2739. },
  2740. EXTENDS: A.TreeView,
  2741. prototype: {
  2742. /**
  2743. * Direction of the drag (i.e. could be 'up' or 'down').
  2744. *
  2745. * @property direction
  2746. * @type String
  2747. * @protected
  2748. */
  2749. direction: BELOW,
  2750. /**
  2751. * Drop action (i.e. could be 'append', 'below' or 'above').
  2752. *
  2753. * @attribute dropAction
  2754. * @default null
  2755. * @type String
  2756. */
  2757. dropAction: null,
  2758. /**
  2759. * Last Y.
  2760. *
  2761. * @attribute lastY
  2762. * @default 0
  2763. * @type Number
  2764. */
  2765. lastY: 0,
  2766. node: null,
  2767. /**
  2768. * Reference for the current drop node.
  2769. *
  2770. * @attribute nodeContent
  2771. * @default null
  2772. * @type Node
  2773. */
  2774. nodeContent: null,
  2775. /**
  2776. * Descructor lifecycle implementation for the TreeViewDD class.
  2777. * Purges events attached to the node (and all child nodes).
  2778. *
  2779. * @method destructor
  2780. * @protected
  2781. */
  2782. destructor: function() {
  2783. var instance = this;
  2784. var helper = instance.get(HELPER);
  2785. if (helper) {
  2786. helper.remove(true);
  2787. }
  2788. if (instance.ddDelegate) {
  2789. instance.ddDelegate.destroy();
  2790. }
  2791. },
  2792. /**
  2793. * Bind the events on the TreeViewDD UI. Lifecycle.
  2794. *
  2795. * @method bindUI
  2796. * @protected
  2797. */
  2798. bindUI: function() {
  2799. var instance = this;
  2800. A.TreeViewDD.superclass.bindUI.apply(this, arguments);
  2801. instance._bindDragDrop();
  2802. },
  2803. /**
  2804. * Create the DOM structure for the TreeViewDD. Lifecycle.
  2805. *
  2806. * @method renderUI
  2807. * @protected
  2808. */
  2809. renderUI: function() {
  2810. var instance = this;
  2811. A.TreeViewDD.superclass.renderUI.apply(this, arguments);
  2812. // creating drag helper and hiding it
  2813. var helper = A.Node.create(HELPER_TPL).hide();
  2814. // append helper to the body
  2815. A.one(BODY).append(helper);
  2816. instance.set(HELPER, helper);
  2817. // set DRAG_CURSOR to the default arrow
  2818. DDM.set(DRAG_CURSOR, DEFAULT);
  2819. },
  2820. /**
  2821. * Bind DragDrop events.
  2822. *
  2823. * @method _bindDragDrop
  2824. * @protected
  2825. */
  2826. _bindDragDrop: function() {
  2827. var instance = this;
  2828. var boundingBox = instance.get(BOUNDING_BOX);
  2829. var dragInitHandle = null;
  2830. instance._createDragInitHandler = function() {
  2831. instance.ddDelegate = new A.DD.Delegate(
  2832. {
  2833. bubbleTargets: instance,
  2834. container: boundingBox,
  2835. invalid: DOT+CSS_TREE_NODE_CONTENT_INVALID,
  2836. nodes: DOT+CSS_TREE_NODE_CONTENT,
  2837. target: true
  2838. }
  2839. );
  2840. var dd = instance.ddDelegate.dd;
  2841. dd.plug(A.Plugin.DDProxy, {
  2842. moveOnEnd: false,
  2843. positionProxy: false,
  2844. borderStyle: null
  2845. })
  2846. .plug(A.Plugin.DDNodeScroll, {
  2847. scrollDelay: instance.get(SCROLL_DELAY),
  2848. node: boundingBox
  2849. });
  2850. dd.removeInvalid('a');
  2851. if (dragInitHandle) {
  2852. dragInitHandle.detach();
  2853. }
  2854. };
  2855. // Check for mobile devices and execute _createDragInitHandler before events
  2856. if (!UA.touch) {
  2857. // only create the drag on the init elements if the user mouseover the boundingBox for init performance reasons
  2858. dragInitHandle = boundingBox.on(['focus', 'mousedown', 'mousemove'], instance._createDragInitHandler);
  2859. }
  2860. else {
  2861. instance._createDragInitHandler();
  2862. }
  2863. // drag & drop listeners
  2864. instance.on('drag:align', instance._onDragAlign);
  2865. instance.on('drag:start', instance._onDragStart);
  2866. instance.on('drop:exit', instance._onDropExit);
  2867. instance.after('drop:hit', instance._afterDropHit);
  2868. instance.on('drop:hit', instance._onDropHit);
  2869. instance.on('drop:over', instance._onDropOver);
  2870. },
  2871. /**
  2872. * Set the append CSS state on the passed <code>nodeContent</code>.
  2873. *
  2874. * @method _appendState
  2875. * @param {Node} nodeContent
  2876. * @protected
  2877. */
  2878. _appendState: function(nodeContent) {
  2879. var instance = this;
  2880. instance.dropAction = APPEND;
  2881. instance.get(HELPER).addClass(CSS_TREE_DRAG_STATE_APPEND);
  2882. nodeContent.addClass(CSS_TREE_DRAG_INSERT_APPEND);
  2883. },
  2884. /**
  2885. * Set the going down CSS state on the passed <code>nodeContent</code>.
  2886. *
  2887. * @method _goingDownState
  2888. * @param {Node} nodeContent
  2889. * @protected
  2890. */
  2891. _goingDownState: function(nodeContent) {
  2892. var instance = this;
  2893. instance.dropAction = BELOW;
  2894. instance.get(HELPER).addClass(CSS_TREE_DRAG_STATE_INSERT_BELOW);
  2895. nodeContent.addClass(CSS_TREE_DRAG_INSERT_BELOW);
  2896. },
  2897. /**
  2898. * Set the going up CSS state on the passed <code>nodeContent</code>.
  2899. *
  2900. * @method _goingUpState
  2901. * @param {Node} nodeContent
  2902. * @protected
  2903. */
  2904. _goingUpState: function(nodeContent) {
  2905. var instance = this;
  2906. instance.dropAction = ABOVE;
  2907. instance.get(HELPER).addClass(CSS_TREE_DRAG_STATE_INSERT_ABOVE);
  2908. nodeContent.addClass(CSS_TREE_DRAG_INSERT_ABOVE);
  2909. },
  2910. /**
  2911. * Set the reset CSS state on the passed <code>nodeContent</code>.
  2912. *
  2913. * @method _resetState
  2914. * @param {Node} nodeContent
  2915. * @protected
  2916. */
  2917. _resetState: function(nodeContent) {
  2918. var instance = this;
  2919. var helper = instance.get(HELPER);
  2920. helper.removeClass(CSS_TREE_DRAG_STATE_APPEND);
  2921. helper.removeClass(CSS_TREE_DRAG_STATE_INSERT_ABOVE);
  2922. helper.removeClass(CSS_TREE_DRAG_STATE_INSERT_BELOW);
  2923. if (nodeContent) {
  2924. nodeContent.removeClass(CSS_TREE_DRAG_INSERT_ABOVE);
  2925. nodeContent.removeClass(CSS_TREE_DRAG_INSERT_APPEND);
  2926. nodeContent.removeClass(CSS_TREE_DRAG_INSERT_BELOW);
  2927. }
  2928. },
  2929. /**
  2930. * Update the CSS node state (i.e. going down, going up, append etc).
  2931. *
  2932. * @method _updateNodeState
  2933. * @param {EventFacade} event
  2934. * @protected
  2935. */
  2936. _updateNodeState: function(event) {
  2937. var instance = this;
  2938. var drag = event.drag;
  2939. var drop = event.drop;
  2940. var nodeContent = drop.get(NODE);
  2941. var dropNode = nodeContent.get(PARENT_NODE);
  2942. var dragNode = drag.get(NODE).get(PARENT_NODE);
  2943. var dropTreeNode = dropNode.getData(TREE_NODE);
  2944. // reset the classNames from the last nodeContent
  2945. instance._resetState(instance.nodeContent);
  2946. // cannot drop the dragged element into any of its children
  2947. // nor above an undraggable element
  2948. // using DOM contains method for performance reason
  2949. if (!!dropTreeNode.get(DRAGGABLE) && !dragNode.contains(dropNode)) {
  2950. // nArea splits the height in 3 areas top/center/bottom
  2951. // these areas are responsible for defining the state when the mouse is over any of them
  2952. var nArea = nodeContent.get(OFFSET_HEIGHT) / 3;
  2953. var yTop = nodeContent.getY();
  2954. var yCenter = yTop + nArea;
  2955. var yBottom = yTop + nArea*2;
  2956. var mouseY = drag.mouseXY[1];
  2957. // UP: mouse on the top area of the node
  2958. if ((mouseY > yTop) && (mouseY < yCenter)) {
  2959. instance._goingUpState(nodeContent);
  2960. }
  2961. // DOWN: mouse on the bottom area of the node
  2962. else if (mouseY > yBottom) {
  2963. instance._goingDownState(nodeContent);
  2964. }
  2965. // APPEND: mouse on the center area of the node
  2966. else if ((mouseY > yCenter) && (mouseY < yBottom)) {
  2967. // if it's a folder set the state to append
  2968. if (dropTreeNode && !dropTreeNode.isLeaf()) {
  2969. instance._appendState(nodeContent);
  2970. }
  2971. // if it's a leaf we need to set the ABOVE or BELOW state instead of append
  2972. else {
  2973. if (instance.direction === UP) {
  2974. instance._goingUpState(nodeContent);
  2975. }
  2976. else {
  2977. instance._goingDownState(nodeContent);
  2978. }
  2979. }
  2980. }
  2981. }
  2982. instance.nodeContent = nodeContent;
  2983. },
  2984. /**
  2985. * Fires after the drop hit event.
  2986. *
  2987. * @method _afterDropHit
  2988. * @param {EventFacade} event drop hit event facade
  2989. * @protected
  2990. */
  2991. _afterDropHit: function(event) {
  2992. var instance = this;
  2993. var dropAction = instance.dropAction;
  2994. var dragNode = event.drag.get(NODE).get(PARENT_NODE);
  2995. var dropNode = event.drop.get(NODE).get(PARENT_NODE);
  2996. var dropTreeNode = dropNode.getData(TREE_NODE);
  2997. var dragTreeNode = dragNode.getData(TREE_NODE);
  2998. var output = instance.getEventOutputMap(instance);
  2999. output.tree.dropNode = dropTreeNode;
  3000. output.tree.dragNode = dragTreeNode;
  3001. if (dropAction === ABOVE) {
  3002. dropTreeNode.insertBefore(dragTreeNode);
  3003. instance.bubbleEvent('dropInsert', output);
  3004. }
  3005. else if (dropAction === BELOW) {
  3006. dropTreeNode.insertAfter(dragTreeNode);
  3007. instance.bubbleEvent('dropInsert', output);
  3008. }
  3009. else if (dropAction === APPEND) {
  3010. if (dropTreeNode && !dropTreeNode.isLeaf()) {
  3011. if (!dropTreeNode.get(EXPANDED)) {
  3012. // expand node when drop a child on it
  3013. dropTreeNode.expand();
  3014. }
  3015. dropTreeNode.appendChild(dragTreeNode);
  3016. instance.bubbleEvent('dropAppend', output);
  3017. }
  3018. }
  3019. instance._resetState(instance.nodeContent);
  3020. // bubbling drop event
  3021. instance.bubbleEvent('drop', output);
  3022. instance.dropAction = null;
  3023. },
  3024. /**
  3025. * Fires on drag align event.
  3026. *
  3027. * @method _onDragAlign
  3028. * @param {EventFacade} event append event facade
  3029. * @protected
  3030. */
  3031. _onDragAlign: function(event) {
  3032. var instance = this;
  3033. var lastY = instance.lastY;
  3034. var y = event.target.lastXY[1];
  3035. // if the y change
  3036. if (y !== lastY) {
  3037. // set the drag direction
  3038. instance.direction = (y < lastY) ? UP : DOWN;
  3039. }
  3040. instance.lastY = y;
  3041. },
  3042. /**
  3043. * Fires on drag start event.
  3044. *
  3045. * @method _onDragStart
  3046. * @param {EventFacade} event append event facade
  3047. * @protected
  3048. */
  3049. _onDragStart: function(event) {
  3050. var instance = this;
  3051. var drag = event.target;
  3052. var dragNode = drag.get(NODE).get(PARENT_NODE);
  3053. var dragTreeNode = dragNode.getData(TREE_NODE);
  3054. var lastSelected = instance.get(LAST_SELECTED);
  3055. // select drag node
  3056. if (lastSelected) {
  3057. lastSelected.unselect();
  3058. }
  3059. dragTreeNode.select();
  3060. // initialize drag helper
  3061. var helper = instance.get(HELPER);
  3062. var helperLabel = helper.one(DOT+CSS_TREE_DRAG_HELPER_LABEL);
  3063. // show helper, we need display block here, yui dd hide it with display none
  3064. helper.setStyle(DISPLAY, BLOCK).show();
  3065. // set the CSS_TREE_DRAG_HELPER_LABEL html with the label of the dragged node
  3066. helperLabel.html( dragTreeNode.get(LABEL) );
  3067. // update the DRAG_NODE with the new helper
  3068. drag.set(DRAG_NODE, helper);
  3069. },
  3070. /**
  3071. * Fires on drop over event.
  3072. *
  3073. * @method _onDropOver
  3074. * @param {EventFacade} event append event facade
  3075. * @protected
  3076. */
  3077. _onDropOver: function(event) {
  3078. var instance = this;
  3079. instance._updateNodeState(event);
  3080. },
  3081. /**
  3082. * Fires on drop hit event.
  3083. *
  3084. * @method _onDropHit
  3085. * @param {EventFacade} event append event facade
  3086. * @protected
  3087. */
  3088. _onDropHit: function(event) {
  3089. var dropNode = event.drop.get(NODE).get(PARENT_NODE);
  3090. var dropTreeNode = dropNode.getData(TREE_NODE);
  3091. if (!isTreeNode(dropTreeNode)) {
  3092. event.preventDefault();
  3093. }
  3094. },
  3095. /**
  3096. * Fires on drop exit event.
  3097. *
  3098. * @method _onDropExit
  3099. * @param {EventFacade} event append event facade
  3100. * @protected
  3101. */
  3102. _onDropExit: function() {
  3103. var instance = this;
  3104. instance.dropAction = null;
  3105. instance._resetState(instance.nodeContent);
  3106. }
  3107. }
  3108. }
  3109. );
  3110. A.TreeViewDD = TreeViewDD;
  3111. }, '@VERSION@' ,{requires:['aui-tree-node','aui-tree-paginator','aui-tree-io','dd-delegate','dd-proxy'], skinnable:true});
  3112. AUI.add('aui-tree-io', function(A) {
  3113. var Lang = A.Lang,
  3114. isFunction = Lang.isFunction,
  3115. isString = Lang.isString,
  3116. EVENT_IO_REQUEST_SUCCESS = 'ioRequestSuccess',
  3117. CONTENT_BOX = 'contentBox',
  3118. IO = 'io',
  3119. OWNER_TREE = 'ownerTree',
  3120. LOADED = 'loaded',
  3121. LOADING = 'loading',
  3122. NODE = 'node',
  3123. TREE = 'tree',
  3124. getCN = A.getClassName,
  3125. CSS_TREE_NODE_IO_LOADING = getCN(TREE, NODE, IO, LOADING);
  3126. function TreeViewIO(config) {
  3127. var instance = this;
  3128. instance.publish(
  3129. EVENT_IO_REQUEST_SUCCESS,
  3130. {
  3131. defaultFn: instance._onIOSuccessDefault
  3132. }
  3133. );
  3134. }
  3135. TreeViewIO.ATTRS = {
  3136. /**
  3137. * IO options for the current TreeNode load the children.
  3138. *
  3139. * @attribute io
  3140. * @default Default IO Configuration.
  3141. * @type Object
  3142. */
  3143. io: {
  3144. lazyAdd: false,
  3145. value: null,
  3146. setter: function(v) {
  3147. return this._setIO(v);
  3148. }
  3149. }
  3150. };
  3151. TreeViewIO.prototype = {
  3152. initializer: function() {
  3153. var instance = this;
  3154. instance.publish(
  3155. );
  3156. },
  3157. /**
  3158. * Create nodes.
  3159. *
  3160. * @method createNodes
  3161. * @param nodes
  3162. */
  3163. createNodes: function(nodes) {
  3164. var instance = this;
  3165. var paginator = instance.get('paginator');
  3166. A.Array.each(
  3167. A.Array(nodes),
  3168. function(node) {
  3169. var childrenLength = instance.getChildrenLength();
  3170. if (paginator && paginator.total <= childrenLength) {
  3171. return;
  3172. }
  3173. instance.appendChild(
  3174. instance.createNode(node)
  3175. );
  3176. }
  3177. );
  3178. instance._syncPaginatorUI(nodes);
  3179. },
  3180. /**
  3181. * Initialize the IO transaction setup on the <a
  3182. * href="TreeNode.html#config_io">io</a> attribute.
  3183. *
  3184. * @method initIO
  3185. */
  3186. initIO: function() {
  3187. var instance = this;
  3188. var io = instance.get(IO);
  3189. if (isFunction(io.cfg.data)) {
  3190. io.cfg.data = io.cfg.data.call(instance, instance);
  3191. }
  3192. instance._syncPaginatorIOData(io);
  3193. if (isFunction(io.loader)) {
  3194. var loader = A.bind(io.loader, instance);
  3195. // apply loader in the TreeNodeIO scope
  3196. loader(io.url, io.cfg, instance);
  3197. }
  3198. else {
  3199. A.io.request(io.url, io.cfg);
  3200. }
  3201. },
  3202. /**
  3203. * IO Start handler.
  3204. *
  3205. * @method ioStartHandler
  3206. */
  3207. ioStartHandler: function() {
  3208. var instance = this;
  3209. var contentBox = instance.get(CONTENT_BOX);
  3210. instance.set(LOADING, true);
  3211. contentBox.addClass(CSS_TREE_NODE_IO_LOADING);
  3212. },
  3213. /**
  3214. * IO Complete handler.
  3215. *
  3216. * @method ioCompleteHandler
  3217. */
  3218. ioCompleteHandler: function() {
  3219. var instance = this;
  3220. var contentBox = instance.get(CONTENT_BOX);
  3221. instance.set(LOADING, false);
  3222. instance.set(LOADED, true);
  3223. contentBox.removeClass(CSS_TREE_NODE_IO_LOADING);
  3224. },
  3225. /**
  3226. * IO Success handler.
  3227. *
  3228. * @method ioSuccessHandler
  3229. */
  3230. ioSuccessHandler: function() {
  3231. var instance = this;
  3232. var io = instance.get(IO);
  3233. var args = Array.prototype.slice.call(arguments);
  3234. var length = args.length;
  3235. // if using the first argument as the JSON object
  3236. var nodes = args[1];
  3237. // if using (event, id, o) yui callback syntax
  3238. if (length >= 3) {
  3239. var o = args[2];
  3240. // try to convert responseText to JSON
  3241. try {
  3242. nodes = A.JSON.parse(o.responseText);
  3243. }
  3244. catch(e) {}
  3245. }
  3246. var formatter = io.formatter;
  3247. if (formatter) {
  3248. nodes = formatter(nodes);
  3249. }
  3250. instance.createNodes(nodes);
  3251. instance.fire(EVENT_IO_REQUEST_SUCCESS, nodes);
  3252. },
  3253. /**
  3254. * IO Failure handler.
  3255. *
  3256. * @method ioFailureHandler
  3257. */
  3258. ioFailureHandler: function() {
  3259. var instance = this;
  3260. instance.fire('ioRequestFailure');
  3261. instance.set(LOADING, false);
  3262. instance.set(LOADED, false);
  3263. },
  3264. _onIOSuccessDefault: function(event) {
  3265. var instance = this;
  3266. var ownerTree = instance.get(OWNER_TREE);
  3267. if (ownerTree && ownerTree.ddDelegate) {
  3268. ownerTree.ddDelegate.syncTargets();
  3269. }
  3270. },
  3271. /**
  3272. * Setter for <a href="TreeNodeIO.html#config_io">io</a>.
  3273. *
  3274. * @method _setIO
  3275. * @protected
  3276. * @param {Object} v
  3277. * @return {Object}
  3278. */
  3279. _setIO: function(v) {
  3280. var instance = this;
  3281. if (!v) {
  3282. return null;
  3283. }
  3284. else if (isString(v)) {
  3285. v = { url: v };
  3286. }
  3287. v = v || {};
  3288. v.cfg = v.cfg || {};
  3289. v.cfg.on = v.cfg.on || {};
  3290. var defCallbacks = {
  3291. start: A.bind(instance.ioStartHandler, instance),
  3292. complete: A.bind(instance.ioCompleteHandler, instance),
  3293. success: A.bind(instance.ioSuccessHandler, instance),
  3294. failure: A.bind(instance.ioFailureHandler, instance)
  3295. };
  3296. A.each(defCallbacks, function(fn, name) {
  3297. var userFn = v.cfg.on[name];
  3298. fn.defaultFn = true;
  3299. if (isFunction(userFn)) {
  3300. // wrapping user callback and default callback, invoking both handlers
  3301. var wrappedFn = A.bind(
  3302. function() {
  3303. fn.apply(instance, arguments);
  3304. userFn.apply(instance, arguments);
  3305. },
  3306. instance
  3307. );
  3308. wrappedFn.wrappedFn = true;
  3309. v.cfg.on[name] = wrappedFn;
  3310. }
  3311. else {
  3312. // get from defCallbacks map
  3313. v.cfg.on[name] = fn;
  3314. }
  3315. });
  3316. return v;
  3317. }
  3318. };
  3319. A.TreeViewIO = TreeViewIO;
  3320. }, '@VERSION@' ,{requires:['aui-io','json'], skinnable:false});
  3321. AUI.add('aui-tree', function(A){}, '@VERSION@' ,{skinnable:true, use:['aui-tree-data', 'aui-tree-node', 'aui-tree-io', 'aui-tree-paginator', 'aui-tree-view']});