Created
February 9, 2011 20:30
-
-
Save ericf/819214 to your computer and use it in GitHub Desktop.
MVC-ish YUI 3 Setup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * CaseWindow | |
| */ | |
| var CaseWindow, | |
| CASE_WINDOW = 'caseWindow', | |
| ATTRS = {}, | |
| VIEWS = {}, | |
| USER_ID = 'userID', | |
| CASE_ID = 'caseID', | |
| CASE_PATH = 'casePath', | |
| CASE_INFO_PATH = 'caseInfoPath', | |
| CASE_RESOURCE = 'caseResource', | |
| CASE_INFO_RESOURCE = 'caseInfoResource', | |
| TITLE = 'title', | |
| STEP = 'step', | |
| INFO_NODES = 'infoNodes', | |
| STATE = 'state', | |
| DIAGNOSES = 'diagnoses', | |
| CONTENT = 'content', | |
| HOST = 'host', | |
| // actions | |
| START = 'start', | |
| MORE = 'more', | |
| READY = 'ready', | |
| DIAGNOSE = 'diagnose', | |
| CHANGE = 'Change', | |
| E_CASE_DATA = 'caseData', | |
| YLang = Y.Lang, | |
| isValue = YLang.isValue, | |
| isArray = YLang.isArray, | |
| isString = YLang.isString, | |
| isNumber = YLang.isNumber; | |
| // *** Attributes *** // | |
| ATTRS[ USER_ID ] = { validator: isString, initOnly: true }; | |
| ATTRS[ CASE_ID ] = { validator: isString, initOnly: true }; | |
| ATTRS[ CASE_PATH ] = { validator: isString, initOnly: true }; | |
| ATTRS[ CASE_INFO_PATH ] = { validator: isString, initOnly: true }; | |
| ATTRS[ CASE_RESOURCE ] = { valueFn: '_initCaseResource', writeOnce: true }; | |
| ATTRS[ CASE_INFO_RESOURCE ] = { valueFn: '_initCaseInfoResource', writeOnce: true }; | |
| ATTRS[ TITLE ] = { validator: isString, writeOnce: true }; | |
| ATTRS[ STEP ] = { validator: isNumber }; | |
| ATTRS[ INFO_NODES ] = { writeOnce: true }; | |
| ATTRS[ STATE ] = { validator: isString }; | |
| ATTRS[ DIAGNOSES ] = { validator: isArray }; | |
| // *** CaseWindow *** // | |
| CaseWindow = Y.Base.create(CASE_WINDOW, Y.Base, [], { | |
| // *** Prototype *** // | |
| // *** Lifecycle Methods *** // | |
| initializer : function () { | |
| // these attributes much have values | |
| this._requireAttrs([ USER_ID, CASE_ID, CASE_PATH, CASE_INFO_PATH ]); | |
| // publish events | |
| this.publish(E_CASE_DATA, { defaultFn: this._defCaseDataFn }); | |
| // attribute change event handlers | |
| this.after(STATE+CHANGE, this._afterStateChange); | |
| // get initial data | |
| this.get(CASE_INFO_RESOURCE).GET({ on: { success: Y.bind(function(e){ | |
| this.get(CASE_RESOURCE).GET(); | |
| }, this)}}); | |
| }, | |
| // *** Public Methods *** // | |
| showView : function (newViewClass, prevViewClass) { | |
| var content = Y.one('#content'), | |
| newViewName = newViewClass.NS, | |
| prevViewName = prevViewClass ? prevViewClass.NS : null, | |
| tmp, viewContent; | |
| this.plug(newViewClass, { after: { | |
| contentChange : function(e){ | |
| tmp = Y.Markout('body').div().node().hide().append(e.newVal); | |
| } | |
| }}); | |
| viewContent = tmp ? tmp.get('children') : this[newViewName].get('content'); | |
| function transToNewView () { | |
| content.get('children').remove().destroy(true); | |
| content.removeClass(prevViewName).addClass(newViewName); | |
| content.setContent(viewContent).transition('viewIn'); | |
| Y.one('doc').set('scrollTop', 0); | |
| if (tmp) { | |
| tmp.remove().destroy(true); | |
| } | |
| } | |
| if (prevViewClass) { | |
| content.transition('viewOut', Y.bind(function(){ | |
| this.unplug(prevViewClass); | |
| transToNewView(); | |
| }, this)); | |
| } else { | |
| transToNewView(); | |
| } | |
| }, | |
| start : function () { | |
| this.get(CASE_RESOURCE).POST({ entity: { action: START } }); | |
| }, | |
| more : function () { | |
| this.get(CASE_RESOURCE).POST({ entity: { | |
| action : MORE, | |
| step : this.get(STEP), | |
| diagnoses : this.getDiagnoses() | |
| }}); | |
| }, | |
| ready : function () { | |
| this.get(CASE_RESOURCE).POST({ entity: { | |
| action : READY, | |
| step : this.get(STEP), | |
| diagnoses : this.getDiagnoses() | |
| }}); | |
| }, | |
| diagnose : function (diagnosis, answers) { | |
| this.get(CASE_RESOURCE).POST({ entity: { | |
| action : DIAGNOSE, | |
| diagnosis : diagnosis, | |
| answers : answers | |
| }}); | |
| }, | |
| getDiagnoses : function () { | |
| var view = this[this.get(STATE)], | |
| diagnoses = view ? view.get(DIAGNOSES) : null; | |
| return diagnoses || this.get(DIAGNOSES); | |
| }, | |
| // *** Private Methods *** // | |
| _requireAttrs : function (attrs) { | |
| Y.each(attrs, Y.bind(function(attr){ | |
| if ( ! isValue(this.get(attr))) { | |
| Y.error('A CaseWindow needs to be configured with: ' + attr); | |
| } | |
| }, this)); | |
| }, | |
| _initCaseResource : function () { | |
| var uri = this.get(CASE_PATH) + '{userID}/{caseID}/'; | |
| return new Y.Resource({ | |
| uri : Y.Lang.sub(uri, { | |
| userID : this.get(USER_ID), | |
| caseID : this.get(CASE_ID) | |
| }), | |
| headers : { | |
| 'Accept' : 'application/json', | |
| 'Content-Type' : 'application/json' | |
| }, | |
| on : { | |
| success : Y.bind(function(e){ | |
| this.fire(E_CASE_DATA, { data: e.entity }); | |
| }, this) | |
| } | |
| }); | |
| }, | |
| _initCaseInfoResource : function () { | |
| return new Y.Resource({ | |
| uri : this.get(CASE_INFO_PATH), | |
| headers : { Accept: 'application/json' }, | |
| on : { | |
| success : Y.bind(function(e){ | |
| var info = []; | |
| Y.each(e.entity.info, function(i){ | |
| info.push(Y.Node.create(i)); | |
| }); | |
| this.set(TITLE, e.entity.title); | |
| this.set(INFO_NODES, Y.all(info)); | |
| }, this) | |
| } | |
| }); | |
| }, | |
| _defCaseDataFn : function (e) { | |
| var data = e.data; | |
| this.set(STATE, data.state); | |
| this.set(STEP, data.step); | |
| this.set(DIAGNOSES, data.diagnoses); | |
| }, | |
| _afterStateChange : function (e) { | |
| var VIEWS = CaseWindow.VIEWS; | |
| this.showView(VIEWS[e.newVal], VIEWS[e.prevVal]); | |
| } | |
| }, { | |
| // *** Static *** // | |
| ATTRS : ATTRS, | |
| VIEWS : VIEWS | |
| }); | |
| // *** Transitions *** // | |
| Y.mix(Y.Transition.fx, { | |
| viewIn : { | |
| opacity : 1, | |
| duration : 0.5, | |
| on : { | |
| start : function(){ | |
| this.setStyle('opacity', 0); | |
| } | |
| } | |
| }, | |
| viewOut : { | |
| opacity : 0, | |
| duration : 0.5 | |
| } | |
| }); | |
| // *** Namespace *** // | |
| Y.CaseWindow = CaseWindow; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>MVC-ish YUI 3 Setup</title> | |
| </head> | |
| <body> | |
| … | |
| <script src="yui/yui-min.js"></script> | |
| <script> | |
| YUI( /* config */ ).use('window-case', function(Y){ | |
| // CaseWindow configuration comes from server/database | |
| new Y.CaseWindow({ | |
| "userID" : "7kwfecrx", | |
| "caseID" : "6test", | |
| "casePath" : "/api/case/", | |
| "caseInfoPath" : "/resources/cases/6test.json" | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * CaseWindow — Intro View | |
| */ | |
| Y.mix(Y.CaseWindow.VIEWS, { | |
| intro : Y.Base.create('intro', Y.Plugin.Base, [Y.BaseComponentMgr], { | |
| initializer : function () { | |
| var host = this.get(HOST), | |
| content = Y.Markout(), | |
| moreIntro = Y.one('#intro-more').hide(), | |
| startButton; | |
| this.addComponent('introOverlay', { | |
| requires : ['overlay', 'overlay-extras'], | |
| initializer : function(){ | |
| return new Y.Overlay({ | |
| width : '500px', | |
| centered : true, | |
| zIndex : 100, | |
| visible : false, | |
| render : true, | |
| srcNode : moreIntro.show(), | |
| headerContent : moreIntro.one('h2'), | |
| bodyContent : moreIntro.one('p'), | |
| footerContent : (function(){ | |
| var controls = Y.Markout().div({ 'class': 'controls' }); | |
| controls.button({ 'class': 'default' }, 'Okay, Start'); | |
| return controls.node(); | |
| }()), | |
| plugins : [ | |
| Y.Plugin.OverlayModal, | |
| Y.Plugin.OverlayKeepaligned | |
| ] | |
| }); | |
| }, | |
| destructor : function(overlay){ | |
| moreIntro.appendTo('#intro'); | |
| overlay.destroy(); | |
| } | |
| }); | |
| content.node().append(Y.one('#intro')); | |
| startButton = content.div({ id: 'start' }).button({ 'class': 'large default' }, 'Start').node(); | |
| startButton.on('click', Y.bind(function(e){ | |
| e.preventDefault(); | |
| this.use('introOverlay', function(overlay){ | |
| overlay.show().get('boundingBox').one('button').once('click', Y.bind(function(e){ | |
| e.preventDefault(); | |
| host.start(); | |
| }, this)); | |
| }); | |
| }, this)); | |
| this.set(CONTENT, content.node()); | |
| }, | |
| destructor : function () { | |
| Y.one('#intro').appendTo('body'); | |
| } | |
| }, { NS: 'intro' }) | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * CaseWindow — Steps View | |
| */ | |
| Y.mix(Y.CaseWindow.VIEWS, { | |
| steps : Y.Base.create('steps', Y.Plugin.Base, [Y.BaseComponentMgr], { | |
| initializer : function () { | |
| var host = this.get(HOST), | |
| content = Y.Markout(), | |
| infoViewerNode, infoViewerContentNode, differentialNode; | |
| infoViewerNode = content.div({ id: 'infoViewer', className: 'section' }); | |
| infoViewerNode.h2('1) Read Patient Information'); | |
| infoViewerContentNode = infoViewerNode.div({ className: 'yui3-infoviewer-loading yui3-infoviewer-content' }).node(); | |
| differentialNode = content.div({ id: 'differential', className: 'section' }).node().hide(); | |
| this.set(CONTENT, content.node()); | |
| this.addComponent('infoViewer', { | |
| requires : ['infoviewer'], | |
| initializer : function(){ | |
| return new Y.InfoViewer({ | |
| srcNode : infoViewerContentNode, | |
| infoNodes : host.get(INFO_NODES), | |
| step : host.get(STEP), | |
| render : true | |
| }); | |
| } | |
| }); | |
| this.addComponent('differential', { | |
| requires : ['differential'], | |
| initializer : function(){ | |
| return new Y.Differential({ | |
| isLastStep : host.get(STEP) === host.get(INFO_NODES).size() - 1, | |
| children : host.get(DIAGNOSES), | |
| render : differentialNode.show('fadeIn', { duration: 0.20 }) | |
| }); | |
| } | |
| }); | |
| this.addComponent('anotherStepOverlay', { | |
| requires : ['overlay', 'overlay-extras'], | |
| initializer : function(){ | |
| return new Y.Overlay({ | |
| width : '500px', | |
| centered : true, | |
| zIndex : 100, | |
| visible : false, | |
| render : true, | |
| headerContent : Y.Markout().h2('New Information Available').node(), | |
| bodyContent : Y.Markout().p('Some new last-minute information has become available that you should consider before making your diagnosis final.').node(), | |
| footerContent : (function(){ | |
| var controls = Y.Markout().div({ 'class': 'controls' }); | |
| controls.button({ 'class': 'default' }, 'Okay, View Info'); | |
| return controls.node(); | |
| }()), | |
| plugins : [ | |
| Y.Plugin.OverlayModal, | |
| Y.Plugin.OverlayKeepaligned | |
| ] | |
| }); | |
| } | |
| }); | |
| // create InfoViewer and Differential, and bind to host events | |
| this.use('infoViewer', 'differential', function(infoViewer, differential){ | |
| this.afterHostEvent(STEP+CHANGE, function(e){ | |
| infoViewer.set(STEP, e.newVal); | |
| if (e.newVal === host.get(INFO_NODES).size() - 1) { | |
| differential.set('isLastStep', true); | |
| } | |
| }); | |
| differential.on('more', Y.bind(host.more, host)); | |
| differential.on('ready', Y.bind(function(e){ | |
| var anotherStepHandler = this.afterHostEvent(STEP+CHANGE, function(e){ | |
| anotherStepHandler.detach(); | |
| this.use('anotherStepOverlay', function(overlay){ | |
| overlay.show().get('boundingBox').one('button').once('click', Y.bind(overlay.hide, overlay)); | |
| }); | |
| }); | |
| host.ready(); | |
| }, this)); | |
| this.afterHostEvent(DIAGNOSES+CHANGE, function(e){ | |
| Y.Array.invoke(differential.removeAll().toJSON(), 'destroy'); | |
| differential.add(e.newVal); | |
| }); | |
| }); | |
| }, | |
| _getDiagnoses : function () { | |
| var differential = this.getComponent('differential'), | |
| diagnoses = null; | |
| if (differential) { | |
| diagnoses = []; | |
| differential.each(function(diagnosis){ | |
| diagnoses.push({ | |
| text : diagnosis.get('text'), | |
| value : diagnosis.get('value') | |
| }); | |
| }); | |
| } | |
| return diagnoses; | |
| } | |
| }, { | |
| NS : 'steps', | |
| ATTRS : { | |
| diagnoses : { getter: '_getDiagnoses' } | |
| } | |
| }) | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment