Javascript basics

This commit is contained in:
Ruud committed 2011-02-14 18:55:19 +01:00
1 parent f72ad06c6f
commit f16ccf7905
13 files changed
+5166 -18

No files matched your search

+8
View File
@@ -1,9 +1,11 @@
from couchpotato.core.auth import requires_auth from couchpotato.core.auth import requires_auth
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from flask.app import Flask from flask.app import Flask
from flask.globals import request
from flask.helpers import url_for from flask.helpers import url_for
from flask.module import Module from flask.module import Module
from flask.templating import render_template from flask.templating import render_template
from werkzeug.utils import redirect
app = Flask(__name__) app = Flask(__name__)
log = CPLog(__name__) log = CPLog(__name__)
@@ -14,3 +16,9 @@ web = Module(__name__, 'web')
@requires_auth @requires_auth
def index(): def index():
return render_template('index.html') return render_template('index.html')
@app.errorhandler(404)
def page_not_found(error):
index_url = url_for('web.index')
url = request.path[len(index_url):]
return redirect(index_url + '#' + url)
-1
View File
@@ -1,4 +1,3 @@
from blinker.base import signal
from couchpotato import web from couchpotato import web
from couchpotato.api import api from couchpotato.api import api
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

+128
View File
@@ -0,0 +1,128 @@
var CouchPotato = new Class({
Implements: [Options],
defaults: {
page: 'movie',
action: 'index',
params: {}
},
pages: [],
tabse: [
{'href': 'movie', 'title':'Gimmy gimmy gimmy!', 'label':'Wanted'},
{'href': 'manage', 'title':'Do stuff to your existing movies!', 'label':'Manage'},
{'href': 'feed', 'title':'Which wanted movies are released soon?', 'label':'Soon'},
{'href': 'log', 'title':'Show recent logs.', 'class':'logLink', 'label':'Logs'},
{'href': 'config', 'title':'Change settings.', 'id':'showConfig'}
],
initialize: function(options) {
var self = this;
self.setOptions(options);
self.c = $(document.body)
self.route = new Route();
History.addEvent('change', self.createPage.bind(self));
History.handleInitialState();
self.createLayout()
},
createLayout: function(){
var self = this;
self.c.adopt(
self.header = new Element('div.header').adopt(
self.navigation = new Element('ul.navigation'),
self.add_form = new Element('div.add_form')
),
self.content = new Element('div.content'),
self.footer = new Element('div.footer')
)
},
createPage: function(url) {
var self = this;
self.route.parse(url);
var page = self.route.getPage().capitalize();
var action = self.route.getAction();
var params = self.route.getParams();
if(!self.pages[page]){
page = new Page[page]();
self.pages[page] = page;
}
page = self.pages[page]
page.open(action, params)
}
});
var PageBase = new Class({
Implements: [Options],
initialize: function(options) {
},
open: function(action, params){
var self = this;
console.log(action, params, self.getName());
},
getName: function(){
return this.name
}
});
var Route = new Class({
page: '',
action: 'index',
params: {},
parse: function(url){
var self = this;
url = url.split('/')
self.page = url.shift()
self.action = url.shift()
self.params = {}
var key
url.each(function(el, nr){
if(nr%2 == 0)
key = el
else if(key) {
self.params[key] = el
key = null
}
})
return self
},
getPage: function(){
return this.page
},
getAction: function(){
return this.action
},
getParams: function(){
return this.params
},
get: function(param){
return this.params[param]
}
});
+176
View File
@@ -0,0 +1,176 @@
// packager build History/*
/*
---
name: Class.Binds
description: Alternate Class.Binds Implementation
authors: Scott Kyle (@appden), Christoph Pojer (@cpojer)
license: MIT-style license.
requires: [Core/Class, Core/Function]
provides: Class.Binds
...
*/
Class.Binds = new Class({
$bound: {},
bound: function(name){
return this.$bound[name] ? this.$bound[name] : this.$bound[name] = this[name].bind(this);
}
});
/*
---
name: History
description: History Management via popstate or hashchange.
authors: Christoph Pojer (@cpojer)
license: MIT-style license.
requires: [Core/Events, Core/Element.Event, Class-Extras/Class.Binds]
provides: History
...
*/
(function(){
var events = Element.NativeEvents,
location = window.location,
base = location.pathname,
history = window.history,
hasPushState = ('pushState' in history),
event = hasPushState ? 'popstate' : 'hashchange';
this.History = new new Class({
Implements: [Class.Binds, Events],
initialize: hasPushState ? function(){
events[event] = 2;
window.addEvent(event, this.bound('pop'));
} : function(){
events[event] = 1;
window.addEvent(event, this.bound('pop'));
this.hash = location.hash;
var hashchange = ('onhashchange' in window);
if (!(hashchange && (document.documentMode === undefined || document.documentMode > 7)))
this.timer = this.check.periodical(200, this);
},
push: hasPushState ? function(url, title, state){
if (base && base != url) base = null;
history.pushState(state || null, title || null, url);
this.onChange(url, state);
} : function(url){
location.hash = url;
},
replace: hasPushState ? function(url, title, state){
history.replaceState(state || null, title || null, url);
} : function(url){
this.hash = '#' + url;
this.push(url);
},
pop: hasPushState ? function(event){
var url = location.pathname;
if (url == base){
base = null;
return;
}
this.onChange(url, event.event.state);
} : function(){
var hash = location.hash;
if (this.hash == hash) return;
this.hash = hash;
this.onChange(hash.substr(1));
},
onChange: function(url, state){
this.fireEvent('change', [url, state || {}]);
},
back: function(){
history.back();
},
forward: function(){
history.forward();
},
getPath: function(){
return hasPushState ? location.pathname : location.hash.substr(1);
},
hasPushState: function(){
return hasPushState;
},
check: function(){
if (this.hash != location.hash) this.pop();
}
});
})();
/*
---
name: History.handleInitialState
description: Provides a helper method to handle the initial state of your application.
authors: Christoph Pojer (@cpojer)
license: MIT-style license.
requires: [History]
provides: History.handleInitialState
...
*/
History.handleInitialState = function(base){
if (!base) base = '';
var location = window.location,
pathname = location.pathname.substr(base.length),
hash = location.hash,
hasPushState = History.hasPushState();
if (!hasPushState && pathname.length > 1){
window.location = (base || '/') + '#' + pathname;
return true;
}
if (!hash || hash.length <= 1) return false;
if (hasPushState){
(function(){
History.push(hash.substr(1));
}).delay(1);
return false;
}
if (!pathname || pathname == '/') return false;
window.location = (base || '/') + hash;
return true;
};
File diff suppressed because it is too large. Load diff
+573
View File
@@ -0,0 +1,573 @@
// MooTools: the javascript framework.
// Load this file's selection again by visiting: http://mootools.net/more/452f2740e09082a2109bec9f69fbf8dc
// Or build this file again with packager using: packager build More/URI More/Element.Delegation More/Element.Shortcuts
/*
---
script: More.js
name: More
description: MooTools More
license: MIT-style license
authors:
- Guillermo Rauch
- Thomas Aylott
- Scott Kyle
- Arian Stolwijk
- Tim Wienk
- Christoph Pojer
- Aaron Newton
requires:
- Core/MooTools
provides: [MooTools.More]
...
*/
MooTools.More = {
'version': '1.3.0.1',
'build': '6dce99bed2792dffcbbbb4ddc15a1fb9a41994b5'
};
/*
---
script: String.QueryString.js
name: String.QueryString
description: Methods for dealing with URI query strings.
license: MIT-style license
authors:
- Sebastian Markbåge
- Aaron Newton
- Lennart Pilon
- Valerio Proietti
requires:
- Core/Array
- Core/String
- /MooTools.More
provides: [String.QueryString]
...
*/
String.implement({
parseQueryString: function(decodeKeys, decodeValues){
if (decodeKeys == null) decodeKeys = true;
if (decodeValues == null) decodeValues = true;
var vars = this.split(/[&;]/),
object = {};
if (!vars.length) return object;
vars.each(function(val){
var index = val.indexOf('='),
value = val.substr(index + 1),
keys = index < 0 ? [''] : val.substr(0, index).match(/([^\]\[]+|(\B)(?=\]))/g),
obj = object;
if (decodeValues) value = decodeURIComponent(value);
keys.each(function(key, i){
if (decodeKeys) key = decodeURIComponent(key);
var current = obj[key];
if (i < keys.length - 1) obj = obj[key] = current || {};
else if (typeOf(current) == 'array') current.push(value);
else obj[key] = current != null ? [current, value] : value;
});
});
return object;
},
cleanQueryString: function(method){
return this.split('&').filter(function(val){
var index = val.indexOf('='),
key = index < 0 ? '' : val.substr(0, index),
value = val.substr(index + 1);
return method ? method.call(null, key, value) : (value || value === 0);
}).join('&');
}
});
/*
---
script: URI.js
name: URI
description: Provides methods useful in managing the window location and uris.
license: MIT-style license
authors:
- Sebastian Markbåge
- Aaron Newton
requires:
- Core/Object
- Core/Class
- Core/Class.Extras
- Core/Element
- /String.QueryString
provides: [URI]
...
*/
(function(){
var toString = function(){
return this.get('value');
};
var URI = this.URI = new Class({
Implements: Options,
options: {
/*base: false*/
},
regex: /^(?:(\w+):)?(?:\/\/(?:(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)?(\.\.?$|(?:[^?#\/]*\/)*)([^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
parts: ['scheme', 'user', 'password', 'host', 'port', 'directory', 'file', 'query', 'fragment'],
schemes: {http: 80, https: 443, ftp: 21, rtsp: 554, mms: 1755, file: 0},
initialize: function(uri, options){
this.setOptions(options);
var base = this.options.base || URI.base;
if (!uri) uri = base;
if (uri && uri.parsed) this.parsed = Object.clone(uri.parsed);
else this.set('value', uri.href || uri.toString(), base ? new URI(base) : false);
},
parse: function(value, base){
var bits = value.match(this.regex);
if (!bits) return false;
bits.shift();
return this.merge(bits.associate(this.parts), base);
},
merge: function(bits, base){
if ((!bits || !bits.scheme) && (!base || !base.scheme)) return false;
if (base){
this.parts.every(function(part){
if (bits[part]) return false;
bits[part] = base[part] || '';
return true;
});
}
bits.port = bits.port || this.schemes[bits.scheme.toLowerCase()];
bits.directory = bits.directory ? this.parseDirectory(bits.directory, base ? base.directory : '') : '/';
return bits;
},
parseDirectory: function(directory, baseDirectory){
directory = (directory.substr(0, 1) == '/' ? '' : (baseDirectory || '/')) + directory;
if (!directory.test(URI.regs.directoryDot)) return directory;
var result = [];
directory.replace(URI.regs.endSlash, '').split('/').each(function(dir){
if (dir == '..' && result.length > 0) result.pop();
else if (dir != '.') result.push(dir);
});
return result.join('/') + '/';
},
combine: function(bits){
return bits.value || bits.scheme + '://' +
(bits.user ? bits.user + (bits.password ? ':' + bits.password : '') + '@' : '') +
(bits.host || '') + (bits.port && bits.port != this.schemes[bits.scheme] ? ':' + bits.port : '') +
(bits.directory || '/') + (bits.file || '') +
(bits.query ? '?' + bits.query : '') +
(bits.fragment ? '#' + bits.fragment : '');
},
set: function(part, value, base){
if (part == 'value'){
var scheme = value.match(URI.regs.scheme);
if (scheme) scheme = scheme[1];
if (scheme && this.schemes[scheme.toLowerCase()] == null) this.parsed = { scheme: scheme, value: value };
else this.parsed = this.parse(value, (base || this).parsed) || (scheme ? { scheme: scheme, value: value } : { value: value });
} else if (part == 'data'){
this.setData(value);
} else {
this.parsed[part] = value;
}
return this;
},
get: function(part, base){
switch(part){
case 'value': return this.combine(this.parsed, base ? base.parsed : false);
case 'data' : return this.getData();
}
return this.parsed[part] || '';
},
go: function(){
document.location.href = this.toString();
},
toURI: function(){
return this;
},
getData: function(key, part){
var qs = this.get(part || 'query');
if (!(qs || qs === 0)) return key ? null : {};
var obj = qs.parseQueryString();
return key ? obj[key] : obj;
},
setData: function(values, merge, part){
if (typeof values == 'string'){
var data = this.getData();
data[arguments[0]] = arguments[1];
values = data;
} else if (merge){
values = Object.merge(this.getData(), values);
}
return this.set(part || 'query', Object.toQueryString(values));
},
clearData: function(part){
return this.set(part || 'query', '');
},
toString: toString,
valueOf: toString
});
URI.regs = {
endSlash: /\/$/,
scheme: /^(\w+):/,
directoryDot: /\.\/|\.$/
};
URI.base = new URI(Array.from(document.getElements('base[href]', true)).getLast(), {base: document.location});
String.implement({
toURI: function(options){
return new URI(this, options);
}
});
})();
/*
---
name: Events.Pseudos
description: Adds the functionallity to add pseudo events
license: MIT-style license
authors:
- Arian Stolwijk
requires: [Core/Class.Extras, Core/Slick.Parser, More/MooTools.More]
provides: [Events.Pseudos]
...
*/
Events.Pseudos = function(pseudos, addEvent, removeEvent){
var storeKey = 'monitorEvents:';
var storageOf = function(object){
return {
store: object.store ? function(key, value){
object.store(storeKey + key, value);
} : function(key, value){
(object.$monitorEvents || (object.$monitorEvents = {}))[key] = value;
},
retrieve: object.retrieve ? function(key, dflt){
return object.retrieve(storeKey + key, dflt);
} : function(key, dflt){
if (!object.$monitorEvents) return dflt;
return object.$monitorEvents[key] || dflt;
}
};
};
var splitType = function(type){
if (type.indexOf(':') == -1) return null;
var parsed = Slick.parse(type).expressions[0][0],
parsedPseudos = parsed.pseudos;
return (pseudos && pseudos[parsedPseudos[0].key]) ? {
event: parsed.tag,
value: parsedPseudos[0].value,
pseudo: parsedPseudos[0].key,
original: type
} : null;
};
return {
addEvent: function(type, fn, internal){
var split = splitType(type);
if (!split) return addEvent.call(this, type, fn, internal);
var storage = storageOf(this),
events = storage.retrieve(type, []),
pseudoArgs = Array.from(pseudos[split.pseudo]),
proxy = pseudoArgs[1];
var self = this;
var monitor = function(){
pseudoArgs[0].call(self, split, fn, arguments, proxy);
};
events.include({event: fn, monitor: monitor});
storage.store(type, events);
var eventType = split.event;
if (proxy && proxy[eventType]) eventType = proxy[eventType].base;
addEvent.call(this, type, fn, internal);
return addEvent.call(this, eventType, monitor, internal);
},
removeEvent: function(type, fn){
var split = splitType(type);
if (!split) return removeEvent.call(this, type, fn);
var storage = storageOf(this),
events = storage.retrieve(type),
pseudoArgs = Array.from(pseudos[split.pseudo]),
proxy = pseudoArgs[1];
if (!events) return this;
var eventType = split.event;
if (proxy && proxy[eventType]) eventType = proxy[eventType].base;
removeEvent.call(this, type, fn);
events.each(function(monitor, i){
if (!fn || monitor.event == fn) removeEvent.call(this, eventType, monitor.monitor);
delete events[i];
}, this);
storage.store(type, events);
return this;
}
};
};
(function(){
var pseudos = {
once: function(split, fn, args){
fn.apply(this, args);
this.removeEvent(split.original, fn);
}
};
Events.definePseudo = function(key, fn){
pseudos[key] = fn;
};
var proto = Events.prototype;
Events.implement(Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent));
})();
/*
---
name: Element.Event.Pseudos
description: Adds the functionality to add pseudo events for Elements
license: MIT-style license
authors:
- Arian Stolwijk
requires: [Core/Element.Event, Events.Pseudos]
provides: [Element.Event.Pseudos]
...
*/
(function(){
var pseudos = {
once: function(split, fn, args){
fn.apply(this, args);
this.removeEvent(split.original, fn);
}
};
Event.definePseudo = function(key, fn, proxy){
pseudos[key] = [fn, proxy];
};
var proto = Element.prototype;
[Element, Window, Document].invoke('implement', Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent));
})();
/*
---
script: Element.Delegation.js
name: Element.Delegation
description: Extends the Element native object to include the delegate method for more efficient event management.
credits:
- "Event checking based on the work of Daniel Steigerwald. License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz"
license: MIT-style license
authors:
- Aaron Newton
- Daniel Steigerwald
requires: [/MooTools.More, Element.Event.Pseudos]
provides: [Element.Delegation]
...
*/
Event.definePseudo('relay', function(split, fn, args, proxy){
var event = args[0];
var check = proxy ? proxy.condition : null;
for (var target = event.target; target && target != this; target = target.parentNode){
var finalTarget = document.id(target);
if (Slick.match(target, split.value) && (!check || check.call(finalTarget, event))){
if (finalTarget) fn.call(finalTarget, event, finalTarget);
return;
}
}
}, {
mouseenter: {
base: 'mouseover',
condition: Element.Events.mouseenter.condition
},
mouseleave: {
base: 'mouseout',
condition: Element.Events.mouseleave.condition
}
});
/*
---
script: Element.Shortcuts.js
name: Element.Shortcuts
description: Extends the Element native object to include some shortcut methods.
license: MIT-style license
authors:
- Aaron Newton
requires:
- Core/Element.Style
- /MooTools.More
provides: [Element.Shortcuts]
...
*/
Element.implement({
isDisplayed: function(){
return this.getStyle('display') != 'none';
},
isVisible: function(){
var w = this.offsetWidth,
h = this.offsetHeight;
return (w == 0 && h == 0) ? false : (w > 0 && h > 0) ? true : this.style.display != 'none';
},
toggle: function(){
return this[this.isDisplayed() ? 'hide' : 'show']();
},
hide: function(){
var d;
try {
//IE fails here if the element is not in the dom
d = this.getStyle('display');
} catch(e){}
if (d == 'none') return this;
return this.store('element:_originalDisplay', d || '').setStyle('display', 'none');
},
show: function(display){
if (!display && this.isDisplayed()) return this;
display = display || this.retrieve('element:_originalDisplay') || 'block';
return this.setStyle('display', (display == 'none') ? 'block' : display);
},
swapClass: function(remove, add){
return this.removeClass(remove).addClass(add);
}
});
Document.implement({
clearSelection: function(){
if (document.selection && document.selection.empty){
document.selection.empty();
} else if (window.getSelection){
var selection = window.getSelection();
if (selection && selection.removeAllRanges) selection.removeAllRanges();
}
}
});
+61
View File
@@ -0,0 +1,61 @@
var Page = {}
Page.Movie = new Class({
Extends: PageBase,
name: 'movie',
initialize: function(options){
}
})
Page.Manage = new Class({
Extends: PageBase,
name: 'manage',
initialize: function(options){
}
})
Page.Soon = new Class({
Extends: PageBase,
name: 'soon',
initialize: function(options){
}
})
Page.Config = new Class({
Extends: PageBase,
name: 'config',
initialize: function(options){
}
})
Page.Log = new Class({
Extends: PageBase,
name: 'log',
initialize: function(options){
}
})
+161
View File
@@ -0,0 +1,161 @@
html {
color: #343434;
font-size: 12px;
line-height: 1.5;
font-family: "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif;
}
body {
margin: 0;
padding: 0;
background: #fff;
overflow-y: scroll;
}
body.noscroll { overflow: hidden; }
#clean {
background: transparent !important;
}
pre {
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
}
input, textarea {
font-size: 12px;
font-family: "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif;
}
a img {
border:none;
}
a {
text-decoration:none;
color: #6ea1d7;
outline: 0;
}
a:hover { color: #4d66c4; }
.page {
width: 960px;
margin: 0 auto;
line-height: 24px;
padding: 0 0 20px;
}
.page .noticeMe {
background-color: lightgoldenrodyellow;
display: block;
padding: 20px 10px;
margin: 0 -10px 40px;
font-size: 19px;
text-align: center;
}
.content {
clear:both;
padding: 130px 10px 10px;
}
.footer {
text-align:center;
padding: 50px 0 0 0;
color: #999;
font-size: 10px;
clear: both;
}
.footer .check {
color: #333;
}
#toTop {
background: black;
position: fixed;
bottom: 0;
right: 0;
padding: 10px 10px 10px 40px;
background: #f7f7f7 url('../images/toTop.gif') no-repeat 10px center;
border-radius: 5px 0 0 0;
-moz-border-radius: 5px 0 0 0;
-webkit-border-radius: 5px 0 0 0;
}
form {
padding:0;
margin:0;
}
.spinner{
background: #f7f7f7 url('../images/spinner.gif') no-repeat center;
}
/*** Navigation ***/
#header {
background: #f7f7f7;
padding:10px;
margin-bottom: 20px;
border-bottom: 1px solid #f1f1f1;
height: 60px;
-moz-box-shadow: 0 0 30px rgba(0,0,0,0.1);
-webkit-box-shadow: 0 0 30px rgba(0,0,0,0.1);
position: fixed;
width: 99%;
}
#header .navigation {
width: 960px;
margin: 0 auto;
overflow:hidden;
}
#header .navigation ul {
float: left;
padding: 0;
margin: 0 0 0 6px;
width: 450px;
}
#header .navigation ul li {
color: #8b8b8b;
display: block;
font-size:20px;
font-weight: bold;
margin: 0;
text-align: center;
float: left;
}
#header .navigation ul li a {
display: block;
padding: 15px;
}
#header .navigation ul li:first-child a { padding-left: 10px; }
#header .navigation ul li a.logLink { font-size: 13px; padding: 23px 20px 15px; }
#header .navigation ul li a#showConfig {
background: url('../../media/images/gear.png') no-repeat center;
height: 35px;
width: 10px;
}
#header .navigation ul li span {
display: block;
margin-top: 5px;
}
#header .navigation ul li.disabled {
color: #e5e5e5;
}
#header .navigation ul li a:link, #header .navigation ul li a:visited {
color: #2c2c2c;
}
#header .navigation ul li a:hover, #header .navigation ul li a:active {
color: #8b8b8b;
}
+21 -12
View File
@@ -1,14 +1,23 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<link rel="stylesheet" href="{{ url_for('.static', filename='style/main.css') }}"> <link rel="stylesheet" href="{{ url_for('.static', filename='style/main.css') }}">
<title>CouchPotato</title> <script type="text/javascript" src="{{ url_for('.static', filename='scripts/mootools.js') }}"></script>
</head> <script type="text/javascript" src="{{ url_for('.static', filename='scripts/mootools_more.js') }}"></script>
<body> <script type="text/javascript" src="{{ url_for('.static', filename='scripts/couchpotato.js') }}"></script>
<div id="content">{% block content %}{% endblock %}</div> <script type="text/javascript" src="{{ url_for('.static', filename='scripts/history.js') }}"></script>
<div id="footer"> <script type="text/javascript" src="{{ url_for('.static', filename='scripts/pages.js') }}"></script>
{% block footer %} <link href="{{ url_for('.static', filename='images/favicon.ico') }}" rel="icon" type="image/x-icon" />
Footer
{% endblock %} <script type="text/javascript">
</div> window.addEvent('domready', function() {
</body> var cp = new CouchPotato({
'url': '{{ request.path }}',
'api_url': '{{ url_for('api.index') }}'
});
})
</script>
<title>CouchPotato</title>
</head>
<body></body>
</html>
-5
View File
@@ -1,6 +1 @@
{% extends "_desktop.html" %} {% extends "_desktop.html" %}
{% block content %}
{{ url_for('.static', filename='style/main.css') }}
{{ url_for('api.index') }}
{% endblock %}