Skip to content

Commit

Permalink
Add missing project files
Browse files Browse the repository at this point in the history
  • Loading branch information
burnhamrobertp committed Nov 19, 2014
1 parent a8480b6 commit 5d06972
Show file tree
Hide file tree
Showing 7 changed files with 330 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var/
*.egg-info/
.installed.cfg
*.egg
.idea

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
32 changes: 32 additions & 0 deletions LICENSE
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.
Empty file added README.md
Empty file.
5 changes: 5 additions & 0 deletions __init__.py
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')
76 changes: 76 additions & 0 deletions response.py
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();" })
39 changes: 39 additions & 0 deletions setup.py
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'
]
)
177 changes: 177 additions & 0 deletions static/js/sajax.js
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();
}

0 comments on commit 5d06972

Please sign in to comment.