From 705a88c54d889577ecc6c03da80e8d3a15e5cea2 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Mon, 12 Apr 2010 13:21:00 +0200 Subject: [PATCH 01/17] Added the media controller. --- scribeengine/controllers/media.py | 16 ++++++++++++++++ scribeengine/tests/functional/test_media.py | 7 +++++++ 2 files changed, 23 insertions(+) create mode 100644 scribeengine/controllers/media.py create mode 100644 scribeengine/tests/functional/test_media.py diff --git a/scribeengine/controllers/media.py b/scribeengine/controllers/media.py new file mode 100644 index 0000000..a4c1487 --- /dev/null +++ b/scribeengine/controllers/media.py @@ -0,0 +1,16 @@ +import logging + +from pylons import request, response, session, tmpl_context as c +from pylons.controllers.util import abort, redirect_to + +from scribeengine.lib.base import BaseController, render + +log = logging.getLogger(__name__) + +class MediaController(BaseController): + + def index(self): + # Return a rendered template + #return render('/media.mako') + # or, return a response + return 'Hello World' diff --git a/scribeengine/tests/functional/test_media.py b/scribeengine/tests/functional/test_media.py new file mode 100644 index 0000000..5207fba --- /dev/null +++ b/scribeengine/tests/functional/test_media.py @@ -0,0 +1,7 @@ +from scribeengine.tests import * + +class TestMediaController(TestController): + + def test_index(self): + response = self.app.get(url(controller='media', action='index')) + # Test response... From ff0e6e009333946b27cebfcb896129692de95077 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Wed, 14 Apr 2010 08:32:38 +0200 Subject: [PATCH 02/17] Added tables and models for files and media types. --- scribeengine/model/__init__.py | 32 ++++++++++++++++++++++---------- scribeengine/model/classes.py | 14 ++++++++++++++ scribeengine/model/tables.py | 15 +++++++++++++++ 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/scribeengine/model/__init__.py b/scribeengine/model/__init__.py index 6af5860..466a984 100644 --- a/scribeengine/model/__init__.py +++ b/scribeengine/model/__init__.py @@ -28,11 +28,12 @@ from sqlalchemy.orm import mapper, relation, backref from scribeengine.model import meta from scribeengine.model.tables import categories_table, comments_table, \ - pages_table, permissions_table, posts_table, roles_table, tags_table, \ - users_table, variables_table, categories_posts_table, \ - permissions_roles_table, posts_tags_table, roles_users_table -from scribeengine.model.classes import Category, Comment, Page, Permission, \ - Post, Role, Tag, User, Variable + files_table, media_types_table, pages_table, permissions_table, \ + posts_table, roles_table, tags_table, users_table, variables_table, \ + categories_posts_table, permissions_roles_table, posts_tags_table, \ + roles_users_table +from scribeengine.model.classes import Category, Comment, File, MediaType, \ + Page, Permission, Post, Role, Tag, User, Variable def init_model(engine): """Call me before using any of the tables or classes in the model""" @@ -41,25 +42,36 @@ def init_model(engine): mapper(Category, categories_table) mapper(Comment, comments_table) +mapper(File, files_table) +mapper(MediaType, media_types_table, + properties={ + u'files': relation(File, backref=u'media_type') + } +) mapper(Page, pages_table) mapper(Permission, permissions_table) mapper(Post, posts_table, properties={ - u'categories': relation(Category, backref='posts', secondary=categories_posts_table), - u'comments': relation(Comment, backref=u'post', order_by=Comment.created.asc()), - u'tags': relation(Tag, backref=backref(u'posts', order_by='posts.created DESC'), secondary=posts_tags_table) + u'categories': relation(Category, backref=u'posts', + secondary=categories_posts_table), + u'comments': relation(Comment, backref=u'post', + order_by=Comment.created.asc()), + u'tags': relation(Tag, + backref=backref(u'posts', order_by='posts.created DESC'), + secondary=posts_tags_table) } ) mapper(Role, roles_table, properties={ - u'permissions': relation(Permission, backref=u'roles', secondary=permissions_roles_table) + u'permissions': relation(Permission, backref=u'roles', + secondary=permissions_roles_table) } ) mapper(Tag, tags_table) mapper(User, users_table, properties={ u'comments': relation(Comment, backref=u'user'), - #u'pages': relation(Page, backref=u'user'), + u'files': relation(File, backref=u'user'), u'posts': relation(Post, backref=u'user'), u'roles': relation(Role, backref=u'users', secondary=roles_users_table) } diff --git a/scribeengine/model/classes.py b/scribeengine/model/classes.py index 3c2bef0..489b89a 100644 --- a/scribeengine/model/classes.py +++ b/scribeengine/model/classes.py @@ -55,6 +55,20 @@ class Comment(BaseModel): pass +class File(BaseModel): + """ + A file in the media library. + """ + pass + + +class MediaType(BaseModel): + """ + Distinguishes between different types of media. + """ + pass + + class Page(BaseModel): """ A page on the blog. This is separate from a blog entry, for things like diff --git a/scribeengine/model/tables.py b/scribeengine/model/tables.py index c8819ad..159810d 100644 --- a/scribeengine/model/tables.py +++ b/scribeengine/model/tables.py @@ -50,6 +50,21 @@ comments_table = Table(u'comments', metadata, Column(u'modified', DateTime, default=datetime.now()) ) +files_table = Table(u'files', metadata, + Column(u'id', Integer, primary_key=True), + Column(u'user_id', Integer, ForeignKey(u'users.id'), nullable=False), + Column(u'media_type_id', Integer, ForeignKey(u'media_types.id'), nullable=False), + Column(u'filename', Unicode(255), nullable=False, index=True), + Column(u'mimetype', Unicode(255)), + Column(u'path', Unicode(255)), + Column(u'size', Integer, default=0) +) + +media_types_table = Table(u'media_types', metadata, + Column(u'id', Integer, primary_key=True), + Column(u'title', Unicode(255), nullable=False, index=True) +) + # Definition of the "pages" table pages_table = Table(u'pages', metadata, Column(u'id', Integer, primary_key=True), From 74054e69a47ae81aa537a9148677d2a210103a05 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Wed, 14 Apr 2010 08:47:53 +0200 Subject: [PATCH 03/17] Added setup options. --- development.ini | 5 ++ scribeengine/config/deployment.ini_tmpl | 5 ++ scribeengine/websetup.py | 84 ++++++++++++------------- 3 files changed, 52 insertions(+), 42 deletions(-) diff --git a/development.ini b/development.ini index 21b96c1..f2e9cd5 100644 --- a/development.ini +++ b/development.ini @@ -53,6 +53,11 @@ mail.smtp.password = mymailpassword # Server-related settings server.timezone = 'Africa/Johannesburg' +# Setup options +setup.create_tables = true +setup.create_user = false +setup.blog_details = false + # WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* # Debug mode will enable the interactive debugging tool, allowing ANYONE to # execute malicious code after an exception is raised. diff --git a/scribeengine/config/deployment.ini_tmpl b/scribeengine/config/deployment.ini_tmpl index bbb4277..0dd278d 100644 --- a/scribeengine/config/deployment.ini_tmpl +++ b/scribeengine/config/deployment.ini_tmpl @@ -53,6 +53,11 @@ mail.smtp.password = mymailpassword # Server-related settings server.timezone = 'Africa/Johannesburg' +# Setup options (for when you run "paster setup-app config.ini") +setup.create_tables = true +setup.create_user = false +setup.blog_details = false + # WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* # Debug mode will enable the interactive debugging tool, allowing ANYONE to # execute malicious code after an exception is raised. diff --git a/scribeengine/websetup.py b/scribeengine/websetup.py index f9bbd16..d6e00e1 100644 --- a/scribeengine/websetup.py +++ b/scribeengine/websetup.py @@ -23,9 +23,14 @@ """ Setup the ScribeEngine application """ +import os +import hashlib +import hmac import logging from datetime import datetime +from paste.deploy.converters import asbool + from scribeengine.config.environment import load_environment log = logging.getLogger(__name__) @@ -35,55 +40,50 @@ def setup_app(command, conf, vars): conf.local_conf['setup-app'] = True load_environment(conf.global_conf, conf.local_conf) - import os - import hashlib - import hmac from scribeengine.model.meta import metadata, Session, engine from scribeengine.model import Category, Permission, Post, Variable, \ User, Role - if os.name == 'posix': + if os.name == u'posix': import readline - # Let's prompt the user for an e-mail address, password and nick for the first user in the system. - print 'First User:' - email = raw_input('E-mail address [admin@scribeengine.org]: ') - password = raw_input('Password [P@ssw0rd]: ') - nick = raw_input('Nick [Admin]: ') + if asbool(conf.local_conf[u'setup.create_tables']): + # Create the tables if they don't already exist + metadata.create_all(bind=engine, checkfirst=True) - if not email: - email = u'admin@scribeengine.org' - else: - email = unicode(email) - if not password: - password = u'P@ssw0rd' - else: - password = unicode(password) - if not nick: - nick = u'Admin' - else: - nick = unicode(nick) - password = unicode(hmac.new(conf[u'security.salt'], password, - hashlib.sha256).hexdigest(), u'utf-8') + if asbool(conf.local_conf[u'setup.create_user']): + # Let's prompt the user for an e-mail address, password and nick for the + # first user in the system. + print 'First User:' + email = raw_input('E-mail address [admin@scribeengine.org]: ') + password = raw_input('Password [P@ssw0rd]: ') + nick = raw_input('Nick [Admin]: ') + if not email: + email = u'admin@scribeengine.org' + else: + email = unicode(email) + if not password: + password = u'P@ssw0rd' + else: + password = unicode(password) + if not nick: + nick = u'Admin' + else: + nick = unicode(nick) + password = unicode(hmac.new(conf[u'security.salt'], password, + hashlib.sha256).hexdigest(), u'utf-8') + perm_addposts = Permission(name=u'Add Posts') + perm_editmyposts = Permission(name=u'Edit My Posts') + perm_delmyposts = Permission(name=u'Delete My Posts') + role_admin = Role(name=u'Administrator') + role_admin.permissions.extend([perm_addposts, perm_editmyposts, perm_delmyposts]) + user = User(email=email, password=password, nick=nick) + user.roles.append(role_admin) + Session.add(user) - # Create the tables if they don't already exist - metadata.create_all(bind=engine, checkfirst=True) + if asbool(conf.local_conf[u'setup.blog_details']): + blog_title = Variable(key=u'blog title', value=u'ScribeEngine') + blog_slogan = Variable(key=u'blog slogan', value=u'open source blog software') + Session.add_all([blog_title, blog_slogan]) - blog_title = Variable(key=u'blog title', value=u'ScribeEngine') - blog_slogan = Variable(key=u'blog slogan', value=u'open source blog software') - - pylons_cat = Category(name=u'Pylons', url=u'pylons') - database_cat = Category(name=u'Database', url=u'database') - - perm_addposts = Permission(name=u'Add Posts') - perm_editmyposts = Permission(name=u'Edit My Posts') - perm_delmyposts = Permission(name=u'Delete My Posts') - - role_admin = Role(name=u'Administrator') - role_admin.permissions.extend([perm_addposts, perm_editmyposts, perm_delmyposts]) - - user = User(email=email, password=password, nick=nick) - user.roles.append(role_admin) - - Session.add_all([blog_title, blog_slogan, user]) Session.commit() From 63950167b1e451127cb46f304c2c31deeda9b9b4 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 15 Apr 2010 07:47:15 +0200 Subject: [PATCH 04/17] Added jsTree jQuery Plugin. Started on a browser function (fetching the directories). --- development.ini | 4 +- scribeengine/config/deployment.ini_tmpl | 4 +- scribeengine/controllers/media.py | 46 +- scribeengine/lib/base.py | 1 + .../public/scripts/jquery.metadata.js | 122 + .../public/scripts/jtree/jquery.tree.js | 2064 +++++++++++++++++ .../jtree/themes/default/dot_for_ie.gif | Bin 0 -> 43 bytes .../scripts/jtree/themes/default/icons.png | Bin 0 -> 6680 bytes .../scripts/jtree/themes/default/style.css | 30 + .../scripts/jtree/themes/default/throbber.gif | Bin 0 -> 1844 bytes 10 files changed, 2259 insertions(+), 12 deletions(-) create mode 100644 scribeengine/public/scripts/jquery.metadata.js create mode 100644 scribeengine/public/scripts/jtree/jquery.tree.js create mode 100644 scribeengine/public/scripts/jtree/themes/default/dot_for_ie.gif create mode 100644 scribeengine/public/scripts/jtree/themes/default/icons.png create mode 100644 scribeengine/public/scripts/jtree/themes/default/style.css create mode 100644 scribeengine/public/scripts/jtree/themes/default/throbber.gif diff --git a/development.ini b/development.ini index f2e9cd5..5212c77 100644 --- a/development.ini +++ b/development.ini @@ -34,8 +34,8 @@ beaker.session.timeout = 1209600 # SQLAlchemy database URL sqlalchemy.url = sqlite:///%(here)s/scribeengine.sqlite -# Images directory -paths.images = %(here)s/images +# Media upload directory +paths.media = %(here)s/media # Themes directory paths.themes = %(here)s/themes diff --git a/scribeengine/config/deployment.ini_tmpl b/scribeengine/config/deployment.ini_tmpl index 0dd278d..4e25484 100644 --- a/scribeengine/config/deployment.ini_tmpl +++ b/scribeengine/config/deployment.ini_tmpl @@ -34,8 +34,8 @@ app_instance_uuid = ${app_instance_uuid} # SQLAlchemy database URL sqlalchemy.url = sqlite:///production.db -# Images directory -paths.images = %(here)s/images +# Media upload directory +paths.media = %(here)s/media # Themes directory paths.themes = %(here)s/themes diff --git a/scribeengine/controllers/media.py b/scribeengine/controllers/media.py index a4c1487..38a431a 100644 --- a/scribeengine/controllers/media.py +++ b/scribeengine/controllers/media.py @@ -1,16 +1,46 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# ScribeEngine - Open Source Blog Software # +# --------------------------------------------------------------------------- # +# Copyright (c) 2010 Raoul Snyman # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### + +import os import logging -from pylons import request, response, session, tmpl_context as c -from pylons.controllers.util import abort, redirect_to - -from scribeengine.lib.base import BaseController, render +from scribeengine.lib.base import * +from scribeengine.lib import utils +from scribeengine.model import MediaType, File +from scribeengine.model.meta import Session log = logging.getLogger(__name__) class MediaController(BaseController): + def _get_directories(self, parent=None, tree={}): + if not parent: + parent = config[u'paths.media'] + for dirpath in os.listdir(parent): + if os.path.isdir(dirpath): + tree[os.path.abspath(dirpath)] = {u'path': dirpath, u'children': {}} + self._get_directories(os.path.abspath(dirpath), + tree[os.path.abspath(dirpath)][u'children']) + def index(self): - # Return a rendered template - #return render('/media.mako') - # or, return a response - return 'Hello World' + c.directories = self._get_directories() + return render(u'/media/index.html') diff --git a/scribeengine/lib/base.py b/scribeengine/lib/base.py index 0071e79..9f09ff2 100644 --- a/scribeengine/lib/base.py +++ b/scribeengine/lib/base.py @@ -77,6 +77,7 @@ class BaseController(WSGIController): c.month_posts[post.created.day] = [] c.month_posts[post.created.day].append(post) self._add_javascript(u'jquery.js') + self._add_javascript(u'jquery.metadata.js') if c.jsvalidation: self._add_javascript(u'jquery.validate.js') self._add_javascript(u'ScribeEngine.js') diff --git a/scribeengine/public/scripts/jquery.metadata.js b/scribeengine/public/scripts/jquery.metadata.js new file mode 100644 index 0000000..ad8bfba --- /dev/null +++ b/scribeengine/public/scripts/jquery.metadata.js @@ -0,0 +1,122 @@ +/* + * Metadata - jQuery plugin for parsing metadata from elements + * + * Copyright (c) 2006 John Resig, Yehuda Katz, J�örn Zaefferer, Paul McLanahan + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Revision: $Id: jquery.metadata.js 4187 2007-12-16 17:15:27Z joern.zaefferer $ + * + */ + +/** + * Sets the type of metadata to use. Metadata is encoded in JSON, and each property + * in the JSON will become a property of the element itself. + * + * There are three supported types of metadata storage: + * + * attr: Inside an attribute. The name parameter indicates *which* attribute. + * + * class: Inside the class attribute, wrapped in curly braces: { } + * + * elem: Inside a child element (e.g. a script tag). The + * name parameter indicates *which* element. + * + * The metadata for an element is loaded the first time the element is accessed via jQuery. + * + * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements + * matched by expr, then redefine the metadata type and run another $(expr) for other elements. + * + * @name $.metadata.setType + * + * @example

This is a p

+ * @before $.metadata.setType("class") + * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" + * @desc Reads metadata from the class attribute + * + * @example

This is a p

+ * @before $.metadata.setType("attr", "data") + * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" + * @desc Reads metadata from a "data" attribute + * + * @example

This is a p

+ * @before $.metadata.setType("elem", "script") + * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" + * @desc Reads metadata from a nested script element + * + * @param String type The encoding type + * @param String name The name of the attribute to be used to get metadata (optional) + * @cat Plugins/Metadata + * @descr Sets the type of encoding to be used when loading metadata for the first time + * @type undefined + * @see metadata() + */ + +(function($) { + +$.extend({ + metadata : { + defaults : { + type: 'class', + name: 'metadata', + cre: /({.*})/, + single: 'metadata' + }, + setType: function( type, name ){ + this.defaults.type = type; + this.defaults.name = name; + }, + get: function( elem, opts ){ + var settings = $.extend({},this.defaults,opts); + // check for empty string in single property + if ( !settings.single.length ) settings.single = 'metadata'; + + var data = $.data(elem, settings.single); + // returned cached data if it already exists + if ( data ) return data; + + data = "{}"; + + if ( settings.type == "class" ) { + var m = settings.cre.exec( elem.className ); + if ( m ) + data = m[1]; + } else if ( settings.type == "elem" ) { + if( !elem.getElementsByTagName ) + return undefined; + var e = elem.getElementsByTagName(settings.name); + if ( e.length ) + data = $.trim(e[0].innerHTML); + } else if ( elem.getAttribute != undefined ) { + var attr = elem.getAttribute( settings.name ); + if ( attr ) + data = attr; + } + + if ( data.indexOf( '{' ) <0 ) + data = "{" + data + "}"; + + data = eval("(" + data + ")"); + + $.data( elem, settings.single, data ); + return data; + } + } +}); + +/** + * Returns the metadata object for the first member of the jQuery object. + * + * @name metadata + * @descr Returns element's metadata object + * @param Object opts An object contianing settings to override the defaults + * @type jQuery + * @cat Plugins/Metadata + */ +$.fn.metadata = function( opts ){ + return $.metadata.get( this[0], opts ); +}; + +})(jQuery); \ No newline at end of file diff --git a/scribeengine/public/scripts/jtree/jquery.tree.js b/scribeengine/public/scripts/jtree/jquery.tree.js new file mode 100644 index 0000000..077f4e5 --- /dev/null +++ b/scribeengine/public/scripts/jtree/jquery.tree.js @@ -0,0 +1,2064 @@ +/* + * jsTree 0.9.9a + * http://jstree.com/ + * + * Copyright (c) 2009 Ivan Bozhanov (vakata.com) + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Date: 2009-10-06 + * + */ + +(function($) { + // jQuery plugin + $.tree = { + datastores : { }, + plugins : { }, + defaults : { + data : { + async : false, // Are async requests used to load open_branch contents + type : "html", // One of included datastores + opts : { method: "GET", url: false } // Options passed to datastore + }, + selected : false, // FALSE or STRING or ARRAY + opened : [], // ARRAY OF INITIALLY OPENED NODES + languages : [], // ARRAY of string values (which will be used as CSS classes - so they must be valid) + ui : { + dots : true, // BOOL - dots or no dots + animation : 0, // INT - duration of open/close animations in miliseconds + scroll_spd : 4, + theme_path : false, // Path to the theme CSS file - if set to false and theme_name is not false - will lookup jstree-path-here/themes/theme-name-here/style.css + theme_name : "default",// if set to false no theme will be loaded + selected_parent_close : "select_parent", // false, "deselect", "select_parent" + selected_delete : "select_previous" // false, "select_previous" + }, + types : { + "default" : { + clickable : true, // can be function + renameable : true, // can be function + deletable : true, // can be function + creatable : true, // can be function + draggable : true, // can be function + max_children : -1, // -1 - not set, 0 - no children, 1 - one child, etc // can be function + max_depth : -1, // -1 - not set, 0 - no children, 1 - one level of children, etc // can be function + valid_children : "all", // all, none, array of values // can be function + icon : { + image : false, + position : false + } + } + }, + rules : { + multiple : false, // FALSE | CTRL | ON - multiple selection off/ with or without holding Ctrl + multitree : "none", // all, none, array of tree IDs to accept from + type_attr : "rel", // STRING attribute name (where is the type stored as string) + createat : "bottom", // STRING (top or bottom) new nodes get inserted at top or bottom + drag_copy : "ctrl", // FALSE | CTRL | ON - drag to copy off/ with or without holding Ctrl + drag_button : "left", // left, right or both + use_max_children : true, + use_max_depth : true, + + max_children: -1, + max_depth : -1, + valid_children : "all" + }, + lang : { + new_node : "New folder", + loading : "Loading ..." + }, + callback : { + beforechange: function(NODE,TREE_OBJ) { return true }, + beforeopen : function(NODE,TREE_OBJ) { return true }, + beforeclose : function(NODE,TREE_OBJ) { return true }, + beforemove : function(NODE,REF_NODE,TYPE,TREE_OBJ) { return true }, + beforecreate: function(NODE,REF_NODE,TYPE,TREE_OBJ) { return true }, + beforerename: function(NODE,LANG,TREE_OBJ) { return true }, + beforedelete: function(NODE,TREE_OBJ) { return true }, + beforedata : function(NODE,TREE_OBJ) { return { id : $(NODE).attr("id") || 0 } }, // PARAMETERS PASSED TO SERVER + ondata : function(DATA,TREE_OBJ) { return DATA; }, // modify data before parsing it + onparse : function(STR,TREE_OBJ) { return STR; }, // modify string before visualizing it + onhover : function(NODE,TREE_OBJ) { }, // node hovered + onselect : function(NODE,TREE_OBJ) { }, // node selected + ondeselect : function(NODE,TREE_OBJ) { }, // node deselected + onchange : function(NODE,TREE_OBJ) { }, // focus changed + onrename : function(NODE,TREE_OBJ,RB) { }, // node renamed + onmove : function(NODE,REF_NODE,TYPE,TREE_OBJ,RB) { }, // move completed + oncopy : function(NODE,REF_NODE,TYPE,TREE_OBJ,RB) { }, // copy completed + oncreate : function(NODE,REF_NODE,TYPE,TREE_OBJ,RB) { }, // node created + ondelete : function(NODE,TREE_OBJ,RB) { }, // node deleted + onopen : function(NODE,TREE_OBJ) { }, // node opened + onopen_all : function(TREE_OBJ) { }, // all nodes opened + onclose_all : function(TREE_OBJ) { }, // all nodes closed + onclose : function(NODE,TREE_OBJ) { }, // node closed + error : function(TEXT,TREE_OBJ) { }, // error occured + ondblclk : function(NODE,TREE_OBJ) { TREE_OBJ.toggle_branch.call(TREE_OBJ, NODE); TREE_OBJ.select_branch.call(TREE_OBJ, NODE); }, + onrgtclk : function(NODE,TREE_OBJ,EV) { }, // right click - to prevent use: EV.preventDefault(); EV.stopPropagation(); return false + onload : function(TREE_OBJ) { }, + oninit : function(TREE_OBJ) { }, + onfocus : function(TREE_OBJ) { }, + ondestroy : function(TREE_OBJ) { }, + onsearch : function(NODES, TREE_OBJ) { NODES.addClass("search"); }, + ondrop : function(NODE,REF_NODE,TYPE,TREE_OBJ) { }, + check : function(RULE,NODE,VALUE,TREE_OBJ) { return VALUE; }, + check_move : function(NODE,REF_NODE,TYPE,TREE_OBJ) { return true; } + }, + plugins : { } + }, + + create : function () { return new tree_component(); }, + focused : function () { return tree_component.inst[tree_component.focused]; }, + reference : function (obj) { + var o = $(obj); + if(!o.size()) o = $("#" + obj); + if(!o.size()) return null; + o = (o.is(".tree")) ? o.attr("id") : o.parents(".tree:eq(0)").attr("id"); + return tree_component.inst[o] || null; + }, + rollback : function (data) { + for(var i in data) { + if(!data.hasOwnProperty(i)) continue; + var tmp = tree_component.inst[i]; + var lock = !tmp.locked; + + // if not locked - lock the tree + if(lock) tmp.lock(true); + // Cancel ongoing rename + tmp.inp = false; + tmp.container.html(data[i].html).find(".dragged").removeClass("dragged").end().find(".hover").removeClass("hover"); + + if(data[i].selected) { + tmp.selected = $("#" + data[i].selected); + tmp.selected_arr = []; + tmp.container + .find("a.clicked").each( function () { + tmp.selected_arr.push(tmp.get_node(this)); + }); + } + // if this function set the lock - unlock + if(lock) tmp.lock(false); + + delete lock; + delete tmp; + } + }, + drop_mode : function (opts) { + opts = $.extend(opts, { show : false, type : "default", str : "Foreign node" }); + tree_component.drag_drop.foreign = true; + tree_component.drag_drop.isdown = true; + tree_component.drag_drop.moving = true; + tree_component.drag_drop.appended = false; + tree_component.drag_drop.f_type = opts.type; + tree_component.drag_drop.f_data = opts; + + + if(!opts.show) { + tree_component.drag_drop.drag_help = false; + tree_component.drag_drop.drag_node = false; + } + else { + tree_component.drag_drop.drag_help = $(""); + tree_component.drag_drop.drag_node = tree_component.drag_drop.drag_help.find("li:eq(0)"); + } + if($.tree.drag_start !== false) $.tree.drag_start.call(null, false); + }, + drag_start : false, + drag : false, + drag_end : false + }; + $.fn.tree = function (opts) { + return this.each(function() { + var conf = $.extend({},opts); + if(tree_component.inst && tree_component.inst[$(this).attr('id')]) tree_component.inst[$(this).attr('id')].destroy(); + if(conf !== false) new tree_component().init(this, conf); + }); + }; + + // core + function tree_component () { + return { + cntr : ++tree_component.cntr, + settings : $.extend({},$.tree.defaults), + + init : function(elem, conf) { + var _this = this; + this.container = $(elem); + if(this.container.size == 0) return false; + tree_component.inst[this.cntr] = this; + if(!this.container.attr("id")) this.container.attr("id","jstree_" + this.cntr); + tree_component.inst[this.container.attr("id")] = tree_component.inst[this.cntr]; + tree_component.focused = this.cntr; + this.settings = $.extend(true, {}, this.settings, conf); + + // DEAL WITH LANGUAGE VERSIONS + if(this.settings.languages && this.settings.languages.length) { + this.current_lang = this.settings.languages[0]; + var st = false; + var id = "#" + this.container.attr("id"); + for(var ln = 0; ln < this.settings.languages.length; ln++) { + st = tree_component.add_css(id + " ." + this.settings.languages[ln]); + if(st !== false) st.style.display = (this.settings.languages[ln] == this.current_lang) ? "" : "none"; + } + } + else this.current_lang = false; + // THEMES + this.container.addClass("tree"); + if(this.settings.ui.theme_name !== false) { + if(this.settings.ui.theme_path === false) { + $("script").each(function () { + if(this.src.toString().match(/jquery\.tree.*?js$/)) { _this.settings.ui.theme_path = this.src.toString().replace(/jquery\.tree.*?js$/, "") + "themes/" + _this.settings.ui.theme_name + "/style.css"; return false; } + }); + } + if(this.settings.ui.theme_path != "" && $.inArray(this.settings.ui.theme_path, tree_component.themes) == -1) { + tree_component.add_sheet({ url : this.settings.ui.theme_path }); + tree_component.themes.push(this.settings.ui.theme_path); + } + this.container.addClass("tree-" + this.settings.ui.theme_name); + } + // TYPE ICONS + var type_icons = ""; + for(var t in this.settings.types) { + if(!this.settings.types.hasOwnProperty(t)) continue; + if(!this.settings.types[t].icon) continue; + if( this.settings.types[t].icon.image || this.settings.types[t].icon.position) { + if(t == "default") type_icons += "#" + this.container.attr("id") + " li > a ins { "; + else type_icons += "#" + this.container.attr("id") + " li[rel=" + t + "] > a ins { "; + if(this.settings.types[t].icon.image) type_icons += " background-image:url(" + this.settings.types[t].icon.image + "); "; + if(this.settings.types[t].icon.position) type_icons += " background-position:" + this.settings.types[t].icon.position + "; "; + type_icons += "} "; + } + } + if(type_icons != "") tree_component.add_sheet({ str : type_icons }); + + if(this.settings.rules.multiple) this.selected_arr = []; + this.offset = false; + this.hovered = false; + this.locked = false; + + if(tree_component.drag_drop.marker === false) tree_component.drag_drop.marker = $("
").attr({ id : "jstree-marker" }).hide().appendTo("body"); + this.callback("oninit", [this]); + this.refresh(); + this.attach_events(); + this.focus(); + }, + refresh : function (obj) { + if(this.locked) return this.error("LOCKED"); + var _this = this; + if(obj && !this.settings.data.async) obj = false; + this.is_partial_refresh = obj ? true : false; + + // SAVE OPENED + this.opened = Array(); + if(this.settings.opened != false) { + $.each(this.settings.opened, function (i, item) { + if(this.replace(/^#/,"").length > 0) { _this.opened.push("#" + this.replace(/^#/,"")); } + }); + this.settings.opened = false; + } + else { + this.container.find("li.open").each(function (i) { if(this.id) { _this.opened.push("#" + this.id); } }); + } + + // SAVE SELECTED + if(this.selected) { + this.settings.selected = Array(); + if(obj) { + $(obj).find("li:has(a.clicked)").each(function () { + if(this.id) _this.settings.selected.push("#" + this.id); + }); + } + else { + if(this.selected_arr) { + $.each(this.selected_arr, function () { + if(this.attr("id")) _this.settings.selected.push("#" + this.attr("id")); + }); + } + else { + if(this.selected.attr("id")) this.settings.selected.push("#" + this.selected.attr("id")); + } + } + } + else if(this.settings.selected !== false) { + var tmp = Array(); + if((typeof this.settings.selected).toLowerCase() == "object") { + $.each(this.settings.selected, function () { + if(this.replace(/^#/,"").length > 0) tmp.push("#" + this.replace(/^#/,"")); + }); + } + else { + if(this.settings.selected.replace(/^#/,"").length > 0) tmp.push("#" + this.settings.selected.replace(/^#/,"")); + } + this.settings.selected = tmp; + } + + if(obj && this.settings.data.async) { + this.opened = Array(); + obj = this.get_node(obj); + obj.find("li.open").each(function (i) { _this.opened.push("#" + this.id); }); + if(obj.hasClass("open")) obj.removeClass("open").addClass("closed"); + if(obj.hasClass("leaf")) obj.removeClass("leaf"); + obj.children("ul:eq(0)").html(""); + return this.open_branch(obj, true, function () { _this.reselect.apply(_this); }); + } + + var _this = this; + var _datastore = new $.tree.datastores[this.settings.data.type](); + if(this.container.children("ul").size() == 0) { + this.container.html(""); + } + _datastore.load(this.callback("beforedata",[false,this]),this,this.settings.data.opts,function(data) { + data = _this.callback("ondata",[data, _this]); + _datastore.parse(data,_this,_this.settings.data.opts,function(str) { + str = _this.callback("onparse", [str, _this]); + _this.container.empty().append($("
    ").html(str)); + _this.container.find("li:last-child").addClass("last").end().find("li:has(ul)").not(".open").addClass("closed"); + _this.container.find("li").not(".open").not(".closed").addClass("leaf"); + _this.reselect(); + }); + }); + }, + reselect : function (is_callback) { + var _this = this; + + if(!is_callback) this.cl_count = 0; + else this.cl_count --; + // REOPEN BRANCHES + if(this.opened && this.opened.length) { + var opn = false; + for(var j = 0; this.opened && j < this.opened.length; j++) { + if(this.settings.data.async) { + var tmp = this.get_node(this.opened[j]); + if(tmp.size() && tmp.hasClass("closed") > 0) { + opn = true; + var tmp = this.opened[j].toString().replace('/','\\/'); + delete this.opened[j]; + this.open_branch(tmp, true, function () { _this.reselect.apply(_this, [true]); } ); + this.cl_count ++; + } + } + else this.open_branch(this.opened[j], true); + } + if(this.settings.data.async && opn) return; + if(this.cl_count > 0) return; + delete this.opened; + } + if(this.cl_count > 0) return; + + // DOTS and RIGHT TO LEFT + this.container.css("direction","ltr").children("ul:eq(0)").addClass("ltr"); + if(this.settings.ui.dots == false) this.container.children("ul:eq(0)").addClass("no_dots"); + + // REPOSITION SCROLL + if(this.scrtop) { + this.container.scrollTop(_this.scrtop); + delete this.scrtop; + } + // RESELECT PREVIOUSLY SELECTED + if(this.settings.selected !== false) { + $.each(this.settings.selected, function (i) { + if(_this.is_partial_refresh) _this.select_branch($(_this.settings.selected[i].toString().replace('/','\\/'), _this.container), (_this.settings.rules.multiple !== false) ); + else _this.select_branch($(_this.settings.selected[i].toString().replace('/','\\/'), _this.container), (_this.settings.rules.multiple !== false && i > 0) ); + }); + this.settings.selected = false; + } + this.callback("onload", [_this]); + }, + + get : function (obj, format, opts) { + if(!format) format = this.settings.data.type; + if(!opts) opts = this.settings.data.opts; + return new $.tree.datastores[format]().get(obj, this, opts); + }, + + attach_events : function () { + var _this = this; + + this.container + .bind("mousedown.jstree", function (event) { + if(tree_component.drag_drop.isdown) { + tree_component.drag_drop.move_type = false; + event.preventDefault(); + event.stopPropagation(); + event.stopImmediatePropagation(); + return false; + } + }) + .bind("mouseup.jstree", function (event) { + setTimeout( function() { _this.focus.apply(_this); }, 5); + }) + .bind("click.jstree", function (event) { + //event.stopPropagation(); + return true; + }); + $("li", this.container.get(0)) + .live("click", function(event) { // WHEN CLICK IS ON THE ARROW + if(event.target.tagName != "LI") return true; + _this.off_height(); + if(event.pageY - $(event.target).offset().top > _this.li_height) return true; + _this.toggle_branch.apply(_this, [event.target]); + event.stopPropagation(); + return false; + }); + $("a", this.container.get(0)) + .live("click", function (event) { // WHEN CLICK IS ON THE TEXT OR ICON + if(event.which && event.which == 3) return true; + if(_this.locked) { + event.preventDefault(); + event.target.blur(); + return _this.error("LOCKED"); + } + _this.select_branch.apply(_this, [event.target, event.ctrlKey || _this.settings.rules.multiple == "on"]); + if(_this.inp) { _this.inp.blur(); } + event.preventDefault(); + event.target.blur(); + return false; + }) + .live("dblclick", function (event) { // WHEN DOUBLECLICK ON TEXT OR ICON + if(_this.locked) { + event.preventDefault(); + event.stopPropagation(); + event.target.blur(); + return _this.error("LOCKED"); + } + _this.callback("ondblclk", [_this.get_node(event.target).get(0), _this]); + event.preventDefault(); + event.stopPropagation(); + event.target.blur(); + }) + .live("contextmenu", function (event) { + if(_this.locked) { + event.target.blur(); + return _this.error("LOCKED"); + } + return _this.callback("onrgtclk", [_this.get_node(event.target).get(0), _this, event]); + }) + .live("mouseover", function (event) { + if(_this.locked) { + event.preventDefault(); + event.stopPropagation(); + return _this.error("LOCKED"); + } + if(_this.hovered !== false && (event.target.tagName == "A" || event.target.tagName == "INS")) { + _this.hovered.children("a").removeClass("hover"); + _this.hovered = false; + } + _this.callback("onhover",[_this.get_node(event.target).get(0), _this]); + }) + .live("mousedown", function (event) { + if(_this.settings.rules.drag_button == "left" && event.which && event.which != 1) return true; + if(_this.settings.rules.drag_button == "right" && event.which && event.which != 3) return true; + _this.focus.apply(_this); + if(_this.locked) return _this.error("LOCKED"); + // SELECT LIST ITEM NODE + var obj = _this.get_node(event.target); + // IF ITEM IS DRAGGABLE + if(_this.settings.rules.multiple != false && _this.selected_arr.length > 1 && obj.children("a:eq(0)").hasClass("clicked")) { + var counter = 0; + for(var i in _this.selected_arr) { + if(!_this.selected_arr.hasOwnProperty(i)) continue; + if(_this.check("draggable", _this.selected_arr[i])) { + _this.selected_arr[i].addClass("dragged"); + tree_component.drag_drop.origin_tree = _this; + counter ++; + } + } + if(counter > 0) { + if(_this.check("draggable", obj)) tree_component.drag_drop.drag_node = obj; + else tree_component.drag_drop.drag_node = _this.container.find("li.dragged:eq(0)"); + tree_component.drag_drop.isdown = true; + tree_component.drag_drop.drag_help = $("
    ").append("
      "); + var tmp = tree_component.drag_drop.drag_node.clone(); + if(_this.settings.languages.length > 0) tmp.find("a").not("." + _this.current_lang).hide(); + tree_component.drag_drop.drag_help.children("ul:eq(0)").append(tmp); + tree_component.drag_drop.drag_help.find("li:eq(0)").removeClass("last").addClass("last").children("a").html(" Multiple selection").end().children("ul").remove(); + + tree_component.drag_drop.dragged = _this.container.find("li.dragged"); + } + } + else { + if(_this.check("draggable", obj)) { + tree_component.drag_drop.drag_node = obj; + tree_component.drag_drop.drag_help = $("
      ").append("
        "); + var tmp = obj.clone(); + if(_this.settings.languages.length > 0) tmp.find("a").not("." + _this.current_lang).hide(); + tree_component.drag_drop.drag_help.children("ul:eq(0)").append(tmp); + tree_component.drag_drop.drag_help.find("li:eq(0)").removeClass("last").addClass("last"); + tree_component.drag_drop.isdown = true; + tree_component.drag_drop.foreign = false; + tree_component.drag_drop.origin_tree = _this; + obj.addClass("dragged"); + + tree_component.drag_drop.dragged = _this.container.find("li.dragged"); + } + } + tree_component.drag_drop.init_x = event.pageX; + tree_component.drag_drop.init_y = event.pageY; + obj.blur(); + event.preventDefault(); + event.stopPropagation(); + return false; + }); + }, + focus : function () { + if(this.locked) return false; + if(tree_component.focused != this.cntr) { + tree_component.focused = this.cntr; + this.callback("onfocus",[this]); + } + }, + + off_height : function () { + if(this.offset === false) { + this.container.css({ position : "relative" }); + this.offset = this.container.offset(); + var tmp = 0; + tmp = parseInt($.curCSS(this.container.get(0), "paddingTop", true),10); + if(tmp) this.offset.top += tmp; + tmp = parseInt($.curCSS(this.container.get(0), "borderTopWidth", true),10); + if(tmp) this.offset.top += tmp; + this.container.css({ position : "" }); + } + if(!this.li_height) { + var tmp = this.container.find("ul li.closed, ul li.leaf").eq(0); + this.li_height = tmp.height(); + if(tmp.children("ul:eq(0)").size()) this.li_height -= tmp.children("ul:eq(0)").height(); + if(!this.li_height) this.li_height = 18; + } + }, + scroll_check : function (x,y) { + var _this = this; + var cnt = _this.container; + var off = _this.container.offset(); + + var st = cnt.scrollTop(); + var sl = cnt.scrollLeft(); + // DETECT HORIZONTAL SCROLL + var h_cor = (cnt.get(0).scrollWidth > cnt.width()) ? 40 : 20; + + if(y - off.top < 20) cnt.scrollTop(Math.max( (st - _this.settings.ui.scroll_spd) ,0)); // NEAR TOP + if(cnt.height() - (y - off.top) < h_cor) cnt.scrollTop(st + _this.settings.ui.scroll_spd); // NEAR BOTTOM + if(x - off.left < 20) cnt.scrollLeft(Math.max( (sl - _this.settings.ui.scroll_spd),0)); // NEAR LEFT + if(cnt.width() - (x - off.left) < 40) cnt.scrollLeft(sl + _this.settings.ui.scroll_spd); // NEAR RIGHT + + if(cnt.scrollLeft() != sl || cnt.scrollTop() != st) { + tree_component.drag_drop.move_type = false; + tree_component.drag_drop.ref_node = false; + tree_component.drag_drop.marker.hide(); + } + tree_component.drag_drop.scroll_time = setTimeout( function() { _this.scroll_check(x,y); }, 50); + }, + scroll_into_view : function (obj) { + obj = obj ? this.get_node(obj) : this.selected; + if(!obj) return false; + var off_t = obj.offset().top; + var beg_t = this.container.offset().top; + var end_t = beg_t + this.container.height(); + var h_cor = (this.container.get(0).scrollWidth > this.container.width()) ? 40 : 20; + if(off_t + 5 < beg_t) this.container.scrollTop(this.container.scrollTop() - (beg_t - off_t + 5) ); + if(off_t + h_cor > end_t) this.container.scrollTop(this.container.scrollTop() + (off_t + h_cor - end_t) ); + }, + + get_node : function (obj) { + return $(obj).closest("li"); + }, + get_type : function (obj) { + obj = !obj ? this.selected : this.get_node(obj); + if(!obj) return; + var tmp = obj.attr(this.settings.rules.type_attr); + return tmp || "default"; + }, + set_type : function (str, obj) { + obj = !obj ? this.selected : this.get_node(obj); + if(!obj || !str) return; + obj.attr(this.settings.rules.type_attr, str); + }, + get_text : function (obj, lang) { + obj = this.get_node(obj); + if(!obj || obj.size() == 0) return ""; + if(this.settings.languages && this.settings.languages.length) { + lang = lang ? lang : this.current_lang; + obj = obj.children("a." + lang); + } + else obj = obj.children("a:visible"); + var val = ""; + obj.contents().each(function () { + if(this.nodeType == 3) { val = this.data; return false; } + }); + return val; + }, + + check : function (rule, obj) { + if(this.locked) return false; + var v = false; + // if root node + if(obj === -1) { if(typeof this.settings.rules[rule] != "undefined") v = this.settings.rules[rule]; } + else { + obj = !obj ? this.selected : this.get_node(obj); + if(!obj) return; + var t = this.get_type(obj); + if(typeof this.settings.types[t] != "undefined" && typeof this.settings.types[t][rule] != "undefined") v = this.settings.types[t][rule]; + else if(typeof this.settings.types["default"] != "undefined" && typeof this.settings.types["default"][rule] != "undefined") v = this.settings.types["default"][rule]; + } + if(typeof v == "function") v = v.call(null, obj, this); + v = this.callback("check", [rule, obj, v, this]); + return v; + }, + check_move : function (nod, ref_node, how) { + if(this.locked) return false; + if($(ref_node).closest("li.dragged").size()) return false; + + var tree1 = nod.parents(".tree:eq(0)").get(0); + var tree2 = ref_node.parents(".tree:eq(0)").get(0); + // if different trees + if(tree1 && tree1 != tree2) { + var m = $.tree.reference(tree2.id).settings.rules.multitree; + if(m == "none" || ($.isArray(m) && $.inArray(tree1.id, m) == -1)) return false; + } + + var p = (how != "inside") ? this.parent(ref_node) : this.get_node(ref_node); + nod = this.get_node(nod); + if(p == false) return false; + var r = { + max_depth : this.settings.rules.use_max_depth ? this.check("max_depth", p) : -1, + max_children : this.settings.rules.use_max_children ? this.check("max_children", p) : -1, + valid_children : this.check("valid_children", p) + }; + var nod_type = (typeof nod == "string") ? nod : this.get_type(nod); + if(typeof r.valid_children != "undefined" && (r.valid_children == "none" || (typeof r.valid_children == "object" && $.inArray(nod_type, $.makeArray(r.valid_children)) == -1))) return false; + + if(this.settings.rules.use_max_children) { + if(typeof r.max_children != "undefined" && r.max_children != -1) { + if(r.max_children == 0) return false; + var c_count = 1; + if(tree_component.drag_drop.moving == true && tree_component.drag_drop.foreign == false) { + c_count = tree_component.drag_drop.dragged.size(); + c_count = c_count - p.find('> ul > li.dragged').size(); + } + if(r.max_children < p.find('> ul > li').size() + c_count) return false; + } + } + + if(this.settings.rules.use_max_depth) { + if(typeof r.max_depth != "undefined" && r.max_depth === 0) return this.error("MOVE: MAX-DEPTH REACHED"); + // check for max_depth up the chain + var mx = (r.max_depth > 0) ? r.max_depth : false; + var i = 0; + var t = p; + while(t !== -1) { + t = this.parent(t); + i ++; + var m = this.check("max_depth",t); + if(m >= 0) { + mx = (mx === false) ? (m - i) : Math.min(mx, m - i); + } + if(mx !== false && mx <= 0) return this.error("MOVE: MAX-DEPTH REACHED"); + } + if(mx !== false && mx <= 0) return this.error("MOVE: MAX-DEPTH REACHED"); + if(mx !== false) { + var incr = 1; + if(typeof nod != "string") { + var t = nod; + // possible async problem - when nodes are not all loaded down the chain + while(t.size() > 0) { + if(mx - incr < 0) return this.error("MOVE: MAX-DEPTH REACHED"); + t = t.children("ul").children("li"); + incr ++; + } + } + } + } + if(this.callback("check_move", [nod, ref_node, how, this]) == false) return false; + return true; + }, + + hover_branch : function (obj) { + if(this.locked) return this.error("LOCKED"); + var _this = this; + var obj = _this.get_node(obj); + if(!obj.size()) return this.error("HOVER: NOT A VALID NODE"); + if(!_this.check("clickable", obj)) return this.error("SELECT: NODE NOT SELECTABLE"); + if(this.hovered) this.hovered.children("A").removeClass("hover"); + this.hovered = obj; + this.hovered.children("a").addClass("hover"); + this.scroll_into_view(this.hovered); + }, + select_branch : function (obj, multiple) { + if(this.locked) return this.error("LOCKED"); + if(!obj && this.hovered !== false) obj = this.hovered; + var _this = this; + obj = _this.get_node(obj); + if(!obj.size()) return this.error("SELECT: NOT A VALID NODE"); + obj.children("a").removeClass("hover"); + // CHECK AGAINST RULES FOR SELECTABLE NODES + if(!_this.check("clickable", obj)) return this.error("SELECT: NODE NOT SELECTABLE"); + if(_this.callback("beforechange",[obj.get(0),_this]) === false) return this.error("SELECT: STOPPED BY USER"); + // IF multiple AND obj IS ALREADY SELECTED - DESELECT IT + if(this.settings.rules.multiple != false && multiple && obj.children("a.clicked").size() > 0) { + return this.deselect_branch(obj); + } + if(this.settings.rules.multiple != false && multiple) { + this.selected_arr.push(obj); + } + if(this.settings.rules.multiple != false && !multiple) { + for(var i in this.selected_arr) { + if(!this.selected_arr.hasOwnProperty(i)) continue; + this.selected_arr[i].children("A").removeClass("clicked"); + this.callback("ondeselect", [this.selected_arr[i].get(0), _this]); + } + this.selected_arr = []; + this.selected_arr.push(obj); + if(this.selected && this.selected.children("A").hasClass("clicked")) { + this.selected.children("A").removeClass("clicked"); + this.callback("ondeselect", [this.selected.get(0), _this]); + } + } + if(!this.settings.rules.multiple) { + if(this.selected) { + this.selected.children("A").removeClass("clicked"); + this.callback("ondeselect", [this.selected.get(0), _this]); + } + } + // SAVE NEWLY SELECTED + this.selected = obj; + if(this.hovered !== false) { + this.hovered.children("A").removeClass("hover"); + this.hovered = obj; + } + + // FOCUS NEW NODE AND OPEN ALL PARENT NODES IF CLOSED + this.selected.children("a").addClass("clicked").end().parents("li.closed").each( function () { _this.open_branch(this, true); }); + + // SCROLL SELECTED NODE INTO VIEW + this.scroll_into_view(this.selected); + + this.callback("onselect", [this.selected.get(0), _this]); + this.callback("onchange", [this.selected.get(0), _this]); + }, + deselect_branch : function (obj) { + if(this.locked) return this.error("LOCKED"); + var _this = this; + var obj = this.get_node(obj); + if(obj.children("a.clicked").size() == 0) return this.error("DESELECT: NODE NOT SELECTED"); + + obj.children("a").removeClass("clicked"); + this.callback("ondeselect", [obj.get(0), _this]); + if(this.settings.rules.multiple != false && this.selected_arr.length > 1) { + this.selected_arr = []; + this.container.find("a.clicked").filter(":first-child").parent().each(function () { + _this.selected_arr.push($(this)); + }); + if(obj.get(0) == this.selected.get(0)) { + this.selected = this.selected_arr[0]; + } + } + else { + if(this.settings.rules.multiple != false) this.selected_arr = []; + this.selected = false; + } + this.callback("onchange", [obj.get(0), _this]); + }, + toggle_branch : function (obj) { + if(this.locked) return this.error("LOCKED"); + var obj = this.get_node(obj); + if(obj.hasClass("closed")) return this.open_branch(obj); + if(obj.hasClass("open")) return this.close_branch(obj); + }, + open_branch : function (obj, disable_animation, callback) { + var _this = this; + + if(this.locked) return this.error("LOCKED"); + var obj = this.get_node(obj); + if(!obj.size()) return this.error("OPEN: NO SUCH NODE"); + if(obj.hasClass("leaf")) return this.error("OPEN: OPENING LEAF NODE"); + if(this.settings.data.async && obj.find("li").size() == 0) { + + if(this.callback("beforeopen",[obj.get(0),this]) === false) return this.error("OPEN: STOPPED BY USER"); + + obj.children("ul:eq(0)").remove().end().append(""); + obj.removeClass("closed").addClass("open"); + + var _datastore = new $.tree.datastores[this.settings.data.type](); + _datastore.load(this.callback("beforedata",[obj,this]),this,this.settings.data.opts,function(data){ + data = _this.callback("ondata", [data, _this]); + if(!data || data.length == 0) { + obj.removeClass("closed").removeClass("open").addClass("leaf").children("ul").remove(); + if(callback) callback.call(); + return; + } + _datastore.parse(data,_this,_this.settings.data.opts,function(str){ + str = _this.callback("onparse", [str, _this]); + // if(obj.children('ul:eq(0)').children('li').size() > 1) obj.children("ul").find('.loaading').parent().replaceWith(str); else + obj.children("ul:eq(0)").replaceWith($("
          ").html(str)); + obj.find("li:last-child").addClass("last").end().find("li:has(ul)").not(".open").addClass("closed"); + obj.find("li").not(".open").not(".closed").addClass("leaf"); + _this.open_branch.apply(_this, [obj]); + if(callback) callback.call(); + }); + }); + return true; + } + else { + if(!this.settings.data.async) { + if(this.callback("beforeopen",[obj.get(0),this]) === false) return this.error("OPEN: STOPPED BY USER"); + } + if(parseInt(this.settings.ui.animation) > 0 && !disable_animation ) { + obj.children("ul:eq(0)").css("display","none"); + obj.removeClass("closed").addClass("open"); + obj.children("ul:eq(0)").slideDown(parseInt(this.settings.ui.animation), function() { + $(this).css("display",""); + if(callback) callback.call(); + }); + } else { + obj.removeClass("closed").addClass("open"); + if(callback) callback.call(); + } + this.callback("onopen", [obj.get(0), this]); + return true; + } + }, + close_branch : function (obj, disable_animation) { + if(this.locked) return this.error("LOCKED"); + var _this = this; + var obj = this.get_node(obj); + if(!obj.size()) return this.error("CLOSE: NO SUCH NODE"); + if(_this.callback("beforeclose",[obj.get(0),_this]) === false) return this.error("CLOSE: STOPPED BY USER"); + if(parseInt(this.settings.ui.animation) > 0 && !disable_animation && obj.children("ul:eq(0)").size() == 1) { + obj.children("ul:eq(0)").slideUp(parseInt(this.settings.ui.animation), function() { + if(obj.hasClass("open")) obj.removeClass("open").addClass("closed"); + $(this).css("display",""); + }); + } + else { + if(obj.hasClass("open")) obj.removeClass("open").addClass("closed"); + } + if(this.selected && this.settings.ui.selected_parent_close !== false && obj.children("ul:eq(0)").find("a.clicked").size() > 0) { + obj.find("li:has(a.clicked)").each(function() { + _this.deselect_branch(this); + }); + if(this.settings.ui.selected_parent_close == "select_parent" && obj.children("a.clicked").size() == 0) this.select_branch(obj, (this.settings.rules.multiple != false && this.selected_arr.length > 0) ); + } + this.callback("onclose", [obj.get(0), this]); + }, + open_all : function (obj, callback) { + if(this.locked) return this.error("LOCKED"); + var _this = this; + obj = obj ? this.get_node(obj) : this.container; + + var s = obj.find("li.closed").size(); + if(!callback) this.cl_count = 0; + else this.cl_count --; + if(s > 0) { + this.cl_count += s; + // maybe add .andSelf() + obj.find("li.closed").each( function () { var __this = this; _this.open_branch.apply(_this, [this, true, function() { _this.open_all.apply(_this, [__this, true]); } ]); }); + } + else if(this.cl_count == 0) this.callback("onopen_all",[this]); + }, + close_all : function (obj) { + if(this.locked) return this.error("LOCKED"); + var _this = this; + obj = obj ? this.get_node(obj) : this.container; + // maybe add .andSelf() + obj.find("li.open").each( function () { _this.close_branch(this, true); }); + this.callback("onclose_all",[this]); + }, + + set_lang : function (i) { + if(!$.isArray(this.settings.languages) || this.settings.languages.length == 0) return false; + if(this.locked) return this.error("LOCKED"); + if(!$.inArray(i,this.settings.languages) && typeof this.settings.languages[i] != "undefined") i = this.settings.languages[i]; + if(typeof i == "undefined") return false; + if(i == this.current_lang) return true; + var st = false; + var id = "#" + this.container.attr("id"); + st = tree_component.get_css(id + " ." + this.current_lang); + if(st !== false) st.style.display = "none"; + st = tree_component.get_css(id + " ." + i); + if(st !== false) st.style.display = ""; + this.current_lang = i; + return true; + }, + get_lang : function () { + if(!$.isArray(this.settings.languages) || this.settings.languages.length == 0) return false; + return this.current_lang; + }, + + create : function (obj, ref_node, position) { + if(this.locked) return this.error("LOCKED"); + + var root = false; + if(ref_node == -1) { root = true; ref_node = this.container; } + else ref_node = ref_node ? this.get_node(ref_node) : this.selected; + + if(!root && (!ref_node || !ref_node.size())) return this.error("CREATE: NO NODE SELECTED"); + + var pos = position; + + var tmp = ref_node; // for type calculation + if(position == "before") { + position = ref_node.parent().children().index(ref_node); + ref_node = ref_node.parents("li:eq(0)"); + } + if(position == "after") { + position = ref_node.parent().children().index(ref_node) + 1; + ref_node = ref_node.parents("li:eq(0)"); + } + if(!root && ref_node.size() == 0) { root = true; ref_node = this.container; } + + if(!root) { + if(!this.check("creatable", ref_node)) return this.error("CREATE: CANNOT CREATE IN NODE"); + if(ref_node.hasClass("closed")) { + if(this.settings.data.async && ref_node.children("ul").size() == 0) { + var _this = this; + return this.open_branch(ref_node, true, function () { _this.create.apply(_this, [obj, ref_node, position]); } ); + } + else this.open_branch(ref_node, true); + } + } + + // creating new object to pass to parseJSON + var torename = false; + if(!obj) obj = {}; + else obj = $.extend(true, {}, obj); + if(!obj.attributes) obj.attributes = {}; + if(!obj.attributes[this.settings.rules.type_attr]) obj.attributes[this.settings.rules.type_attr] = this.get_type(tmp) || "default"; + if(this.settings.languages.length) { + if(!obj.data) { obj.data = {}; torename = true; } + for(var i = 0; i < this.settings.languages.length; i++) { + if(!obj.data[this.settings.languages[i]]) obj.data[this.settings.languages[i]] = ((typeof this.settings.lang.new_node).toLowerCase() != "string" && this.settings.lang.new_node[i]) ? this.settings.lang.new_node[i] : this.settings.lang.new_node; + } + } + else { + if(!obj.data) { obj.data = this.settings.lang.new_node; torename = true; } + } + + obj = this.callback("ondata",[obj, this]); + var obj_s = $.tree.datastores.json().parse(obj,this); + obj_s = this.callback("onparse", [obj_s, this]); + var $li = $(obj_s); + + if($li.children("ul").size()) { + if(!$li.is(".open")) $li.addClass("closed"); + } + else $li.addClass("leaf"); + $li.find("li:last-child").addClass("last").end().find("li:has(ul)").not(".open").addClass("closed"); + $li.find("li").not(".open").not(".closed").addClass("leaf"); + + var r = { + max_depth : this.settings.rules.use_max_depth ? this.check("max_depth", (root ? -1 : ref_node) ) : -1, + max_children : this.settings.rules.use_max_children ? this.check("max_children", (root ? -1 : ref_node) ) : -1, + valid_children : this.check("valid_children", (root ? -1 : ref_node) ) + }; + var nod_type = this.get_type($li); + if(typeof r.valid_children != "undefined" && (r.valid_children == "none" || ($.isArray(r.valid_children) && $.inArray(nod_type, r.valid_children) == -1))) return this.error("CREATE: NODE NOT A VALID CHILD"); + + if(this.settings.rules.use_max_children) { + if(typeof r.max_children != "undefined" && r.max_children != -1 && r.max_children >= this.children(ref_node).size()) return this.error("CREATE: MAX_CHILDREN REACHED"); + } + + if(this.settings.rules.use_max_depth) { + if(typeof r.max_depth != "undefined" && r.max_depth === 0) return this.error("CREATE: MAX-DEPTH REACHED"); + // check for max_depth up the chain + var mx = (r.max_depth > 0) ? r.max_depth : false; + var i = 0; + var t = ref_node; + + while(t !== -1 && !root) { + t = this.parent(t); + i ++; + var m = this.check("max_depth",t); + if(m >= 0) { + mx = (mx === false) ? (m - i) : Math.min(mx, m - i); + } + if(mx !== false && mx <= 0) return this.error("CREATE: MAX-DEPTH REACHED"); + } + if(mx !== false && mx <= 0) return this.error("CREATE: MAX-DEPTH REACHED"); + if(mx !== false) { + var incr = 1; + var t = $li; + while(t.size() > 0) { + if(mx - incr < 0) return this.error("CREATE: MAX-DEPTH REACHED"); + t = t.children("ul").children("li"); + incr ++; + } + } + } + + if((typeof position).toLowerCase() == "undefined" || position == "inside") + position = (this.settings.rules.createat == "top") ? 0 : ref_node.children("ul:eq(0)").children("li").size(); + if(ref_node.children("ul").size() == 0 || (root == true && ref_node.children("ul").children("li").size() == 0) ) { + if(!root) var a = this.moved($li,ref_node.children("a:eq(0)"),"inside", true); + else var a = this.moved($li,this.container.children("ul:eq(0)"),"inside", true); + } + else if(pos == "before" && ref_node.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").size()) + var a = this.moved($li,ref_node.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").children("a:eq(0)"),"before", true); + else if(pos == "after" && ref_node.children("ul:eq(0)").children("li:nth-child(" + (position) + ")").size()) + var a = this.moved($li,ref_node.children("ul:eq(0)").children("li:nth-child(" + (position) + ")").children("a:eq(0)"),"after", true); + else if(ref_node.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").size()) + var a = this.moved($li,ref_node.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").children("a:eq(0)"),"before", true); + else + var a = this.moved($li,ref_node.children("ul:eq(0)").children("li:last").children("a:eq(0)"),"after",true); + + if(a === false) return this.error("CREATE: ABORTED"); + + if(torename) { + this.select_branch($li.children("a:eq(0)")); + this.rename(); + } + return $li; + }, + rename : function (obj, new_name) { + if(this.locked) return this.error("LOCKED"); + obj = obj ? this.get_node(obj) : this.selected; + var _this = this; + if(!obj || !obj.size()) return this.error("RENAME: NO NODE SELECTED"); + if(!this.check("renameable", obj)) return this.error("RENAME: NODE NOT RENAMABLE"); + if(!this.callback("beforerename",[obj.get(0), _this.current_lang, _this])) return this.error("RENAME: STOPPED BY USER"); + + obj.parents("li.closed").each(function () { _this.open_branch(this) }); + if(this.current_lang) obj = obj.find("a." + this.current_lang); + else obj = obj.find("a:first"); + + // Rollback + var rb = {}; + rb[this.container.attr("id")] = this.get_rollback(); + + var icn = obj.children("ins").clone(); + if((typeof new_name).toLowerCase() == "string") { + obj.text(new_name).prepend(icn); + _this.callback("onrename", [_this.get_node(obj).get(0), _this, rb]); + } + else { + var last_value = ""; + obj.contents().each(function () { + if(this.nodeType == 3) { last_value = this.data; return false; } + }); + _this.inp = $(""); + _this.inp + .val(last_value.replace(/&/g,"&").replace(/>/g,">").replace(/</g,"<")) + .bind("mousedown", function (event) { event.stopPropagation(); }) + .bind("mouseup", function (event) { event.stopPropagation(); }) + .bind("click", function (event) { event.stopPropagation(); }) + .bind("keyup", function (event) { + var key = event.keyCode || event.which; + if(key == 27) { this.value = last_value; this.blur(); return } + if(key == 13) { this.blur(); return; } + }); + _this.inp.blur(function(event) { + if(this.value == "") this.value = last_value; + obj.text(this.value).prepend(icn); + obj.get(0).style.display = ""; + obj.prevAll("span").remove(); + _this.inp = false; + _this.callback("onrename", [_this.get_node(obj).get(0), _this, rb]); + }); + + var spn = $("").addClass(obj.attr("class")).append(icn).append(_this.inp); + obj.get(0).style.display = "none"; + obj.parent().prepend(spn); + _this.inp.get(0).focus(); + _this.inp.get(0).select(); + } + }, + remove : function(obj) { + if(this.locked) return this.error("LOCKED"); + var _this = this; + + // Rollback + var rb = {}; + rb[this.container.attr("id")] = this.get_rollback(); + + if(obj && (!this.selected || this.get_node(obj).get(0) != this.selected.get(0) )) { + obj = this.get_node(obj); + if(obj.size()) { + if(!this.check("deletable", obj)) return this.error("DELETE: NODE NOT DELETABLE"); + if(!this.callback("beforedelete",[obj.get(0), _this])) return this.error("DELETE: STOPPED BY USER"); + $parent = obj.parent(); + if(obj.find("a.clicked").size()) { + var reset_selected = false; + _this.selected_arr = []; + this.container.find("a.clicked").filter(":first-child").parent().each(function () { + if(!reset_selected && this == _this.selected.get(0)) reset_selected = true; + if($(this).parents().index(obj) != -1) return true; + _this.selected_arr.push($(this)); + }); + if(reset_selected) this.selected = this.selected_arr[0] || false; + } + obj = obj.remove(); + $parent.children("li:last").addClass("last"); + if($parent.children("li").size() == 0) { + $li = $parent.parents("li:eq(0)"); + $li.removeClass("open").removeClass("closed").addClass("leaf").children("ul").remove(); + } + this.callback("ondelete", [obj.get(0), this, rb]); + } + } + else if(this.selected) { + if(!this.check("deletable", this.selected)) return this.error("DELETE: NODE NOT DELETABLE"); + if(!this.callback("beforedelete",[this.selected.get(0), _this])) return this.error("DELETE: STOPPED BY USER"); + $parent = this.selected.parent(); + var obj = this.selected; + if(this.settings.rules.multiple == false || this.selected_arr.length == 1) { + var stop = true; + var tmp = this.settings.ui.selected_delete == "select_previous" ? this.prev(this.selected) : false; + } + obj = obj.remove(); + $parent.children("li:last").addClass("last"); + if($parent.children("li").size() == 0) { + $li = $parent.parents("li:eq(0)"); + $li.removeClass("open").removeClass("closed").addClass("leaf").children("ul").remove(); + } + if(!stop && this.settings.rules.multiple != false) { + var _this = this; + this.selected_arr = []; + this.container.find("a.clicked").filter(":first-child").parent().each(function () { + _this.selected_arr.push($(this)); + }); + if(this.selected_arr.length > 0) { + this.selected = this.selected_arr[0]; + this.remove(); + } + } + if(stop && tmp) this.select_branch(tmp); + this.callback("ondelete", [obj.get(0), this, rb]); + } + else return this.error("DELETE: NO NODE SELECTED"); + }, + + next : function (obj, strict) { + obj = this.get_node(obj); + if(!obj.size()) return false; + if(strict) return (obj.nextAll("li").size() > 0) ? obj.nextAll("li:eq(0)") : false; + + if(obj.hasClass("open")) return obj.find("li:eq(0)"); + else if(obj.nextAll("li").size() > 0) return obj.nextAll("li:eq(0)"); + else return obj.parents("li").next("li").eq(0); + }, + prev : function(obj, strict) { + obj = this.get_node(obj); + if(!obj.size()) return false; + if(strict) return (obj.prevAll("li").size() > 0) ? obj.prevAll("li:eq(0)") : false; + + if(obj.prev("li").size()) { + var obj = obj.prev("li").eq(0); + while(obj.hasClass("open")) obj = obj.children("ul:eq(0)").children("li:last"); + return obj; + } + else return obj.parents("li:eq(0)").size() ? obj.parents("li:eq(0)") : false; + }, + parent : function(obj) { + obj = this.get_node(obj); + if(!obj.size()) return false; + return obj.parents("li:eq(0)").size() ? obj.parents("li:eq(0)") : -1; + }, + children : function(obj) { + if(obj === -1) return this.container.children("ul:eq(0)").children("li"); + + obj = this.get_node(obj); + if(!obj.size()) return false; + return obj.children("ul:eq(0)").children("li"); + }, + + toggle_dots : function () { + if(this.settings.ui.dots) { + this.settings.ui.dots = false; + this.container.children("ul:eq(0)").addClass("no_dots"); + } + else { + this.settings.ui.dots = true; + this.container.children("ul:eq(0)").removeClass("no_dots"); + } + }, + + callback : function (cb, args) { + var p = false; + var r = null; + for(var i in this.settings.plugins) { + if(typeof $.tree.plugins[i] != "object") continue; + p = $.tree.plugins[i]; + if(p.callbacks && typeof p.callbacks[cb] == "function") r = p.callbacks[cb].apply(this, args); + if(typeof r !== "undefined" && r !== null) { + if(cb == "ondata" || cb == "onparse") args[0] = r; // keep the chain if data or parse + else return r; + } + } + p = this.settings.callback[cb]; + if(typeof p == "function") return p.apply(null, args); + }, + get_rollback : function () { + var rb = {}; + rb.html = this.container.html(); + rb.selected = this.selected ? this.selected.attr("id") : false; + return rb; + }, + moved : function (what, where, how, is_new, is_copy, rb) { + var what = $(what); + var $parent = $(what).parents("ul:eq(0)"); + var $where = $(where); + if($where.is("ins")) $where = $where.parent(); + + // Rollback + if(!rb) { + var rb = {}; + rb[this.container.attr("id")] = this.get_rollback(); + if(!is_new) { + var tmp = what.size() > 1 ? what.eq(0).parents(".tree:eq(0)") : what.parents(".tree:eq(0)"); + if(tmp.get(0) != this.container.get(0)) { + tmp = tree_component.inst[tmp.attr("id")]; + rb[tmp.container.attr("id")] = tmp.get_rollback(); + } + delete tmp; + } + } + + if(how == "inside" && this.settings.data.async) { + var _this = this; + if(this.get_node($where).hasClass("closed")) { + return this.open_branch(this.get_node($where), true, function () { _this.moved.apply(_this, [what, where, how, is_new, is_copy, rb]); }); + } + if(this.get_node($where).find("> ul > li > a.loading").size() == 1) { + setTimeout(function () { _this.moved.apply(_this, [what, where, how, is_new, is_copy]); }, 200); + return; + } + } + + + // IF MULTIPLE + if(what.size() > 1) { + var _this = this; + var tmp = this.moved(what.eq(0), where, how, false, is_copy, rb); + what.each(function (i) { + if(i == 0) return; + if(tmp) { // if tmp is false - the previous move was a no-go + tmp = _this.moved(this, tmp.children("a:eq(0)"), "after", false, is_copy, rb); + } + }); + return what; + } + + if(is_copy) { + _what = what.clone(); + _what.each(function (i) { + this.id = this.id + "_copy"; + $(this).find("li").each(function () { + this.id = this.id + "_copy"; + }); + $(this).removeClass("dragged").find("a.clicked").removeClass("clicked").end().find("li.dragged").removeClass("dragged"); + }); + } + else _what = what; + if(is_new) { + if(!this.callback("beforecreate", [this.get_node(what).get(0), this.get_node(where).get(0),how,this])) return false; + } + else { + if(!this.callback("beforemove", [this.get_node(what).get(0), this.get_node(where).get(0),how,this])) return false; + } + + if(!is_new) { + var tmp = what.parents(".tree:eq(0)"); + // if different trees + if(tmp.get(0) != this.container.get(0)) { + tmp = tree_component.inst[tmp.attr("id")]; + + // if there are languages - otherwise - no cleanup needed + if(tmp.settings.languages.length) { + var res = []; + // if new tree has no languages - use current visible + if(this.settings.languages.length == 0) res.push("." + tmp.current_lang); + else { + for(var i in this.settings.languages) { + if(!this.settings.languages.hasOwnProperty(i)) continue; + for(var j in tmp.settings.languages) { + if(!tmp.settings.languages.hasOwnProperty(j)) continue; + if(this.settings.languages[i] == tmp.settings.languages[j]) res.push("." + this.settings.languages[i]); + } + } + } + if(res.length == 0) return this.error("MOVE: NO COMMON LANGUAGES"); + _what.find("a").not(res.join(",")).remove(); + } + _what.find("a.clicked").removeClass("clicked"); + } + } + what = _what; + + // ADD NODE TO NEW PLACE + switch(how) { + case "before": + $where.parents("ul:eq(0)").children("li.last").removeClass("last"); + $where.parent().before(what.removeClass("last")); + $where.parents("ul:eq(0)").children("li:last").addClass("last"); + break; + case "after": + $where.parents("ul:eq(0)").children("li.last").removeClass("last"); + $where.parent().after(what.removeClass("last")); + $where.parents("ul:eq(0)").children("li:last").addClass("last"); + break; + case "inside": + if($where.parent().children("ul:first").size()) { + if(this.settings.rules.createat == "top") { + $where.parent().children("ul:first").prepend(what.removeClass("last")).children("li:last").addClass("last"); + + // restored this section + var tmp_node = $where.parent().children("ul:first").children("li:first"); + if(tmp_node.size()) { + how = "before"; + where = tmp_node; + } + } + else { + // restored this section + var tmp_node = $where.parent().children("ul:first").children(".last"); + if(tmp_node.size()) { + how = "after"; + where = tmp_node; + } + + $where.parent().children("ul:first").children(".last").removeClass("last").end().append(what.removeClass("last")).children("li:last").addClass("last"); + } + } + else { + what.addClass("last"); + $where.parent().removeClass("leaf").append("
            "); + if(!$where.parent().hasClass("open")) $where.parent().addClass("closed"); + $where.parent().children("ul:first").prepend(what); + } + if($where.parent().hasClass("closed")) { this.open_branch($where); } + break; + default: + break; + } + // CLEANUP OLD PARENT + if($parent.find("li").size() == 0) { + var $li = $parent.parent(); + $li.removeClass("open").removeClass("closed").addClass("leaf"); + if(!$li.is(".tree")) $li.children("ul").remove(); + $li.parents("ul:eq(0)").children("li.last").removeClass("last").end().children("li:last").addClass("last"); + } + else { + $parent.children("li.last").removeClass("last"); + $parent.children("li:last").addClass("last"); + } + + // NO LONGER CORRECT WITH position PARAM - if(is_new && how != "inside") where = this.get_node(where).parents("li:eq(0)"); + if(is_copy) this.callback("oncopy", [this.get_node(what).get(0), this.get_node(where).get(0), how, this, rb]); + else if(is_new) this.callback("oncreate", [this.get_node(what).get(0), ($where.is("ul") ? -1 : this.get_node(where).get(0) ), how, this, rb]); + else this.callback("onmove", [this.get_node(what).get(0), this.get_node(where).get(0), how, this, rb]); + return what; + }, + error : function (code) { + this.callback("error",[code,this]); + return false; + }, + lock : function (state) { + this.locked = state; + if(this.locked) this.container.children("ul:eq(0)").addClass("locked"); + else this.container.children("ul:eq(0)").removeClass("locked"); + }, + cut : function (obj) { + if(this.locked) return this.error("LOCKED"); + obj = obj ? this.get_node(obj) : this.container.find("a.clicked").filter(":first-child").parent(); + if(!obj || !obj.size()) return this.error("CUT: NO NODE SELECTED"); + tree_component.cut_copy.copy_nodes = false; + tree_component.cut_copy.cut_nodes = obj; + }, + copy : function (obj) { + if(this.locked) return this.error("LOCKED"); + obj = obj ? this.get_node(obj) : this.container.find("a.clicked").filter(":first-child").parent(); + if(!obj || !obj.size()) return this.error("COPY: NO NODE SELECTED"); + tree_component.cut_copy.copy_nodes = obj; + tree_component.cut_copy.cut_nodes = false; + }, + paste : function (obj, position) { + if(this.locked) return this.error("LOCKED"); + + var root = false; + if(obj == -1) { root = true; obj = this.container; } + else obj = obj ? this.get_node(obj) : this.selected; + + if(!root && (!obj || !obj.size())) return this.error("PASTE: NO NODE SELECTED"); + if(!tree_component.cut_copy.copy_nodes && !tree_component.cut_copy.cut_nodes) return this.error("PASTE: NOTHING TO DO"); + + var _this = this; + + var pos = position; + + if(position == "before") { + position = obj.parent().children().index(obj); + obj = obj.parents("li:eq(0)"); + } + else if(position == "after") { + position = obj.parent().children().index(obj) + 1; + obj = obj.parents("li:eq(0)"); + } + else if((typeof position).toLowerCase() == "undefined" || position == "inside") { + position = (this.settings.rules.createat == "top") ? 0 : obj.children("ul:eq(0)").children("li").size(); + } + if(!root && obj.size() == 0) { root = true; obj = this.container; } + + if(tree_component.cut_copy.copy_nodes && tree_component.cut_copy.copy_nodes.size()) { + var ok = true; + if(!root && !this.check_move(tree_component.cut_copy.copy_nodes, obj.children("a:eq(0)"), "inside")) return false; + + if(obj.children("ul").size() == 0 || (root == true && obj.children("ul").children("li").size() == 0) ) { + if(!root) var a = this.moved(tree_component.cut_copy.copy_nodes,obj.children("a:eq(0)"),"inside", false, true); + else var a = this.moved(tree_component.cut_copy.copy_nodes,this.container.children("ul:eq(0)"),"inside", false, true); + } + else if(pos == "before" && obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").size()) + var a = this.moved(tree_component.cut_copy.copy_nodes,obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").children("a:eq(0)"),"before", false, true); + else if(pos == "after" && obj.children("ul:eq(0)").children("li:nth-child(" + (position) + ")").size()) + var a = this.moved(tree_component.cut_copy.copy_nodes,obj.children("ul:eq(0)").children("li:nth-child(" + (position) + ")").children("a:eq(0)"),"after", false, true); + else if(obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").size()) + var a = this.moved(tree_component.cut_copy.copy_nodes,obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").children("a:eq(0)"),"before", false, true); + else + var a = this.moved(tree_component.cut_copy.copy_nodes,obj.children("ul:eq(0)").children("li:last").children("a:eq(0)"),"after", false, true); + tree_component.cut_copy.copy_nodes = false; + } + if(tree_component.cut_copy.cut_nodes && tree_component.cut_copy.cut_nodes.size()) { + var ok = true; + obj.parents().andSelf().each(function () { + if(tree_component.cut_copy.cut_nodes.index(this) != -1) { + ok = false; + return false; + } + }); + if(!ok) return this.error("Invalid paste"); + if(!root && !this.check_move(tree_component.cut_copy.cut_nodes, obj.children("a:eq(0)"), "inside")) return false; + + if(obj.children("ul").size() == 0 || (root == true && obj.children("ul").children("li").size() == 0) ) { + if(!root) var a = this.moved(tree_component.cut_copy.cut_nodes,obj.children("a:eq(0)"),"inside"); + else var a = this.moved(tree_component.cut_copy.cut_nodes,this.container.children("ul:eq(0)"),"inside"); + } + else if(pos == "before" && obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").size()) + var a = this.moved(tree_component.cut_copy.cut_nodes,obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").children("a:eq(0)"),"before"); + else if(pos == "after" && obj.children("ul:eq(0)").children("li:nth-child(" + (position) + ")").size()) + var a = this.moved(tree_component.cut_copy.cut_nodes,obj.children("ul:eq(0)").children("li:nth-child(" + (position) + ")").children("a:eq(0)"),"after"); + else if(obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").size()) + var a = this.moved(tree_component.cut_copy.cut_nodes,obj.children("ul:eq(0)").children("li:nth-child(" + (position + 1) + ")").children("a:eq(0)"),"before"); + else + var a = this.moved(tree_component.cut_copy.cut_nodes,obj.children("ul:eq(0)").children("li:last").children("a:eq(0)"),"after"); + tree_component.cut_copy.cut_nodes = false; + } + }, + search : function(str, func) { + var _this = this; + if(!str || (this.srch && str != this.srch) ) { + this.srch = ""; + this.srch_opn = false; + this.container.find("a.search").removeClass("search"); + } + this.srch = str; + if(!str) return; + + if(!func) func = "contains"; + if(this.settings.data.async) { + if(!this.srch_opn) { + var dd = $.extend( { "search" : str } , this.callback("beforedata", [false, this] ) ); + $.ajax({ + type : this.settings.data.opts.method, + url : this.settings.data.opts.url, + data : dd, + dataType : "text", + success : function (data) { + _this.srch_opn = $.unique(data.split(",")); + _this.search.apply(_this,[str, func]); + } + }); + } + else if(this.srch_opn.length) { + if(this.srch_opn && this.srch_opn.length) { + var opn = false; + for(var j = 0; j < this.srch_opn.length; j++) { + if(this.get_node("#" + this.srch_opn[j]).size() > 0) { + opn = true; + var tmp = "#" + this.srch_opn[j]; + delete this.srch_opn[j]; + this.open_branch(tmp, true, function () { _this.search.apply(_this,[str, func]); } ); + } + } + if(!opn) { + this.srch_opn = []; + _this.search.apply(_this,[str, func]); + } + } + } + else { + this.srch_opn = false; + var selector = "a"; + // IF LANGUAGE VERSIONS + if(this.settings.languages.length) selector += "." + this.current_lang; + this.callback("onsearch", [this.container.find(selector + ":" + func + "('" + str + "')"), this]); + } + } + else { + var selector = "a"; + // IF LANGUAGE VERSIONS + if(this.settings.languages.length) selector += "." + this.current_lang; + var nn = this.container.find(selector + ":" + func + "('" + str + "')"); + nn.parents("li.closed").each( function () { _this.open_branch(this, true); }); + this.callback("onsearch", [nn, this]); + } + }, + add_sheet : tree_component.add_sheet, + + destroy : function() { + this.callback("ondestroy", [this]); + + this.container.unbind(".jstree"); + $("#" + this.container.attr("id")).die("click.jstree").die("dblclick.jstree").die("mouseover.jstree").die("mouseout.jstree").die("mousedown.jstree"); + this.container.removeClass("tree ui-widget ui-widget-content tree-default tree-" + this.settings.ui.theme_name).children("ul").removeClass("no_dots ltr locked").find("li").removeClass("leaf").removeClass("open").removeClass("closed").removeClass("last").children("a").removeClass("clicked hover search"); + + if(this.cntr == tree_component.focused) { + for(var i in tree_component.inst) { + if(i != this.cntr && i != this.container.attr("id")) { + tree_component.inst[i].focus(); + break; + } + } + } + + tree_component.inst[this.cntr] = false; + tree_component.inst[this.container.attr("id")] = false; + delete tree_component.inst[this.cntr]; + delete tree_component.inst[this.container.attr("id")]; + tree_component.cntr --; + } + } + }; + + // instance manager + tree_component.cntr = 0; + tree_component.inst = {}; + + // themes + tree_component.themes = []; + + // drag'n'drop stuff + tree_component.drag_drop = { + isdown : false, // Is there a drag + drag_node : false, // The actual node + drag_help : false, // The helper + dragged : false, + + init_x : false, + init_y : false, + moving : false, + + origin_tree : false, + marker : false, + + move_type : false, // before, after or inside + ref_node : false, // reference node + appended : false, // is helper appended + + foreign : false, // Is the dragged node a foreign one + droppable : [], // Array of classes that can be dropped onto the tree + + open_time : false, // Timeout for opening nodes + scroll_time : false // Timeout for scrolling + }; + tree_component.mouseup = function(event) { + var tmp = tree_component.drag_drop; + if(tmp.open_time) clearTimeout(tmp.open_time); + if(tmp.scroll_time) clearTimeout(tmp.scroll_time); + + if(tmp.moving && $.tree.drag_end !== false) $.tree.drag_end.call(null, event, tmp); + + if(tmp.foreign === false && tmp.drag_node && tmp.drag_node.size()) { + tmp.drag_help.remove(); + if(tmp.move_type) { + var tree1 = tree_component.inst[tmp.ref_node.parents(".tree:eq(0)").attr("id")]; + if(tree1) tree1.moved(tmp.dragged, tmp.ref_node, tmp.move_type, false, (tmp.origin_tree.settings.rules.drag_copy == "on" || (tmp.origin_tree.settings.rules.drag_copy == "ctrl" && event.ctrlKey) ) ); + } + tmp.move_type = false; + tmp.ref_node = false; + } + if(tmp.foreign !== false) { + if(tmp.drag_help) tmp.drag_help.remove(); + if(tmp.move_type) { + var tree1 = tree_component.inst[tmp.ref_node.parents(".tree:eq(0)").attr("id")]; + if(tree1) tree1.callback("ondrop",[tmp.f_data, tree1.get_node(tmp.ref_node).get(0), tmp.move_type, tree1]); + } + tmp.foreign = false; + tmp.move_type = false; + tmp.ref_node = false; + } + // RESET EVERYTHING + if(tree_component.drag_drop.marker) tree_component.drag_drop.marker.hide(); + if(tmp.dragged && tmp.dragged.size()) tmp.dragged.removeClass("dragged"); + tmp.dragged = false; + tmp.drag_help = false; + tmp.drag_node = false; + tmp.f_type = false; + tmp.f_data = false; + tmp.init_x = false; + tmp.init_y = false; + tmp.moving = false; + tmp.appended = false; + tmp.origin_tree = false; + if(tmp.isdown) { + tmp.isdown = false; + event.preventDefault(); + event.stopPropagation(); + return false; + } + }; + tree_component.mousemove = function(event) { + var tmp = tree_component.drag_drop; + var is_start = false; + + if(tmp.isdown) { + if(!tmp.moving && Math.abs(tmp.init_x - event.pageX) < 5 && Math.abs(tmp.init_y - event.pageY) < 5) { + event.preventDefault(); + event.stopPropagation(); + return false; + } + else { + if(!tmp.moving) { + tree_component.drag_drop.moving = true; + is_start = true; + } + } + + if(tmp.open_time) clearTimeout(tmp.open_time); + + if(tmp.drag_help !== false) { + if(!tmp.appended) { + if(tmp.foreign !== false) tmp.origin_tree = $.tree.focused(); + $("body").append(tmp.drag_help); + tmp.w = tmp.drag_help.width(); + tmp.appended = true; + } + tmp.drag_help.css({ "left" : (event.pageX + 5 ), "top" : (event.pageY + 15) }); + } + + if(is_start && $.tree.drag_start !== false) $.tree.drag_start.call(null, event, tmp); + if($.tree.drag !== false) $.tree.drag.call(null, event, tmp); + + if(event.target.tagName == "DIV" && event.target.id == "jstree-marker") return false; + + var et = $(event.target); + if(et.is("ins")) et = et.parent(); + var cnt = et.is(".tree") ? et : et.parents(".tree:eq(0)"); + + // if not moving over a tree + if(cnt.size() == 0 || !tree_component.inst[cnt.attr("id")]) { + if(tmp.scroll_time) clearTimeout(tmp.scroll_time); + if(tmp.drag_help !== false) tmp.drag_help.find("li:eq(0) ins").addClass("forbidden"); + tmp.move_type = false; + tmp.ref_node = false; + tree_component.drag_drop.marker.hide(); + return false; + } + + var tree2 = tree_component.inst[cnt.attr("id")]; + tree2.off_height(); + + if(tmp.scroll_time) clearTimeout(tmp.scroll_time); + tmp.scroll_time = setTimeout( function() { tree2.scroll_check(event.pageX,event.pageY); }, 50); + + var mov = false; + var st = cnt.scrollTop(); + + if(event.target.tagName == "A" || event.target.tagName == "INS") { + // just in case if hover is over the draggable + if(et.is("#jstree-dragged")) return false; + if(tree2.get_node(event.target).hasClass("closed")) { + tmp.open_time = setTimeout( function () { tree2.open_branch(et); }, 500); + } + + var et_off = et.offset(); + var goTo = { + x : (et_off.left - 1), + y : (event.pageY - et_off.top) + }; + + var arr = []; + if(goTo.y < tree2.li_height/3 + 1 ) arr = ["before","inside","after"]; + else if(goTo.y > tree2.li_height*2/3 - 1 ) arr = ["after","inside","before"]; + else { + if(goTo.y < tree2.li_height/2) arr = ["inside","before","after"]; + else arr = ["inside","after","before"]; + } + var ok = false; + var nn = (tmp.foreign == false) ? tmp.origin_tree.container.find("li.dragged") : tmp.f_type; + $.each(arr, function(i, val) { + if(tree2.check_move(nn, et, val)) { + mov = val; + ok = true; + return false; + } + }); + if(ok) { + switch(mov) { + case "before": + goTo.y = et_off.top - 2; + tree_component.drag_drop.marker.attr("class","marker"); + break; + case "after": + goTo.y = et_off.top - 2 + tree2.li_height; + tree_component.drag_drop.marker.attr("class","marker"); + break; + case "inside": + goTo.x -= 2; + goTo.y = et_off.top - 2 + tree2.li_height/2; + tree_component.drag_drop.marker.attr("class","marker_plus"); + break; + } + tmp.move_type = mov; + tmp.ref_node = $(event.target); + if(tmp.drag_help !== false) tmp.drag_help.find(".forbidden").removeClass("forbidden"); + tree_component.drag_drop.marker.css({ "left" : goTo.x , "top" : goTo.y }).show(); + } + } + + if( (et.is(".tree") || et.is("ul") ) && et.find("li:eq(0)").size() == 0) { + var et_off = et.offset(); + tmp.move_type = "inside"; + tmp.ref_node = cnt.children("ul:eq(0)"); + if(tmp.drag_help !== false) tmp.drag_help.find(".forbidden").removeClass("forbidden"); + tree_component.drag_drop.marker.attr("class","marker_plus"); + tree_component.drag_drop.marker.css({ "left" : (et_off.left + 10) , "top" : et_off.top + 15 }).show(); + } + else if( (event.target.tagName != "A" && event.target.tagName != "INS") || !ok) { + if(tmp.drag_help !== false) tmp.drag_help.find("li:eq(0) ins").addClass("forbidden"); + tmp.move_type = false; + tmp.ref_node = false; + tree_component.drag_drop.marker.hide(); + } + event.preventDefault(); + event.stopPropagation(); + return false; + } + return true; + }; + $(function () { + $(document).bind("mousemove.jstree", tree_component.mousemove); + $(document).bind("mouseup.jstree", tree_component.mouseup); + }); + + // cut, copy, paste stuff + tree_component.cut_copy = { + copy_nodes : false, + cut_nodes : false + }; + + // css stuff + tree_component.css = false; + tree_component.get_css = function(rule_name, delete_flag) { + rule_name = rule_name.toLowerCase(); + var css_rules = tree_component.css.cssRules || tree_component.css.rules; + var j = 0; + do { + if(css_rules.length && j > css_rules.length + 5) return false; + if(css_rules[j].selectorText && css_rules[j].selectorText.toLowerCase() == rule_name) { + if(delete_flag == true) { + if(tree_component.css.removeRule) document.styleSheets[i].removeRule(j); + if(tree_component.css.deleteRule) document.styleSheets[i].deleteRule(j); + return true; + } + else return css_rules[j]; + } + } + while (css_rules[++j]); + return false; + }; + tree_component.add_css = function(rule_name) { + if(tree_component.get_css(rule_name)) return false; + (tree_component.css.insertRule) ? tree_component.css.insertRule(rule_name + ' { }', 0) : tree_component.css.addRule(rule_name, null, 0); + return tree_component.get_css(rule_name); + }; + tree_component.remove_css = function(rule_name) { + return tree_component.get_css(rule_name, true); + }; + tree_component.add_sheet = function(opts) { + if(opts.str) { + var tmp = document.createElement("style"); + tmp.setAttribute('type',"text/css"); + if(tmp.styleSheet) { + document.getElementsByTagName("head")[0].appendChild(tmp); + tmp.styleSheet.cssText = opts.str; + } + else { + tmp.appendChild(document.createTextNode(opts.str)); + document.getElementsByTagName("head")[0].appendChild(tmp); + } + return tmp.sheet || tmp.styleSheet; + } + if(opts.url) { + if(document.createStyleSheet) { + try { document.createStyleSheet(opts.url); } catch (e) { }; + } + else { + var newSS = document.createElement('link'); + newSS.rel = 'stylesheet'; + newSS.type = 'text/css'; + newSS.media = "all"; + newSS.href = opts.url; + // var styles = "@import url(' " + url + " ');"; + // newSS.href ='data:text/css,'+escape(styles); + document.getElementsByTagName("head")[0].appendChild(newSS); + return newSS.styleSheet; + } + } + }; + $(function () { + var u = navigator.userAgent.toLowerCase(); + var v = (u.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1]; + + var css = '/* TREE LAYOUT */ .tree ul { margin:0 0 0 5px; padding:0 0 0 0; list-style-type:none; } .tree li { display:block; min-height:18px; line-height:18px; padding:0 0 0 15px; margin:0 0 0 0; /* Background fix */ clear:both; } .tree li ul { display:none; } .tree li a, .tree li span { display:inline-block;line-height:16px;height:16px;color:black;white-space:nowrap;text-decoration:none;padding:1px 4px 1px 4px;margin:0; } .tree li a:focus { outline: none; } .tree li a input, .tree li span input { margin:0;padding:0 0;display:inline-block;height:12px !important;border:1px solid white;background:white;font-size:10px;font-family:Verdana; } .tree li a input:not([class="xxx"]), .tree li span input:not([class="xxx"]) { padding:1px 0; } /* FOR DOTS */ .tree .ltr li.last { float:left; } .tree > ul li.last { overflow:visible; } /* OPEN OR CLOSE */ .tree li.open ul { display:block; } .tree li.closed ul { display:none !important; } /* FOR DRAGGING */ #jstree-dragged { position:absolute; top:-10px; left:-10px; margin:0; padding:0; } #jstree-dragged ul ul ul { display:none; } #jstree-marker { padding:0; margin:0; line-height:5px; font-size:1px; overflow:hidden; height:5px; position:absolute; left:-45px; top:-30px; z-index:1000; background-color:transparent; background-repeat:no-repeat; display:none; } #jstree-marker.marker { width:45px; background-position:-32px top; } #jstree-marker.marker_plus { width:5px; background-position:right top; } /* BACKGROUND DOTS */ .tree li li { overflow:hidden; } .tree > .ltr > li { display:table; } /* ICONS */ .tree ul ins { display:inline-block; text-decoration:none; width:16px; height:16px; } .tree .ltr ins { margin:0 4px 0 0px; } '; + if($.browser.msie) { + if($.browser.version == 6) css += '.tree li { height:18px; zoom:1; } .tree li li { overflow:visible; } .tree .ltr li.last { margin-top: expression( (this.previousSibling && /open/.test(this.previousSibling.className) ) ? "-2px" : "0"); } .marker { width:45px; background-position:-32px top; } .marker_plus { width:5px; background-position:right top; }'; + if($.browser.version == 7) css += '.tree li li { overflow:visible; } .tree .ltr li.last { margin-top: expression( (this.previousSibling && /open/.test(this.previousSibling.className) ) ? "-2px" : "0"); }'; + } + if($.browser.opera) css += '.tree > ul > li.last:after { content:"."; display: block; height:1px; clear:both; visibility:hidden; }'; + if($.browser.mozilla && $.browser.version.indexOf("1.8") == 0) css += '.tree .ltr li a { display:inline; float:left; } .tree li ul { clear:both; }'; + tree_component.css = tree_component.add_sheet({ str : css }); + }); +})(jQuery); + +// Datastores +// HTML and JSON are included here by default +(function ($) { + $.extend($.tree.datastores, { + "html" : function () { + return { + get : function(obj, tree, opts) { + return obj && $(obj).size() ? $('
            ').append(tree.get_node(obj).clone()).html() : tree.container.children("ul:eq(0)").html(); + }, + parse : function(data, tree, opts, callback) { + if(callback) callback.call(null, data); + return data; + }, + load : function(data, tree, opts, callback) { + if(opts.url) { + $.ajax({ + 'type' : opts.method, + 'url' : opts.url, + 'data' : data, + 'dataType' : "html", + 'success' : function (d, textStatus) { + callback.call(null, d); + }, + 'error' : function (xhttp, textStatus, errorThrown) { + callback.call(null, false); + tree.error(errorThrown + " " + textStatus); + } + }); + } + else { + callback.call(null, opts.static || tree.container.children("ul:eq(0)").html()); + } + } + }; + }, + "json" : function () { + return { + get : function(obj, tree, opts) { + var _this = this; + if(!obj || $(obj).size() == 0) obj = tree.container.children("ul").children("li"); + else obj = $(obj); + + if(!opts) opts = {}; + if(!opts.outer_attrib) opts.outer_attrib = [ "id", "rel", "class" ]; + if(!opts.inner_attrib) opts.inner_attrib = [ ]; + + if(obj.size() > 1) { + var arr = []; + obj.each(function () { + arr.push(_this.get(this, tree, opts)); + }); + return arr; + } + if(obj.size() == 0) return []; + + var json = { attributes : {}, data : {} }; + if(obj.hasClass("open")) json.data.state = "open"; + if(obj.hasClass("closed")) json.data.state = "closed"; + + for(var i in opts.outer_attrib) { + if(!opts.outer_attrib.hasOwnProperty(i)) continue; + var val = (opts.outer_attrib[i] == "class") ? obj.attr(opts.outer_attrib[i]).replace(/(^| )last( |$)/ig," ").replace(/(^| )(leaf|closed|open)( |$)/ig," ") : obj.attr(opts.outer_attrib[i]); + if(typeof val != "undefined" && val.toString().replace(" ","").length > 0) json.attributes[opts.outer_attrib[i]] = val; + delete val; + } + + if(tree.settings.languages.length) { + for(var i in tree.settings.languages) { + if(!tree.settings.languages.hasOwnProperty(i)) continue; + var a = obj.children("a." + tree.settings.languages[i]); + if(opts.force || opts.inner_attrib.length || a.children("ins").get(0).style.backgroundImage.toString().length || a.children("ins").get(0).className.length) { + json.data[tree.settings.languages[i]] = {}; + json.data[tree.settings.languages[i]].title = tree.get_text(obj,tree.settings.languages[i]); + if(a.children("ins").get(0).style.className.length) { + json.data[tree.settings.languages[i]].icon = a.children("ins").get(0).style.className; + } + if(a.children("ins").get(0).style.backgroundImage.length) { + json.data[tree.settings.languages[i]].icon = a.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")",""); + } + if(opts.inner_attrib.length) { + json.data[tree.settings.languages[i]].attributes = {}; + for(var j in opts.inner_attrib) { + if(!opts.inner_attrib.hasOwnProperty(j)) continue; + var val = a.attr(opts.inner_attrib[j]); + if(typeof val != "undefined" && val.toString().replace(" ","").length > 0) json.data[tree.settings.languages[i]].attributes[opts.inner_attrib[j]] = val; + delete val; + } + } + } + else { + json.data[tree.settings.languages[i]] = tree.get_text(obj,tree.settings.languages[i]); + } + } + } + else { + var a = obj.children("a"); + json.data.title = tree.get_text(obj); + + if(a.children("ins").size() && a.children("ins").get(0).className.length) { + json.data.icon = a.children("ins").get(0).className; + } + if(a.children("ins").size() && a.children("ins").get(0).style.backgroundImage.length) { + json.data.icon = a.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")",""); + } + + if(opts.inner_attrib.length) { + json.data.attributes = {}; + for(var j in opts.inner_attrib) { + if(!opts.inner_attrib.hasOwnProperty(j)) continue; + var val = a.attr(opts.inner_attrib[j]); + if(typeof val != "undefined" && val.toString().replace(" ","").length > 0) json.data.attributes[opts.inner_attrib[j]] = val; + delete val; + } + } + } + + if(obj.children("ul").size() > 0) { + json.children = []; + obj.children("ul").children("li").each(function () { + json.children.push(_this.get(this, tree, opts)); + }); + } + return json; + }, + parse : function(data, tree, opts, callback) { + if(Object.prototype.toString.apply(data) === "[object Array]") { + var str = ''; + for(var i = 0; i < data.length; i ++) { + if(typeof data[i] == "function") continue; + str += this.parse(data[i], tree, opts); + } + if(callback) callback.call(null, str); + return str; + } + + if(!data || !data.data) { + if(callback) callback.call(null, false); + return ""; + } + + var str = ''; + str += "
          •  "; + } + else str += " "; + str += ( (typeof data.data[tree.settings.languages[i]].title).toLowerCase() != "undefined" ? data.data[tree.settings.languages[i]].title : data.data[tree.settings.languages[i]] ) + ""; + } + } + else { + var attr = {}; + attr["href"] = ""; + attr["style"] = ""; + attr["class"] = ""; + if((typeof data.data.attributes).toLowerCase() != "undefined") { + for(var i in data.data.attributes) { + if(!data.data.attributes.hasOwnProperty(i)) continue; + if(i == "style" || i == "class") attr[i] += " " + data.data.attributes[i]; + else attr[i] = data.data.attributes[i]; + } + } + str += " "; + } + else str += " "; + str += ( (typeof data.data.title).toLowerCase() != "undefined" ? data.data.title : data.data ) + ""; + } + if(data.children && data.children.length) { + str += '
              '; + for(var i = 0; i < data.children.length; i++) { + str += this.parse(data.children[i], tree, opts); + } + str += '
            '; + } + str += "
          • "; + if(callback) callback.call(null, str); + return str; + }, + load : function(data, tree, opts, callback) { + if(opts.static) { + callback.call(null, opts.static); + } + else { + $.ajax({ + 'type' : opts.method, + 'url' : opts.url, + 'data' : data, + 'dataType' : "json", + 'success' : function (d, textStatus) { + callback.call(null, d); + }, + 'error' : function (xhttp, textStatus, errorThrown) { + callback.call(null, false); + tree.error(errorThrown + " " + textStatus); + } + }); + } + } + } + } + }); +})(jQuery); \ No newline at end of file diff --git a/scribeengine/public/scripts/jtree/themes/default/dot_for_ie.gif b/scribeengine/public/scripts/jtree/themes/default/dot_for_ie.gif new file mode 100644 index 0000000000000000000000000000000000000000..c0cc5fda7cfb9539720de442a3caca9c9a3fc4cb GIT binary patch literal 43 vcmZ?wbhEHbWMW`qXkcKFla>7c|G(l-7DfgJMg|=QAOOiQFfqBrF<1it%E1S( literal 0 HcmV?d00001 diff --git a/scribeengine/public/scripts/jtree/themes/default/icons.png b/scribeengine/public/scripts/jtree/themes/default/icons.png new file mode 100644 index 0000000000000000000000000000000000000000..b12618a80b8c6e24b32b7ee56024cfe7cb6a8a41 GIT binary patch literal 6680 zcmV+z8t3JSP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000j|Nkl(d*9`^JoCq0NCH@# zF${_R&Uw#!bKkqY-+X`1^ZY*V^C}Uc>)5hpp%76Zf^!ZLi#1_(^D$w7vmv9$R!%Rk zzVZ?NkE8mAU&$x`evhILjjq2r*7d-rYo3#_-y08P&qo{}pajHb{#FighL;!2d3a(q zUn<}&xBaUeam4qjtKUxj_Iieu4=0f*WaaV~S-SL(sxOO}8{GtS)`AGe_d!84s@S}K z1lC&oM8qPZK`ETopako; z6NzQwVyGQtg%s!V?|tg=-|qHBVW{coO!4qTze8&%DJ|jY#~$Roi>{kbu$kDXasK5TiX%7OQ;( z2RKa7fjEnE@vNX`HwW%*h=A#;wW8mQ?he!*I^BjfnrKvEwV!pKAjZczhp|B>{)xlw zqXWfBcLC{#0GzX8+HSP}+lROk_n!kFsAS@Gg*PCol8f*=LrFkuRuAQ+spdrTO6Drby= zR4Sc+E*_8d8wZvH);W#!J-k#K(P)flG)gRyz*z%0Lcaq<2>c+wN^wqdC5*b{nwfje z3quDM5{9s?zJaON-b%c1FeQTq_8S2mQ01H<>}jh;%5W*8XJbV@J-tud^mwDWg!Of{f3UERr=UIFVg-oP2pT zclA}5^V|z_kw^jYc$@)6b*y~<*OZSKM{8Sqzi^-u`RgU^(!D zk^Hv#gZUzQyExsD*}~7o>CeT5b>hO$#09nDf=|Tx8)V6ow@BCbiU=={9ed-}JMXN2 zsj~8tp2wC|RZZP__ucE?7(Dpwp2rTvZPchL*_YS#fC&Z>!32JG(XZINZaL2BjQdQ8 zH33$K4DG=K|4>}~4<}xK{ckG1_dN#Pe*0rDS5(MZjg3zOyfI?LloRj2e@@YfC&o`W z_-0^tPz=3gUYA6~#df+L)|NZt1)>gb%Uxg1oVBk6D z#K+H^`Aj4XDKrMQZiV7v2m%UAO9u=XJosc_Nndwhr2CR9K%BwZ5HT99eZZlV!x@7! z1`&f3ji7PPp_EclxO)REYRQ5Y-P}xS&K%;47gNyMitN|{jg8RUj7uh2b?dE*KHIqQ zw+HeR9zA-beB~)@w2zW34^$DX3G(${#&s4XL#8u4&>|wDl&V_*Gd=?OE}UBq$^hPq z6%;f#6Fc=(qKO2d*7E*SPc5ojx9;Z2P$&H$21dH`Kp)WPFpafdh6iTj-Oli1K4&Ej z;VP`>WBqh?oeUx(=ZkD}aO2ikY@JaGoe2a48#bW-@)yvWPiksvwyaxsC*di2=Am6fOUh4StzJ8;GGH_Hh>J-fXn*@!hBCQM^Y!1~TV&?*horCy<` zXgm$+Wh7+>>)ac-SeXByXOx;UT&X$5ot*=NF5;Q&KK=2>40!LoLB~#Z`U-Wa1ps`JUQI*$yL=Hg z5f0BRIG&A0FB+`W+@df{cwK}`ClYjIr*i;wu3t~_>eY#3Crp_8Qf1`@eZhfy+waZ; zt;YEtewGJDA`$8fHqy|#p6hho+jc}T zPPliX;r2hr2}1}1VR(8lN-4Dfe%B16q^#_+(v}w5Mc85O!blLzi~#GvI}FY%2a?XQ zX~Tvm{I<5){fh_UC@4{g_G$N16crS;6`Fx-%XIblx?nRl8#3G51sy_JaV0}r#voE7 zN~!J72EiRkP{E)4HZ&d+NR466tO($*wH4=k4kb%<(`I;B=S%z`=jLKkyqTpfeh=9@d6L zA`v!!{9jc6;Kx~bU=jA*AGojMpc$i%zvGJY{$t)N%O6^G^QuStpMX|psf$KM5*Z#S z4jZ%+iADfH8_Dy)eQhoR7;wX|?>~6sHA_z(dD_r%<>O|L{dKipd&ej9`nrI7;DI{Z zAGnJLg5a#pIMnUpfn9rJ4!ULR8JGQW;tPdWR*c=vc{hzb;jU>H|GA=M=+IR=-XZOK z+;rZ=r%Hc0;>_MSsb`*fM*d$MXtbXp(k{ybbNzwhvSL{>=~)mbSeuENMZc)};f+@v zzwo$24=Wuuxb$z-CFN(xye}F623|Mv$bY%^XMY?th+!W$*Wj!|DaFcpz5+&XZ1 z?VB7lyzGc;FFWovbl2%6R~|G~o^D#xn7`S553_0Paf7hPexdX92CQM;;fMn}G9flaA@j9Cb(oOj3=1fES zlb^r)->=3mSo2|W`xl)_I#ZVVFPf=W?~dE(zg5wc?7#(JHSDM@_^9@s@^fY0_V;_e zz*UN}vN9%3n#5gq-PLO`u?r70n2yF09eDVuBwj}&W2z75?H3;n)vFFH2P&-7IN!%hwc(}O349OdG|p;7EKPq|&!EIe^e0G?%ewkEp&*XM12MO|8Twb5TZT2?L< zBCxX|x~c8c^2_9zx;6VtJQ3mb*I%c%6G%56C|Mrpv`?$oNpV3@TW4GQT5HXC#L@K9 zLe@nKDHwe)Af(r>q4BMkcK`8De!fIask)@HsOUMPX=$tVF4&*q<>KG|C}H-%11Hz0 zTv`!@Qke#tOQ+w;%l|lw==@i9-G>NlIpb)iJ-bTn;RF;H4?hWow?7ib0nY>H-glme zb@=aYX25$JanUI0lMds$`R{+@Y0Pc{zWw&wqLj+^2D;3>A;zG!Mr%zNh8Sb0s;ZiP z$|i>2edg!6j zXB-#=K{p5H9NAUG+~Zu#>}~N5beBhZPGM^;K@boG0bv;C1@k-)&+`bwkT4AMV)v$a z#~gFa0e@HLZVpVR(`c=`Ik4;W?&`wca$rupK9xjf&z>!3opn}wU0q#CB9TBu2!bF# zb;Ioa!W|tQy_!V&l6c*CptY9v_VyCr_vz^9ptZG?>gsA1FJ4SM9>?=M(&;q5@8_NR zbvrN@^H#53o!|O`1Iq!ME0Q}qJBh_I_Y244@qBUZd0yU?T~{Yx=h(P$W1lO^^E}X6 zODdHjl}Ztd#fZgX6c!d@veY@9PVa_{zO4f@Svb=l=p3|3Hw(j~{a!_u#>U;o;#sckb-mx%0@8BfgH^ZZ9e-@_0Pg zuV2r}$(fv-G#ZUnRaM>H-N^q_k^f%#w0XNlQvRyMP;G9?-eKOp&iZoY4kYpsKq%iy zk&o$|w5`vk7;@9%)@iXIUrXh`!0$uwMu`MP`H?@4ps7akilJ{bBf@>_s`rfO+$HlE z_Fk&P3xDDyFI)&Q+D0D-t5Ep7fgL^^iyWBJy&O)R%{5h*T2g>V_})by$5BvGMU@al2va{GSn|) zut3aWE?+13Fs?{4V?p|bQq;SOzLD3f;hf_gY5^446Ivm_FQ2l(1VLAR%s)R>i-_ZQ z&)d$DSBFirx$=WL(s}#DvGDnAnm;9cl2)pKO93!>jHXmt^Gus&uhQ^R|DFS#bk;yu zXQ`n@r#qor$^`^cY8FQ%_U9rcuPm(gQQBA0%+xf3slU`~Gl0l3-uhHd@=4~#=fPWD zY4>lysnGXV{#LgVhTk3fb=>k6^YgYHS#f2BMSuUktH3=OTm51ouy8vYGBlb-(_h-$ zl`T>G-3N682cnh$cp#v~5BNys1309lb0K_2N$pK$Z29M+QP)_MmN#_RbW-98UwgS? zP(Boj4P9v56UqUqayN2-d{sv%3*41~dbPL50LqF%%JdK+R7xC!#fqWeXW-SxiQ8bZ+FW zwT7cvr}lqv>zi)X+ZX;N00-P@CGr~Q(Nk-Z6D8fZV4^71JrmZdy}SBcyu*A(s}}8B z*>_$YA((ygq(?jedM-O{83`c}FW|#y)`}6BP)ON|^QFyvv{Weq4FU6?`ljcAY4=EKQf?Yl7+^t|3)Zc4cK^3ZD9J7O$H9Oa)hMNH$W z@k=*@!>0RBjDHb2eQm|uteh_*u1<|TDFHOei>5YV1WV#HL&YfpAw)Y-p3thK`5GMG z00(1a7`AI!Lj`IY{I6y)o0{U&vfI=|Caf!d$6Lq551R6d9|{sz*dJ~P6Lh{Y54JoP zsrA$wQuSgcW!GrmXCe4^8M&3#;ORLlk~aW)orYY_whE^3*yvP*&E-KL%uCQQxDUfx zE37CabE>tCtV^-HQgonXc}nY;y6F*0m5$QyXF{Z2{y{`$pPnJxQ|9NC!JX}UjgzXu z@Se7x*N8V#ZT7CoZ^J}Y<4j?T8h+YunpN?c_Je;6iB;EeXQPV7+Th06 dtwLDJL#a0_K>wk&Y~4#Tit}rd{U6a{{Rfg56CMBn literal 0 HcmV?d00001 From 2e76729d6d82e44f53b3a12f57ee4c9270357d6c Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Wed, 21 Apr 2010 15:32:12 +0200 Subject: [PATCH 05/17] Trying to fix the directories. --- scribeengine/controllers/media.py | 33 ++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/scribeengine/controllers/media.py b/scribeengine/controllers/media.py index 38a431a..b71e112 100644 --- a/scribeengine/controllers/media.py +++ b/scribeengine/controllers/media.py @@ -22,6 +22,7 @@ import os import logging +from pprint import pprint from scribeengine.lib.base import * from scribeengine.lib import utils @@ -35,12 +36,34 @@ class MediaController(BaseController): def _get_directories(self, parent=None, tree={}): if not parent: parent = config[u'paths.media'] + parent = os.path.abspath(parent) + dir_start = os.path.split(parent)[1] + tree[dir_start] = {} + for root, dirs, files in os.walk(parent): + root_parts = root.split(os.sep) + root_start = u'' + for root_part in root_parts: + if root_part == dir_start: + root_start = root_part + break + + for dirpath in dirs: + root_parts = + full_dirpath = os.path.join(root, dirpath) + tree[full_dirpath] = {} + for dirpath in os.listdir(parent): - if os.path.isdir(dirpath): - tree[os.path.abspath(dirpath)] = {u'path': dirpath, u'children': {}} - self._get_directories(os.path.abspath(dirpath), - tree[os.path.abspath(dirpath)][u'children']) + full_dirpath = os.path.abspath(dirpath) + print 'path:', full_dirpath + if os.path.isdir(full_dirpath): + tree[full_dirpath] = { + u'path': dirpath, + u'children': self._get_directories(full_dirpath) + } + return tree def index(self): c.directories = self._get_directories() - return render(u'/media/index.html') + pprint(c.directories) + return c.directories + #return render(u'/media/index.html') From 1ea6a3396f1215e445b639cbeb084d81753c1603 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Wed, 21 Apr 2010 15:50:16 +0200 Subject: [PATCH 06/17] Finally fixed the directory list! --- scribeengine/controllers/media.py | 37 +++++++++---------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/scribeengine/controllers/media.py b/scribeengine/controllers/media.py index b71e112..35f30d1 100644 --- a/scribeengine/controllers/media.py +++ b/scribeengine/controllers/media.py @@ -22,7 +22,7 @@ import os import logging -from pprint import pprint +from pprint import pprint, pformat from scribeengine.lib.base import * from scribeengine.lib import utils @@ -34,36 +34,19 @@ log = logging.getLogger(__name__) class MediaController(BaseController): def _get_directories(self, parent=None, tree={}): - if not parent: - parent = config[u'paths.media'] - parent = os.path.abspath(parent) - dir_start = os.path.split(parent)[1] - tree[dir_start] = {} + old_root = parent + dirname = os.path.split(parent)[1] + tree[dirname] = {u'dirpath': parent, u'children': {}} for root, dirs, files in os.walk(parent): - root_parts = root.split(os.sep) - root_start = u'' - for root_part in root_parts: - if root_part == dir_start: - root_start = root_part - break - + if root != old_root: + break for dirpath in dirs: - root_parts = full_dirpath = os.path.join(root, dirpath) - tree[full_dirpath] = {} - - for dirpath in os.listdir(parent): - full_dirpath = os.path.abspath(dirpath) - print 'path:', full_dirpath - if os.path.isdir(full_dirpath): - tree[full_dirpath] = { - u'path': dirpath, - u'children': self._get_directories(full_dirpath) - } - return tree + self._get_directories(full_dirpath, tree[dirname][u'children']) def index(self): - c.directories = self._get_directories() + c.directories = {} + self._get_directories(config[u'paths.media'], c.directories) pprint(c.directories) - return c.directories + return pformat(c.directories, indent=2) #return render(u'/media/index.html') From 030166f356b1c0267269981694608e2861d53c23 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 22 Apr 2010 08:12:04 +0200 Subject: [PATCH 07/17] Added the initial directory tree for the media library. --- scribeengine/controllers/media.py | 23 +++++++++----- .../scripts/jtree/themes/default/style.css | 1 + scribeengine/templates/media/index.mako | 31 +++++++++++++++++++ 3 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 scribeengine/templates/media/index.mako diff --git a/scribeengine/controllers/media.py b/scribeengine/controllers/media.py index 35f30d1..ba12036 100644 --- a/scribeengine/controllers/media.py +++ b/scribeengine/controllers/media.py @@ -29,24 +29,31 @@ from scribeengine.lib import utils from scribeengine.model import MediaType, File from scribeengine.model.meta import Session +try: + import json +except ImportError: + import simplejson as json + log = logging.getLogger(__name__) class MediaController(BaseController): - def _get_directories(self, parent=None, tree={}): + def _get_directories(self, parent=None, tree=[]): old_root = parent dirname = os.path.split(parent)[1] - tree[dirname] = {u'dirpath': parent, u'children': {}} + node = {'data': dirname, u'state': u'open', u'children': []} for root, dirs, files in os.walk(parent): if root != old_root: break for dirpath in dirs: full_dirpath = os.path.join(root, dirpath) - self._get_directories(full_dirpath, tree[dirname][u'children']) + self._get_directories(full_dirpath, node[u'children']) + tree.append(node) def index(self): - c.directories = {} - self._get_directories(config[u'paths.media'], c.directories) - pprint(c.directories) - return pformat(c.directories, indent=2) - #return render(u'/media/index.html') + self._add_javascript(u'jtree/jquery.tree.js') + directories = [] + self._get_directories(config[u'paths.media'], directories) + c.directories = json.dumps(directories) + #return pformat(c.directories, indent=2) + return render(u'/media/index.mako') diff --git a/scribeengine/public/scripts/jtree/themes/default/style.css b/scribeengine/public/scripts/jtree/themes/default/style.css index fab2676..8f58ce6 100644 --- a/scribeengine/public/scripts/jtree/themes/default/style.css +++ b/scribeengine/public/scripts/jtree/themes/default/style.css @@ -1,3 +1,4 @@ +.tree-default { font-family: "Lucida Grande", "Trebuchet MS", "Lucida Sans", "Arial", sans-serif; font-size: 80%; } /* LOCKED */ .tree-default .locked li a { color:gray; } /* DOTS */ diff --git a/scribeengine/templates/media/index.mako b/scribeengine/templates/media/index.mako new file mode 100644 index 0000000..63f7e70 --- /dev/null +++ b/scribeengine/templates/media/index.mako @@ -0,0 +1,31 @@ + + + + + ${c.page_title} +% for script in c.scripts: + +% endfor +% if c.jsinit: + +% endif + + +
            + + + \ No newline at end of file From 583065510023a5966f1864327eca7f1134ff6b57 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 23 Apr 2010 15:07:12 +0200 Subject: [PATCH 08/17] Added the fileBrowser hook stuff. --- scribeengine/controllers/media.py | 9 +- .../public/scripts/ScribeEngine.Media.js | 35 ++++++++ .../public/scripts/ScribeEngine.Post.js | 12 +-- scribeengine/public/scripts/ScribeEngine.js | 87 ++++++++++++++++--- scribeengine/templates/media/index.mako | 28 +++--- 5 files changed, 133 insertions(+), 38 deletions(-) create mode 100644 scribeengine/public/scripts/ScribeEngine.Media.js diff --git a/scribeengine/controllers/media.py b/scribeengine/controllers/media.py index ba12036..be902e4 100644 --- a/scribeengine/controllers/media.py +++ b/scribeengine/controllers/media.py @@ -38,6 +38,10 @@ log = logging.getLogger(__name__) class MediaController(BaseController): + def __before__(self): + BaseController.__before__(self) + self._add_javascript('ScribeEngine.Media.js') + def _get_directories(self, parent=None, tree=[]): old_root = parent dirname = os.path.split(parent)[1] @@ -53,7 +57,10 @@ class MediaController(BaseController): def index(self): self._add_javascript(u'jtree/jquery.tree.js') directories = [] - self._get_directories(config[u'paths.media'], directories) + path = os.path.join(config[u'paths.media'], u'user%s' % c.current_user.id) + if not os.path.exists(path): + os.makedirs(path) + self._get_directories(path, directories) c.directories = json.dumps(directories) #return pformat(c.directories, indent=2) return render(u'/media/index.mako') diff --git a/scribeengine/public/scripts/ScribeEngine.Media.js b/scribeengine/public/scripts/ScribeEngine.Media.js new file mode 100644 index 0000000..a3bb8e2 --- /dev/null +++ b/scribeengine/public/scripts/ScribeEngine.Media.js @@ -0,0 +1,35 @@ +/***************************************************************************** + * ScribeEngine - Open Source Blog Software * + * ------------------------------------------------------------------------- * + * Copyright (c) 2010 Raoul Snyman * + * ------------------------------------------------------------------------- * + * This program is free software; you can redistribute it and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; version 2 of the License. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * + * Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + *****************************************************************************/ + +ScribeEngine.Namespace.create("ScribeEngine.Media", { + new_directory: function () + { + var dirname = prompt("New Directory:", "directory"); + }, + get_files: function (node, tree) + { + node = $(node); + alert(node.children("a").text()); + } +}); + +ScribeEngine.Events.load(function () { + ScribeEngine.Events.click("#new-directory", ScribeEngine.Media.new_directory); + ScribeEngine.Events.click("#file-select", window.close); +}); diff --git a/scribeengine/public/scripts/ScribeEngine.Post.js b/scribeengine/public/scripts/ScribeEngine.Post.js index 9380b3a..45da5b6 100644 --- a/scribeengine/public/scripts/ScribeEngine.Post.js +++ b/scribeengine/public/scripts/ScribeEngine.Post.js @@ -23,15 +23,5 @@ ScribeEngine.Namespace.create("ScribeEngine.Post", { ScribeEngine.Events.load(function () { ScribeEngine.Widgets.tagEditor("#post-tags"); - $('textarea').tinymce({ - script_url: "/scripts/tinymce/tiny_mce.js", - theme: "advanced", - dialog_type: "modal", - theme_advanced_toolbar_location: "top", - theme_advanced_toolbar_align: "left", - theme_advanced_statusbar_location: "bottom", - theme_advanced_resizing: true, - theme_advanced_resize_horizontal: false - }); - + ScribeEngine.Widgets.tinymce("textarea"); }); diff --git a/scribeengine/public/scripts/ScribeEngine.js b/scribeengine/public/scripts/ScribeEngine.js index 4e1e3c9..c55f727 100644 --- a/scribeengine/public/scripts/ScribeEngine.js +++ b/scribeengine/public/scripts/ScribeEngine.js @@ -119,18 +119,81 @@ ScribeEngine.Namespace.create("ScribeEngine.Widgets", { /** * Adds a datepicker to an element. */ - datepicker: function (selector) - { - $(selector).datepicker({showButtonPanel: true, dateFormat: "dd/mm/yy"}); - }, - tagEditor: function (selector) - { - $(selector).tagEditor({completeOnBlur: true, initialParse: true}); - }, - elastic: function (selector) - { - $(selector).elastic(); - } + datepicker: function (selector) + { + $(selector).datepicker({showButtonPanel: true, dateFormat: "dd/mm/yy"}); + }, + tagEditor: function (selector) + { + $(selector).tagEditor({completeOnBlur: true, initialParse: true}); + }, + elastic: function (selector) + { + $(selector).elastic(); + }, + fileBrowser: function (field_name, url, type, win) + { + alert("Field_Name: " + field_name + "\nURL: " + url + "\nType: " + type + "\nWin: " + win); // debug/testing + var cmsURL = window.location.toString(); // script URL - use an absolute path! + if (cmsURL.indexOf("?") < 0) + { + //add the type as the only query parameter + cmsURL = cmsURL + "?type=" + type; + } + else + { + //add the type as an additional query parameter + // (PHP session ID is now included if there is one at all) + cmsURL = cmsURL + "&type=" + type; + } + tinyMCE.activeEditor.windowManager.open( + { + file: "/media", + title: "Media Library", + width: 600, // Your dimensions may differ - toy around with them! + height: 400, + resizable: "yes", + inline: "yes", // This parameter only has an effect if you use the inlinepopups plugin! + close_previous: "no" + }, + { + window: win, + input: field_name + } + ); + return false; + }, + tinymce: function (selector) + { + $(selector).tinymce({ + script_url: "/scripts/tinymce/tiny_mce.js", + theme: "advanced", + dialog_type: "modal", + theme_advanced_toolbar_location: "top", + theme_advanced_toolbar_align: "left", + theme_advanced_statusbar_location: "bottom", + theme_advanced_resizing: true, + theme_advanced_resize_horizontal: false, + file_browser_callback: "ScribeEngine.Widgets.fileBrowser" + }); + }, + tree: function (selector, data, onselect) + { + $(selector).tree({ + data: + { + type: "json", + opts: + { + static: data + } + }, + callback: + { + onselect: onselect + } + }); + } }); ScribeEngine.Namespace.create("ScribeEngine.General", { diff --git a/scribeengine/templates/media/index.mako b/scribeengine/templates/media/index.mako index 63f7e70..71e8cb1 100644 --- a/scribeengine/templates/media/index.mako +++ b/scribeengine/templates/media/index.mako @@ -10,22 +10,22 @@ % if c.jsinit: % endif + -
            +
            +
            +
            + + +
            - \ No newline at end of file + From 9af09feef57e0b2008360727daaed0466d57ee46 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 30 Apr 2010 15:08:35 +0200 Subject: [PATCH 09/17] Added an initial "create directory" method. --- scribeengine/controllers/media.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scribeengine/controllers/media.py b/scribeengine/controllers/media.py index 405002c..2460efe 100644 --- a/scribeengine/controllers/media.py +++ b/scribeengine/controllers/media.py @@ -70,3 +70,17 @@ class MediaController(BaseController): c.files = self._get_files(path) #return pformat(c.directories, indent=2) return render(u'/media/index.mako') + + def create_directory(self): + """ + Create a directory, called via AJAX. + """ + dirname = request.GET.get(u'directory') + parent = request.GET.get(u'parent') + if dirname and parent: + parent = os.path.abspath(parent) + os.makedirs(os.path.join(parent, dirname)) + return u'1' + else: + return u'0' + From 0fd1f5844f03c2148e9f3cf94e46bf196c2a29b7 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 28 May 2010 08:51:45 +0200 Subject: [PATCH 10/17] Upgraded jQuery and jsTree. --- scribeengine/controllers/media.py | 12 +- .../public/scripts/ScribeEngine.Media.js | 7 +- scribeengine/public/scripts/ScribeEngine.js | 21 +- scribeengine/public/scripts/jquery.js | 6259 ++++++++++++++++- .../public/scripts/jstree/jquery.jstree.js | 142 + .../scripts/jstree/themes/default/d.png | Bin 0 -> 7635 bytes .../themes/default/dot_for_ie.gif | Bin .../scripts/jstree/themes/default/style.css | 56 + .../jstree/themes/default/throbber.gif | Bin 0 -> 1849 bytes .../public/scripts/jtree/jquery.tree.js | 2064 ------ .../scripts/jtree/themes/default/icons.png | Bin 6680 -> 0 bytes .../scripts/jtree/themes/default/style.css | 31 - .../scripts/jtree/themes/default/throbber.gif | Bin 1844 -> 0 bytes 13 files changed, 6460 insertions(+), 2132 deletions(-) mode change 100755 => 100644 scribeengine/public/scripts/jquery.js create mode 100644 scribeengine/public/scripts/jstree/jquery.jstree.js create mode 100644 scribeengine/public/scripts/jstree/themes/default/d.png rename scribeengine/public/scripts/{jtree => jstree}/themes/default/dot_for_ie.gif (100%) create mode 100644 scribeengine/public/scripts/jstree/themes/default/style.css create mode 100644 scribeengine/public/scripts/jstree/themes/default/throbber.gif delete mode 100644 scribeengine/public/scripts/jtree/jquery.tree.js delete mode 100644 scribeengine/public/scripts/jtree/themes/default/icons.png delete mode 100644 scribeengine/public/scripts/jtree/themes/default/style.css delete mode 100644 scribeengine/public/scripts/jtree/themes/default/throbber.gif diff --git a/scribeengine/controllers/media.py b/scribeengine/controllers/media.py index 2460efe..536fef1 100644 --- a/scribeengine/controllers/media.py +++ b/scribeengine/controllers/media.py @@ -24,6 +24,8 @@ import os import logging from pprint import pprint, pformat +from pylons.decorators import jsonify + from scribeengine.lib.base import * from scribeengine.lib import utils from scribeengine.model import MediaType, File @@ -45,10 +47,12 @@ class MediaController(BaseController): def _get_directories(self, parent=None, tree=[]): old_root = parent dirname = os.path.split(parent)[1] - node = {'data': dirname, u'state': u'open', u'children': []} + node = {'data': dirname, u'state': u'open'} for root, dirs, files in os.walk(parent): if root != old_root: break + if dirs: + node[u'children'] = [] for dirpath in dirs: full_dirpath = os.path.join(root, dirpath) self._get_directories(full_dirpath, node[u'children']) @@ -60,7 +64,7 @@ class MediaController(BaseController): break def index(self): - self._add_javascript(u'jtree/jquery.tree.js') + self._add_javascript(u'jstree/jquery.jstree.js') directories = [] path = os.path.join(config[u'paths.media'], u'user%s' % c.current_user.id) if not os.path.exists(path): @@ -71,6 +75,7 @@ class MediaController(BaseController): #return pformat(c.directories, indent=2) return render(u'/media/index.mako') + @jsonify def create_directory(self): """ Create a directory, called via AJAX. @@ -79,7 +84,8 @@ class MediaController(BaseController): parent = request.GET.get(u'parent') if dirname and parent: parent = os.path.abspath(parent) - os.makedirs(os.path.join(parent, dirname)) + log.debug(parent) + #os.makedirs(os.path.join(parent, dirname)) return u'1' else: return u'0' diff --git a/scribeengine/public/scripts/ScribeEngine.Media.js b/scribeengine/public/scripts/ScribeEngine.Media.js index aec6672..cb23fca 100644 --- a/scribeengine/public/scripts/ScribeEngine.Media.js +++ b/scribeengine/public/scripts/ScribeEngine.Media.js @@ -24,12 +24,7 @@ ScribeEngine.Namespace.create("ScribeEngine.Media", { }, get_files: function (node, tree) { - tree_string = ""; - while (node) - { - alert($(tree.get_node(node)).text()); - node = tree.parent(node); - } + alert(tree.get_path(node)); } }); diff --git a/scribeengine/public/scripts/ScribeEngine.js b/scribeengine/public/scripts/ScribeEngine.js index c55f727..d9d78b3 100644 --- a/scribeengine/public/scripts/ScribeEngine.js +++ b/scribeengine/public/scripts/ScribeEngine.js @@ -179,19 +179,22 @@ ScribeEngine.Namespace.create("ScribeEngine.Widgets", { }, tree: function (selector, data, onselect) { - $(selector).tree({ - data: - { - type: "json", - opts: + $(selector).jstree({ + json_data: { + data: { + type: "json", + opts: + { static: data + } + }, + callback: + { + onselect: onselect } }, - callback: - { - onselect: onselect - } + plugins : [ "themes", "json_data"] }); } }); diff --git a/scribeengine/public/scripts/jquery.js b/scribeengine/public/scripts/jquery.js old mode 100755 new mode 100644 index b1ae21d..5c4c146 --- a/scribeengine/public/scripts/jquery.js +++ b/scribeengine/public/scripts/jquery.js @@ -1,19 +1,6240 @@ -/* - * jQuery JavaScript Library v1.3.2 - * http://jquery.com/ - * - * Copyright (c) 2009 John Resig - * Dual licensed under the MIT and GPL licenses. - * http://docs.jquery.com/License - * - * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) - * Revision: 6246 - */ -(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
            "]||!O.indexOf("",""]||(!O.indexOf("",""]||!O.indexOf("",""]||!o.support.htmlSerialize&&[1,"div
            ","
            "]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); -/* - * Sizzle CSS Selector Engine - v0.9.3 - * Copyright 2009, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return UT[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="

            ";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="
            ";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("
            ").append(M.responseText.replace(//g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='
            ';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})(); \ No newline at end of file +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function( window, undefined ) { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // (both of which we optimize for) + quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/, + + // Is it a simple selector + isSimple = /^.[^:#\[\.,]*$/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // Has the ready events already been bound? + readyBound = false, + + // The functions to execute on DOM ready + readyList = [], + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwnProperty = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + indexOf = Array.prototype.indexOf; + +jQuery.fn = jQuery.prototype = { + init: function( selector, context ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context ) { + this.context = document; + this[0] = document.body; + this.selector = "body"; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + doc = (context ? context.ownerDocument || context : document); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + if ( elem ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $("TAG") + } else if ( !context && /^\w+$/.test( selector ) ) { + this.selector = selector; + this.context = document; + selector = document.getElementsByTagName( selector ); + return jQuery.merge( this, selector ); + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return (context || rootjQuery).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return jQuery( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if (selector.selector !== undefined) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.4.2", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = jQuery(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + (this.selector ? " " : "") + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // If the DOM is already ready + if ( jQuery.isReady ) { + // Execute the function immediately + fn.call( document, jQuery ); + + // Otherwise, remember the function for later + } else if ( readyList ) { + // Add the function to the wait list + readyList.push( fn ); + } + + return this; + }, + + eq: function( i ) { + return i === -1 ? + this.slice( i ) : + this.slice( i, +i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || jQuery(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging object literal values or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) { + var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src + : jQuery.isArray(copy) ? [] : {}; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // Handle when the DOM is ready + ready: function() { + // Make sure that the DOM is not already loaded + if ( !jQuery.isReady ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 13 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If there are functions bound, to execute + if ( readyList ) { + // Execute all of them + var fn, i = 0; + while ( (fn = readyList[ i++ ]) ) { + fn.call( document, jQuery ); + } + + // Reset the list of functions + readyList = null; + } + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyBound ) { + return; + } + + readyBound = true; + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + return jQuery.ready(); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent("onreadystatechange", DOMContentLoaded); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return toString.call(obj) === "[object Function]"; + }, + + isArray: function( obj ) { + return toString.call(obj) === "[object Array]"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) { + return false; + } + + // Not own constructor property must be Object + if ( obj.constructor + && !hasOwnProperty.call(obj, "constructor") + && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwnProperty.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw msg; + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@") + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]") + .replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) { + + // Try to use the native JSON parser first + return window.JSON && window.JSON.parse ? + window.JSON.parse( data ) : + (new Function("return " + data))(); + + } else { + jQuery.error( "Invalid JSON: " + data ); + } + }, + + noop: function() {}, + + // Evalulates a script in a global context + globalEval: function( data ) { + if ( data && rnotwhite.test(data) ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.getElementsByTagName("head")[0] || document.documentElement, + script = document.createElement("script"); + + script.type = "text/javascript"; + + if ( jQuery.support.scriptEval ) { + script.appendChild( document.createTextNode( data ) ); + } else { + script.text = data; + } + + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709). + head.insertBefore( script, head.firstChild ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction(object); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( var value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} + } + } + + return object; + }, + + trim: function( text ) { + return (text || "").replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // The extra typeof function check is to prevent crashes + // in Safari 2 (See: #3039) + if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = []; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + if ( !inv !== !callback( elems[ i ], i ) ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var ret = [], value; + + // Go through the array, translating each of the items to their + // new value (or values). + for ( var i = 0, length = elems.length; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + proxy: function( fn, proxy, thisObject ) { + if ( arguments.length === 2 ) { + if ( typeof proxy === "string" ) { + thisObject = fn; + fn = thisObject[ proxy ]; + proxy = undefined; + + } else if ( proxy && !jQuery.isFunction( proxy ) ) { + thisObject = proxy; + proxy = undefined; + } + } + + if ( !proxy && fn ) { + proxy = function() { + return fn.apply( thisObject || this, arguments ); + }; + } + + // Set the guid of unique handler to the same of original handler, so it can be removed + if ( fn ) { + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + } + + // So proxy can be declared as an argument + return proxy; + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = /(webkit)[ \/]([\w.]+)/.exec( ua ) || + /(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) || + /(msie) ([\w.]+)/.exec( ua ) || + !/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + browser: {} +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +if ( indexOf ) { + jQuery.inArray = function( elem, array ) { + return indexOf.call( array, elem ); + }; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch( error ) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +function evalScript( i, elem ) { + if ( elem.src ) { + jQuery.ajax({ + url: elem.src, + async: false, + dataType: "script" + }); + } else { + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } +} + +// Mutifunctional method to get and set values to a collection +// The value/s can be optionally by executed if its a function +function access( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; +} + +function now() { + return (new Date).getTime(); +} +(function() { + + jQuery.support = {}; + + var root = document.documentElement, + script = document.createElement("script"), + div = document.createElement("div"), + id = "script" + now(); + + div.style.display = "none"; + div.innerHTML = "
            a"; + + var all = div.getElementsByTagName("*"), + a = div.getElementsByTagName("a")[0]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return; + } + + jQuery.support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: div.firstChild.nodeType === 3, + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText insted) + style: /red/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: a.getAttribute("href") === "/a", + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55$/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: div.getElementsByTagName("input")[0].value === "on", + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: document.createElement("select").appendChild( document.createElement("option") ).selected, + + parentNode: div.removeChild( div.appendChild( document.createElement("div") ) ).parentNode === null, + + // Will be defined later + deleteExpando: true, + checkClone: false, + scriptEval: false, + noCloneEvent: true, + boxModel: null + }; + + script.type = "text/javascript"; + try { + script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); + } catch(e) {} + + root.insertBefore( script, root.firstChild ); + + // Make sure that the execution of code works by injecting a script + // tag with appendChild/createTextNode + // (IE doesn't support this, fails, and uses .text instead) + if ( window[ id ] ) { + jQuery.support.scriptEval = true; + delete window[ id ]; + } + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete script.test; + + } catch(e) { + jQuery.support.deleteExpando = false; + } + + root.removeChild( script ); + + if ( div.attachEvent && div.fireEvent ) { + div.attachEvent("onclick", function click() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + jQuery.support.noCloneEvent = false; + div.detachEvent("onclick", click); + }); + div.cloneNode(true).fireEvent("onclick"); + } + + div = document.createElement("div"); + div.innerHTML = ""; + + var fragment = document.createDocumentFragment(); + fragment.appendChild( div.firstChild ); + + // WebKit doesn't clone checked state correctly in fragments + jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; + + // Figure out if the W3C box model works as expected + // document.body must exist before we can do this + jQuery(function() { + var div = document.createElement("div"); + div.style.width = div.style.paddingLeft = "1px"; + + document.body.appendChild( div ); + jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; + document.body.removeChild( div ).style.display = 'none'; + + div = null; + }); + + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + var eventSupported = function( eventName ) { + var el = document.createElement("div"); + eventName = "on" + eventName; + + var isSupported = (eventName in el); + if ( !isSupported ) { + el.setAttribute(eventName, "return;"); + isSupported = typeof el[eventName] === "function"; + } + el = null; + + return isSupported; + }; + + jQuery.support.submitBubbles = eventSupported("submit"); + jQuery.support.changeBubbles = eventSupported("change"); + + // release memory in IE + root = script = div = all = a = null; +})(); + +jQuery.props = { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" +}; +var expando = "jQuery" + now(), uuid = 0, windowData = {}; + +jQuery.extend({ + cache: {}, + + expando:expando, + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + "object": true, + "applet": true + }, + + data: function( elem, name, data ) { + if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { + return; + } + + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ], cache = jQuery.cache, thisCache; + + if ( !id && typeof name === "string" && data === undefined ) { + return null; + } + + // Compute a unique ID for the element + if ( !id ) { + id = ++uuid; + } + + // Avoid generating a new cache unless none exists and we + // want to manipulate it. + if ( typeof name === "object" ) { + elem[ expando ] = id; + thisCache = cache[ id ] = jQuery.extend(true, {}, name); + + } else if ( !cache[ id ] ) { + elem[ expando ] = id; + cache[ id ] = {}; + } + + thisCache = cache[ id ]; + + // Prevent overriding the named cache with undefined values + if ( data !== undefined ) { + thisCache[ name ] = data; + } + + return typeof name === "string" ? thisCache[ name ] : thisCache; + }, + + removeData: function( elem, name ) { + if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { + return; + } + + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ]; + + // If we want to remove a specific section of the element's data + if ( name ) { + if ( thisCache ) { + // Remove the section of cache data + delete thisCache[ name ]; + + // If we've removed all the data, remove the element's cache + if ( jQuery.isEmptyObject(thisCache) ) { + jQuery.removeData( elem ); + } + } + + // Otherwise, we want to remove all of the element's data + } else { + if ( jQuery.support.deleteExpando ) { + delete elem[ jQuery.expando ]; + + } else if ( elem.removeAttribute ) { + elem.removeAttribute( jQuery.expando ); + } + + // Completely remove the data cache + delete cache[ id ]; + } + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + if ( typeof key === "undefined" && this.length ) { + return jQuery.data( this[0] ); + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + } + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } else { + return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() { + jQuery.data( this, key, value ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); +jQuery.extend({ + queue: function( elem, type, data ) { + if ( !elem ) { + return; + } + + type = (type || "fx") + "queue"; + var q = jQuery.data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( !data ) { + return q || []; + } + + if ( !q || jQuery.isArray(data) ) { + q = jQuery.data( elem, type, jQuery.makeArray(data) ); + + } else { + q.push( data ); + } + + return q; + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), fn = queue.shift(); + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift("inprogress"); + } + + fn.call(elem, function() { + jQuery.dequeue(elem, type); + }); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function( i, elem ) { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; + + return this.queue( type, function() { + var elem = this; + setTimeout(function() { + jQuery.dequeue( elem, type ); + }, time ); + }); + }, + + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + } +}); +var rclass = /[\n\t]/g, + rspace = /\s+/, + rreturn = /\r/g, + rspecialurl = /href|src|style/, + rtype = /(button|input)/i, + rfocusable = /(button|input|object|select|textarea)/i, + rclickable = /^(a|area)$/i, + rradiocheck = /radio|checkbox/; + +jQuery.fn.extend({ + attr: function( name, value ) { + return access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name, fn ) { + return this.each(function(){ + jQuery.attr( this, name, "" ); + if ( this.nodeType === 1 ) { + this.removeAttribute( name ); + } + }); + }, + + addClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.addClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( value && typeof value === "string" ) { + var classNames = (value || "").split( rspace ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className ) { + elem.className = value; + + } else { + var className = " " + elem.className + " ", setClass = elem.className; + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { + setClass += " " + classNames[c]; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.removeClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + var classNames = (value || "").split(rspace); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + var className = (" " + elem.className + " ").replace(rclass, " "); + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[c] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this); + self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, i = 0, self = jQuery(this), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery.data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " "; + for ( var i = 0, l = this.length; i < l; i++ ) { + if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + if ( value === undefined ) { + var elem = this[0]; + + if ( elem ) { + if ( jQuery.nodeName( elem, "option" ) ) { + return (elem.attributes.value || {}).specified ? elem.value : elem.text; + } + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + if ( option.selected ) { + // Get the specifc value for the option + value = jQuery(option).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + } + + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { + return elem.getAttribute("value") === null ? "on" : elem.value; + } + + + // Everything else, we just grab the value + return (elem.value || "").replace(rreturn, ""); + + } + + return undefined; + } + + var isFunction = jQuery.isFunction(value); + + return this.each(function(i) { + var self = jQuery(this), val = value; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call(this, i, self.val()); + } + + // Typecast each time if the value is a Function and the appended + // value is therefore different each time. + if ( typeof val === "number" ) { + val += ""; + } + + if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { + this.checked = jQuery.inArray( self.val(), val ) >= 0; + + } else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray(val); + + jQuery( "option", this ).each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + this.selectedIndex = -1; + } + + } else { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + // don't set attributes on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { + return undefined; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery(elem)[name](value); + } + + var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), + // Whether we are setting (or getting) + set = value !== undefined; + + // Try to normalize/fix the name + name = notxml && jQuery.props[ name ] || name; + + // Only do all the following if this is a node (faster for style) + if ( elem.nodeType === 1 ) { + // These attributes require special treatment + var special = rspecialurl.test( name ); + + // Safari mis-reports the default selected property of an option + // Accessing the parent's selectedIndex property fixes it + if ( name === "selected" && !jQuery.support.optSelected ) { + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + + // If applicable, access the attribute via the DOM 0 way + if ( name in elem && notxml && !special ) { + if ( set ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } + + elem[ name ] = value; + } + + // browsers index elements by id/name on forms, give priority to attributes. + if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { + return elem.getAttributeNode( name ).nodeValue; + } + + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + if ( name === "tabIndex" ) { + var attributeNode = elem.getAttributeNode( "tabIndex" ); + + return attributeNode && attributeNode.specified ? + attributeNode.value : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + + return elem[ name ]; + } + + if ( !jQuery.support.style && notxml && name === "style" ) { + if ( set ) { + elem.style.cssText = "" + value; + } + + return elem.style.cssText; + } + + if ( set ) { + // convert the value to a string (all browsers do this but IE) see #1070 + elem.setAttribute( name, "" + value ); + } + + var attr = !jQuery.support.hrefNormalized && notxml && special ? + // Some attributes require a special call on IE + elem.getAttribute( name, 2 ) : + elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return attr === null ? undefined : attr; + } + + // elem is actually elem.style ... set the style + // Using attr for specific style information is now deprecated. Use style instead. + return jQuery.style( elem, name, value ); + } +}); +var rnamespaces = /\.(.*)$/, + fcleanup = function( nm ) { + return nm.replace(/[^\w\s\.\|`]/g, function( ch ) { + return "\\" + ch; + }); + }; + +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code originated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function( elem, types, handler, data ) { + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // For whatever reason, IE has trouble passing the window object + // around, causing it to be cloned in the process + if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) { + elem = window; + } + + var handleObjIn, handleObj; + + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure + var elemData = jQuery.data( elem ); + + // If no elemData is found then we must be trying to bind to one of the + // banned noData elements + if ( !elemData ) { + return; + } + + var events = elemData.events = elemData.events || {}, + eventHandle = elemData.handle, eventHandle; + + if ( !eventHandle ) { + elemData.handle = eventHandle = function() { + // Handle the second event of a trigger and when + // an event is called after a page has unloaded + return typeof jQuery !== "undefined" && !jQuery.event.triggered ? + jQuery.event.handle.apply( eventHandle.elem, arguments ) : + undefined; + }; + } + + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native events in IE. + eventHandle.elem = elem; + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = types.split(" "); + + var type, i = 0, namespaces; + + while ( (type = types[ i++ ]) ) { + handleObj = handleObjIn ? + jQuery.extend({}, handleObjIn) : + { handler: handler, data: data }; + + // Namespaced event handlers + if ( type.indexOf(".") > -1 ) { + namespaces = type.split("."); + type = namespaces.shift(); + handleObj.namespace = namespaces.slice(0).sort().join("."); + + } else { + namespaces = []; + handleObj.namespace = ""; + } + + handleObj.type = type; + handleObj.guid = handler.guid; + + // Get the current list of functions bound to this event + var handlers = events[ type ], + special = jQuery.event.special[ type ] || {}; + + // Init the event handler queue + if ( !handlers ) { + handlers = events[ type ] = []; + + // Check for a special event handler + // Only use addEventListener/attachEvent if the special + // events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add the function to the element's handler list + handlers.push( handleObj ); + + // Keep track of which events have been used, for global triggering + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, pos ) { + // don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + var ret, type, fn, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, + elemData = jQuery.data( elem ), + events = elemData && elemData.events; + + if ( !elemData || !events ) { + return; + } + + // types is actually an event object here + if ( types && types.type ) { + handler = types.handler; + types = types.type; + } + + // Unbind all events for the element + if ( !types || typeof types === "string" && types.charAt(0) === "." ) { + types = types || ""; + + for ( type in events ) { + jQuery.event.remove( elem, type + types ); + } + + return; + } + + // Handle multiple events separated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + types = types.split(" "); + + while ( (type = types[ i++ ]) ) { + origType = type; + handleObj = null; + all = type.indexOf(".") < 0; + namespaces = []; + + if ( !all ) { + // Namespaced event handlers + namespaces = type.split("."); + type = namespaces.shift(); + + namespace = new RegExp("(^|\\.)" + + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)") + } + + eventType = events[ type ]; + + if ( !eventType ) { + continue; + } + + if ( !handler ) { + for ( var j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( all || namespace.test( handleObj.namespace ) ) { + jQuery.event.remove( elem, origType, handleObj.handler, j ); + eventType.splice( j--, 1 ); + } + } + + continue; + } + + special = jQuery.event.special[ type ] || {}; + + for ( var j = pos || 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( handler.guid === handleObj.guid ) { + // remove the given handler for the given type + if ( all || namespace.test( handleObj.namespace ) ) { + if ( pos == null ) { + eventType.splice( j--, 1 ); + } + + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + + if ( pos != null ) { + break; + } + } + } + + // remove generic event handler if no more handlers exist + if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + removeEvent( elem, type, elemData.handle ); + } + + ret = null; + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + var handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + delete elemData.events; + delete elemData.handle; + + if ( jQuery.isEmptyObject( elemData ) ) { + jQuery.removeData( elem ); + } + } + }, + + // bubbling is internal + trigger: function( event, data, elem /*, bubbling */ ) { + // Event object or event type + var type = event.type || event, + bubbling = arguments[3]; + + if ( !bubbling ) { + event = typeof event === "object" ? + // jQuery.Event object + event[expando] ? event : + // Object literal + jQuery.extend( jQuery.Event(type), event ) : + // Just the event type (string) + jQuery.Event(type); + + if ( type.indexOf("!") >= 0 ) { + event.type = type = type.slice(0, -1); + event.exclusive = true; + } + + // Handle a global trigger + if ( !elem ) { + // Don't bubble custom events when global (to avoid too much overhead) + event.stopPropagation(); + + // Only trigger if we've ever bound an event for it + if ( jQuery.event.global[ type ] ) { + jQuery.each( jQuery.cache, function() { + if ( this.events && this.events[type] ) { + jQuery.event.trigger( event, data, this.handle.elem ); + } + }); + } + } + + // Handle triggering a single element + + // don't do events on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { + return undefined; + } + + // Clean up in case it is reused + event.result = undefined; + event.target = elem; + + // Clone the incoming data, if any + data = jQuery.makeArray( data ); + data.unshift( event ); + } + + event.currentTarget = elem; + + // Trigger the event, it is assumed that "handle" is a function + var handle = jQuery.data( elem, "handle" ); + if ( handle ) { + handle.apply( elem, data ); + } + + var parent = elem.parentNode || elem.ownerDocument; + + // Trigger an inline bound script + try { + if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { + if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { + event.result = false; + } + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (e) {} + + if ( !event.isPropagationStopped() && parent ) { + jQuery.event.trigger( event, data, parent, true ); + + } else if ( !event.isDefaultPrevented() ) { + var target = event.target, old, + isClick = jQuery.nodeName(target, "a") && type === "click", + special = jQuery.event.special[ type ] || {}; + + if ( (!special._default || special._default.call( elem, event ) === false) && + !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { + + try { + if ( target[ type ] ) { + // Make sure that we don't accidentally re-trigger the onFOO events + old = target[ "on" + type ]; + + if ( old ) { + target[ "on" + type ] = null; + } + + jQuery.event.triggered = true; + target[ type ](); + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (e) {} + + if ( old ) { + target[ "on" + type ] = old; + } + + jQuery.event.triggered = false; + } + } + }, + + handle: function( event ) { + var all, handlers, namespaces, namespace, events; + + event = arguments[0] = jQuery.event.fix( event || window.event ); + event.currentTarget = this; + + // Namespaced event handlers + all = event.type.indexOf(".") < 0 && !event.exclusive; + + if ( !all ) { + namespaces = event.type.split("."); + event.type = namespaces.shift(); + namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + var events = jQuery.data(this, "events"), handlers = events[ event.type ]; + + if ( events && handlers ) { + // Clone the handlers to prevent manipulation + handlers = handlers.slice(0); + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Filter the functions by class + if ( all || namespace.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, arguments ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + } + + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + + fix: function( event ) { + if ( event[ expando ] ) { + return event; + } + + // store a copy of the original event object + // and "clone" to set read-only properties + var originalEvent = event; + event = jQuery.Event( originalEvent ); + + for ( var i = this.props.length, prop; i; ) { + prop = this.props[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary + if ( !event.target ) { + event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either + } + + // check if target is a textnode (safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var doc = document.documentElement, body = document.body; + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Add which for key events + if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) { + event.which = event.charCode || event.keyCode; + } + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) { + event.metaKey = event.ctrlKey; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button !== undefined ) { + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + } + + return event; + }, + + // Deprecated, use jQuery.guid instead + guid: 1E8, + + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady, + teardown: jQuery.noop + }, + + live: { + add: function( handleObj ) { + jQuery.event.add( this, handleObj.origType, jQuery.extend({}, handleObj, {handler: liveHandler}) ); + }, + + remove: function( handleObj ) { + var remove = true, + type = handleObj.origType.replace(rnamespaces, ""); + + jQuery.each( jQuery.data(this, "events").live || [], function() { + if ( type === this.origType.replace(rnamespaces, "") ) { + remove = false; + return false; + } + }); + + if ( remove ) { + jQuery.event.remove( this, handleObj.origType, liveHandler ); + } + } + + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( this.setInterval ) { + this.onbeforeunload = eventHandle; + } + + return false; + }, + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + } +}; + +var removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + elem.removeEventListener( type, handle, false ); + } : + function( elem, type, handle ) { + elem.detachEvent( "on" + type, handle ); + }; + +jQuery.Event = function( src ) { + // Allow instantiation without the 'new' keyword + if ( !this.preventDefault ) { + return new jQuery.Event( src ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + // Event type + } else { + this.type = src; + } + + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = now(); + + // Mark it as fixed + this[ expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + } + // otherwise set the returnValue property of the original event to false (IE) + e.returnValue = false; + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function( event ) { + // Check if mouse(over|out) are still within the same parent element + var parent = event.relatedTarget; + + // Firefox sometimes assigns relatedTarget a XUL element + // which we cannot access the parentNode property of + try { + // Traverse up the tree + while ( parent && parent !== this ) { + parent = parent.parentNode; + } + + if ( parent !== this ) { + // set the correct event type + event.type = event.data; + + // handle event if we actually just moused on to a non sub-element + jQuery.event.handle.apply( this, arguments ); + } + + // assuming we've left the element since we most likely mousedover a xul element + } catch(e) { } +}, + +// In case of event delegation, we only need to rename the event.type, +// liveHandler will take care of the rest. +delegate = function( event ) { + event.type = event.data; + jQuery.event.handle.apply( this, arguments ); +}; + +// Create mouseenter and mouseleave events +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + setup: function( data ) { + jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); + }, + teardown: function( data ) { + jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + } + }; +}); + +// submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function( data, namespaces ) { + if ( this.nodeName.toLowerCase() !== "form" ) { + jQuery.event.add(this, "click.specialSubmit", function( e ) { + var elem = e.target, type = elem.type; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + return trigger( "submit", this, arguments ); + } + }); + + jQuery.event.add(this, "keypress.specialSubmit", function( e ) { + var elem = e.target, type = elem.type; + + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + return trigger( "submit", this, arguments ); + } + }); + + } else { + return false; + } + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialSubmit" ); + } + }; + +} + +// change delegation, happens here so we have bind. +if ( !jQuery.support.changeBubbles ) { + + var formElems = /textarea|input|select/i, + + changeFilters, + + getVal = function( elem ) { + var type = elem.type, val = elem.value; + + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; + + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; + + } else if ( elem.nodeName.toLowerCase() === "select" ) { + val = elem.selectedIndex; + } + + return val; + }, + + testChange = function testChange( e ) { + var elem = e.target, data, val; + + if ( !formElems.test( elem.nodeName ) || elem.readOnly ) { + return; + } + + data = jQuery.data( elem, "_change_data" ); + val = getVal(elem); + + // the current data will be also retrieved by beforeactivate + if ( e.type !== "focusout" || elem.type !== "radio" ) { + jQuery.data( elem, "_change_data", val ); + } + + if ( data === undefined || val === data ) { + return; + } + + if ( data != null || val ) { + e.type = "change"; + return jQuery.event.trigger( e, arguments[1], elem ); + } + }; + + jQuery.event.special.change = { + filters: { + focusout: testChange, + + click: function( e ) { + var elem = e.target, type = elem.type; + + if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { + return testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = elem.type; + + if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + return testChange.call( this, e ); + } + }, + + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information/focus[in] is not needed anymore + beforeactivate: function( e ) { + var elem = e.target; + jQuery.data( elem, "_change_data", getVal(elem) ); + } + }, + + setup: function( data, namespaces ) { + if ( this.type === "file" ) { + return false; + } + + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + } + + return formElems.test( this.nodeName ); + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialChange" ); + + return formElems.test( this.nodeName ); + } + }; + + changeFilters = jQuery.event.special.change.filters; +} + +function trigger( type, elem, args ) { + args[0].type = type; + return jQuery.event.handle.apply( elem, args ); +} + +// Create "bubbling" focus and blur events +if ( document.addEventListener ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + jQuery.event.special[ fix ] = { + setup: function() { + this.addEventListener( orig, handler, true ); + }, + teardown: function() { + this.removeEventListener( orig, handler, true ); + } + }; + + function handler( e ) { + e = jQuery.event.fix( e ); + e.type = fix; + return jQuery.event.handle.call( this, e ); + } + }); +} + +jQuery.each(["bind", "one"], function( i, name ) { + jQuery.fn[ name ] = function( type, data, fn ) { + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ name ](key, data, type[key], fn); + } + return this; + } + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + var handler = name === "one" ? jQuery.proxy( fn, function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }) : fn; + + if ( type === "unload" && name !== "one" ) { + this.one( type, data, fn ); + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.add( this[i], type, handler, data ); + } + } + + return this; + }; +}); + +jQuery.fn.extend({ + unbind: function( type, fn ) { + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.remove( this[i], type, fn ); + } + } + + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.live( types, data, fn, selector ); + }, + + undelegate: function( selector, types, fn ) { + if ( arguments.length === 0 ) { + return this.unbind( "live" ); + + } else { + return this.die( types, null, fn, selector ); + } + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + + triggerHandler: function( type, data ) { + if ( this[0] ) { + var event = jQuery.Event( type ); + event.preventDefault(); + event.stopPropagation(); + jQuery.event.trigger( event, data, this[0] ); + return event.result; + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, i = 1; + + // link all the functions, so any of them can unbind this click handler + while ( i < args.length ) { + jQuery.proxy( fn, args[ i++ ] ); + } + + return this.click( jQuery.proxy( fn, function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + })); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +var liveMap = { + focus: "focusin", + blur: "focusout", + mouseenter: "mouseover", + mouseleave: "mouseout" +}; + +jQuery.each(["live", "die"], function( i, name ) { + jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { + var type, i = 0, match, namespaces, preType, + selector = origSelector || this.selector, + context = origSelector ? this : jQuery( this.context ); + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + types = (types || "").split(" "); + + while ( (type = types[ i++ ]) != null ) { + match = rnamespaces.exec( type ); + namespaces = ""; + + if ( match ) { + namespaces = match[0]; + type = type.replace( rnamespaces, "" ); + } + + if ( type === "hover" ) { + types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); + continue; + } + + preType = type; + + if ( type === "focus" || type === "blur" ) { + types.push( liveMap[ type ] + namespaces ); + type = type + namespaces; + + } else { + type = (liveMap[ type ] || type) + namespaces; + } + + if ( name === "live" ) { + // bind live handler + context.each(function(){ + jQuery.event.add( this, liveConvert( type, selector ), + { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); + }); + + } else { + // unbind live handler + context.unbind( liveConvert( type, selector ), fn ); + } + } + + return this; + } +}); + +function liveHandler( event ) { + var stop, elems = [], selectors = [], args = arguments, + related, match, handleObj, elem, j, i, l, data, + events = jQuery.data( this, "events" ); + + // Make sure we avoid non-left-click bubbling in Firefox (#3861) + if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) { + return; + } + + event.liveFired = this; + + var live = events.live.slice(0); + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { + selectors.push( handleObj.selector ); + + } else { + live.splice( j--, 1 ); + } + } + + match = jQuery( event.target ).closest( selectors, event.currentTarget ); + + for ( i = 0, l = match.length; i < l; i++ ) { + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( match[i].selector === handleObj.selector ) { + elem = match[i].elem; + related = null; + + // Those two events require additional checking + if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { + related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; + } + + if ( !related || related !== elem ) { + elems.push({ elem: elem, handleObj: handleObj }); + } + } + } + } + + for ( i = 0, l = elems.length; i < l; i++ ) { + match = elems[i]; + event.currentTarget = match.elem; + event.data = match.handleObj.data; + event.handleObj = match.handleObj; + + if ( match.handleObj.origHandler.apply( match.elem, args ) === false ) { + stop = false; + break; + } + } + + return stop; +} + +function liveConvert( type, selector ) { + return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&"); +} + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( fn ) { + return fn ? this.bind( name, fn ) : this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } +}); + +// Prevent memory leaks in IE +// Window isn't included so as not to unbind existing unload events +// More info: +// - http://isaacschlueter.com/2006/10/msie-memory-leaks/ +if ( window.attachEvent && !window.addEventListener ) { + window.attachEvent("onunload", function() { + for ( var id in jQuery.cache ) { + if ( jQuery.cache[ id ].handle ) { + // Try/Catch is to handle iframes being unloaded, see #4280 + try { + jQuery.event.remove( jQuery.cache[ id ].handle.elem ); + } catch(e) {} + } + } + }); +} +/*! + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context), + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set ); + } + } + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } + + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } + + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } + + return results; +}; + +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ + var set, match; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = context.getElementsByTagName("*"); + } + + return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + var filter = Expr.filter[ type ], found, item, left = match[1]; + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw "Syntax error, unrecognized expression: " + msg; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part){ + var isPartStr = typeof part === "string"; + + if ( isPartStr && !/\W/.test(part) ) { + part = part.toLowerCase(); + + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = part.toLowerCase(); + checkFn = dirNodeCheck; + } + + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = part.toLowerCase(); + checkFn = dirNodeCheck; + } + + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + return match[1].toLowerCase(); + }, + CHILD: function(match){ + if ( match[1] === "nth" ) { + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + // Accessing this property makes selected-by-default + // options in Safari work properly + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 === i; + }, + eq: function(elem, i, match){ + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } else { + Sizzle.error( "Syntax error, unrecognized expression: " + name ); + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + if ( type === "first" ) { + return true; + } + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first === 0 ) { + return diff === 0; + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){ + return "\\" + (num - 0 + 1); + })); +} + +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.compareDocumentPosition ? -1 : 1; + } + + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.sourceIndex ? -1 : 1; + } + + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.ownerDocument ? -1 : 1; + } + + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +function getText( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += getText( elem.childNodes ); + } + } + + return ret; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date).getTime(); + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; + + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + root = form = null; // release memory in IE +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } + + div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

            "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + div = null; // release memory in IE + })(); +} + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
            "; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +var contains = document.compareDocumentPosition ? function(a, b){ + return !!(a.compareDocumentPosition(b) & 16); +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; + +var isXML = function(elem){ + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = getText; +jQuery.isXMLDoc = isXML; +jQuery.contains = contains; + +return; + +window.Sizzle = Sizzle; + +})(); +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + slice = Array.prototype.slice; + +// Implement the identical functionality for filter and not +var winnow = function( elements, qualifier, keep ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return (elem === qualifier) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + }); +}; + +jQuery.fn.extend({ + find: function( selector ) { + var ret = this.pushStack( "", "find", selector ), length = 0; + + for ( var i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( var n = length; n < ret.length; n++ ) { + for ( var r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && jQuery.filter( selector, this ).length > 0; + }, + + closest: function( selectors, context ) { + if ( jQuery.isArray( selectors ) ) { + var ret = [], cur = this[0], match, matches = {}, selector; + + if ( cur && selectors.length ) { + for ( var i = 0, l = selectors.length; i < l; i++ ) { + selector = selectors[i]; + + if ( !matches[selector] ) { + matches[selector] = jQuery.expr.match.POS.test( selector ) ? + jQuery( selector, context || this.context ) : + selector; + } + } + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( selector in matches ) { + match = matches[selector]; + + if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { + ret.push({ selector: selector, elem: cur }); + delete matches[selector]; + } + } + cur = cur.parentNode; + } + } + + return ret; + } + + var pos = jQuery.expr.match.POS.test( selectors ) ? + jQuery( selectors, context || this.context ) : null; + + return this.map(function( i, cur ) { + while ( cur && cur.ownerDocument && cur !== context ) { + if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) { + return cur; + } + cur = cur.parentNode; + } + return null; + }); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + if ( !elem || typeof elem === "string" ) { + return jQuery.inArray( this[0], + // If it receives a string, the selector is used + // If it receives nothing, the siblings are used + elem ? jQuery( elem ) : this.parent().children() ); + } + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context || this.context ) : + jQuery.makeArray( selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( elem.parentNode.firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, slice.call(arguments).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], cur = elem[dir]; + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); +var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g, + rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i, + rtagName = /<([\w:]+)/, + rtbody = /"; + }, + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
            ", "
            " ], + thead: [ 1, "", "
            " ], + tr: [ 2, "", "
            " ], + td: [ 3, "", "
            " ], + col: [ 2, "", "
            " ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and From 37dabf63860662ff79e884239e3b265d49cfb1b3 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 4 Jun 2010 08:16:01 +0200 Subject: [PATCH 13/17] Added file images. Added visual file selection. --- scribeengine/controllers/media.py | 4 +-- scribeengine/public/images/file-image.png | Bin 0 -> 3906 bytes scribeengine/public/images/file-unknown.png | Bin 0 -> 1723 bytes .../public/scripts/ScribeEngine.Media.js | 32 +++++++++++++++--- scribeengine/public/styles/style.css | 3 ++ scribeengine/templates/media/index.mako | 11 +++--- 6 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 scribeengine/public/images/file-image.png create mode 100644 scribeengine/public/images/file-unknown.png diff --git a/scribeengine/controllers/media.py b/scribeengine/controllers/media.py index f3d0436..43b7cff 100644 --- a/scribeengine/controllers/media.py +++ b/scribeengine/controllers/media.py @@ -72,7 +72,7 @@ class MediaController(BaseController): self._get_directories(path, directories) c.directories = json.dumps(directories) c.files = self._get_files(path) - #return pformat(c.directories, indent=2) + c.page_title = u'Media Browser' return render(u'/media/index.mako') @jsonify @@ -80,7 +80,7 @@ class MediaController(BaseController): path = request.GET.get(u'path', u'').split(u',') dirpath = os.path.join(config[u'paths.media'], *path) #log.debug(dirpath) - return self._get_files(dirpath) + return {u'results': self._get_files(dirpath)} @jsonify def create_directory(self): diff --git a/scribeengine/public/images/file-image.png b/scribeengine/public/images/file-image.png new file mode 100644 index 0000000000000000000000000000000000000000..a56f9affd39c85f22dfbc7e8800468aaf2b87a7d GIT binary patch literal 3906 zcmV-I554e-P)bivR^gfi@sn z7a8I!wDSNqFb#|X8NjYLAO>{Vw*68*UjR|(fDnzZ8{Ka_SDT-kJInfpYZkaGhG8J3 zyaC7qxq1U?DG)m)J~x{K1VZ3ZeB%0ZMu5h1=W1qSBNx|#gZ)eRNNS#4_I(zL{r|R}Dpb91 zM&oFkGg&K(mU0nSRG1MT(K>aou9QM48bvoXarNun1ao;HLp=gkfMzSiI@%E|gwL~{14P~8Naip- z<9i6(1v2U|iP=GFD8=K{F}LH?lF#&mBV!Zc8Z z#4rRGwGR=xqMvwBkv2o#f-~r%doD*f21HvA&n6B?%;L zTGp?iGQ4N8#futGLGnpdi(M>#l6CnpO70Hw#uNbBkj$>=Amt8HkCKtVu>v%Lp_Cs5 zHSy)}ByQVr0s%=&>?Fz61&WC@$#jrpONixHLO5p8w>-uaHsZqIJ4fn-$C*s7LNt{LsxdwZDJ4oNj|KvP^!P>`_80mISjsmc z5~`3~BQe|41S1yBNtfAcHqpDZm8W0&IjefF<&Mw+dQ|p{NrBHQ7^&P4(b9*6Qd2~X zF$zu1gxu32wJ?}S^r4d_qSj%AaFMFiVD}Bb_bMU%2+#=L3B1OZBW0c%-iT?QGC|SZ zUZ(Z3B%ye~V~XZWR+F!|JhP%dM?7$d5XyZGo3wE z@rq2UgGgZbj3%s2(IEd%7eI;dZ-?WOY#@u2nnROEd1S{10^uO-?O`tIE8(Xq=#d#B$Uj%4TBq4?viw_Vr4l^CW$8@rbpgD>Vnwqhr zbTAs|ZP)?)@UIrY-LXN0l0K!!TuGHZA!V3U*GjB#6XQqrk<_m=!^wD*iaCp^qKnxL&K?2d zsR6&p1^w=Mx zEQJ*f5N%0tNVJo4dO(DD?3e#Vf7dvoIe-xkk&T9NOv#kCzW5qYk0V{*z>y(@gfUzC z57M!>jeNP2iU{#y;UWsf5o&OP(NDEMKLTVm1@P(Lt~-|I&xUUH#V=dhOKV4%XGePZ zho^^mF4ICZ;mvo>Ksb(-ghFr$uc+29qy`wDRRpuqrA&tUXl4|K4w#N%EU`j=aHYbRwZeD&{^NX=4LbBLsY=HPg$Q%xQn_y@dAr&=r z4bCtb?qJ=H1Ze$vN8q}!_vz28fQb<}Wssoj?@!W|O(MaIvJOPb@%ny>f?C0B<|q%m z(d$2#1!A6EfchRP&`r0HNe8GwRm!Z}o`N~;jSFCd2v9*2!%`?yapb@eVz~f8Z6UOz zH4*D89`X$~FFbL*p*<027)g>s%L@Cmn+)lOyk_2}*YiEv#SVJa4*D0A#@FA$8n z#KVH5Rc2{6##JZVPDg=Io_GTlFc=*k#h7tP5J3ouu_Q$7DhtDw?EUB%fAh=Llx&3% zEEeWp1L{$3UP5HGBLACD8;}i035YT$ox^;T>w}1bR0U!aq)Q(%)3lyH8tcIdDnIly z6B+DGi4KuQm

            Sg6@f;*H5rvro#Vh@1pD&i<1!(6SFQ_K~qOcrPtDZj2*Z6Q=^ zkYgJs`JIV0EzT6r55*Uh_Y04J#)-q;uJ5p+`8KAGtsykxV2C17xf`K{H!7xGxFmO+ ztBZo^NQsKFIBHHHLpHCqy-8A=tUlaMO2iNdtmXhRY{F$3dcXA{r6b?qz40MN>>gN< z{)KmehNq`;DCLQ~nf>eEVBJUy5{rJ7Bp?)He^!t@mB`>YK?>4g zZ)!K|4tM*8nehOXc9X6LrjSeaa^#J*$kA8%>&$fs`Gu<2HJ*Yo-<;VS{Q-$31#)d; z#72vxD;N7~hXV%)St&Xy5t^I=32_{NqAsCa%U{zMik|KSmci`zQZ(OL#>(zw$IBha z-;D4;^lEY<%oicQ`U%*%rGS9X&B2+(Uo!K}Ev$ZS3)3AtQL!TVbO!eWMIhftTW~ck zLIIF3Z6T^Pu~>{1p|sx(jy@E_{M{@UPd>*xZ@2R1u1+3LUW|*FpLp&1!oZ_H0v~^l zA*ipSuInPDoKG9%^ReVQc71mhhX(KG_Ui}Py1kj!brUFKALYqmiZcmLlq*zDIJCF7 zV_6o(Qagu#97O&0Nv}1&%71TP%YW?qJ;qZJ0K~k6dvu*S@$~^Ngf}G+Qu!?wk9uy6 zK94ro7=dILrOP*S{|k>Ww)JsjFv{y|*KpNklU&z5$y@JNNN-D%Zt<9CV&{!3Fq4{@ z=L7uo!~;}Z0}K%J3S|ds#06dD8Sq7)Hl`Yhj^j|NREj_uuxm!lvj#Lq*VXr8PmN<2 zvt;%U^TO^N&%0&fi8QNMcCkNjBSUT1B6mV8q{!r*xoDlIcv0Pb-vD>c0F4GfAV9bt zl|R<}a6R02-+e#XuwjGVwryJ;aL;-UI9CW|(7EYOK6v!I*oA3SFop`miS+$G`73`w z$Or(C2rH)Z&iVEDnoy6pcJ;muZgmb_mjM#6K^kaWBqk3&_~1Wp+O%nnSBrLf2IK$- zKz>dN%!_hl3oHNRr+`M9Ay!`VeR{6F2W184)~E%%p&>Nj0*-&}i|3U1GTJSnouW5Y z#I59U$~l~h$5Muf%Jb)!JN8XC-E`aWKuH1)Bx*`?(V z?;^kI4hnmIP9&&M6-}Y+l8z}Ra}J#E?pK3c`%&QdJL}p-Pi!7tDWIJSZZ$AXwG zlBA*rQ?m{laen%%KLzf`GupLr?E?1f7;&RS-;x;pJuR&4PILK19VEk&Y&Pq2&z?Px z-gVbqe+y&*`yAg7;GE#jj?(MAOS3jfh9V>*20gJ+rk85A3Mf`wj}0Dk-VSL0c1Gp5 zOC-z^TYvULYRKpFzUUeU2M1re`|i8%17?7V_ONJe5Fk4E@1AHyBxGSKNjw$=w?fI5 zi+7~eKrJh!sNO#n1r=}S6Vy;B6v*XrAM@zZqwjf@|Bl(&+3DJMf);QRY>bxTF3Q4X z=e`q^Dh@@D16=`%I=pzV=!8Jm-lM2ep#3Q5?{2DzKV#=loH#M~&_fU1dg#!hu}0z- zr3ScmiLud9#_T*byuN*i4-W^)Tz>cB86X8xOI(lW`fqPIe$IbV{KUk>=;qCvZ+Y|0 zH;(`%zv4H*LffF<;+wo5jYC^5~3qrAW7861$TwjNalnO^n1hAn$ z?H{gcJMZ=RgO5J?=q*n?@x;EfiC@$P=Q$3VEwYF_I6%)t?qwMRr`Yn502Mz zei7ajSHJM)E6<7=M{ zQfFS*uIu{LTH`p*r)b-Dl@6x_Zr=RVzg)Kb=I_1x?z<1(e*5i@0J-`@&iNYP0%g-Q z5p`yq<=Pi8&pOi3G%02M$LcjheAWyql}g2jAAb1nHg4S5|JGY?{pg;1?s*KD1?-ym z^EJQ)^1!%~^4oy3l`UIL_QPPX##+hy|<^Y>-P3GIR5_v3Kbv3PQJ5d1OlO; zpnyW5%p`1WZSUN<^XSo|%*@Ou61lm#`T6;;UcI7FD8DsZEbDs?d=^M9i3v| zK|g-{=oae%_4fAe%sDVHFgQ3kG&D3kJUlu&$`TtJA0KD4*%M-u6O&+YCdD|D95A>X zF)oJ-29GPo%&JdM{VtnJ2<;}U_DQs@;-gq*Vpf? zzkdKe>Pk%B%lFh8MssUlKbt)xTw4=~8nRM!!7IOyb#e414P^g`y|Kqp$WJdNq`K*xl+M zt3so(_b3O#Tc0M8V;_Hitc~lAj!?>Ts2B-vtV-hpOMpo zgaqHn-DfLSLrhPaj0GBzJ(v_mQ*&-qM#&SbgKlL_7XogaJmaIyKojtT2s7N5BO#BfV6YAeTfV zCL|FFx3V%*BBek*jd(V4`AkD-$#2}`f=evECuF`FTFJ3DceLzAk5lalHiKW%w#kNJaMUFTsC16|C4mSl`-XbNT0qR9%8VxYS=Bt%PxLh?I*XATJ+ za%BL$v7gS<5x}h?Su3SN^f>-A-1fU0OJAzT_}aTVq^1G{MTa|ZF=d|d=}S&P%zTGQ zI|nIrbo$mwu}0Ka*JZP5@lWq#2=YKU(vDrDMz*rN8kU^&P_uNP)S={XqP=P-PRpI1 zGZGbCKKTdsii|OZ$vb9#bj(qxtlp$iBz!uMTfK@451x3qCtY8o!{cuCalZN z7AQgLgXSenOBWcuN09zHc ul").html(""); - $.each(data, function () { + $.each(data.results, function () { var filename = this; + var extension = filename.substr(filename.length - 4); + if (extension == ".png" || extension == ".jpg") + { + var filetype = "file-image"; + } + else + { + var filetype = "file-unknown"; + } if (filename.length > 15) { filename = filename.substr(0, 12) + "..."; } $("#file-list > ul").append( $("

          • ") - .append($("
            ").attr("class", "file").html(" ")) - .append($("
            ").attr("class", "caption").attr("title", filename).text(filename)) + .append($("").attr("href", "#").attr("class", "file") + .html("").click(ScribeEngine.Media.selectFile)) + .append($("").attr("href", "#").attr("class", "caption").attr("title", filename).text(filename).click(ScribeEngine.Media.selectFile)) ); }); } ); + }, + selectFile: function (e) + { + var li = ScribeEngine.Events.getElement(e).parent(); + if (!li.is("li")) + { + li = li.parent(); + } + li.parent().children("li").children(".selected").removeClass("selected"); + li.children("a").addClass("selected").blur(); } }); ScribeEngine.Events.load(function () { ScribeEngine.Events.click("#new-directory", ScribeEngine.Media.newDirectory); - ScribeEngine.Events.click("#file-select", window.close); + ScribeEngine.Events.click("#file-select", ScribeEngine.Media.closeWindow); }); diff --git a/scribeengine/public/styles/style.css b/scribeengine/public/styles/style.css index a78b713..d8f9712 100644 --- a/scribeengine/public/styles/style.css +++ b/scribeengine/public/styles/style.css @@ -512,6 +512,9 @@ fieldset.form-details .form-text { color: #000; } +/* Media Browser */ + + /* Pagination */ .pagination { diff --git a/scribeengine/templates/media/index.mako b/scribeengine/templates/media/index.mako index 1ea90c7..d33464b 100644 --- a/scribeengine/templates/media/index.mako +++ b/scribeengine/templates/media/index.mako @@ -11,15 +11,18 @@ % endif From e3836b5a4118ae471cdc4d26a7b1feb5645ff0d2 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Sat, 5 Jun 2010 19:38:28 +0200 Subject: [PATCH 14/17] Moved the image file stuff to the server side. Fixed up the initial file display. --- scribeengine/controllers/media.py | 9 ++++-- .../public/scripts/ScribeEngine.Media.js | 28 +++++++++---------- scribeengine/templates/media/index.mako | 10 +++---- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/scribeengine/controllers/media.py b/scribeengine/controllers/media.py index 43b7cff..134d373 100644 --- a/scribeengine/controllers/media.py +++ b/scribeengine/controllers/media.py @@ -60,7 +60,13 @@ class MediaController(BaseController): def _get_files(self, dirpath): for root, dirs, files in os.walk(os.path.abspath(dirpath)): - return files + filelist = [] + for filename in files: + if os.path.splitext(filename)[1] in [u'.png', u'.jpg', u'.gif']: + filelist.append({u'name': filename, u'type': u'/images/file-image.png'}) + else: + filelist.append({u'name': filename, u'type': u'/images/file-unknown.png'}) + return filelist break def index(self): @@ -79,7 +85,6 @@ class MediaController(BaseController): def get_files(self): path = request.GET.get(u'path', u'').split(u',') dirpath = os.path.join(config[u'paths.media'], *path) - #log.debug(dirpath) return {u'results': self._get_files(dirpath)} @jsonify diff --git a/scribeengine/public/scripts/ScribeEngine.Media.js b/scribeengine/public/scripts/ScribeEngine.Media.js index 2ee0875..fb6f60c 100644 --- a/scribeengine/public/scripts/ScribeEngine.Media.js +++ b/scribeengine/public/scripts/ScribeEngine.Media.js @@ -36,25 +36,23 @@ ScribeEngine.Namespace.create("ScribeEngine.Media", { function (data, textStatus) { $("#file-list > ul").html(""); $.each(data.results, function () { - var filename = this; - var extension = filename.substr(filename.length - 4); - if (extension == ".png" || extension == ".jpg") + var file = this; + if (file.name.length > 15) { - var filetype = "file-image"; - } - else - { - var filetype = "file-unknown"; - } - if (filename.length > 15) - { - filename = filename.substr(0, 12) + "..."; + file.name = file.name.substr(0, 12) + "..."; } $("#file-list > ul").append( $("
          • ") - .append($("").attr("href", "#").attr("class", "file") - .html("").click(ScribeEngine.Media.selectFile)) - .append($("").attr("href", "#").attr("class", "caption").attr("title", filename).text(filename).click(ScribeEngine.Media.selectFile)) + .append( + $("").attr("href", "#").attr("class", "file") + .html("") + .click(ScribeEngine.Media.selectFile) + ) + .append( + $("").attr("href", "#").attr("class", "caption") + .attr("title", file.name).text(file.name) + .click(ScribeEngine.Media.selectFile) + ) ); }); } diff --git a/scribeengine/templates/media/index.mako b/scribeengine/templates/media/index.mako index d33464b..6743731 100644 --- a/scribeengine/templates/media/index.mako +++ b/scribeengine/templates/media/index.mako @@ -29,13 +29,13 @@
            +% if len(file[u'name']) > 15: + ${file[u'name'][:12]}...
          • % else: -
            ${filename}
            +
            ${file[u'name']}
            % endif % endfor From 5268a19a482482dd1e611daf74e17a22289b7830 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Sun, 6 Jun 2010 22:10:03 +0200 Subject: [PATCH 15/17] Fixed a bug in the browser template. --- scribeengine/public/scripts/ScribeEngine.Media.js | 5 +++-- scribeengine/public/scripts/ScribeEngine.js | 3 +++ scribeengine/templates/media/index.mako | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/scribeengine/public/scripts/ScribeEngine.Media.js b/scribeengine/public/scripts/ScribeEngine.Media.js index fb6f60c..2a77354 100644 --- a/scribeengine/public/scripts/ScribeEngine.Media.js +++ b/scribeengine/public/scripts/ScribeEngine.Media.js @@ -46,17 +46,16 @@ ScribeEngine.Namespace.create("ScribeEngine.Media", { .append( $("").attr("href", "#").attr("class", "file") .html("") - .click(ScribeEngine.Media.selectFile) ) .append( $("").attr("href", "#").attr("class", "caption") .attr("title", file.name).text(file.name) - .click(ScribeEngine.Media.selectFile) ) ); }); } ); + return false; }, selectFile: function (e) { @@ -67,10 +66,12 @@ ScribeEngine.Namespace.create("ScribeEngine.Media", { } li.parent().children("li").children(".selected").removeClass("selected"); li.children("a").addClass("selected").blur(); + return false; } }); ScribeEngine.Events.load(function () { ScribeEngine.Events.click("#new-directory", ScribeEngine.Media.newDirectory); ScribeEngine.Events.click("#file-select", ScribeEngine.Media.closeWindow); + ScribeEngine.Events.liveClick("#file-list > ul > li > a", ScribeEngine.Media.selectFile); }); diff --git a/scribeengine/public/scripts/ScribeEngine.js b/scribeengine/public/scripts/ScribeEngine.js index 33f4967..955ab21 100644 --- a/scribeengine/public/scripts/ScribeEngine.js +++ b/scribeengine/public/scripts/ScribeEngine.js @@ -90,6 +90,9 @@ ScribeEngine.Namespace.create("ScribeEngine.Events", { keypress: function (selector, func) { $(selector).bind("keypress", func); }, + liveClick: function (selector, func) { + $(selector).live("click", func); + }, getElement: function(event) { var targ; if (!event) { diff --git a/scribeengine/templates/media/index.mako b/scribeengine/templates/media/index.mako index 6743731..a0beb7f 100644 --- a/scribeengine/templates/media/index.mako +++ b/scribeengine/templates/media/index.mako @@ -31,11 +31,11 @@
      + % if len(file[u'name']) > 15: - ${file[u'name'][:12]}...
    + ${file[u'name'][:12]}... % else: - ${file[u'name']}
+ ${file[u'name']} % endif % endfor From e10466d808e9c5389d60f0c43a318ef4ac4b50c7 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 11 Nov 2010 07:17:00 +0200 Subject: [PATCH 16/17] Commit last changes. --- scribeengine/controllers/media.py | 2 ++ scribeengine/templates/media/index.mako | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/scribeengine/controllers/media.py b/scribeengine/controllers/media.py index 134d373..ae50db1 100644 --- a/scribeengine/controllers/media.py +++ b/scribeengine/controllers/media.py @@ -42,6 +42,7 @@ class MediaController(BaseController): def __before__(self): BaseController.__before__(self) + self._add_javascript(u'tinymce/tiny_mce_popup.js') self._add_javascript(u'ScribeEngine.Media.js') def _get_directories(self, parent=None, tree=[]): @@ -70,6 +71,7 @@ class MediaController(BaseController): break def index(self): + log.debug(request.params) self._add_javascript(u'jstree/jquery.jstree.js') directories = [] path = os.path.join(config[u'paths.media'], u'user%s' % c.current_user.id) diff --git a/scribeengine/templates/media/index.mako b/scribeengine/templates/media/index.mako index a0beb7f..43a9cda 100644 --- a/scribeengine/templates/media/index.mako +++ b/scribeengine/templates/media/index.mako @@ -14,6 +14,7 @@ body { margin: 0; padding: 0; font-family: Arial, sans-serif; } img { border: 0; } input[type=button] { background: #f0f0f0 url(/images/media-button.png) top left repeat-x; border: 1px solid #ccc; color: #000; height: 24px; } + span.separator { border-left: 1px solid #ccc; height: 24px; margin: 0 5px; overflow: hidden; width: 1px; } #directory-tree { border-right: 1px solid #999; border-bottom: 1px solid #999; height: 370px; float: left; padding-right: 4px; width: 195px; } #file-list { border-bottom: 1px solid #999; height: 370px; padding-left: 4px; float: left; width: 396px; } #button-bar { clear: both; height: 30px; line-height: 30px; } @@ -42,8 +43,9 @@
- + +