3 changed files with 509 additions and 0 deletions
@ -0,0 +1,411 @@ |
|||||
|
/* |
||||
|
--- |
||||
|
description: Templated is a MooTools mixin class which creates elements for classes using a string-based HTML template which may included embedded attach points and events. |
||||
|
|
||||
|
license: MIT-style |
||||
|
|
||||
|
authors: |
||||
|
- David Walsh |
||||
|
|
||||
|
requires: |
||||
|
- core/1.3: '*' |
||||
|
|
||||
|
provides: [Templated] |
||||
|
|
||||
|
... |
||||
|
*/ |
||||
|
|
||||
|
// Create scope limiter
|
||||
|
(function(scope) { |
||||
|
|
||||
|
// Create some vars for strings
|
||||
|
// This will save bytes when compressed
|
||||
|
var strData = "data", |
||||
|
strWidget = "widget", |
||||
|
strAttach = "attach", |
||||
|
dataWidgetType = strData + "-" + strWidget + "-type", |
||||
|
dataWidgetProps = strData + "-" + strWidget + "-props", |
||||
|
dataWidgetAttachPoint = strData + "-" + strWidget + "-" + strAttach + "-point", |
||||
|
dataWidgetAttachEvent = strData + "-" + strWidget + "-" + strAttach + "-event", |
||||
|
dataWidgetized = strData + "-widgetized"; |
||||
|
|
||||
|
// Templated is a mixin for UI widgets
|
||||
|
scope.Templated = new Class({ |
||||
|
|
||||
|
// The usual options object
|
||||
|
options: { |
||||
|
// The default template
|
||||
|
template: "<div></div>", |
||||
|
|
||||
|
// The URL to get the template from *instead* of the string
|
||||
|
templateUrl: "", |
||||
|
|
||||
|
// A node reference for where this UI widget will be placed...in reference to
|
||||
|
element: null, |
||||
|
|
||||
|
// Should this widget be parsed for sub-widgets?
|
||||
|
widgetsInTemplate: true, |
||||
|
|
||||
|
// Property mappings (should be an object)
|
||||
|
// These override defaults
|
||||
|
propertyMappings: null, |
||||
|
|
||||
|
// Default property mappings
|
||||
|
// Thse properties on the element will be moved to the respective nodes within the template
|
||||
|
defaultPropertyMappings: null, |
||||
|
|
||||
|
// Should messages be debug to the console
|
||||
|
debugMode: true |
||||
|
}, |
||||
|
|
||||
|
// Create placeholders for attached points and events
|
||||
|
_attachPoints: [], |
||||
|
_attachEvents: [], |
||||
|
|
||||
|
// Parse
|
||||
|
parse: function() { |
||||
|
|
||||
|
// Get shortcuts to the options and element
|
||||
|
var options = this.options, |
||||
|
nodeRef = options.element = options.element || new Element("div").inject(document.body); |
||||
|
|
||||
|
// *IF* a templateUrl is specified, can't do anything until template is loaded
|
||||
|
// Defer parsing until we've got it
|
||||
|
if(options.templateUrl && Templated.templates && !Templated.templates[options.templateUrl]) { |
||||
|
this.debug("[Templated:parse] Need to load template from URL: " + options.templateUrl); |
||||
|
this.getTemplate(); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// If already data-widgetized...gtfo
|
||||
|
if(nodeRef.retrieve("widget")) { |
||||
|
this.debug("[Templated:parse] Node already widgetized, leaving ", nodeRef); |
||||
|
return nodeRef.domNode; |
||||
|
} |
||||
|
|
||||
|
// Mix noderef properties with options
|
||||
|
options.defaultPropertyMappings = options.defaultPropertyMappings || { // THESE OVERRIDE CLASSES IN THE TEMPLATE!!!!
|
||||
|
"id": "domNode", |
||||
|
"style": "domNode", |
||||
|
"class": "domNode" |
||||
|
}; |
||||
|
Object.merge(options, this.getNodeProps(nodeRef)); |
||||
|
|
||||
|
// postMixInProperties runs after options have been mixed with defaults but before
|
||||
|
// any templating is done
|
||||
|
this.postMixInProperties(); |
||||
|
|
||||
|
// Build rendering - creates the actual nodes, attachpoints, and attachevents
|
||||
|
this.buildRendering(); |
||||
|
|
||||
|
// Fire the "postCreate" method, which runs after nodes are created *but* before the nodes are rendered to the page
|
||||
|
this.postCreate(); |
||||
|
|
||||
|
// Cleanup creation
|
||||
|
this.cleanupCreation(); |
||||
|
|
||||
|
// "Startup": The widget is in the DOM and the widget is ready to go
|
||||
|
this.startup(); |
||||
|
|
||||
|
// Return the domNode
|
||||
|
this.debug("[Templated:parse] At the end of parse, this is: ", this); |
||||
|
return this.domNode; |
||||
|
}, |
||||
|
|
||||
|
// Creates build rendering
|
||||
|
buildRendering: function() { |
||||
|
// Get shortcuts to the options and element
|
||||
|
var options = this.options, nodeRef = options.element; |
||||
|
|
||||
|
// Do string substitution on the template
|
||||
|
var template = this.template = options.template.substitute(options || {}); |
||||
|
|
||||
|
// Create the DOM node within a DIV that's not rendered to the page
|
||||
|
var bitchNode = this.bitchNode = new Element("div", { html: template.trim() }), |
||||
|
domNode = this.domNode = document.id(bitchNode.childNodes[0]); |
||||
|
|
||||
|
// Look for subwidgets if told to...
|
||||
|
if(options.widgetsInTemplate) { |
||||
|
this.debug("[Templated:parse] Looking for subwidgets under domNode", domNode); |
||||
|
this.makeSubWidgets(this.domNode); |
||||
|
} |
||||
|
|
||||
|
// Create the attachpoints for me, then my kiddies
|
||||
|
this.makeAttachPoints(domNode); |
||||
|
if(options.widgetsInTemplate) domNode.getElements("[" + dataWidgetAttachPoint + "]").each(this.makeAttachPoints, this); |
||||
|
this.debug("[Templated:parse] Creating attachpoints", this._attachPoints); |
||||
|
|
||||
|
// Create the attachevents for me, then my kiddies
|
||||
|
this.makeAttachEvents(domNode); |
||||
|
if(options.widgetsInTemplate) domNode.getElements("[" + dataWidgetAttachEvent + "]").each(this.makeAttachEvents, this); |
||||
|
this.debug("Creating attachevents", this._attachEvents); |
||||
|
|
||||
|
// Map properties to nodes within the template
|
||||
|
// Mix the custom mappings with the default
|
||||
|
// This needs to happen after attachpoints
|
||||
|
var mappings = options.propertyMappings ? Object.merge(options.defaultPropertyMappings, options.propertyMappings) : options.defaultPropertyMappings; |
||||
|
Object.each(mappings, function(value, key) { |
||||
|
// Ignore the value if not present in the object
|
||||
|
if(!this[value]) return; |
||||
|
// Assign the value to the key
|
||||
|
var currentProp = nodeRef.get(key); |
||||
|
if(currentProp != "") this[value].set(key, currentProp); |
||||
|
}.bind(this)); |
||||
|
|
||||
|
// If this widget has a "containerNode", grab it's childNodes *or* inject innerHTML
|
||||
|
if(this.containerNode) { |
||||
|
var kids = nodeRef.childNodes; |
||||
|
kids.length ? $$(kids).inject(this.containerNode) : this.containerNode.set("html", nodeRef.get("html")); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// "postMixInProperties" -- Fired after options have been mixed in
|
||||
|
postMixInProperties: function() { |
||||
|
this.debug("[Templated:postMixInProperties] postMixInProperties!"); |
||||
|
}, |
||||
|
|
||||
|
// "PostCreate" -- Fired after nodes are created, attachpoints and events are found
|
||||
|
postCreate: function() { |
||||
|
this.debug("[Templated:postCreate] postCreate!"); |
||||
|
}, |
||||
|
|
||||
|
// "CleanupCreation" -- Removes the old element, destroys bitch node
|
||||
|
cleanupCreation: function() { |
||||
|
// Get hold of the dom node and bitch nodes
|
||||
|
var domNode = this.domNode, bitchNode = this.bitchNode, nodeRef = this.options.element; |
||||
|
|
||||
|
// Put the domNode where it should go and destroy the node reference
|
||||
|
domNode.replaces(nodeRef); |
||||
|
nodeRef.destroy(); |
||||
|
|
||||
|
// Mark as data-widgetized and store the widget within data
|
||||
|
domNode.set(dataWidgetized, true); |
||||
|
domNode.store("widget", this); |
||||
|
|
||||
|
// Remove the bitch node
|
||||
|
bitchNode.destroy(); |
||||
|
}, |
||||
|
|
||||
|
// "StartUp" -- Fired when node is in place
|
||||
|
startup: function(){ |
||||
|
this.debug("[Templated:startup] startup!"); |
||||
|
}, |
||||
|
|
||||
|
// Focus on focus node, if present
|
||||
|
focus: function() { |
||||
|
var node = this.focusNode; |
||||
|
node && node.focus(); |
||||
|
}, |
||||
|
|
||||
|
// Create subwidgets from this
|
||||
|
makeSubWidgets: function(domNode) { |
||||
|
if(!domNode) domNode = this.domNode; |
||||
|
domNode.getElements("["+ dataWidgetType +"]:not([" + dataWidgetized + "])").each(function(node){ |
||||
|
// Store the subwidget's attachpoints, attachevents, class type, and properties
|
||||
|
var points = node.get(dataWidgetAttachPoint), |
||||
|
events = node.get(dataWidgetAttachEvent), |
||||
|
widgetProps = this.getNodeProps(node), |
||||
|
klass = node.get(dataWidgetType).trim(); |
||||
|
|
||||
|
// Create the widget
|
||||
|
if(scope[klass]) { |
||||
|
var widget = new scope[klass](Object.merge(widgetProps, { element: node })); |
||||
|
this.debug("[parse:makeSubWidgets] Creating child widget: ", klass, widget); |
||||
|
// Get access to its dom node
|
||||
|
widgetDomNode = widget.domNode; |
||||
|
// Add attachments back to the widget
|
||||
|
points && widgetDomNode.set(dataWidgetAttachPoint, points.trim()); |
||||
|
events && widgetDomNode.set(dataWidgetAttachEvent, events.trim()); |
||||
|
} |
||||
|
}, this); |
||||
|
}, |
||||
|
|
||||
|
// Makes attachpoints
|
||||
|
makeAttachPoints: function(node) { |
||||
|
var points = node.get(dataWidgetAttachPoint); |
||||
|
if(points) { |
||||
|
points.trim().split(",").each(function(attach) { |
||||
|
attach = attach.trim(); |
||||
|
this[attach] = node.retrieve("widget") || node; |
||||
|
this.debug("[Templated:makeAttachPoints] " + attach, node); |
||||
|
this._attachPoints.push({ node: node, name: attach }); |
||||
|
}, this); |
||||
|
node.set(dataWidgetAttachPoint, ""); |
||||
|
node.set("data-widgetized-attach-point", points); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// Makes attachevents
|
||||
|
makeAttachEvents: function(node) { |
||||
|
// Temporarily store this widget's events so they may be added to this.domNode later
|
||||
|
var events = node.get(dataWidgetAttachEvent); |
||||
|
// If there are events....
|
||||
|
if(events) { |
||||
|
// For every event found....
|
||||
|
events.trim().split(",").each(function(event) { |
||||
|
// Trim the event
|
||||
|
event = event.trim(); |
||||
|
// Split the event:method pair
|
||||
|
var eventFn = event.split(":"); |
||||
|
// Trim and rename each piece
|
||||
|
var nativeEvent = eventFn[0].trim(), |
||||
|
classEvent = eventFn[1].trim(); |
||||
|
this.debug("[Templated:makeAttachEvents] " + nativeEvent + " / " + classEvent,node); |
||||
|
|
||||
|
// If the method isn't found on this, create a stub for it'
|
||||
|
if(!this[classEvent]) { |
||||
|
this.debug("cant find ", classEvent, " in: ", this, " creating sub for it"); |
||||
|
this[classEvent] = function(){}; |
||||
|
} |
||||
|
|
||||
|
// Bind "this" to the event
|
||||
|
var ev = this[classEvent].bind(this); |
||||
|
|
||||
|
// Add the event to the domNode
|
||||
|
node.addEvent(nativeEvent, ev); |
||||
|
|
||||
|
// Store the event
|
||||
|
this._attachEvents.push({ type: nativeEvent, event: ev, node: node }); |
||||
|
}, this); |
||||
|
|
||||
|
// Remove the event from its former place and add to -ized data item
|
||||
|
var set = { |
||||
|
"data-widgetized-attach-event": events |
||||
|
}; |
||||
|
set[dataWidgetAttachEvent] = ""; |
||||
|
node.set(set); |
||||
|
//node.set("data-widget-attach-event","");
|
||||
|
//node.set("data-widgetized-attach-event",events);
|
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// Destroy: removes node events
|
||||
|
destroy: function() { |
||||
|
// Get reference to domNode
|
||||
|
var domNode = this.domNode, events = this._attachEvents, points = this._attachPoints; |
||||
|
|
||||
|
// Clear out children
|
||||
|
domNode.getElements("[" + dataWidgetized + "]").each(function(widget) { |
||||
|
widget.destroy(); |
||||
|
}); |
||||
|
|
||||
|
// Remove events
|
||||
|
if(events.length) { |
||||
|
events.each(function(event) { |
||||
|
if(event.node) event.node.removeEvents(); |
||||
|
}); |
||||
|
} |
||||
|
// Remove node connections
|
||||
|
if(points.length) { |
||||
|
points.each(function(point) { |
||||
|
if(point.name != "domNode") this[point.name] = null; |
||||
|
}, this); |
||||
|
} |
||||
|
// Destroy the dom node and its children, fin
|
||||
|
domNode.store("widget", null).destroy(); |
||||
|
}, |
||||
|
|
||||
|
// Gets the in-node properties for a widget
|
||||
|
getNodeProps: function(node) { |
||||
|
var props = node.get(dataWidgetProps), |
||||
|
widgetProps = {}; |
||||
|
// Create the widget
|
||||
|
if(props) { |
||||
|
// Not using JSON.parse because it's too restricting, especially with quotes
|
||||
|
var json = "{" + props.trim() + "}"; |
||||
|
if(JSON && JSON.decode) { // MooTools
|
||||
|
widgetProps = JSON.decode(json); |
||||
|
} |
||||
|
else { // Native
|
||||
|
eval("widgetProps = " + json); |
||||
|
} |
||||
|
} |
||||
|
return widgetProps; |
||||
|
}, |
||||
|
|
||||
|
debug: function(one, two, three, four) { |
||||
|
if(this.options.debugMode && console && console.log) { |
||||
|
console.log("[" + (this.domNode ? this.domNode.id : "") + "] ", one, two || "", three || "", four || ""); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// If Request is available....
|
||||
|
if(Request) { |
||||
|
Templated.templates = {}; |
||||
|
// Return the template
|
||||
|
Templated.implement({ |
||||
|
// Method to return cached template or retrieve new one synchronously
|
||||
|
getTemplate: function() { |
||||
|
/* |
||||
|
var url = this.options.templateUrl; |
||||
|
// Try to return cached first
|
||||
|
if(Templated.templates[url]) { |
||||
|
return Templated.templates[url]; |
||||
|
} |
||||
|
else { |
||||
|
// Send a new request
|
||||
|
return new Request({ |
||||
|
url: url, |
||||
|
async: false, // Used to ensure that necessary templates are there
|
||||
|
onSuccess: function(template) { |
||||
|
this.options.template = template; |
||||
|
Templated.templates[url] = template; |
||||
|
this.parse(); |
||||
|
}.bind(this) |
||||
|
}).send(); |
||||
|
} |
||||
|
*/ |
||||
|
|
||||
|
var url = this.options.templateUrl; |
||||
|
// Try to return cached first
|
||||
|
if(!Templated.templates[url]) { |
||||
|
// Send a new request
|
||||
|
return new Request({ |
||||
|
url: url, |
||||
|
async: false, // Used to ensure that necessary templates are there
|
||||
|
onSuccess: function(template) { |
||||
|
this.options.template = template; |
||||
|
Templated.templates[url] = template; |
||||
|
this.parse(); |
||||
|
}.bind(this), |
||||
|
onFailure: function() { |
||||
|
Templated.templates[url] = Templated.prototype.options.template; |
||||
|
} |
||||
|
}).send(); |
||||
|
} |
||||
|
return Templated.templates[url]; |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// Allow for parsing of an element and its children
|
||||
|
Element.implement({ |
||||
|
parse: function() { |
||||
|
|
||||
|
var elFn = function(element) { |
||||
|
// Get the widget type
|
||||
|
var klass = element.get(dataWidgetType); |
||||
|
// If the class exists....
|
||||
|
if(klass && scope[klass]) { |
||||
|
// Create the new class instance
|
||||
|
new scope[klass]({ element: element }); |
||||
|
} |
||||
|
else { |
||||
|
window.console && console.log && console.log("klass does not exist! ", klass); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// Grab this and all nodes which are not already widgetized
|
||||
|
elFn(this); |
||||
|
$$(this.getElements("["+ dataWidgetType +"]:not(" + dataWidgetized + ")")).each(elFn); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// Get widget from id
|
||||
|
document.widget = function(idOrNode) { |
||||
|
return document.id(idOrNode).retrieve("widget") || null; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
})(this); // Scope limiter
|
@ -0,0 +1,96 @@ |
|||||
|
var AboutSettingTab = new Class({ |
||||
|
|
||||
|
tab: '', |
||||
|
content: '', |
||||
|
|
||||
|
initialize: function(){ |
||||
|
var self = this; |
||||
|
|
||||
|
App.addEvent('load', self.addSettings.bind(self)) |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
addSettings: function(){ |
||||
|
var self = this; |
||||
|
|
||||
|
self.settings = App.getPage('Settings') |
||||
|
self.settings.addEvent('create', function(){ |
||||
|
var tab = self.settings.createTab('about', { |
||||
|
'label': 'About', |
||||
|
'name': 'about' |
||||
|
}); |
||||
|
|
||||
|
self.tab = tab.tab; |
||||
|
self.content = tab.content; |
||||
|
|
||||
|
self.createAbout(); |
||||
|
|
||||
|
}) |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
createAbout: function(){ |
||||
|
var self = this; |
||||
|
|
||||
|
var millennium = new Date(2008, 7, 16), |
||||
|
today = new Date(), |
||||
|
one_day = 1000*60*60*24; |
||||
|
|
||||
|
self.settings.createGroup({ |
||||
|
'label': 'About CouchPotato' |
||||
|
}).inject(self.content).adopt( |
||||
|
new Element('div.shutdown').adopt( |
||||
|
new Element('a.button.red', { |
||||
|
'text': 'Shutdown', |
||||
|
'events': { |
||||
|
'click': App.shutdown.bind(App) |
||||
|
} |
||||
|
}), |
||||
|
new Element('a.button.orange', { |
||||
|
'text': 'Restart', |
||||
|
'events': { |
||||
|
'click': App.restart.bind(App) |
||||
|
} |
||||
|
}) |
||||
|
), |
||||
|
new Element('div.usenet').adopt( |
||||
|
new Element('span', { |
||||
|
'text': 'Help support CouchPotato and save some money for yourself by signing up for an account at' |
||||
|
}), |
||||
|
new Element('a', { |
||||
|
'href': 'https://usenetserver.com/partners/?a_aid=couchpotato&a_bid=3f357c6f', |
||||
|
'text': 'UsenetServer' |
||||
|
}), |
||||
|
new Element('a', { |
||||
|
'href': 'http://www.newshosting.com/partners/?a_aid=couchpotato&a_bid=a0b022df', |
||||
|
'text': 'Newshosting' |
||||
|
}), |
||||
|
new Element('span', { |
||||
|
'text': 'For as low as $7.95 per month, you’ll get:' |
||||
|
}), |
||||
|
new Element('ul').adopt( |
||||
|
new Element('li[text=Unlimited downloads]'), |
||||
|
new Element('li[text=Uncapped speeds]'), |
||||
|
new Element('li[text=Free SSL Encrypted connections]'), |
||||
|
new Element('li', { |
||||
|
'text': Math.ceil((today.getTime()-millennium.getTime())/(one_day))+" days retention" |
||||
|
}) |
||||
|
) |
||||
|
), |
||||
|
new Element('div.donate', { |
||||
|
'html': '<form action="https://www.paypal.com/cgi-bin/webscr" method="post"> |
||||
|
<input type="hidden" name="cmd" value="_s-xclick"> |
||||
|
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----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-----END PKCS7-----"> |
||||
|
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!"> |
||||
|
</form> |
||||
|
I'm building CouchPotato in my spare time, so if you want to buy me a Pepsi while I'm coding, that would be awesome!' |
||||
|
}) |
||||
|
); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
window.addEvent('domready', function(){ |
||||
|
window.About = new AboutSettingTab(); |
||||
|
}); |
Loading…
Reference in new issue