-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a8480b6
commit 5d06972
Showing
7 changed files
with
330 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
Copyright (c) 2012 by Freedom Dumlao. | ||
|
||
Some rights reserved. | ||
|
||
Redistribution and use in source and binary forms of the software as well | ||
as documentation, with or without modification, are permitted provided | ||
that the following conditions are met: | ||
|
||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
|
||
* Redistributions in binary form must reproduce the above | ||
copyright notice, this list of conditions and the following | ||
disclaimer in the documentation and/or other materials provided | ||
with the distribution. | ||
|
||
* The names of the contributors may not be used to endorse or | ||
promote products derived from this software without specific | ||
prior written permission. | ||
|
||
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND | ||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT | ||
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | ||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||
DAMAGE. |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import pkg_resources | ||
|
||
|
||
def get_javascript_string(): | ||
return pkg_resources.resource_string('sajax', 'static/js/sajax.js') |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
from flask import jsonify, session, url_for | ||
import json, os, pprint | ||
from config import * | ||
|
||
|
||
class SResponse: | ||
"""An object which eases the work between ajax and python""" | ||
data = [] | ||
|
||
def __init__(self, cls=None): | ||
self.data = [] | ||
|
||
# If we're loading a view and have not yet loaded its static dependencies, asynchronously load them | ||
if cls.__class__.__name__.find('View') != -1: | ||
folder = cls.__class__.__name__.replace('View', '').lower() | ||
|
||
# if its not in loaded, it hasn't been loaded | ||
if folder not in session['sajax']['loaded_dep']: | ||
# css first, /static/css/obt_folder.css | ||
if os.path.isfile(ROOT+'/static/css/obt_'+folder+'.css'): | ||
self.data.append({'action': 'load', 'data': url_for('static', filename='css/obt_%s.css' % folder)}) | ||
|
||
# first the js file at /static/js/folder/folder.js if it exists | ||
if os.path.isfile(ROOT+'/static/js/%s/%s.js' % (folder, folder)): | ||
self.data.append({'action': 'load', 'data': url_for('static', filename='js/%s/%s.js' % (folder, folder))}) | ||
|
||
# then all the rest of the js files in /static/js/folder/ | ||
if os.path.isdir(ROOT+'/static/js/'+folder): | ||
for file in os.listdir(ROOT+'/static/js/'+folder): | ||
if (file != folder+'.js'): | ||
self.data.append({'action': 'load', 'data': url_for('static', filename='js/%s/%s' % (folder, file))}) | ||
|
||
# this folder's js files might have defined an object | ||
self.data.append({'action': 'js', 'data': "if (typeof %s != 'undefined') window.%s = new %s()" % (folder, folder, folder)}) | ||
# The files will be loaded, mark them as such | ||
session['sajax']['loaded_dep'].append(folder) | ||
|
||
def __add__(self, other): | ||
if isinstance(other.data, basestring): | ||
decoder = json.JSONDecoder() | ||
self.data += decoder.decode(other.data)['r'] | ||
elif isinstance(other.data, list): | ||
self.data += other.data | ||
|
||
return self | ||
|
||
def get_json(self): | ||
return jsonify(r=self.data) | ||
|
||
def assign(self, selector, html): | ||
self.data.append({ 'action': 'as', 'selector': selector, 'data': html }) | ||
|
||
def append(self, selector, html): | ||
self.data.append({ 'action': 'ap', 'selector': selector, 'data': html }) | ||
|
||
def append_template(self, selector, html, template_id): | ||
self.data.append({ 'action': 'ap_t', 'selector': selector, 'data': html, 'id': template_id }) | ||
|
||
def script(self, js): | ||
self.data.append({ 'action': 'js', 'data': js }) | ||
|
||
def position(self, selector, keyword): | ||
self.data.append({ 'action': 'js', 'data': "$('%s').data('position', '%s').addClass('positioned'); sajax.position('%s');" % (selector, keyword, selector) }) | ||
|
||
def remove(self, selector): | ||
self.data.append({ 'action': 'js', 'data': "$('%s').remove()" % selector }) | ||
|
||
def alert(self, text): | ||
self.data.append({ 'action': 'alert', 'data': text}) | ||
|
||
def call(self, path): | ||
self.data.append({ 'action': 'js', 'data': "sajax.call('%s')" % path}) | ||
|
||
def error(self, baseSelector, error): | ||
self.data.append({ 'action': 'assign', 'selector': baseSelector+' .error', 'data': error }) | ||
self.data.append({ 'action': 'js', 'data': "$('"+baseSelector+" .error').show();" }) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
""" | ||
sajax | ||
------------- | ||
Python / jQuery AJAX library, structured similarly to old xajax library | ||
""" | ||
from setuptools import setup | ||
|
||
setup( | ||
name='sajax', | ||
version='0.1', | ||
url='https://github.com/harkenn/sajax', | ||
license='BSD', | ||
author='Robert Burnham', | ||
author_email='[email protected]', | ||
description="Python / jQuery AJAX library", | ||
long_description=__doc__, | ||
py_modules=['sajax'], | ||
zip_safe=False, | ||
include_package_data=True, | ||
platforms='any', | ||
install_requires=[ | ||
'Flask>=0.9' | ||
], | ||
classifiers=[ | ||
'Environment :: Web Environment', | ||
'Intended Audience :: Developers', | ||
'License :: OSI Approved :: BSD License', | ||
'Operating System :: OS Independent', | ||
'Programming Language :: Python', | ||
'Programming Language :: Python :: 2', | ||
'Programming Language :: Python :: 2.6', | ||
'Programming Language :: Python :: 2.7', | ||
'Programming Language :: Python :: 3', | ||
'Programming Language :: Python :: 3.3', | ||
'Topic :: Internet :: WWW/HTTP :: Dynamic Content', | ||
'Topic :: Software Development :: Libraries :: Python Modules' | ||
] | ||
) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
function sajax() { | ||
this.loads_pending = 0; | ||
} | ||
|
||
/** | ||
* Position element(s) by keyword | ||
* | ||
* @param selector | ||
*/ | ||
sajax.prototype.position = function(selector) { | ||
selector = selector === undefined ? '' : selector; | ||
|
||
var positioned = $('.positioned'+selector), i, elem, data; | ||
for (i = 0; i < positioned.length; i++) { | ||
elem = $(positioned[i]), data = elem.data(); | ||
|
||
switch(data['position']) { | ||
case 'top-left': | ||
elem.css({ 'left': '0px', 'top': '0px' }); | ||
break; | ||
case 'top-center': | ||
elem.css({ 'left': ($(window).width()-elem.outerWidth())/2+'px', 'top': '0px' }); | ||
break; | ||
case 'top-right': | ||
elem.css({ 'left': $(window).width()-elem.outerWidth()+'px', 'top': '0px' }); | ||
break; | ||
case 'center': | ||
elem.css({ 'left': ($(window).width()-elem.outerWidth())/2+'px', 'top': ($(window).height()-elem.outerHeight())/2+'px' }); | ||
break; | ||
case 'bottom-left': | ||
elem.css({ 'left': '0px', 'top': $(window).height()-elem.outerHeight()+'px' }); | ||
break; | ||
case 'bottom-right': | ||
elem.css({ 'top': $(window).height()-elem.outerHeight()+'px', 'left': $(window).width()-elem.outerWidth()+'px' }); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Process sajax response (data) | ||
* | ||
* sajax.call binds this as the success processing method. data is a json array of | ||
* commands (denoted sometimes by an abbreviation) to take action on and any corresponding | ||
* data (such as JS that needs evaluating, or some HTML to be assigned). | ||
* | ||
* @param data | ||
*/ | ||
sajax.prototype.parseResponse = function(data) { | ||
// Limit to 20 iterations (10 seconds) | ||
var i = data.i === undefined ? 0 : data.i; | ||
// Store delayed data to be called via timeout | ||
var delayed_data = [] | ||
|
||
if (i > 20) | ||
throw 'Exceeded parseResponse processing limit'; | ||
|
||
$.each(data.r, function() { | ||
// If we have a load queued and we haven't already waited 10 seconds, continue to wait | ||
if (delayed_data.length > 0 || (sajax.loads_pending > 0 && this.action != 'load')) { | ||
delayed_data.push(this); | ||
} else { | ||
// Process the action for this iteration of data.r | ||
switch(this.action) { | ||
case 'as': | ||
$(this.selector).html(this.data); | ||
break; | ||
case 'ap': | ||
$(this.selector).append(this.data); | ||
break; | ||
case 'ap_t': | ||
// append to selector only if the id of the template is not on the page | ||
if ($(this.id).length == 0) | ||
$(this.selector).append(this.data); | ||
break; | ||
case 'js': | ||
eval(this.data); | ||
break; | ||
case 'alert': | ||
alert(this.data); | ||
break; | ||
case 'load': | ||
sajax.load(this.data); | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
}); | ||
|
||
// If there was one or more delayed_data, set a timeout to re-process | ||
if (delayed_data.length > 0) | ||
setTimeout(function() { sajax.parseResponse({'r': delayed_data, 'i':++i}) }, 500); | ||
}; | ||
|
||
/** | ||
* load a static file onto the DOM via ajax | ||
* | ||
* @param file | ||
*/ | ||
sajax.prototype.load = function(file) { | ||
if (file != undefined) | ||
this.loads_pending++; | ||
|
||
try { | ||
switch(file.split('.').pop()) { | ||
case 'css': | ||
link = $('<link rel="stylesheet" type="text/css" href="'+file+'">'); | ||
$('head').append(link); | ||
// css files effectively load automatically | ||
this.loads_pending--; | ||
break; | ||
case 'js': | ||
$.getScript(file, function() { sajax.loads_pending--; }); | ||
break; | ||
} | ||
} catch(e) { | ||
this.loads_pending--; | ||
throw e; | ||
} | ||
} | ||
|
||
/** | ||
* Shortcut to initialize a jquery AJAX request via post | ||
* | ||
* @param path | ||
* @param parameters | ||
* @returns {boolean} | ||
*/ | ||
sajax.prototype.call = function(path, parameters) { | ||
if (parameters === undefined) parameters = {}; | ||
if (path.slice(0, 1) !== '/') path = '/' + path; | ||
|
||
$.ajax({ | ||
type: 'POST', | ||
contentType: 'application/json', | ||
url: path, | ||
data: JSON.stringify(parameters), | ||
datatype: 'json', | ||
success: this.parseResponse | ||
}); | ||
|
||
return false; | ||
}; | ||
|
||
/** | ||
* Build array from arguments, retrun | ||
* | ||
* @returns {{}} | ||
*/ | ||
sajax.prototype.buildData = function() { | ||
// extend string holds the js that will be eval'd into the returned object | ||
var e_s = ''; | ||
var data = {}; | ||
|
||
for (var i = 0; i < arguments.length; i++) { | ||
if (typeof(arguments[i]) == 'object') | ||
e_s += 'arguments['+i+'],'; | ||
else if (typeof(arguments[i]) == 'string') | ||
e_s += "$('"+arguments[i].replace("'", "\\'")+"').serializeForm(),"; | ||
} | ||
|
||
if (e_s.length > 1) | ||
eval('$.extend(true, data, '+e_s.substring(0, e_s.length-1)+');'); | ||
|
||
return data; | ||
} | ||
|
||
/** | ||
* Return serialized data for easy form consumption | ||
* | ||
* @param selector | ||
* @returns {{}} | ||
*/ | ||
sajax.prototype.getFormValues = function(selector) { | ||
return $(selector).serializeForm(); | ||
} |