Skip to content

Instantly share code, notes, and snippets.

@josephj
Last active December 12, 2015 06:19
Show Gist options
  • Save josephj/4728012 to your computer and use it in GitHub Desktop.
Save josephj/4728012 to your computer and use it in GitHub Desktop.
YUI Widget Sample
// START WRAPPER: The YUI.add wrapper is added by the build system, when you
// use Shifter to build your component from the raw source in this file
YUI.add("iframe-step", function(Y) {
/* Any frequently used shortcuts, strings and constants */
var Lang = Y.Lang;
/* IframeStep class constructor */
function IframeStep(config) {
IframeStep.superclass.constructor.apply(this, arguments);
}
/*
* Required NAME static field, to identify the Widget class and
* used as an event prefix, to generate class names etc. (set to the
* class name in camel case).
*/
IframeStep.NAME = "iframestep";
/*
* The attribute configuration for the widget. This defines the core user facing state of the widget
*/
IframeStep.ATTRS = {
frames : {
value: [],
validator: Y.Lang.isArray
},
offset : {
value: "0", // The default value for attrA, used if the user does not set a value during construction.
validator: Y.Lang.isNumber
},
/*
, valueFn: "_defAttrAVal" // Can be used as a substitute for "value", when you need access to "this" to set the default value.
, setter: "_setAttrA" // Used to normalize attrA's value while during set. Refers to a prototype method, to make customization easier
, getter: "_getAttrA" // Used to normalize attrA's value while during get. Refers to a prototype method, to make customization easier
, validator: "_validateAttrA" // Used to validate attrA's value before updating it. Refers to a prototype method, to make customization easier
, readOnly: true // Cannot be set by the end user. Can be set by the component developer at any time, using _set
, writeOnce: true // Can only be set once by the end user (usually during construction). Can be set by the component developer at any time, using _set
, lazyAdd: false // Add (configure) the attribute during initialization.
// You only need to set lazyAdd to false if your attribute is
// setting some other state in your setter which needs to be set during initialization
// (not generally recommended - the setter should be used for normalization.
// You should use listeners to update alternate state).
, broadcast: 1 // Whether the attribute change event should be broadcast or not.
*/
listItems: {
value: null
}
// ... attrB, attrC, attrD ... attribute configurations.
// Can also include attributes for the super class if you want to override or add configuration parameters
};
/*
* The HTML_PARSER static constant is used if the Widget supports progressive enhancement, and is
* used to populate the configuration for the IframeStep instance from markup already on the page.
*/
IframeStep.HTML_PARSER = {
listItems: ["li"],
offset: function (srcNode) {
var items,
i,
j,
node;
items = srcNode.all("li");
for (i = 0, j = items.size(); i < j; i++) {
node = items.item(i);
if (node.hasClass("selected")) {
return i;
}
}
},
frames: function (srcNode) {
// If progressive enhancement is to be supported, return the value of "attrA" based on the contents of the srcNode
var frames = [];
srcNode.all("li").each(function (el) {
frames.push({
url : el.one("a").get("href"),
title : el.one("a").getHTML(),
hasRendered : false
});
});
return frames;
}
};
/* Templates for any markup the widget uses. Usually includes {} tokens, which are replaced through `Y.Lang.sub()` */
IframeStep.MYNODE_TEMPLATE = "<div id={mynodeid}></div>";
/* IframeStep extends the base Widget class */
Y.extend(IframeStep, Y.Widget, {
initializer: function() {
/*
* initializer is part of the lifecycle introduced by
* the Base class. It is invoked during construction,
* and can be used to setup instance specific state or publish events which
* require special configuration (if they don't need custom configuration,
* events are published lazily only if there are subscribers).
*
* It does not need to invoke the superclass initializer.
* init() will call initializer() for all classes in the hierarchy.
*/
this.publish("myEvent", {
defaultFn: this._defMyEventFn,
bubbles:false
});
},
destructor : function() {
/*
* destructor is part of the lifecycle introduced by
* the Widget class. It is invoked during destruction,
* and can be used to cleanup instance specific state.
*
* Anything under the boundingBox will be cleaned up by the Widget base class
* We only need to clean up nodes/events attached outside of the bounding Box
*
* It does not need to invoke the superclass destructor.
* destroy() will call initializer() for all classes in the hierarchy.
*/
},
renderUI : function() {
console.log("renderUI");
/*
* renderUI is part of the lifecycle introduced by the
* Widget class. Widget's renderer method invokes:
*
* renderUI()
* bindUI()
* syncUI()
*
* renderUI is intended to be used by the Widget subclass
* to create or insert new elements into the DOM.
*/
// this._mynode = Node.create(Y.Lang.sub(IframeStep.MYNODE_TEMPLATE, {mynodeid: this.get("id") + "_mynode"}));
var itemClass = this.getClassName("item");
this.get("srcNode").all("li").addClass(itemClass);
this.get("srcNode").all("li").remove("a");
},
bindUI : function() {
console.log("bindUI");
/*
* bindUI is intended to be used by the Widget subclass
* to bind any event listeners which will drive the Widget UI.
*
* It will generally bind event listeners for attribute change
* events, to update the state of the rendered UI in response
* to attribute value changes, and also attach any DOM events,
* to activate the UI.
*/
// this.after("attrAChange", this._afterAttrAChange);
},
syncUI : function() {
console.log("syncUI");
/*
* syncUI is intended to be used by the Widget subclass to
* update the UI to reflect the initial state of the widget,
* after renderUI. From there, the event listeners we bound above
* will take over.
*/
// this._uiSetAttrA(this.get("attrA"));
},
// Beyond this point is the IframeStep specific application and rendering logic
/* Attribute state supporting methods (see attribute config above) */
_defAttrAVal : function() {
// this.get("id") + "foo";
},
_setAttrA : function(attrVal, attrName) {
// return attrVal.toUpperCase();
},
_getAttrA : function(attrVal, attrName) {
// return attrVal.toUpperCase();
},
_validateAttrA : function(attrVal, attrName) {
// return Lang.isString(attrVal);
},
/* Listeners, UI update methods */
_afterAttrAChange : function(e) {
/* Listens for changes in state, and asks for a UI update (controller). */
// this._uiSetAttrA(e.newVal);
},
_uiSetAttrA : function(val) {
/* Update the state of attrA in the UI (view) */
// this._mynode.set("innerHTML", val);
},
_defMyEventFn : function(e) {
// The default behavior for the "myEvent" event.
}
});
Y.IframeStep = IframeStep;
}, "0.0.1", {requires:["widget"]});
// END WRAPPER
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="josephj">
<meta name="created" content="2013-02-07">
<title>YUI Widget</title>
<link rel="stylesheet" href="/yui/build/cssreset/reset-min.css">
<link rel="stylesheet" href="/yui/build/cssfonts/fonts-min.css">
<link rel="stylesheet" href="/yui/build/cssbase/base-min.css">
<script type="text/javascript" src="/yui/build/yui/yui-min.js"></script>
<script type="text/javascript" src="iframe-step.js"></script>
<style type="text/css">
</style>
</head>
<body class="yui3-skin-sam">
<div id="foo">
<ul>
<li>
<a href="demo.php?step=1">第一步</a>
</li>
<li>
<a href="demo.php?step=2">第二步</a>
</li>
<li>
<a href="demo.php?step=3">第三步</a>
</li>
<li class="selected">
<a href="demo.php?step=4">第四步</a>
</li>
</ul>
</div>
<script>
YUI({
"combine" : true,
"comboBase" : "/combo/?f=",
"comboSep" : ",",
"root" : "/yui/build/"
}).use("iframe-step", function (Y) {
_tutorial = new Y.IframeStep({
srcNode: "#foo"
});
_tutorial.render();
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment