Clean start
@@ -0,0 +1,4 @@
|
||||
|
||||
node_modules/
|
||||
lib/db.js
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
@@ -0,0 +1,31 @@
|
||||
**Live Demo:** http://glacial-island-2506.herokuapp.com/
|
||||
|
||||
Features ndentJS has that workflowy doesn't have:
|
||||
--------
|
||||
- Live googleDocs-esque editing.
|
||||
|
||||
|
||||
Pending features that workflowy has:
|
||||
--------
|
||||
- Several small bug fixes.
|
||||
- A better UI
|
||||
- Hashtags
|
||||
- Search
|
||||
- Import/Export
|
||||
|
||||
|
||||
Pending features that Workflowy doesn't have:
|
||||
-------
|
||||
- Split Screen:
|
||||
- Revision Control.
|
||||
- Transclusion/Aliasing/Graph-structure.
|
||||
- Latex Editor.
|
||||
|
||||
|
||||
|
||||
Installation and Usage
|
||||
======================
|
||||
|
||||
- A throwaway database account is provided. But, you can edit /lib/db.js with your own credentials.
|
||||
- `npm install`
|
||||
- `node app.js`
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('express');
|
||||
// var routes = require('./routes/routes.js');
|
||||
var fs = require('fs');
|
||||
var http = require('http');
|
||||
var path = require('path');
|
||||
var crypto = require('crypto');
|
||||
var db = require('./lib/db');
|
||||
var helperLib = require('./lib/helperLib.js');
|
||||
|
||||
var app = express()
|
||||
var server = http.Server(app);
|
||||
helperLib.createSocket(server);
|
||||
server.listen(process.env.PORT || 3000);
|
||||
|
||||
|
||||
|
||||
// all environments
|
||||
app.set('port', process.env.PORT || 3000);
|
||||
app.set('views', path.join(__dirname, 'views'));
|
||||
app.set('view engine', 'ejs');
|
||||
app.use(express.favicon());
|
||||
app.use(express.logger('dev'));
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded());
|
||||
app.use(express.methodOverride());
|
||||
app.use(app.router);
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
app.use(express.session({secret: 'secretpasswordforsessions', store: helperLib.getSessionStore()}));
|
||||
|
||||
app.configure(function () {
|
||||
app.use(express.bodyParser()); //not sure...
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'ejs');
|
||||
app.use(express.static(__dirname + '/public')); //ALREADY USING IT.
|
||||
});
|
||||
app.set('view options', {
|
||||
layout: false
|
||||
});
|
||||
|
||||
app.get('/',function(req,res){
|
||||
console.log("\n\nrenderingIndex\n")
|
||||
res.render('index');
|
||||
});
|
||||
|
||||
if(process.argv[2] == "restart"){
|
||||
console.log("restarting");
|
||||
helperLib.setUpDB();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
var mongoose = require('mongoose');
|
||||
var Schema = mongoose.Schema;
|
||||
module.exports.mongoose = mongoose;
|
||||
module.exports.Schema = Schema;
|
||||
|
||||
// Connect to cloud database
|
||||
//https://mongolab.com/
|
||||
var username = "throwaway"
|
||||
var password = "throwaway1";//
|
||||
var address = '@ds037637.mongolab.com:37637/throwaway_db';
|
||||
connect();
|
||||
|
||||
|
||||
// Connect to mongo
|
||||
function connect() {
|
||||
|
||||
var url = 'mongodb://' + username + ':' + password + address;
|
||||
try { mongoose.connect(url); }
|
||||
catch(err) { console.log("Error: Sign In to MongoLab") }
|
||||
console.log("error caught");
|
||||
|
||||
}
|
||||
function disconnect() {
|
||||
mongoose.disconnect()
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
var //cookie = require('cookie'),
|
||||
crypto = require('crypto')
|
||||
, db = require('./db')
|
||||
//, exchange = require('./exchange')
|
||||
, express = require('express')
|
||||
, http = require('http')
|
||||
, MemoryStore = express.session.MemoryStore
|
||||
, ObjectID = require('mongodb').ObjectID,
|
||||
cookie = require('cookie');
|
||||
|
||||
var User = require('../models/User.js');
|
||||
var Node = require('../models/Node.js');
|
||||
var sessionStore = new MemoryStore();
|
||||
var io;
|
||||
var online = [];
|
||||
var lastExchangeData = {};
|
||||
|
||||
|
||||
console.log("\n\nLOOK HERE!!")
|
||||
// console.log(revAlg);
|
||||
|
||||
// var revAlg = require('./revControlAlg.js');
|
||||
// var getTimeHash = revAlg.getTimeHash;
|
||||
console.log("\n\n");
|
||||
|
||||
|
||||
module.exports = {
|
||||
// createUser: function(username, email, password, callback) {
|
||||
// var user = {username: username, email: email
|
||||
// , password: encryptPassword(password)};
|
||||
// db.insertOne('users', user, callback);
|
||||
// },
|
||||
createUser: function(username, password, callback){
|
||||
User.addUser(username, password, callback);
|
||||
},
|
||||
|
||||
getNodes: function(){
|
||||
return Node.findNodes();
|
||||
},
|
||||
|
||||
getSessionStore: function(){
|
||||
return sessionStore;
|
||||
},
|
||||
|
||||
createSocket: function(server) {
|
||||
io = require('socket.io').listen(server);
|
||||
io.sockets.on('connection', function(socket){
|
||||
|
||||
//socket.emit('news', {hello: "world"});
|
||||
socket.on('nodeRequest', function(data){
|
||||
var nodes = Node.findNodes(socket); //finds, then sends through socket.
|
||||
//var nodes = {'keep': 'calm'};
|
||||
//socket.emit('nodeData', nodes); (emit is in findNodes);
|
||||
})
|
||||
|
||||
socket.on("edit", function(data){
|
||||
var id = data[0];
|
||||
var newText = data[1];
|
||||
console.log("\n\n\n\n edit received:" + newText);
|
||||
Node.updateText(id, newText);
|
||||
socket.broadcast.emit("edit", [id, newText]);
|
||||
|
||||
});
|
||||
|
||||
//This works for all ids except negative ids.
|
||||
socket.on("editing", function(id){
|
||||
socket.broadcast.emit("editing", id);
|
||||
});
|
||||
|
||||
|
||||
socket.on("blurred", function(data){
|
||||
console.log('\nBLURRED\n')
|
||||
socket.broadcast.emit("blurred", data);
|
||||
var id = data[0];
|
||||
var text = data[1];
|
||||
Node.updateText(id, text);
|
||||
});
|
||||
|
||||
//I'm pretty sure i don't use this anywhere.
|
||||
socket.on('nodeInsert', function(data){
|
||||
Node.addNode("testText", [], [], function(){});
|
||||
});
|
||||
|
||||
socket.on("transclude", function(data){
|
||||
var parId = data[0];
|
||||
var transcludeId = data[2];
|
||||
var newIndex = data[1];
|
||||
var now = Date.now();
|
||||
Node.updateParent(parId, transcludeId ,newIndex, now );
|
||||
})
|
||||
|
||||
|
||||
|
||||
socket.on("newNode", function(data){
|
||||
//data[0] = [parID, newindex] . data[1] =
|
||||
var modelJson = data[1]; //(includes the negative ID to find later);
|
||||
var parId = data[0][0];
|
||||
var newIndex = data[0][1];
|
||||
|
||||
var now = Date.now();
|
||||
var callback = function(err, instance, now){
|
||||
socket.emit("updateReceived", [modelJson._id ,instance, data[0]]);
|
||||
socket.broadcast.emit("newNode", [ data[0] ,instance]);
|
||||
//io.sockets.emit("newNode", [data[0], instance])
|
||||
//I'm going to have to update the parent Model on this as well...
|
||||
//(and therefore, broadcast the array...)
|
||||
Node.updateParent(parId, instance._id ,newIndex, now );
|
||||
}
|
||||
Node.addNode(modelJson.text, modelJson.children, modelJson.parents, callback);
|
||||
|
||||
});
|
||||
|
||||
socket.on("removeNode", function(data){
|
||||
var thisId = data[0];
|
||||
var thisIndex = data[1];
|
||||
var parId = data[2];
|
||||
socket.broadcast.emit("removeNode", data);
|
||||
Node.removeNode(thisId, thisIndex, parId);
|
||||
|
||||
});
|
||||
|
||||
socket.on("movedNode", function(data){
|
||||
// var ids = [thisModel.get("_id"), oldParModel.get("_id"), newParModel.get("_id")];
|
||||
// var arrays = [thisModel.get("parents"), oldParModel.get("children"), newParModel.get("children")];
|
||||
// var data = [ids, arrays];
|
||||
Node.moveNode(data[0], data[1]);
|
||||
socket.broadcast.emit("movedNode", [data[0], data[2]]);
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
socket.on("getTimeHash", function(){
|
||||
var timeHash = getTimeHash();
|
||||
|
||||
socket.emit("timeHash", timeHash);
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
// io.configure(function (){
|
||||
// io.set('authorization', function (handshakeData, callback) {
|
||||
// if (handshakeData.headers.cookie) {
|
||||
// handshakeData.cookie = cookie.parse(decodeURIComponent(handshakeData.headers.cookie));
|
||||
// handshakeData.sessionID = handshakeData.cookie['connect.sid'];
|
||||
// sessionStore.get(handshakeData.sessionID, function (err, session) {
|
||||
// if (err || !session) {
|
||||
// return callback(null, false);
|
||||
// } else {
|
||||
// handshakeData.session = session;
|
||||
// console.log('session data', session);
|
||||
// return callback(null, true);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// else {
|
||||
// return callback(null, false);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
},
|
||||
|
||||
setUpDB: function(){
|
||||
Node.setUpDB();
|
||||
//getTimeHash();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
var db = require('../lib/db');
|
||||
|
||||
var NodeSchema = new db.Schema({
|
||||
text: {type: String},
|
||||
children: {type: Array},
|
||||
parents: {type: Array}
|
||||
})
|
||||
|
||||
var SnapSchema = new db.Schema({
|
||||
text: {type: String},
|
||||
children: {type: Array},
|
||||
parents: {type: Array},
|
||||
timestamp: {type: Number},
|
||||
cur_id: {type: String}
|
||||
});
|
||||
|
||||
|
||||
|
||||
var rootID;
|
||||
|
||||
var MySnap = db.mongoose.model('snaps', SnapSchema);
|
||||
var MyNode = db.mongoose.model('nodes', NodeSchema);
|
||||
|
||||
// Exports
|
||||
module.exports.addNode = addNode;
|
||||
module.exports.findNodes = findNodes;
|
||||
module.exports.updateParent = updateParent;
|
||||
module.exports.updateText = updateText;
|
||||
module.exports.setUpDB = setUpDB;
|
||||
module.exports.removeNode = removeNode;
|
||||
module.exports.moveNode = moveNode;
|
||||
module.exports.rootNodeId = rootNodeId;
|
||||
module.exports.MySnap = MySnap;
|
||||
|
||||
function rootNodeId(){
|
||||
return rootID;
|
||||
}
|
||||
|
||||
function moveNode(ids, arrays){
|
||||
var thisId = ids[0]; //draggedId
|
||||
var now = Date.now();
|
||||
MyNode.findById(thisId, null, function(err, node){
|
||||
addSnap(node, now);
|
||||
node.parents = arrays[0];
|
||||
node.save();
|
||||
});
|
||||
var oldParId = ids[1];
|
||||
MyNode.findById(oldParId, null, function(err, node){
|
||||
addSnap(node, now);
|
||||
node.children = arrays[1];
|
||||
node.save();
|
||||
});
|
||||
var newParId = ids[2];
|
||||
MyNode.findById(newParId, null, function(err, node){
|
||||
addSnap(node, now);
|
||||
node.children = arrays[2];
|
||||
node.save();
|
||||
});
|
||||
}
|
||||
|
||||
function addSnap(node, now, callback){
|
||||
var instance = new MySnap();
|
||||
instance.text = node.text;
|
||||
instance.children = node.children;
|
||||
instance.parents = node.parents;
|
||||
instance.cur_id = node._id;
|
||||
instance.timestamp = now;
|
||||
instance.save(function(err){
|
||||
if(err){
|
||||
//callback(err);
|
||||
}
|
||||
else{
|
||||
//callback(null, instance);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//this is technically not good asynchronous code.
|
||||
//this coulde be made into a recursive function which takes an array of todo-strings.
|
||||
function addListOfNodes(){
|
||||
addNode("0root", [], [], function(err, rootNode){
|
||||
rootID = rootNodeId._id;
|
||||
var parId = rootNode._id;
|
||||
addNode("Todos", [], [parId], function(err, vadar){ //called vadar because it is the parent/father
|
||||
var vadarId = vadar._id;
|
||||
var childArray = [];
|
||||
addNode("Revision Control", [], [vadarId], function(err, child){
|
||||
childArray.push(child._id);
|
||||
});
|
||||
addNode("LatexEditor", [], [vadarId], function(err, child){
|
||||
childArray.push(child._id);
|
||||
});
|
||||
addNode("Lots of other stuff", [], [vadarId], function(err, child){
|
||||
childArray.push(child._id);
|
||||
vadar.children = childArray;
|
||||
vadar.save();
|
||||
});
|
||||
rootNode.children = [vadarId];
|
||||
rootNode.save();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function setUpDB(){
|
||||
MyNode.remove({}, function(err) { console.log('collection removed') });
|
||||
MySnap.remove({}, function(err) { console.log('collection removed') });
|
||||
addListOfNodes();
|
||||
}
|
||||
|
||||
function removeNode(thisId, thisIndex, parId){
|
||||
var now = Date.now();
|
||||
MyNode.findById(parId, null, function(err, parNode){
|
||||
if(err || parNode == null){
|
||||
return;
|
||||
}
|
||||
addSnap(parNode, now);
|
||||
var temp = parNode.children;
|
||||
console.log(temp.splice(thisIndex, 1));
|
||||
console.log(temp);
|
||||
parNode.children = temp;
|
||||
|
||||
parNode.save();
|
||||
});
|
||||
MyNode.findById(thisId, null, function(err, delNode){
|
||||
if(err || delNode == null){
|
||||
return;
|
||||
}
|
||||
addSnap(delNode, now);
|
||||
if(delNode.parents.length ==1 ){
|
||||
delNode.remove();
|
||||
}
|
||||
else{ //this is the condition that we'll have to take care of if there are dups.
|
||||
delNode.parents = _.without(parents, parId);
|
||||
delNode.save();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function updateText(id, newText){
|
||||
console.log("\nUPDATE TEXT\n" + id + newText);
|
||||
var now = Date.now();
|
||||
MyNode.findById(id, null, function(err, node){
|
||||
if(err || node == null){
|
||||
return;
|
||||
}
|
||||
addSnap(node, now);
|
||||
node.text = newText;
|
||||
node.save();
|
||||
});
|
||||
}
|
||||
|
||||
function updateParent(parId, newId ,newIndex, now){
|
||||
MyNode.findById(parId, null, function(err, parNode){
|
||||
if(err || parNode == null){
|
||||
return;
|
||||
}
|
||||
addSnap(parNode, now);
|
||||
parNode.children.insert(newIndex, newId);
|
||||
parNode.save();
|
||||
})
|
||||
}
|
||||
|
||||
//add Node to the DB.
|
||||
function addNode(text, children, parents, callback){
|
||||
var now = Date.now();
|
||||
var instance = new MyNode();
|
||||
instance.text = text;
|
||||
instance.children = children;
|
||||
instance.parents = parents;
|
||||
addSnap(instance, now);
|
||||
|
||||
instance.save(function (err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
}
|
||||
else {
|
||||
callback(null, instance, now);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function findNodes(socket){
|
||||
var nodes = {'keeping': 'calm'}
|
||||
MyNode.find(function(err, nodes){
|
||||
if(!err){
|
||||
socket.emit('nodeData', nodes)
|
||||
return {'hell': 'yes'}
|
||||
}else{
|
||||
socket.emit('nodeData', "error!!!")
|
||||
return {'hell': 'no'}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
Array.prototype.insert = function (index, item) {
|
||||
this.splice(index, 0, item);
|
||||
};
|
||||
|
||||
Array.prototype.remove = function(from, to) {
|
||||
var rest = this.slice((to || from) + 1 || this.length);
|
||||
this.length = from < 0 ? this.length + from : from;
|
||||
return this.push.apply(this, rest);
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
//(not being used yet)
|
||||
|
||||
var crypto = require('crypto')
|
||||
var db = require('../lib/db');
|
||||
var UserSchema = new db.Schema({
|
||||
username : {type: String, unique: true}
|
||||
, password : String
|
||||
})
|
||||
var MyUser = db.mongoose.model('User', UserSchema);
|
||||
// Exports
|
||||
module.exports.addUser = addUser;
|
||||
// Add user to database
|
||||
function addUser(username, password, callback) {
|
||||
var instance = new MyUser();
|
||||
instance.username = username;
|
||||
instance.password = encryptPassword(password);
|
||||
instance.save(function (err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
}
|
||||
else {
|
||||
callback(null, instance);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function encryptPassword(plainText) {
|
||||
return crypto.createHash('md5').update(plainText).digest('hex');
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "ndent",
|
||||
"version": "0.0.1-2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node app.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "3.1.0",
|
||||
"jade": "0.26.1",
|
||||
"mongoose": "2.6.5",
|
||||
"ejs": "0.8.3",
|
||||
"mongodb": "^1.1.7",
|
||||
"socket.io": "0.9.13",
|
||||
"cookie": "0.0.4",
|
||||
"underscore": "1.5.2"
|
||||
},
|
||||
"subdomain": "ndent",
|
||||
"engines": {
|
||||
"node": "0.10.x"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 357 B |
|
After Width: | Height: | Size: 528 B |
|
After Width: | Height: | Size: 423 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 946 B |
|
After Width: | Height: | Size: 451 B |
|
After Width: | Height: | Size: 36 KiB |
@@ -0,0 +1,311 @@
|
||||
$(function(){
|
||||
//alert("jquery works");
|
||||
|
||||
$("body").on("mouseover", "a.expandCollapse", function(event){
|
||||
// console.log("bleh");
|
||||
// debugger;
|
||||
$(event.target).find("a.expandCollapse").css("opacity", "1");
|
||||
$(event.target).closest("a.expandCollapse").css("opacity", "1");
|
||||
// $(event.target).siblings("a.expandCollapse").css("opacity", "1")
|
||||
});
|
||||
$("body").on("mouseleave", "a.expandCollapse", function(event){
|
||||
// console.log("bleh");
|
||||
// debugger;
|
||||
$(event.target).find("a.expandCollapse").css("opacity", ".001");
|
||||
$(event.target).closest("a.expandCollapse").css("opacity", ".001");
|
||||
// $(event.target).siblings("a.expandCollapse").css("opacity", ".001")
|
||||
});
|
||||
|
||||
$("body").on("click", ".expandCollapse", function(event){
|
||||
var LI = $(event.target).parent();
|
||||
LI.children("ul").slideToggle(110);
|
||||
LI.children(".zoomButton").toggleClass("collapsed");
|
||||
});
|
||||
$("body").on("click", ".splitScreen", function(){
|
||||
$(".main2").remove();
|
||||
})
|
||||
$("body").on("keydown", "textarea", keydownHandler);
|
||||
$("body").on("focus", "textarea", function(event){
|
||||
var that = this;
|
||||
voInitializer(that, event);
|
||||
var id = $(event.target).closest("li").attr("data-id");
|
||||
console.log("ABOUT TO EMIT 'EDITING' ");
|
||||
console.log(id);
|
||||
socket.emit("editing", id);
|
||||
});
|
||||
$("body").on("blur", "textarea", function(event){
|
||||
var thisLI = $(event.target).closest("li");
|
||||
var id = thisLI.attr("data-id");
|
||||
var text = thisLI.children().children("textarea").val();
|
||||
//console.log(id);
|
||||
//alert("blurred ID" + id + text);
|
||||
socket.emit("blurred", [id, text]);
|
||||
$("textarea").textareaAutoExpand();
|
||||
});
|
||||
$("body").on("click", ".transclude", function(event){
|
||||
//alert(vo.thisId);
|
||||
alert("Transclusion syncing with the server has not been implemented. KnownBugs:\n0.Don't make infinite loops.\n1.");
|
||||
transclude();
|
||||
});
|
||||
|
||||
// AppRouter.initialize();
|
||||
myRouter = new AppRouter;
|
||||
Backbone.history.start();
|
||||
|
||||
//console.log("typeOF FUNCTION");
|
||||
//console.log($.fn.textareaAutoExpand);
|
||||
});
|
||||
|
||||
|
||||
function createPathMenu(event){
|
||||
//console.log($(event.target).attr("data-id"));
|
||||
var pathDiv = $(event.target).parent().children("#pathDiv")
|
||||
console.log(pathDiv);
|
||||
if(pathDiv.length != 0){pathDiv.remove(); return; }
|
||||
var curId = $(event.target).attr("data-id");
|
||||
var parents = nodesCollection.findWhere({_id:curId}).get("parents");
|
||||
var html = $("<div id='pathDiv' class='dropdown-toggle'><ul></ul></div>");
|
||||
console.log("parents=");
|
||||
console.log(parents);
|
||||
if(parents.length == 1){
|
||||
var parentId = parents[0];
|
||||
var grandParentId = nodesCollection.findWhere({_id:parentId}).get("parents");
|
||||
html.append($("<li><a href=#/" + parentId + ">"+parentId+"</a></li>"));
|
||||
html.append($("<li><a href=#/" + grandParentId + ">"+grandParentId+"</a></li>"));
|
||||
}
|
||||
console.log(html);
|
||||
// alert("something");
|
||||
$(event.target).parent().append(html);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Array.prototype.insert = function (index, item) {
|
||||
this.splice(index, 0, item);
|
||||
};
|
||||
|
||||
//http://stackoverflow.com/questions/500606/javascript-array-delete-elements
|
||||
Array.prototype.remove = function(from, to) {
|
||||
var rest = this.slice((to || from) + 1 || this.length);
|
||||
this.length = from < 0 ? this.length + from : from;
|
||||
return this.push.apply(this, rest);
|
||||
};
|
||||
|
||||
function hasDuplicates(array) {
|
||||
var valuesSoFar = {};
|
||||
for (var i = 0; i < array.length; ++i) {
|
||||
var value = array[i];
|
||||
if (Object.prototype.hasOwnProperty.call(valuesSoFar, value)) {
|
||||
return true;
|
||||
}
|
||||
valuesSoFar[value] = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
voInitializer = function(that, event){
|
||||
//var that = this;
|
||||
vo = {};
|
||||
vo.hitEnter = (event.which == 13);
|
||||
vo.hitTab = (event.which ==9);
|
||||
vo.atEnd = ( $(that).getSelection().end == $(that).val().length);
|
||||
vo.atBeg = ( $(that).getSelection().start == 0);
|
||||
//cursor = $(this).getSelection().start;
|
||||
vo.hitBack = (event.which ==8);
|
||||
vo.empty = ($(that).val().length ==0);
|
||||
//vo.thisLen = $()
|
||||
|
||||
vo.rootLevel = $(that).closest("ul").is(".root")
|
||||
vo.lastBullet = ( $(that).closest("li").is(":first-child") && vo.rootLevel);
|
||||
vo.thisLI = $(event.target).closest("li");
|
||||
vo.thisId = vo.thisLI.attr("data-id"); //data-id.
|
||||
vo.thisIndex = vo.thisLI.index(); //returns -1 if there's no match.
|
||||
vo.thisModel = nodesCollection.findWhere({_id: vo.thisId});
|
||||
|
||||
//alert(thisIndex)
|
||||
//thisModel = nodesCollection.get(thisId);
|
||||
vo.siblingLI = vo.thisLI.prev();
|
||||
vo.siblingIndex = vo.siblingLI.index();
|
||||
vo.siblingId = vo.siblingLI.attr("data-id");
|
||||
vo.siblingModel = nodesCollection.findWhere({_id: vo.siblingId});
|
||||
|
||||
console.log(nodesCollection);
|
||||
console.log(vo.thisModel);
|
||||
|
||||
|
||||
|
||||
|
||||
if(vo.rootLevel){
|
||||
vo.parentLI = undefined;
|
||||
vo.parentId = (vo.thisLI.closest("ul").attr("data-id"))
|
||||
vo.grandParentId = undefined; // won't matter since outTab prevents it. //unless programattic.
|
||||
}
|
||||
else{ //not root level.
|
||||
//debugger;
|
||||
vo.parentLI = vo.thisLI.parent().closest("li");
|
||||
vo.parentId = (vo.parentLI.attr("data-id"));
|
||||
if(vo.parentLI.attr("data-depth") == 0){ //could test this another way.
|
||||
vo.grandParentId = vo.parentLI.closest("ul").attr("data-id");
|
||||
//console.log("grandParentId" + grandParentId)
|
||||
}
|
||||
else{
|
||||
vo.grandParentId = (vo.parentLI.parent().closest("li").attr('data-id'));
|
||||
//console.log("grandParentId" + grandParentId)
|
||||
}
|
||||
}
|
||||
vo.grandParentModel = nodesCollection.findWhere({_id: vo.grandParentId});
|
||||
vo.parentModel = nodesCollection.findWhere({_id: vo.parentId});
|
||||
}
|
||||
|
||||
|
||||
keydownHandler = function(event){ //the entire body is wrapped in this.
|
||||
var that = this;
|
||||
//
|
||||
if(event.which == undefined){ return; }
|
||||
|
||||
voInitializer(that, event);
|
||||
|
||||
//event.preventDefault();
|
||||
//http://stackoverflow.com/questions/20964729/run-keydown-event-handler-after-the-value-of-a-textarea-has-been-changed
|
||||
//keyupp fixes this, but causes other problems.
|
||||
if( !(vo.hitTab || vo.hitEnter || (vo.hitBack && vo.empty))){
|
||||
//The reason this isn't syncing perfectly between bullets is that...
|
||||
//... the text-area val hasn't updated at this point.
|
||||
vo.thisModel.set("text", $(that).val());
|
||||
_.each(vo.thisModel.get("views"), function(view){
|
||||
view.updateText()
|
||||
});
|
||||
}
|
||||
|
||||
if(vo.hitEnter){
|
||||
event.preventDefault();
|
||||
|
||||
if(event.shiftKey){
|
||||
_.each(vo.thisModel.get("views"), function(view){
|
||||
view.collapse();
|
||||
});
|
||||
event.preventDefault();
|
||||
alert("Temporarily is used for expand/collapse (instead of clicking)")
|
||||
}
|
||||
|
||||
if(!event.shiftKey){
|
||||
event.preventDefault();
|
||||
if(vo.empty){
|
||||
addNode("");
|
||||
return;
|
||||
}//if(empty)
|
||||
else{//!empty
|
||||
if(vo.atEnd){
|
||||
//alert("CORRECT!")
|
||||
addNode("");
|
||||
return;
|
||||
}//
|
||||
if(!vo.atEnd && !vo.atBeg){ //split bullet
|
||||
var topStr = '';
|
||||
var botStr = '';
|
||||
splitText(that, botStr, topStr, addNode);
|
||||
return;
|
||||
//addNode(botStr, topStr);
|
||||
}
|
||||
if(!vo.atEnd && vo.atBeg){//addNode (before). (equivalent to splitting bullet)
|
||||
var topStr = '';
|
||||
var botStr = '';
|
||||
splitText(that, botStr, topStr, addNode);
|
||||
return;
|
||||
//addNode(botStr, topStr);
|
||||
}
|
||||
}//!empty
|
||||
|
||||
}
|
||||
} //hitEnter
|
||||
|
||||
if(vo.hitBack && vo.empty){
|
||||
event.preventDefault();
|
||||
removeNode(vo);
|
||||
|
||||
}//hitBack.
|
||||
|
||||
// // START ON HIT TAB
|
||||
// if (vo.hitTab) {
|
||||
|
||||
// event.preventDefault();
|
||||
|
||||
// if (event.shiftKey) {
|
||||
// event.preventDefault();
|
||||
|
||||
|
||||
// if (($(this).parent().parent().parent().hasClass("root"))) {
|
||||
// // do nothing. //alert() //IT USED TO BE ID = 'ROOT' // we use 'root SubList' because it has two classes.
|
||||
// }
|
||||
// else { // OUTDENT!!
|
||||
// var newIndex = $(this).parent().parent().parent().closest("li").index();
|
||||
// debugger;
|
||||
// moveNode(vo.thisModel, vo.thisIndex, vo.parentModel, vo.grandParentModel, newIndex+1, true);
|
||||
// }
|
||||
// }
|
||||
// var hasAboveSibling = (vo.thisIndex != 0);
|
||||
// if(!event.shiftKey && (hasAboveSibling) ){
|
||||
// var newIndex = vo.siblingModel.get("children").length; // no need for a + 1, because 0 index + insert (duh)
|
||||
// moveNode(vo.thisModel, vo.thisIndex, vo.parentModel, vo.siblingModel, newIndex, true);
|
||||
// }
|
||||
// }// END ON HIT TAB
|
||||
if((vo.hitTab && !event.shiftKey) || (event.keyCode == 39 && event.shiftKey)){ //INDENT
|
||||
event.preventDefault();
|
||||
var hasAboveSibling = (vo.thisIndex != 0);
|
||||
if(hasAboveSibling){
|
||||
var newIndex = vo.siblingModel.get("children").length; // no need for a + 1, because 0 index + insert (duh)
|
||||
moveNode(vo.thisModel, vo.thisIndex, vo.parentModel, vo.siblingModel, newIndex, true);
|
||||
}
|
||||
}
|
||||
if((vo.hitTab && event.shiftKey) || (event.keyCode == 37 && event.shiftKey)){// OUTDENT!!
|
||||
if (($(this).parent().parent().parent().hasClass("root"))) {
|
||||
// do nothing. //alert() //IT USED TO BE ID = 'ROOT' // we use 'root SubList' because it has two classes.
|
||||
}
|
||||
else {
|
||||
|
||||
var newSiblingUL = $(this).parent().parent().parent();
|
||||
var newIndex = newSiblingUL.closest("li").index();
|
||||
moveNode(vo.thisModel, vo.thisIndex, vo.parentModel, vo.grandParentModel, newIndex+1, true);
|
||||
setTimeout(function(){ //(MoveNode is asynchronous, so you need to wait a little bit.).
|
||||
newSiblingUL.parent().next().children().children("textarea").focus();
|
||||
}, 100);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(event.keyCode == 38 && event.shiftKey && !vo.thisLI.is(":first-child")) {
|
||||
moveNode(vo.thisModel, vo.thisIndex, vo.parentModel, vo.parentModel, vo.thisIndex-1, true);
|
||||
return;
|
||||
}
|
||||
if(event.keyCode == 40 && event.shiftKey && !vo.thisLI.is(":last-child")) {
|
||||
moveNode(vo.thisModel, vo.thisIndex, vo.parentModel, vo.parentModel, vo.thisIndex+1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Array.prototype.removeOne = function(parId){
|
||||
var parIndex = this.indexOf(parId);
|
||||
this.remove(parIndex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
var nodesCollection = Backbone.Collection.extend({
|
||||
|
||||
model: NodeModel
|
||||
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Rangy Text Inputs, a cross-browser textarea and text input library plug-in for jQuery.
|
||||
|
||||
Part of Rangy, a cross-browser JavaScript range and selection library
|
||||
http://code.google.com/p/rangy/
|
||||
|
||||
Depends on jQuery 1.0 or later.
|
||||
|
||||
Copyright 2010, Tim Down
|
||||
Licensed under the MIT license.
|
||||
Version: 0.1.205
|
||||
Build date: 5 November 2010
|
||||
*/
|
||||
(function(n){function o(e,g){var a=typeof e[g];return a==="function"||!!(a=="object"&&e[g])||a=="unknown"}function p(e,g,a){if(g<0)g+=e.value.length;if(typeof a=="undefined")a=g;if(a<0)a+=e.value.length;return{start:g,end:a}}function k(){return typeof document.body=="object"&&document.body?document.body:document.getElementsByTagName("body")[0]}var i,h,q,l,r,s,t,u,m;n(document).ready(function(){function e(a,b){return function(){var c=this.jquery?this[0]:this,d=c.nodeName.toLowerCase();if(c.nodeType==
|
||||
1&&(d=="textarea"||d=="input"&&c.type=="text")){c=[c].concat(Array.prototype.slice.call(arguments));c=a.apply(this,c);if(!b)return c}if(b)return this}}var g=document.createElement("textarea");k().appendChild(g);if(typeof g.selectionStart!="undefined"&&typeof g.selectionEnd!="undefined"){i=function(a){return{start:a.selectionStart,end:a.selectionEnd,length:a.selectionEnd-a.selectionStart,text:a.value.slice(a.selectionStart,a.selectionEnd)}};h=function(a,b,c){b=p(a,b,c);a.selectionStart=b.start;a.selectionEnd=
|
||||
b.end};m=function(a,b){if(b)a.selectionEnd=a.selectionStart;else a.selectionStart=a.selectionEnd}}else if(o(g,"createTextRange")&&typeof document.selection=="object"&&document.selection&&o(document.selection,"createRange")){i=function(a){var b=0,c=0,d,f,j;if((j=document.selection.createRange())&&j.parentElement()==a){f=a.value.length;d=a.value.replace(/\r\n/g,"\n");c=a.createTextRange();c.moveToBookmark(j.getBookmark());j=a.createTextRange();j.collapse(false);if(c.compareEndPoints("StartToEnd",j)>
|
||||
-1)b=c=f;else{b=-c.moveStart("character",-f);b+=d.slice(0,b).split("\n").length-1;if(c.compareEndPoints("EndToEnd",j)>-1)c=f;else{c=-c.moveEnd("character",-f);c+=d.slice(0,c).split("\n").length-1}}}return{start:b,end:c,length:c-b,text:a.value.slice(b,c)}};h=function(a,b,c){b=p(a,b,c);c=a.createTextRange();var d=b.start-(a.value.slice(0,b.start).split("\r\n").length-1);c.collapse(true);if(b.start==b.end)c.move("character",d);else{c.moveEnd("character",b.end-(a.value.slice(0,b.end).split("\r\n").length-
|
||||
1));c.moveStart("character",d)}c.select()};m=function(a,b){var c=document.selection.createRange();c.collapse(b);c.select()}}else{k().removeChild(g);window.console&&window.console.log&&window.console.log("TextInputs module for Rangy not supported in your browser. Reason: No means of finding text input caret position");return}k().removeChild(g);l=function(a,b,c,d){var f;if(b!=c){f=a.value;a.value=f.slice(0,b)+f.slice(c)}d&&h(a,b,b)};q=function(a){var b=i(a);l(a,b.start,b.end,true)};u=function(a){var b=
|
||||
i(a),c;if(b.start!=b.end){c=a.value;a.value=c.slice(0,b.start)+c.slice(b.end)}h(a,b.start,b.start);return b.text};r=function(a,b,c,d){var f=a.value;a.value=f.slice(0,c)+b+f.slice(c);if(d){b=c+b.length;h(a,b,b)}};s=function(a,b){var c=i(a),d=a.value;a.value=d.slice(0,c.start)+b+d.slice(c.end);c=c.start+b.length;h(a,c,c)};t=function(a,b,c){var d=i(a),f=a.value;a.value=f.slice(0,d.start)+b+d.text+c+f.slice(d.end);b=d.start+b.length;h(a,b,b+d.length)};n.fn.extend({getSelection:e(i,false),setSelection:e(h,
|
||||
true),collapseSelection:e(m,true),deleteSelectedText:e(q,true),deleteText:e(l,true),extractSelectedText:e(u,false),insertText:e(r,true),replaceSelectedText:e(s,true),surroundSelectedText:e(t,true)})})})(jQuery);
|
||||
@@ -0,0 +1,59 @@
|
||||
/*!
|
||||
* jQuery Textarea AutoSize plugin
|
||||
* Author: Javier Julio
|
||||
* Licensed under the MIT license
|
||||
*/
|
||||
;(function ($, window, document, undefined) {
|
||||
|
||||
var pluginName = "textareaAutoExpand";
|
||||
var pluginDataName = "plugin_" + pluginName;
|
||||
|
||||
var containsText = function (value) {
|
||||
return (value.replace(/\s/g, '').length > 0);
|
||||
};
|
||||
|
||||
function Plugin(element, options) {
|
||||
this.element = element;
|
||||
this.$element = $(element);
|
||||
this.init();
|
||||
}
|
||||
|
||||
Plugin.prototype = {
|
||||
init: function() {
|
||||
var height = this.$element.outerHeight();
|
||||
var paddingBottom = parseInt(this.$element.css('paddingBottom'))
|
||||
var paddingTop =parseInt(this.$element.css('paddingTop'));
|
||||
var diff = paddingBottom + paddingTop;
|
||||
|
||||
// alert("height=" + height + "paddingBottom=" + paddingBottom + "paddingTop=" + paddingTop);
|
||||
|
||||
// Firefox: scrollHeight isn't full height on border-box
|
||||
if (this.element.scrollHeight + diff <= height) {
|
||||
diff = 0;
|
||||
}
|
||||
|
||||
if (containsText(this.element.value)) {
|
||||
this.$element.height(this.element.scrollHeight);
|
||||
}
|
||||
|
||||
// keyup is required for IE to properly reset height when deleting text
|
||||
this.$element.on('input keyup', function(event) {
|
||||
console.log("scrollHeight=" + this.scrollHeight + "diff=" + diff);
|
||||
$(this)
|
||||
.height(0)
|
||||
.height(this.scrollHeight - diff);
|
||||
// $(this).css({overflow: 'hidden'})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$.fn[pluginName] = function (options) {
|
||||
this.each(function() {
|
||||
if (!$.data(this, pluginDataName)) {
|
||||
$.data(this, pluginDataName, new Plugin(this, options));
|
||||
}
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
})(jQuery, window, document);
|
||||
@@ -0,0 +1,164 @@
|
||||
voInitializer = function(that, event){
|
||||
|
||||
vo = {};
|
||||
vo.hitEnter = (event.which == 13);
|
||||
vo.hitTab = (event.which ==9);
|
||||
vo.atEnd = ( $(that).getSelection().end == $(that).val().length);
|
||||
vo.atBeg = ( $(that).getSelection().start == 0);
|
||||
//cursor = $(this).getSelection().start;
|
||||
vo.hitBack = (event.which ==8);
|
||||
vo.empty = ($(that).val().length ==0);
|
||||
|
||||
vo.rootLevel = $(that).closest("ul").is(".root")
|
||||
vo.lastBullet = ( $(that).closest("li").is(":first-child") && vo.rootLevel);
|
||||
vo.thisLI = $(event.target).closest("li");
|
||||
vo.thisId = vo.thisLI.attr("data-id"); //data-id.
|
||||
vo.thisIndex = vo.thisLI.index(); //returns -1 if there's no match.
|
||||
vo.thisModel = nodesCollection.findWhere({_id: vo.thisId});
|
||||
|
||||
vo.siblingLI = vo.thisLI.prev();
|
||||
vo.siblingIndex = vo.siblingLI.index();
|
||||
vo.siblingId = vo.siblingLI.attr("data-id");
|
||||
vo.siblingModel = nodesCollection.findWhere({_id: vo.siblingId});
|
||||
|
||||
console.log(nodesCollection);
|
||||
console.log(vo.thisModel);
|
||||
|
||||
|
||||
|
||||
|
||||
if(vo.rootLevel){
|
||||
vo.parentLI = undefined;
|
||||
vo.parentId = (vo.thisLI.closest("ul").attr("data-id"))
|
||||
vo.grandParentId = undefined; // won't matter since outTab prevents it. //unless programattic.
|
||||
}
|
||||
else{ //not root level.
|
||||
vo.parentLI = vo.thisLI.parent().closest("li");
|
||||
vo.parentId = (vo.parentLI.attr("data-id"));
|
||||
if(vo.parentLI.attr("data-depth") == 0){ //could test this another way.
|
||||
vo.grandParentId = vo.parentLI.closest("ul").attr("data-id");
|
||||
}
|
||||
else{
|
||||
vo.grandParentId = (vo.parentLI.parent().closest("li").attr('data-id'));
|
||||
}
|
||||
}
|
||||
vo.grandParentModel = nodesCollection.findWhere({_id: vo.grandParentId});
|
||||
vo.parentModel = nodesCollection.findWhere({_id: vo.parentId});
|
||||
}
|
||||
|
||||
|
||||
keydownHandler = function(event){ //the entire body is wrapped in this.
|
||||
var that = this;
|
||||
//
|
||||
if(event.which == undefined){ return; }
|
||||
|
||||
voInitializer(that, event);
|
||||
|
||||
//minor-bug
|
||||
//event.preventDefault();
|
||||
//http://stackoverflow.com/questions/20964729/run-keydown-event-handler-after-the-value-of-a-textarea-has-been-changed
|
||||
//keyupp fixes this, but causes other problems.
|
||||
if( !(vo.hitTab || vo.hitEnter || (vo.hitBack && vo.empty))){
|
||||
//The reason this isn't syncing perfectly between bullets is that...
|
||||
//... the text-area val hasn't updated at this point.
|
||||
vo.thisModel.set("text", $(that).val());
|
||||
_.each(vo.thisModel.get("views"), function(view){
|
||||
view.updateText()
|
||||
});
|
||||
}
|
||||
|
||||
if(vo.hitEnter){
|
||||
event.preventDefault();
|
||||
|
||||
if(event.shiftKey){
|
||||
_.each(vo.thisModel.get("views"), function(view){
|
||||
view.collapse();
|
||||
});
|
||||
event.preventDefault();
|
||||
alert("Temporarily is used for expand/collapse (instead of clicking)")
|
||||
}
|
||||
|
||||
if(!event.shiftKey){
|
||||
event.preventDefault();
|
||||
if(vo.empty){
|
||||
addNode("");
|
||||
return;
|
||||
}//if(empty)
|
||||
else{//!empty
|
||||
if(vo.atEnd){
|
||||
//alert("CORRECT!")
|
||||
addNode("");
|
||||
return;
|
||||
}//
|
||||
if(!vo.atEnd && !vo.atBeg){ //split bullet
|
||||
var topStr = '';
|
||||
var botStr = '';
|
||||
splitText(that, botStr, topStr, addNode);
|
||||
return;
|
||||
//addNode(botStr, topStr);
|
||||
}
|
||||
if(!vo.atEnd && vo.atBeg){//addNode (before). (equivalent to splitting bullet)
|
||||
var topStr = '';
|
||||
var botStr = '';
|
||||
splitText(that, botStr, topStr, addNode);
|
||||
return;
|
||||
//addNode(botStr, topStr);
|
||||
}
|
||||
}//!empty
|
||||
|
||||
}
|
||||
} //hitEnter
|
||||
|
||||
if(vo.hitBack && vo.empty){
|
||||
event.preventDefault();
|
||||
removeNode(vo);
|
||||
|
||||
}//hitBack.
|
||||
|
||||
if((vo.hitTab && !event.shiftKey) || (event.keyCode == 39 && event.shiftKey)){ //INDENT
|
||||
event.preventDefault();
|
||||
var hasAboveSibling = (vo.thisIndex != 0);
|
||||
if(hasAboveSibling){
|
||||
var newIndex = vo.siblingModel.get("children").length; // no need for a + 1, because 0 index + insert (duh)
|
||||
moveNode(vo.thisModel, vo.thisIndex, vo.parentModel, vo.siblingModel, newIndex, true);
|
||||
}
|
||||
}
|
||||
if((vo.hitTab && event.shiftKey) || (event.keyCode == 37 && event.shiftKey)){// OUTDENT!!
|
||||
if (($(this).parent().parent().parent().hasClass("root"))) {
|
||||
// do nothing. //alert() //IT USED TO BE ID = 'ROOT' // we use 'root SubList' because it has two classes.
|
||||
}
|
||||
else {
|
||||
var newSiblingUL = $(this).parent().parent().parent();
|
||||
var newIndex = newSiblingUL.closest("li").index();
|
||||
moveNode(vo.thisModel, vo.thisIndex, vo.parentModel, vo.grandParentModel, newIndex+1, true);
|
||||
setTimeout(function(){ //(MoveNode is asynchronous, so you need to wait a little bit.).
|
||||
newSiblingUL.parent().next().children().children("textarea").focus();
|
||||
}, 100);
|
||||
}//if->else
|
||||
}//if
|
||||
|
||||
if(event.keyCode == 38 && event.shiftKey && !vo.thisLI.is(":first-child")) {
|
||||
moveNode(vo.thisModel, vo.thisIndex, vo.parentModel, vo.parentModel, vo.thisIndex-1, true);
|
||||
return;
|
||||
}
|
||||
if(event.keyCode == 40 && event.shiftKey && !vo.thisLI.is(":last-child")) {
|
||||
moveNode(vo.thisModel, vo.thisIndex, vo.parentModel, vo.parentModel, vo.thisIndex+1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
}//vo-initializer
|
||||
|
||||
Array.prototype.removeOne = function(parId){
|
||||
var parIndex = this.indexOf(parId);
|
||||
this.remove(parIndex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
addNode = function(botStr, topStr){
|
||||
console.log("ADDNODE (LOGIC)");
|
||||
console.log(vo);
|
||||
|
||||
var randomId = ( -1 * Math.floor( Math.random() * 100000000) )
|
||||
var modelJSON = {
|
||||
_id: randomId
|
||||
, text: botStr
|
||||
, parents: [vo.parentId]
|
||||
, children: []
|
||||
};
|
||||
|
||||
|
||||
if(topStr){
|
||||
console.log("TOPSTR IS");
|
||||
console.log(topStr);
|
||||
vo.thisModel.set("text", topStr);
|
||||
_.each(vo.thisModel.get("views"), function(view){
|
||||
view.updateText(topStr);
|
||||
});
|
||||
socket.emit("edit", [vo.thisId, topStr]);
|
||||
}
|
||||
|
||||
|
||||
var newNode = new NodeModel(modelJSON);
|
||||
nodesCollection.add(newNode);
|
||||
|
||||
vo.parentModel.get("children").insert(vo.thisIndex + 1, randomId);
|
||||
|
||||
socket.emit("newNode", [[vo.parentId, vo.thisIndex+1], modelJSON ]);
|
||||
|
||||
var parentViews = vo.parentModel.get("views");
|
||||
|
||||
var tempIndex = vo.thisIndex+1; //adding nodes alters the index.
|
||||
_.each(parentViews, function(parentView){
|
||||
parentView.addNode(newNode, tempIndex, true);
|
||||
});
|
||||
vo.thisLI.next().children().children("textarea").focus();
|
||||
}
|
||||
|
||||
//topStr is to the left. (also, the bottom part will be to the right. )
|
||||
splitText = function(that, botStr, topStr, callback){
|
||||
var cur = $(that).getSelection().start;
|
||||
var cur1 = cur;
|
||||
var len = $(that).val().length;
|
||||
var bigStr = $(that).val();
|
||||
// var botStr = '';
|
||||
// var topStr = '';
|
||||
var x =0;
|
||||
|
||||
//this is the first half of the string.
|
||||
while(x<cur){
|
||||
topStr+=bigStr[x];
|
||||
x++;
|
||||
}
|
||||
//this is the second half of the string.
|
||||
//copies from the beginning of the cursor to the end of the textarea.
|
||||
while(cur<len) {
|
||||
botStr += bigStr[cur];
|
||||
cur++;
|
||||
}
|
||||
|
||||
callback(botStr, topStr); //addNode();
|
||||
}
|
||||
|
||||
transclude = function(){
|
||||
vo.parentModel.get("children").insert(vo.thisIndex+1, vo.thisId);
|
||||
var modelJSON = {
|
||||
_id: vo.thisId
|
||||
, text: vo.thisModel.get("text")
|
||||
, parents: vo.thisModel.get("parents")
|
||||
, children: vo.thisModel.get("children")
|
||||
}
|
||||
socket.emit("transclude" , [vo.parentId, vo.thisIndex+1, vo.thisId]);
|
||||
var parentViews = vo.parentModel.get("views");
|
||||
var tempIndex = vo.thisIndex+1; //adding nodes alters the index.
|
||||
_.each(parentViews, function(parentView){
|
||||
parentView.addNode(vo.thisModel, tempIndex, true);
|
||||
});
|
||||
vo.thisLI.next().children().children("textarea").focus();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//Handles indenting,outdenting,moving up/down, and drag-n-drop.
|
||||
var moveNode = function(thisModel, dragIndex, oldParModel, newParModel, dropIndex, chr){
|
||||
//removeNode from OldParent part 1 = #models
|
||||
console.log("\n\n");
|
||||
console.log(dragIndex);
|
||||
console.log(oldParModel.get("children"));
|
||||
oldParModel.get("children").remove(dragIndex);
|
||||
thisModel.get("parents").removeOne(oldParModel.get("_id"));
|
||||
console.log(oldParModel.get("children"));
|
||||
console.log("\n\n");
|
||||
|
||||
//removeNode from OldParent part 2 = #views
|
||||
_.each(oldParModel.get("views"), function(oldParView){
|
||||
oldParView.removeNode(dragIndex);
|
||||
});
|
||||
|
||||
//add the Node to the newParent part 1 = #models
|
||||
newParModel.get("children").insert(dropIndex, thisModel.get("_id"));
|
||||
thisModel.get("parents").push(newParModel.get("_id"));
|
||||
|
||||
//add the node to the newParent part 2 = #views
|
||||
_.each(newParModel.get("views"), function(newParView){
|
||||
newParView.addNode(thisModel, dropIndex, chr);
|
||||
});
|
||||
|
||||
var ids = [thisModel.get("_id"), oldParModel.get("_id"), newParModel.get("_id")];
|
||||
var arrays = [thisModel.get("parents"), oldParModel.get("children"), newParModel.get("children")];
|
||||
var indices = [dragIndex, dropIndex];
|
||||
var data = [ids, arrays, indices];
|
||||
console.log("about to emit data!!");
|
||||
console.log(data);
|
||||
if(chr){
|
||||
socket.emit("movedNode", data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
var removeNode = function(vo, broadcast) {
|
||||
upDateParentModelViews(vo, broadcast);
|
||||
//#TODO => This won't work for transcluded nodes with the same parent...
|
||||
if( hasDuplicates(vo.thisModel.get("parents"))){ //later.
|
||||
|
||||
}
|
||||
else{
|
||||
var newParents = _.filter(vo.thisModel.get("parents"), function(parId){
|
||||
return parId != vo.parentId;
|
||||
});
|
||||
vo.thisModel.set("parents", newParents);
|
||||
if(!broadcast){
|
||||
socket.emit("removeNode", [vo.thisId, vo.thisIndex, vo.parentId]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var upDateParentModelViews = function(vo, broadcast){
|
||||
var children = vo.parentModel.get("children");
|
||||
children.remove(vo.thisIndex);
|
||||
vo.parentModel.set("children", children);
|
||||
|
||||
|
||||
if(!broadcast){
|
||||
//UI STUFF
|
||||
console.log("what");
|
||||
if( !vo.thisLI.is(":first-child") ){
|
||||
var len = vo.thisLI.prev().children().children("textarea").val().length;
|
||||
vo.thisLI.prev().children().children("textarea").focus();
|
||||
vo.thisLI.prev().children().children("textarea").setSelection(len, len);
|
||||
}else{
|
||||
var len = vo.thisLI.parent().parent().children().children("textarea").val().length;
|
||||
vo.thisLI.parent().parent().children().children("textarea").focus();
|
||||
vo.thisLI.parent().parent().children().children("textarea").setSelection(len, len);
|
||||
}
|
||||
}
|
||||
|
||||
_.each(vo.parentModel.get("views"), function(parentView){
|
||||
parentView.removeNode(vo.thisIndex);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
var NodeModel = Backbone.Model.extend({
|
||||
|
||||
});
|
||||
@@ -0,0 +1,191 @@
|
||||
|
||||
var socket = null;
|
||||
var AppRouter = Backbone.Router.extend({
|
||||
|
||||
socketEvents: _.extend({}, Backbone.Events),
|
||||
|
||||
routes: {
|
||||
'': 'index',
|
||||
':id': "index"
|
||||
},
|
||||
|
||||
initialize: function(){
|
||||
//alert('initializing router');
|
||||
},
|
||||
|
||||
index: function(otherID){
|
||||
var that = this;
|
||||
//alert('index');
|
||||
//this.viewRoot();
|
||||
if(socket){ //Most of the time.
|
||||
that.viewRoot(otherID);
|
||||
return;
|
||||
}
|
||||
|
||||
//(initialization)
|
||||
socket = io.connect();
|
||||
socket.emit("nodeRequest");
|
||||
|
||||
socket.on('nodeData', function(data){
|
||||
//alert("data");
|
||||
console.log(data);
|
||||
nodesCollection = new nodesCollection(data);
|
||||
var id = nodesCollection.findWhere({text: "0root"}).get("_id");
|
||||
if(otherID){
|
||||
id = otherID
|
||||
}
|
||||
|
||||
|
||||
that.viewRoot(id);
|
||||
});
|
||||
|
||||
socket.on('edit', function(data){
|
||||
var id = data[0];
|
||||
var newText = data[1];
|
||||
|
||||
var curModel = nodesCollection.findWhere({_id: id})
|
||||
curModel.set("text", newText);
|
||||
_.each(curModel.get("views"), function(view){
|
||||
view.updateText(newText);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
socket.on("updateReceived", function(data){
|
||||
//data[0] is _id. data[1] is instance.
|
||||
var instance = data[1];
|
||||
var old_id = data[0];
|
||||
var parId = data[2][0];
|
||||
var newIndex = data[2][1];
|
||||
|
||||
var parentModel = nodesCollection.findWhere({_id: parId});
|
||||
var new_id = instance._id
|
||||
var oldModel = nodesCollection.findWhere({ _id: old_id });
|
||||
oldModel.set("_id", new_id );
|
||||
_.each(oldModel.get("views"), function(view){
|
||||
view.updateId(new_id);
|
||||
});
|
||||
parentModel.get("children")[newIndex] = instance._id;
|
||||
})
|
||||
|
||||
socket.on("newNode", function(data){
|
||||
//need the instance + the index.
|
||||
var modelJson = data[1]; //(includes the negative ID to find later);
|
||||
var parId = data[0][0];
|
||||
var newIndex = data[0][1];
|
||||
|
||||
var newNode = new NodeModel(modelJson);
|
||||
nodesCollection.add(newNode);
|
||||
var parentModel = nodesCollection.findWhere({_id: parId});
|
||||
var parentViews = parentModel.get("views");
|
||||
_.each(parentViews, function(parentView){
|
||||
parentView.addNode(newNode, newIndex).lock();
|
||||
//look at socket.emit("newNode" to see why -1);
|
||||
});
|
||||
parentModel.get("children").insert(newIndex, modelJson._id);
|
||||
});
|
||||
|
||||
socket.on("editing", function(id){
|
||||
console.log("EDITING RECEIVED + ID");
|
||||
console.log(id);
|
||||
if(id < 0){return;}
|
||||
var tempViews = nodesCollection.findWhere({_id: id}).get("views");
|
||||
_.each(tempViews, function(tempView){
|
||||
tempView.lock();
|
||||
//tempView.updateText("editing...");
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("blurred", function(data){
|
||||
// console.log('WHAT THE FUCK!!');
|
||||
// console.log(data);
|
||||
var id = data[0];
|
||||
var text = data[1];
|
||||
//console.log()
|
||||
//alert("blurred\n" + id + text);
|
||||
var tempModel = nodesCollection.findWhere({_id: id});
|
||||
tempModel.set("text", text);
|
||||
var tempViews = tempModel.get("views");
|
||||
_.each(tempViews, function(tempView){
|
||||
tempView.unlock();
|
||||
tempView.updateText(text);
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("removeNode", function(data){
|
||||
var vo = {};
|
||||
vo.thisId = data[0];
|
||||
vo.thisIndex = data[1];
|
||||
vo.parentId = data[2]; //not parId
|
||||
vo.thisModel = nodesCollection.findWhere({_id: vo.thisId});
|
||||
vo.parentModel = nodesCollection.findWhere({_id: vo.parentId});
|
||||
//alert("broadcastRemoveNode")
|
||||
removeNode(vo, true); //true means broadcast.
|
||||
});
|
||||
|
||||
socket.on("movedNode", function(data){
|
||||
var ids = data[0];
|
||||
var indices = data[1];
|
||||
var thisModel = nodesCollection.findWhere({_id: ids[0]});
|
||||
var oldParModel = nodesCollection.findWhere({_id: ids[1]});
|
||||
var newParModel = nodesCollection.findWhere({_id: ids[2]});
|
||||
debugger;
|
||||
moveNode(thisModel, indices[0], oldParModel, newParModel, indices[1]);
|
||||
})
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
viewRoot: function(id){
|
||||
var rootNode = nodesCollection.findWhere({_id: id});
|
||||
// alert("viewNode");
|
||||
console.log("ViewRoot + rootNode");
|
||||
console.log(rootNode);
|
||||
var rootView = new listView({
|
||||
viewWindow: ".main1",
|
||||
model: rootNode,
|
||||
nodesCollection: nodesCollection //nodesCollection might be global (and this would be redundant)
|
||||
})
|
||||
this.changeView(rootView);
|
||||
|
||||
// var rootView = new listView({
|
||||
// viewWindow: ".main2",
|
||||
// model: rootNode,
|
||||
// nodesCollection: nodesCollection //nodesCollection might be global (and this would be redundant)
|
||||
// })
|
||||
// this.changeView(rootView);
|
||||
},
|
||||
|
||||
changeView: function(view) {
|
||||
if ( null != this.currentView ) {
|
||||
this.currentView.undelegateEvents();
|
||||
}
|
||||
this.currentView = view;
|
||||
$("textarea").textareaAutoExpand();
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// socket.on('nodeData', function(data){
|
||||
// console.log("nodeDATA RECEIVED\n");
|
||||
// console.log(data);
|
||||
// nodesCollection = new nodesCollection(data); //nodes
|
||||
// //alert(data);
|
||||
// var model = new NodeModel(data[1]);
|
||||
// console.log("NodeModel(data[1])\n");
|
||||
// console.log(model);
|
||||
// console.log("nodesCollection.models");
|
||||
// console.log(nodesCollection.models);
|
||||
// var rootNode = nodesCollection.findWhere({_id: "52b7422c36dd4c5215ce78bf"});
|
||||
// console.log("rootNode");
|
||||
// console.log(rootNode);
|
||||
// //console.log(rootNode);
|
||||
// that.viewRoot("52b7422c36dd4c5215ce78bf")
|
||||
// });
|
||||
@@ -0,0 +1,554 @@
|
||||
/*!
|
||||
* Nestable jQuery Plugin - Copyright (c) 2012 David Bushell - http://dbushell.com/
|
||||
* Dual-licensed under the BSD or MIT licenses
|
||||
*/
|
||||
;(function($, window, document, undefined)
|
||||
{
|
||||
var hasTouch = 'ontouchstart' in window;
|
||||
|
||||
/**
|
||||
* Detect CSS pointer-events property
|
||||
* events are normally disabled on the dragging element to avoid conflicts
|
||||
* https://github.com/ausi/Feature-detection-technique-for-pointer-events/blob/master/modernizr-pointerevents.js
|
||||
*/
|
||||
var hasPointerEvents = (function()
|
||||
{
|
||||
var el = document.createElement('div'),
|
||||
docEl = document.documentElement;
|
||||
if (!('pointerEvents' in el.style)) {
|
||||
return false;
|
||||
}
|
||||
el.style.pointerEvents = 'auto';
|
||||
el.style.pointerEvents = 'x';
|
||||
docEl.appendChild(el);
|
||||
var supports = window.getComputedStyle && window.getComputedStyle(el, '').pointerEvents === 'auto';
|
||||
docEl.removeChild(el);
|
||||
return !!supports;
|
||||
})();
|
||||
|
||||
var eStart = hasTouch ? 'touchstart' : 'mousedown',
|
||||
eMove = hasTouch ? 'touchmove' : 'mousemove',
|
||||
eEnd = hasTouch ? 'touchend' : 'mouseup';
|
||||
eCancel = hasTouch ? 'touchcancel' : 'mouseup';
|
||||
|
||||
var defaults = {
|
||||
listNodeName : 'ol',
|
||||
itemNodeName : 'li',
|
||||
rootClass : 'dd',
|
||||
listClass : 'dd-list',
|
||||
itemClass : 'dd-item',
|
||||
dragClass : 'dd-dragel',
|
||||
handleClass : 'dd-handle',
|
||||
collapsedClass : 'dd-collapsed',
|
||||
placeClass : 'dd-placeholder',
|
||||
noDragClass : 'dd-nodrag',
|
||||
emptyClass : 'dd-empty',
|
||||
expandBtnHTML : '<button data-action="expand" type="button">Expand</button>',
|
||||
collapseBtnHTML : '<button data-action="collapse" type="button">Collapse</button>',
|
||||
group : 0,
|
||||
maxDepth : 5,
|
||||
threshold : 20
|
||||
};
|
||||
|
||||
defaults = {
|
||||
listNodeName : 'ul',
|
||||
itemNodeName : 'li',
|
||||
rootClass : 'main',
|
||||
listClass : 'dd-list',
|
||||
itemClass : 'node',
|
||||
dragClass : 'dd-dragel',
|
||||
handleClass : 'handle',
|
||||
collapsedClass : 'dd-collapsed',
|
||||
placeClass : 'placeholder',
|
||||
noDragClass : 'dd-nodrag',
|
||||
emptyClass : 'dd-empty',
|
||||
expandBtnHTML : '<a data-action="expand" class="expand expandCollapse">+</a>',
|
||||
collapseBtnHTML : '<a data-action="collapse" class="expand expandCollapse">-</a>',
|
||||
dragHeight : '24',
|
||||
group : 0,
|
||||
maxDepth : 99999,
|
||||
threshold : 15
|
||||
};
|
||||
|
||||
function Plugin(element, options)
|
||||
{
|
||||
this.w = $(window);
|
||||
this.el = $(element);
|
||||
this.options = $.extend({}, defaults, options);
|
||||
this.init();
|
||||
}
|
||||
|
||||
Plugin.prototype = {
|
||||
|
||||
init: function()
|
||||
{
|
||||
var list = this;
|
||||
|
||||
list.reset();
|
||||
|
||||
list.el.data('nestable-group', this.options.group);
|
||||
|
||||
list.placeEl = $('<div class="' + list.options.placeClass + '"/>');
|
||||
|
||||
// $.each(this.el.find(list.options.itemNodeName), function(k, el) {
|
||||
// list.setParent($(el));
|
||||
// });
|
||||
|
||||
// list.el.on('click', 'button', function(e) {
|
||||
// if (list.dragEl || (!hasTouch && e.button !== 0)) {
|
||||
// return;
|
||||
// }
|
||||
// var target = $(e.currentTarget),
|
||||
// action = target.data('action'),
|
||||
// item = target.parent(list.options.itemNodeName);
|
||||
// if (action === 'collapse') {
|
||||
// list.collapseItem(item);
|
||||
// }
|
||||
// if (action === 'expand') {
|
||||
// list.expandItem(item);
|
||||
// }
|
||||
// });
|
||||
|
||||
var onStartEvent = function(e)
|
||||
{
|
||||
var handle = $(e.target);
|
||||
if (!handle.hasClass(list.options.handleClass)) {
|
||||
if (handle.closest('.' + list.options.noDragClass).length) {
|
||||
return;
|
||||
}
|
||||
handle = handle.closest('.' + list.options.handleClass);
|
||||
}
|
||||
if (!handle.length || list.dragEl || (!hasTouch && e.button !== 0) || (hasTouch && e.touches.length !== 1)) {
|
||||
return;
|
||||
}
|
||||
var myVar = setInterval(function() {
|
||||
clearInterval(myVar);
|
||||
e.preventDefault();
|
||||
list.dragStart(hasTouch ? e.touches[0] : e);
|
||||
}, 100);
|
||||
};
|
||||
|
||||
var onMoveEvent = function(e)
|
||||
{
|
||||
if (list.dragEl) {
|
||||
e.preventDefault();
|
||||
list.dragMove(hasTouch ? e.touches[0] : e);
|
||||
}
|
||||
};
|
||||
|
||||
var onEndEvent = function(e)
|
||||
{
|
||||
if (list.dragEl) {
|
||||
e.preventDefault();
|
||||
list.dragStop(hasTouch ? e.touches[0] : e);
|
||||
}
|
||||
};
|
||||
|
||||
if (hasTouch) {
|
||||
list.el[0].addEventListener(eStart, onStartEvent, false);
|
||||
window.addEventListener(eMove, onMoveEvent, false);
|
||||
window.addEventListener(eEnd, onEndEvent, false);
|
||||
window.addEventListener(eCancel, onEndEvent, false);
|
||||
} else {
|
||||
list.el.on(eStart, onStartEvent);
|
||||
list.w.on(eMove, onMoveEvent);
|
||||
list.w.on(eEnd, onEndEvent);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
serialize: function()
|
||||
{
|
||||
var data,
|
||||
depth = 0,
|
||||
list = this;
|
||||
step = function(level, depth)
|
||||
{
|
||||
var array = [ ],
|
||||
items = level.children(list.options.itemNodeName);
|
||||
items.each(function()
|
||||
{
|
||||
var li = $(this),
|
||||
item = $.extend({}, li.data()),
|
||||
sub = li.children(list.options.listNodeName);
|
||||
if (sub.length) {
|
||||
item.children = step(sub, depth + 1);
|
||||
}
|
||||
array.push(item);
|
||||
});
|
||||
return array;
|
||||
};
|
||||
data = step(list.el.find(list.options.listNodeName).first(), depth);
|
||||
return data;
|
||||
},
|
||||
|
||||
serialise: function()
|
||||
{
|
||||
return this.serialize();
|
||||
},
|
||||
|
||||
reset: function()
|
||||
{
|
||||
this.mouse = {
|
||||
offsetX : 0,
|
||||
offsetY : 0,
|
||||
startX : 0,
|
||||
startY : 0,
|
||||
lastX : 0,
|
||||
lastY : 0,
|
||||
nowX : 0,
|
||||
nowY : 0,
|
||||
distX : 0,
|
||||
distY : 0,
|
||||
dirAx : 0,
|
||||
dirX : 0,
|
||||
dirY : 0,
|
||||
lastDirX : 0,
|
||||
lastDirY : 0,
|
||||
distAxX : 0,
|
||||
distAxY : 0
|
||||
};
|
||||
this.moving = false;
|
||||
this.dragEl = null;
|
||||
this.dragRootEl = null;
|
||||
this.dragDepth = 0;
|
||||
this.hasNewRoot = false;
|
||||
this.pointEl = null;
|
||||
},
|
||||
|
||||
// expandItem: function(li)
|
||||
// {
|
||||
// li.removeClass(this.options.collapsedClass);
|
||||
// li.children('[data-action="expand"]').hide();
|
||||
// li.children('[data-action="collapse"]').show();
|
||||
// li.children(this.options.listNodeName).show();
|
||||
// },
|
||||
|
||||
// collapseItem: function(li)
|
||||
// {
|
||||
// var lists = li.children(this.options.listNodeName);
|
||||
// if (lists.length) {
|
||||
// li.addClass(this.options.collapsedClass);
|
||||
// li.children('[data-action="collapse"]').hide();
|
||||
// li.children('[data-action="expand"]').show();
|
||||
// li.children(this.options.listNodeName).hide();
|
||||
// }
|
||||
// },
|
||||
|
||||
// expandAll: function()
|
||||
// {
|
||||
// var list = this;
|
||||
// list.el.find(list.options.itemNodeName).each(function() {
|
||||
// list.expandItem($(this));
|
||||
// });
|
||||
// },
|
||||
|
||||
// collapseAll: function()
|
||||
// {
|
||||
// var list = this;
|
||||
// list.el.find(list.options.itemNodeName).each(function() {
|
||||
// list.collapseItem($(this));
|
||||
// });
|
||||
// },
|
||||
|
||||
// setParent: function(li)
|
||||
// {
|
||||
// // if this node's children's subLists have any children
|
||||
// if (li.children(this.options.listNodeName).children().length) {
|
||||
// li.prepend($(this.options.expandBtnHTML));
|
||||
// li.prepend($(this.options.collapseBtnHTML));
|
||||
// }
|
||||
// li.children('[data-action="expand"]').hide();
|
||||
// },
|
||||
|
||||
// unsetParent: function(li)
|
||||
// {
|
||||
// li.removeClass(this.options.collapsedClass);
|
||||
// li.children('[data-action]').remove();
|
||||
// li.children(this.options.listNodeName).remove();
|
||||
// },
|
||||
|
||||
dragStart: function(e)
|
||||
{
|
||||
var mouse = this.mouse,
|
||||
target = $(e.target),
|
||||
dragItem = target.closest(this.options.itemNodeName);
|
||||
|
||||
console.log("mouse");
|
||||
console.log(mouse);
|
||||
|
||||
// this.placeEl.css('height', dragItem.height());
|
||||
|
||||
mouse.offsetX = e.offsetX !== undefined ? e.offsetX : e.pageX - target.offset().left;
|
||||
mouse.offsetY = e.offsetY !== undefined ? e.offsetY : e.pageY - target.offset().top;
|
||||
mouse.startX = mouse.lastX = e.pageX;
|
||||
mouse.startY = mouse.lastY = e.pageY;
|
||||
|
||||
console.log("offsetXY");
|
||||
console.log(mouse.offsetX + ", " + mouse.offsetY);
|
||||
console.log(e.offsetX + ", " + e.offsetY);
|
||||
|
||||
this.dragRootEl = this.el;
|
||||
|
||||
this.dragEl = $(document.createElement(this.options.listNodeName)).addClass(this.options.listClass + ' ' + this.options.dragClass);
|
||||
this.dragEl.css('width', dragItem.width());
|
||||
|
||||
// fix for zepto.js
|
||||
// dragItem.after(this.placeEl).detach().appendTo(this.dragEl);
|
||||
dragItem.after(this.placeEl);
|
||||
dragItem[0].parentNode.removeChild(dragItem[0]);
|
||||
dragItem.appendTo(this.dragEl);
|
||||
|
||||
$(document.body).append(this.dragEl);
|
||||
this.dragEl.css({
|
||||
'left' : e.pageX - mouse.offsetX,
|
||||
'top' : e.pageY - mouse.offsetY
|
||||
});
|
||||
// total depth of dragging item
|
||||
// var i, depth,
|
||||
// items = this.dragEl.find(this.options.itemNodeName);
|
||||
// for (i = 0; i < items.length; i++) {
|
||||
// depth = $(items[i]).parents(this.options.listNodeName).length;
|
||||
// if (depth > this.dragDepth) {
|
||||
// this.dragDepth = depth;
|
||||
// }
|
||||
// }
|
||||
},
|
||||
|
||||
dragStop: function(e)
|
||||
{
|
||||
// fix for zepto.js
|
||||
// this.placeEl.replaceWith(this.dragEl.children(this.options.itemNodeName + ':first').detach());
|
||||
var el = this.dragEl.children(this.options.itemNodeName).first();
|
||||
el[0].parentNode.removeChild(el[0]);
|
||||
this.placeEl.replaceWith(el);
|
||||
|
||||
this.dragEl.remove();
|
||||
this.el.trigger('change');
|
||||
if (this.hasNewRoot) {
|
||||
this.dragRootEl.trigger('change');
|
||||
}
|
||||
this.reset();
|
||||
$('.handle').find('img').attr('src', 'img/bullet-8.png');
|
||||
},
|
||||
|
||||
dragMove: function(e)
|
||||
{
|
||||
// $closestNode = $('.node').closestEL({left: e.pageX, top: e.pageY});
|
||||
// var offset = $closestNode.children('.content').offset();
|
||||
|
||||
// console.log("node");
|
||||
// console.log($closestNode);
|
||||
// console.log("rectangle");
|
||||
// console.log(offset);
|
||||
|
||||
var list, parent, prev, next, depth,
|
||||
opt = this.options,
|
||||
mouse = this.mouse;
|
||||
|
||||
// this.dragEl.css({
|
||||
// 'left' : e.pageX - mouse.offsetX,
|
||||
// 'top' : e.pageY - mouse.offsetY
|
||||
// });
|
||||
|
||||
// mouse position last events
|
||||
mouse.lastX = mouse.nowX;
|
||||
mouse.lastY = mouse.nowY;
|
||||
// mouse position this events
|
||||
mouse.nowX = e.pageX;
|
||||
mouse.nowY = e.pageY;
|
||||
// distance mouse moved between events
|
||||
mouse.distX = mouse.nowX - mouse.lastX;
|
||||
mouse.distY = mouse.nowY - mouse.lastY;
|
||||
// direction mouse was moving
|
||||
mouse.lastDirX = mouse.dirX;
|
||||
mouse.lastDirY = mouse.dirY;
|
||||
// direction mouse is now moving (on both axis)
|
||||
mouse.dirX = mouse.distX === 0 ? 0 : mouse.distX > 0 ? 1 : -1;
|
||||
mouse.dirY = mouse.distY === 0 ? 0 : mouse.distY > 0 ? 1 : -1;
|
||||
// axis mouse is now moving on
|
||||
var newAx = Math.abs(mouse.distX) > Math.abs(mouse.distY) ? 1 : 0;
|
||||
|
||||
// do nothing on first move
|
||||
if (!mouse.moving) {
|
||||
mouse.dirAx = newAx;
|
||||
mouse.moving = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// calc distance moved on this axis (and direction)
|
||||
if (mouse.dirAx !== newAx) {
|
||||
mouse.distAxX = 0;
|
||||
mouse.distAxY = 0;
|
||||
} else {
|
||||
mouse.distAxX += Math.abs(mouse.distX);
|
||||
if (mouse.dirX !== 0 && mouse.dirX !== mouse.lastDirX) {
|
||||
mouse.distAxX = 0;
|
||||
}
|
||||
mouse.distAxY += Math.abs(mouse.distY);
|
||||
if (mouse.dirY !== 0 && mouse.dirY !== mouse.lastDirY) {
|
||||
mouse.distAxY = 0;
|
||||
}
|
||||
}
|
||||
mouse.dirAx = newAx;
|
||||
|
||||
/**
|
||||
* move horizontal
|
||||
*/
|
||||
if (mouse.dirAx && mouse.distAxX >= opt.threshold) {
|
||||
// reset move distance on x-axis for new phase
|
||||
mouse.distAxX = 0;
|
||||
prev = this.placeEl.prev(opt.itemNodeName);
|
||||
// increase horizontal level if previous sibling exists and is not collapsed
|
||||
if (mouse.distX > 0 && prev.length && !prev.hasClass(opt.collapsedClass)) {
|
||||
// cannot increase level when item above is collapsed
|
||||
list = prev.find(opt.listNodeName).last();
|
||||
// check if depth limit has reached
|
||||
depth = this.placeEl.parents(opt.listNodeName).length;
|
||||
if (depth + this.dragDepth <= opt.maxDepth) {
|
||||
// create new sub-level if one doesn't exist
|
||||
if (!list.length) {
|
||||
list = $('<' + opt.listNodeName + '/>').addClass(opt.listClass);
|
||||
list.append(this.placeEl);
|
||||
prev.append(list);
|
||||
// this.setParent(prev);
|
||||
} else {
|
||||
// else append to next level up
|
||||
list = prev.children(opt.listNodeName).last();
|
||||
list.append(this.placeEl);
|
||||
}
|
||||
}
|
||||
}
|
||||
// decrease horizontal level
|
||||
if (mouse.distX < 0) {
|
||||
// we can't decrease a level if an item preceeds the current one
|
||||
next = this.placeEl.next(opt.itemNodeName);
|
||||
if (!next.length) {
|
||||
parent = this.placeEl.parent();
|
||||
this.placeEl.closest(opt.itemNodeName).after(this.placeEl);
|
||||
// if (!parent.children().length) {
|
||||
// this.unsetParent(parent.parent());
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var isEmpty = false;
|
||||
|
||||
// find list item under cursor
|
||||
if (!hasPointerEvents) {
|
||||
this.dragEl[0].style.visibility = 'hidden';
|
||||
}
|
||||
this.pointEl = $(document.elementFromPoint(e.pageX - document.body.scrollLeft, e.pageY - (window.pageYOffset || document.documentElement.scrollTop)));
|
||||
if (!hasPointerEvents) {
|
||||
this.dragEl[0].style.visibility = 'visible';
|
||||
}
|
||||
if (this.pointEl.hasClass(opt.handleClass)) {
|
||||
this.pointEl = this.pointEl.parent(opt.itemNodeName);
|
||||
}
|
||||
if (this.pointEl.hasClass(opt.emptyClass)) {
|
||||
isEmpty = true;
|
||||
}
|
||||
else if (!this.pointEl.length || !this.pointEl.hasClass(opt.itemClass)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// find parent list of item under cursor
|
||||
var pointElRoot = this.pointEl.closest('.' + opt.rootClass),
|
||||
isNewRoot = this.dragRootEl.data('nestable-id') !== pointElRoot.data('nestable-id');
|
||||
|
||||
/**
|
||||
* move vertical
|
||||
*/
|
||||
if (!mouse.dirAx || isNewRoot || isEmpty) {
|
||||
// check if groups match if dragging over new root
|
||||
if (isNewRoot && opt.group !== pointElRoot.data('nestable-group')) {
|
||||
return;
|
||||
}
|
||||
// check depth limit
|
||||
depth = this.dragDepth - 1 + this.pointEl.parents(opt.listNodeName).length;
|
||||
if (depth > opt.maxDepth) {
|
||||
return;
|
||||
}
|
||||
var before = e.pageY < (this.pointEl.offset().top + this.pointEl.height() / 2);
|
||||
parent = this.placeEl.parent();
|
||||
// if empty create new list to replace empty placeholder
|
||||
if (isEmpty) {
|
||||
list = $(document.createElement(opt.listNodeName)).addClass(opt.listClass);
|
||||
list.append(this.placeEl);
|
||||
this.pointEl.replaceWith(list);
|
||||
}
|
||||
else if (before) {
|
||||
this.pointEl.before(this.placeEl);
|
||||
}
|
||||
else {
|
||||
this.pointEl.after(this.placeEl);
|
||||
}
|
||||
// if (!parent.children().length) {
|
||||
// this.unsetParent(parent.parent());
|
||||
// }
|
||||
if (!this.dragRootEl.find(opt.itemNodeName).length) {
|
||||
this.dragRootEl.append('<div class="' + opt.emptyClass + '"/>');
|
||||
}
|
||||
// parent root list has changed
|
||||
if (isNewRoot) {
|
||||
this.dragRootEl = pointElRoot;
|
||||
this.hasNewRoot = this.el[0] !== this.dragRootEl[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$.fn.nestable = function(params)
|
||||
{
|
||||
var lists = this,
|
||||
retval = this;
|
||||
|
||||
lists.each(function()
|
||||
{
|
||||
var plugin = $(this).data("nestable");
|
||||
|
||||
if (!plugin) {
|
||||
$(this).data("nestable", new Plugin(this, params));
|
||||
$(this).data("nestable-id", new Date().getTime());
|
||||
} else {
|
||||
if (typeof params === 'string' && typeof plugin[params] === 'function') {
|
||||
retval = plugin[params]();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return retval || lists;
|
||||
};
|
||||
|
||||
// Helpers
|
||||
// $('.myselector').closestEL({left: mouse.x, top: mouse.y});
|
||||
$.fn.closestEL = function(offset) {
|
||||
var el = null, elOffset, x = offset.left, y = offset.top, distance, dx, dy, minDistance;
|
||||
this.each(function() {
|
||||
elOffset = $(this).offset();
|
||||
|
||||
if (
|
||||
(x >= elOffset.left) && (x <= elOffset.right) &&
|
||||
(y >= elOffset.top) && (y <= elOffset.bottom)
|
||||
) {
|
||||
el = $(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
var offsets = [[elOffset.left, elOffset.top], [elOffset.right, elOffset.top], [elOffset.left, elOffset.bottom], [elOffset.right, elOffset.bottom]];
|
||||
for (off in offsets) {
|
||||
dx = offsets[off][0] - x;
|
||||
dy = offsets[off][1] - y;
|
||||
distance = Math.sqrt((dx*dx) + (dy*dy));
|
||||
if (minDistance === undefined || distance < minDistance) {
|
||||
minDistance = distance;
|
||||
el = $(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
return el;
|
||||
}
|
||||
|
||||
})(window.jQuery || window.Zepto, window, document);
|
||||
@@ -0,0 +1,13 @@
|
||||
$(function(){
|
||||
// to hide
|
||||
hideSidebar = function(){
|
||||
$('#sidebar').attr('hidden', 'true');
|
||||
$('#panel-col').toggleClass('col-md-offset-2');
|
||||
}
|
||||
|
||||
// to show
|
||||
showSidebar = function(){
|
||||
$('#sidebar').attr('hidden', 'false');
|
||||
$('#panel-col').toggleClass('col-md-offset-2');
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,609 @@
|
||||
/* ===================================================
|
||||
* jquery-sortable.js v0.9.11
|
||||
* http://johnny.github.com/jquery-sortable/
|
||||
* ===================================================
|
||||
* Copyright (c) 2012 Jonas von Andrian
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ========================================================== */
|
||||
|
||||
!function ( $, window, undefined){
|
||||
var eventNames,
|
||||
pluginName = 'sortable',
|
||||
containerDefaults = {
|
||||
// If true, items can be dragged from this container
|
||||
drag: true,
|
||||
// If true, items can be droped onto this container
|
||||
drop: true,
|
||||
// Exclude items from being draggable, if the
|
||||
// selector matches the item
|
||||
exclude: "",
|
||||
// If true, search for nested containers within an item
|
||||
nested: true,
|
||||
// If true, the items are assumed to be arranged vertically
|
||||
vertical: true
|
||||
}, // end container defaults
|
||||
groupDefaults = {
|
||||
// This is executed after the placeholder has been moved.
|
||||
afterMove: function ($placeholder, container) {
|
||||
},
|
||||
// The exact css path between the container and its items, e.g. "> tbody"
|
||||
containerPath: "",
|
||||
// The css selector of the containers
|
||||
containerSelector: "ol, ul",
|
||||
// Distance the mouse has to travel to start dragging
|
||||
distance: 10, // #Jeremy: Edited from "distance: 0,"
|
||||
// The css selector of the drag handle
|
||||
handle: ".handle",
|
||||
// The exact css path between the item and its subcontainers
|
||||
itemPath: "",
|
||||
// The css selector of the items
|
||||
itemSelector: "li",
|
||||
// Check if the dragged item may be inside the container.
|
||||
// Use with care, since the search for a valid container entails a depth first search
|
||||
// and may be quite expensive.
|
||||
isValidTarget: function ($item, container) {
|
||||
return true
|
||||
},
|
||||
// Executed before onDrop if placeholder is detached.
|
||||
// This happens if pullPlaceholder is set to false and the drop occurs outside a container.
|
||||
onCancel: function ($item, container, _super) {
|
||||
},
|
||||
// Executed at the beginning of a mouse move event.
|
||||
// The Placeholder has not been moved yet.
|
||||
onDrag: function ($item, position, _super) {
|
||||
$item.css(position);
|
||||
$item.closest("ul").addClass("selectedUL");
|
||||
//console.log("stuff");
|
||||
},
|
||||
// Called after the drag has been started,
|
||||
// that is the mouse button is beeing held down and
|
||||
// the mouse is moving.
|
||||
// The container is the closest initialized container.
|
||||
// Therefore it might not be the container, that actually contains the item.
|
||||
onDragStart: function ($item, container, _super) {
|
||||
$item.css({
|
||||
height: $item.height(),
|
||||
width: $item.width()
|
||||
})
|
||||
$item.addClass("dragged")
|
||||
$("body").addClass("dragging")
|
||||
},
|
||||
// Called when the mouse button is beeing released
|
||||
onDrop: function ($item, container, _super) {
|
||||
$item.closest("ul").removeClass("selectedUL");
|
||||
$item.removeClass("dragged").removeAttr("style")
|
||||
$("body").removeClass("dragging")
|
||||
},
|
||||
// Called on mousedown.
|
||||
onMousedown: function($item, event, _super) {
|
||||
event.preventDefault()
|
||||
},
|
||||
// Template for the placeholder. Can be any valid jQuery input
|
||||
// e.g. a string, a DOM element.
|
||||
// The placeholder must have the class "placeholder"
|
||||
placeholder: '<li class="placeholder" />', // #Jeremy: Edited from <li class="placeholder" />
|
||||
// If true, the position of the placeholder is calculated on every mousemove.
|
||||
// If false, it is only calculated when the mouse is above a container.
|
||||
pullPlaceholder: true,
|
||||
// Specifies serialization of the container group.
|
||||
// The pair $parent/$children is either container/items or item/subcontainers.
|
||||
// Note that this default method only works, if every item only has one subcontainer
|
||||
serialize: function ($parent, $children, parentIsContainer) {
|
||||
var result = $.extend({}, $parent.data())
|
||||
|
||||
if(parentIsContainer)
|
||||
return $children
|
||||
else if ($children[0]){
|
||||
result.children = $children
|
||||
delete result.subContainer
|
||||
}
|
||||
|
||||
delete result.sortable
|
||||
|
||||
return result
|
||||
},
|
||||
// Set tolerance while dragging. Positive values decrease sensitivity,
|
||||
// negative values increase it.
|
||||
tolerance: 0
|
||||
}, // end group defaults
|
||||
containerGroups = {},
|
||||
groupCounter = 0,
|
||||
emptyBox = {
|
||||
left: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
right:0
|
||||
}
|
||||
eventNames = {
|
||||
start: "touchstart.sortable mousedown.sortable",
|
||||
drop: "touchend.sortable touchcancel.sortable mouseup.sortable",
|
||||
drag: "touchmove.sortable mousemove.sortable",
|
||||
scroll: "scroll.sortable"
|
||||
}
|
||||
|
||||
/*
|
||||
* a is Array [left, right, top, bottom]
|
||||
* b is array [left, top]
|
||||
*/
|
||||
function d(a,b) {
|
||||
var x = Math.max(0, a[0] - b[0], b[0] - a[1]),
|
||||
y = Math.max(0, a[2] - b[1], b[1] - a[3])
|
||||
return x+y;
|
||||
}
|
||||
|
||||
function setDimensions(array, dimensions, tolerance, useOffset) {
|
||||
var i = array.length,
|
||||
offsetMethod = useOffset ? "offset" : "position"
|
||||
tolerance = tolerance || 0
|
||||
|
||||
while(i--){
|
||||
var el = array[i].el ? array[i].el : $(array[i]),
|
||||
// use fitting method
|
||||
pos = el[offsetMethod]()
|
||||
pos.left += parseInt(el.css('margin-left'), 10)
|
||||
pos.top += parseInt(el.css('margin-top'),10)
|
||||
dimensions[i] = [
|
||||
pos.left - tolerance,
|
||||
pos.left + el.outerWidth() + tolerance,
|
||||
pos.top - tolerance,
|
||||
pos.top + el.outerHeight() + tolerance
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
function getRelativePosition(pointer, element) {
|
||||
var offset = element.offset()
|
||||
return {
|
||||
left: pointer.left - offset.left,
|
||||
top: pointer.top - offset.top
|
||||
}
|
||||
}
|
||||
|
||||
function sortByDistanceDesc(dimensions, pointer, lastPointer) {
|
||||
pointer = [pointer.left, pointer.top]
|
||||
lastPointer = lastPointer && [lastPointer.left, lastPointer.top]
|
||||
|
||||
var dim,
|
||||
i = dimensions.length,
|
||||
distances = []
|
||||
|
||||
while(i--){
|
||||
dim = dimensions[i]
|
||||
distances[i] = [i,d(dim,pointer), lastPointer && d(dim, lastPointer)]
|
||||
}
|
||||
distances = distances.sort(function (a,b) {
|
||||
return b[1] - a[1] || b[2] - a[2] || b[0] - a[0]
|
||||
})
|
||||
|
||||
// last entry is the closest
|
||||
return distances
|
||||
}
|
||||
|
||||
function ContainerGroup(options) {
|
||||
this.options = $.extend({}, groupDefaults, options)
|
||||
this.containers = []
|
||||
this.scrollProxy = $.proxy(this.scroll, this)
|
||||
this.dragProxy = $.proxy(this.drag, this)
|
||||
this.dropProxy = $.proxy(this.drop, this)
|
||||
|
||||
if(!this.options.parentContainer){
|
||||
this.placeholder = $(this.options.placeholder)
|
||||
if(!options.isValidTarget)
|
||||
this.options.isValidTarget = undefined
|
||||
}
|
||||
}
|
||||
|
||||
ContainerGroup.get = function (options) {
|
||||
if( !containerGroups[options.group]) {
|
||||
if(!options.group)
|
||||
options.group = groupCounter ++
|
||||
containerGroups[options.group] = new ContainerGroup(options)
|
||||
}
|
||||
return containerGroups[options.group]
|
||||
}
|
||||
|
||||
ContainerGroup.prototype = {
|
||||
dragInit: function (e, itemContainer) {
|
||||
this.$document = $(itemContainer.el[0].ownerDocument)
|
||||
|
||||
if(itemContainer.enabled()){
|
||||
this.toggleListeners('on')
|
||||
|
||||
// get item to drag
|
||||
this.item = $(e.target).closest(this.options.itemSelector)
|
||||
this.itemContainer = itemContainer
|
||||
|
||||
this.setPointer(e)
|
||||
|
||||
this.options.onMousedown(this.item, e, groupDefaults.onMousedown)
|
||||
} else {
|
||||
this.toggleListeners('on', ['drop'])
|
||||
}
|
||||
|
||||
this.dragInitDone = true
|
||||
},
|
||||
drag: function (e) {
|
||||
if(!this.dragging){
|
||||
if(!this.distanceMet(e))
|
||||
return
|
||||
|
||||
this.options.onDragStart(this.item, this.itemContainer, groupDefaults.onDragStart)
|
||||
this.item.before(this.placeholder)
|
||||
this.dragging = true
|
||||
}
|
||||
|
||||
this.setPointer(e)
|
||||
// place item under the cursor
|
||||
this.options.onDrag(this.item,
|
||||
getRelativePosition(this.pointer, this.item.offsetParent()),
|
||||
groupDefaults.onDrag)
|
||||
|
||||
var x = e.pageX,
|
||||
y = e.pageY,
|
||||
box = this.sameResultBox,
|
||||
t = this.options.tolerance
|
||||
|
||||
if(!box || box.top - t > y || box.bottom + t < y || box.left - t > x || box.right + t < x)
|
||||
if(!this.searchValidTarget())
|
||||
this.placeholder.detach()
|
||||
},
|
||||
drop: function (e) {
|
||||
this.toggleListeners('off')
|
||||
|
||||
this.dragInitDone = false
|
||||
|
||||
if(this.dragging){
|
||||
// processing Drop, check if placeholder is detached
|
||||
if(this.placeholder.closest("html")[0])
|
||||
this.placeholder.before(this.item).detach()
|
||||
else
|
||||
this.options.onCancel(this.item, this.itemContainer, groupDefaults.onCancel)
|
||||
|
||||
this.options.onDrop(this.item, this.getContainer(this.item), groupDefaults.onDrop)
|
||||
|
||||
// cleanup
|
||||
this.clearDimensions()
|
||||
this.clearOffsetParent()
|
||||
this.lastAppendedItem = this.sameResultBox = undefined
|
||||
this.dragging = false
|
||||
}
|
||||
},
|
||||
searchValidTarget: function (pointer, lastPointer) {
|
||||
if(!pointer){
|
||||
pointer = this.relativePointer || this.pointer
|
||||
lastPointer = this.lastRelativePointer || this.lastPointer
|
||||
}
|
||||
|
||||
var distances = sortByDistanceDesc(this.getContainerDimensions(),
|
||||
pointer,
|
||||
lastPointer),
|
||||
i = distances.length
|
||||
|
||||
while(i--){
|
||||
var index = distances[i][0],
|
||||
distance = distances[i][1]
|
||||
|
||||
if(!distance || this.options.pullPlaceholder){
|
||||
var container = this.containers[index]
|
||||
if(!container.disabled){
|
||||
if(!this.$getOffsetParent()){
|
||||
var offsetParent = container.getItemOffsetParent()
|
||||
pointer = getRelativePosition(pointer, offsetParent)
|
||||
lastPointer = getRelativePosition(lastPointer, offsetParent)
|
||||
}
|
||||
if(container.searchValidTarget(pointer, lastPointer))
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
if(this.sameResultBox)
|
||||
this.sameResultBox = undefined
|
||||
},
|
||||
movePlaceholder: function (container, item, method, sameResultBox) {
|
||||
var lastAppendedItem = this.lastAppendedItem
|
||||
if(!sameResultBox && lastAppendedItem && lastAppendedItem[0] === item[0])
|
||||
return;
|
||||
|
||||
item[method](this.placeholder)
|
||||
this.lastAppendedItem = item
|
||||
this.sameResultBox = sameResultBox
|
||||
this.options.afterMove(this.placeholder, container)
|
||||
},
|
||||
getContainerDimensions: function () {
|
||||
if(!this.containerDimensions)
|
||||
setDimensions(this.containers, this.containerDimensions = [], this.options.tolerance, !this.$getOffsetParent())
|
||||
return this.containerDimensions
|
||||
},
|
||||
getContainer: function (element) {
|
||||
return element.closest(this.options.containerSelector).data(pluginName)
|
||||
},
|
||||
$getOffsetParent: function () {
|
||||
if(this.offsetParent === undefined){
|
||||
var i = this.containers.length - 1,
|
||||
offsetParent = this.containers[i].getItemOffsetParent()
|
||||
|
||||
if(!this.options.parentContainer){
|
||||
while(i--){
|
||||
if(offsetParent[0] != this.containers[i].getItemOffsetParent()[0]){
|
||||
// If every container has the same offset parent,
|
||||
// use position() which is relative to this parent,
|
||||
// otherwise use offset()
|
||||
// compare #setDimensions
|
||||
offsetParent = false
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.offsetParent = offsetParent
|
||||
}
|
||||
return this.offsetParent
|
||||
},
|
||||
setPointer: function (e) {
|
||||
console.log("setPointer")
|
||||
var pointer = {
|
||||
left: e.pageX,
|
||||
top: e.pageY
|
||||
}
|
||||
|
||||
if(this.$getOffsetParent()){
|
||||
var relativePointer = getRelativePosition(pointer, this.$getOffsetParent())
|
||||
this.lastRelativePointer = this.relativePointer
|
||||
this.relativePointer = relativePointer
|
||||
}
|
||||
|
||||
this.lastPointer = this.pointer
|
||||
this.pointer = pointer
|
||||
},
|
||||
distanceMet: function (e) {
|
||||
return (Math.max(
|
||||
Math.abs(this.pointer.left - e.pageX),
|
||||
Math.abs(this.pointer.top - e.pageY)
|
||||
) >= this.options.distance)
|
||||
},
|
||||
scroll: function (e) {
|
||||
this.clearDimensions()
|
||||
this.clearOffsetParent()
|
||||
},
|
||||
toggleListeners: function (method, events) {
|
||||
var that = this
|
||||
events = events || ['drag','drop','scroll']
|
||||
|
||||
$.each(events,function (i,event) {
|
||||
that.$document[method](eventNames[event], that[event + 'Proxy'])
|
||||
})
|
||||
},
|
||||
clearOffsetParent: function () {
|
||||
this.offsetParent = undefined
|
||||
},
|
||||
// Recursively clear container and item dimensions
|
||||
clearDimensions: function () {
|
||||
this.containerDimensions = undefined
|
||||
var i = this.containers.length
|
||||
while(i--){
|
||||
this.containers[i].clearDimensions()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Container(element, options) {
|
||||
this.el = element
|
||||
this.options = $.extend( {}, containerDefaults, options)
|
||||
|
||||
this.group = ContainerGroup.get(this.options)
|
||||
this.rootGroup = this.options.rootGroup = this.options.rootGroup || this.group
|
||||
this.parentContainer = this.options.parentContainer
|
||||
this.handle = this.rootGroup.options.handle || this.rootGroup.options.itemSelector
|
||||
|
||||
this.el.on(eventNames.start, this.handle, $.proxy(this.dragInit, this))
|
||||
|
||||
if(this.options.drop)
|
||||
this.group.containers.push(this)
|
||||
}
|
||||
|
||||
Container.prototype = {
|
||||
dragInit: function (e) {
|
||||
var rootGroup = this.rootGroup
|
||||
|
||||
if( !rootGroup.dragInitDone &&
|
||||
e.which === 1 &&
|
||||
this.options.drag &&
|
||||
!$(e.target).is(this.options.exclude))
|
||||
rootGroup.dragInit(e, this)
|
||||
},
|
||||
searchValidTarget: function (pointer, lastPointer) {
|
||||
var distances = sortByDistanceDesc(this.getItemDimensions(),
|
||||
pointer,
|
||||
lastPointer),
|
||||
i = distances.length,
|
||||
rootGroup = this.rootGroup,
|
||||
validTarget = !rootGroup.options.isValidTarget ||
|
||||
rootGroup.options.isValidTarget(rootGroup.item, this)
|
||||
|
||||
if(!i && validTarget){
|
||||
rootGroup.movePlaceholder(this, this.el, "append")
|
||||
return true
|
||||
} else
|
||||
while(i--){
|
||||
var index = distances[i][0],
|
||||
distance = distances[i][1]
|
||||
if(!distance && this.hasChildGroup(index)){
|
||||
var found = this.getContainerGroup(index).searchValidTarget(pointer, lastPointer)
|
||||
if(found)
|
||||
return true
|
||||
}
|
||||
else if(validTarget){
|
||||
this.movePlaceholder(index, pointer)
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
movePlaceholder: function (index, pointer) {
|
||||
var item = $(this.items[index]),
|
||||
dim = this.itemDimensions[index],
|
||||
method = "after",
|
||||
width = item.outerWidth(),
|
||||
height = item.outerHeight(),
|
||||
offset = item.offset(),
|
||||
sameResultBox = {
|
||||
left: offset.left,
|
||||
right: offset.left + width,
|
||||
top: offset.top,
|
||||
bottom: offset.top + height
|
||||
}
|
||||
if(this.options.vertical){
|
||||
var yCenter = (dim[2] + dim[3]) / 2,
|
||||
inUpperHalf = pointer.top <= yCenter
|
||||
if(inUpperHalf){
|
||||
method = "before"
|
||||
sameResultBox.bottom -= height / 2
|
||||
} else
|
||||
sameResultBox.top += height / 2
|
||||
} else {
|
||||
var xCenter = (dim[0] + dim[1]) / 2,
|
||||
inLeftHalf = pointer.left <= xCenter
|
||||
if(inLeftHalf){
|
||||
method = "before"
|
||||
sameResultBox.right -= width / 2
|
||||
} else
|
||||
sameResultBox.left += width / 2
|
||||
}
|
||||
if(this.hasChildGroup(index))
|
||||
sameResultBox = emptyBox
|
||||
this.rootGroup.movePlaceholder(this, item, method, sameResultBox)
|
||||
},
|
||||
getItemDimensions: function () {
|
||||
if(!this.itemDimensions){
|
||||
this.items = this.$getChildren(this.el, "item").filter(":not(.placeholder, .dragged)").get()
|
||||
setDimensions(this.items, this.itemDimensions = [], this.options.tolerance)
|
||||
}
|
||||
return this.itemDimensions
|
||||
},
|
||||
getItemOffsetParent: function () {
|
||||
var offsetParent,
|
||||
el = this.el
|
||||
// Since el might be empty we have to check el itself and
|
||||
// can not do something like el.children().first().offsetParent()
|
||||
if(el.css("position") === "relative" || el.css("position") === "absolute" || el.css("position") === "fixed")
|
||||
offsetParent = el
|
||||
else
|
||||
offsetParent = el.offsetParent()
|
||||
return offsetParent
|
||||
},
|
||||
hasChildGroup: function (index) {
|
||||
return this.options.nested && this.getContainerGroup(index)
|
||||
},
|
||||
getContainerGroup: function (index) {
|
||||
var childGroup = $.data(this.items[index], "subContainer")
|
||||
if( childGroup === undefined){
|
||||
var childContainers = this.$getChildren(this.items[index], "container")
|
||||
childGroup = false
|
||||
|
||||
if(childContainers[0]){
|
||||
var options = $.extend({}, this.options, {
|
||||
parentContainer: this,
|
||||
group: groupCounter ++
|
||||
})
|
||||
childGroup = childContainers[pluginName](options).data(pluginName).group
|
||||
}
|
||||
$.data(this.items[index], "subContainer", childGroup)
|
||||
}
|
||||
return childGroup
|
||||
},
|
||||
enabled: function () {
|
||||
return !this.disabled && (!this.parentContainer || this.parentContainer.enabled())
|
||||
},
|
||||
$getChildren: function (parent, type) {
|
||||
var options = this.rootGroup.options,
|
||||
path = options[type + "Path"],
|
||||
selector = options[type + "Selector"]
|
||||
|
||||
parent = $(parent)
|
||||
if(path)
|
||||
parent = parent.find(path)
|
||||
|
||||
return parent.children(selector)
|
||||
},
|
||||
_serialize: function (parent, isContainer) {
|
||||
var that = this,
|
||||
childType = isContainer ? "item" : "container",
|
||||
|
||||
children = this.$getChildren(parent, childType).not(this.options.exclude).map(function () {
|
||||
return that._serialize($(this), !isContainer)
|
||||
}).get()
|
||||
|
||||
return this.rootGroup.options.serialize(parent, children, isContainer)
|
||||
},
|
||||
clearDimensions: function () {
|
||||
this.itemDimensions = undefined
|
||||
if(this.items && this.items[0]){
|
||||
var i = this.items.length
|
||||
while(i--){
|
||||
var group = $.data(this.items[i], "subContainer")
|
||||
if(group)
|
||||
group.clearDimensions()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var API = {
|
||||
enable: function (ignoreChildren) {
|
||||
this.disabled = false
|
||||
},
|
||||
disable: function (ignoreChildren) {
|
||||
this.disabled = true
|
||||
},
|
||||
serialize: function () {
|
||||
return this._serialize(this.el, true)
|
||||
}
|
||||
}
|
||||
|
||||
$.extend(Container.prototype, API)
|
||||
|
||||
/**
|
||||
* jQuery API
|
||||
*
|
||||
* Parameters are
|
||||
* either options on init
|
||||
* or a method name followed by arguments to pass to the method
|
||||
*/
|
||||
$.fn[pluginName] = function(methodOrOptions) {
|
||||
var args = Array.prototype.slice.call(arguments, 1)
|
||||
|
||||
return this.map(function(){
|
||||
var $t = $(this),
|
||||
object = $t.data(pluginName)
|
||||
|
||||
if(object && API[methodOrOptions])
|
||||
return API[methodOrOptions].apply(object, args) || this
|
||||
else if(!object && (methodOrOptions === undefined ||
|
||||
typeof methodOrOptions === "object"))
|
||||
$t.data(pluginName, new Container($t, methodOrOptions))
|
||||
|
||||
return this
|
||||
});
|
||||
};
|
||||
|
||||
}(jQuery, window)
|
||||
@@ -0,0 +1,40 @@
|
||||
$(function(){
|
||||
$('.js-auto-expand').textareaAutoExpand();
|
||||
|
||||
// $('.main').nestable();
|
||||
|
||||
$('.handle').toolbar({
|
||||
content: '#toolbar',
|
||||
position: 'left',
|
||||
hideOnClick: true
|
||||
}).on('toolbarItemClick', function(e){
|
||||
console.log('toolbar item clicked: ' + e.class);
|
||||
});
|
||||
|
||||
// MathJax typesetter
|
||||
typeset = function(nodeID){
|
||||
MathJax.Hub.Queue(["Typeset", MathJax.Hub], nodeID);
|
||||
};
|
||||
|
||||
// Bullet outline on hover
|
||||
$('.handle a').hover(function(){
|
||||
// mouse enter
|
||||
$(this).children('img').attr('src', 'img/bullet-combined.png');
|
||||
},
|
||||
function(){
|
||||
// mouse leave
|
||||
$(this).children('img').attr('src', 'img/bullet-8.png');
|
||||
});
|
||||
|
||||
// Fix for tab border-radius
|
||||
// $('.ui-tabs .ui-tabs-nav li a').click(function(){
|
||||
// var idx = $("ul li.ui-state-active").index();
|
||||
// console.log(idx);
|
||||
// if( idx !== 0){
|
||||
// $('tabs-' + (idx+1)).css('border-radius', '5px 5px 5px 5px');
|
||||
// }
|
||||
// else{
|
||||
// $('tabs-' + (idx+1)).css('border-radius', '0px 5px 5px 5px');
|
||||
// }
|
||||
// });
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
var bulletHash = [];
|
||||
var rootBullets = [];
|
||||
$(function() {
|
||||
// Bullet class declaration
|
||||
function Bullet (parentID, text) {
|
||||
// If root bullet
|
||||
if(parentID === -1){
|
||||
this.ID = bulletHash.length;
|
||||
this.text = text;
|
||||
this.children = [];
|
||||
bulletHash.push(this);
|
||||
rootBullets.push(this.ID);
|
||||
return;
|
||||
}
|
||||
this.ID = bulletHash.length;
|
||||
this.text = text;
|
||||
this.children = [];
|
||||
bulletHash[parentID].children.push(this.ID);
|
||||
bulletHash.push(this);
|
||||
// load(this.ID)
|
||||
return;
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
new Bullet(-1, '')
|
||||
// loadRoot(0);
|
||||
console.log(bulletHash);
|
||||
// bulletHash[0].children = new Array(); //So it doesn't have itself as a child.
|
||||
// bulletHash[0].parents = [];
|
||||
//I could replace this with an object literal...
|
||||
for(var i = 0; i< 5; i++){
|
||||
new Bullet(0, "bullet" + i);
|
||||
// bulletHash[i].push(new Bullet(0,'bullet' + i));
|
||||
console.log(bulletHash);
|
||||
}
|
||||
loadAll();
|
||||
$("textarea").textareaAutoExpand();
|
||||
});
|
||||
|
||||
//Load root nodes and all their children
|
||||
function loadAll() {
|
||||
for(var i = 0; i < rootBullets.length; i++){
|
||||
var rootNodeID = rootBullets[i];
|
||||
$(".root").append(JSONtoUI(bulletHash[rootNodeID]));
|
||||
$("#"+rootNodeID).children(".subList").slideToggle(0); //This makes it so that you can hitTab with luke Skywalker and it will work.
|
||||
loadChildren(rootNodeID);
|
||||
}
|
||||
}
|
||||
|
||||
function loadChildren(bulletID){
|
||||
var childrenBullets = bulletHash[bulletID].children;
|
||||
for(var i = 0; i < childrenBullets.length; i++){
|
||||
var childID = childrenBullets[i];
|
||||
$("#"+bulletID).children().filter(".subList").append( JSONtoUI( bulletHash[childID] ) );
|
||||
$("#"+childID).parent().slideToggle(0); //this refers to the UL in which it's contained...(which, in the base case would hide the entire thing)
|
||||
$("#"+childID).children(".subList").slideToggle(0); //This makes it so that you can hitTab with luke Skywalker and it will work.
|
||||
loadChildren(childID);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Rangy Text Inputs, a cross-browser textarea and text input library plug-in for jQuery.
|
||||
|
||||
Part of Rangy, a cross-browser JavaScript range and selection library
|
||||
http://code.google.com/p/rangy/
|
||||
|
||||
Depends on jQuery 1.0 or later.
|
||||
|
||||
Copyright 2010, Tim Down
|
||||
Licensed under the MIT license.
|
||||
Version: 0.1.205
|
||||
Build date: 5 November 2010
|
||||
*/
|
||||
(function(n){function o(e,g){var a=typeof e[g];return a==="function"||!!(a=="object"&&e[g])||a=="unknown"}function p(e,g,a){if(g<0)g+=e.value.length;if(typeof a=="undefined")a=g;if(a<0)a+=e.value.length;return{start:g,end:a}}function k(){return typeof document.body=="object"&&document.body?document.body:document.getElementsByTagName("body")[0]}var i,h,q,l,r,s,t,u,m;n(document).ready(function(){function e(a,b){return function(){var c=this.jquery?this[0]:this,d=c.nodeName.toLowerCase();if(c.nodeType==
|
||||
1&&(d=="textarea"||d=="input"&&c.type=="text")){c=[c].concat(Array.prototype.slice.call(arguments));c=a.apply(this,c);if(!b)return c}if(b)return this}}var g=document.createElement("textarea");k().appendChild(g);if(typeof g.selectionStart!="undefined"&&typeof g.selectionEnd!="undefined"){i=function(a){return{start:a.selectionStart,end:a.selectionEnd,length:a.selectionEnd-a.selectionStart,text:a.value.slice(a.selectionStart,a.selectionEnd)}};h=function(a,b,c){b=p(a,b,c);a.selectionStart=b.start;a.selectionEnd=
|
||||
b.end};m=function(a,b){if(b)a.selectionEnd=a.selectionStart;else a.selectionStart=a.selectionEnd}}else if(o(g,"createTextRange")&&typeof document.selection=="object"&&document.selection&&o(document.selection,"createRange")){i=function(a){var b=0,c=0,d,f,j;if((j=document.selection.createRange())&&j.parentElement()==a){f=a.value.length;d=a.value.replace(/\r\n/g,"\n");c=a.createTextRange();c.moveToBookmark(j.getBookmark());j=a.createTextRange();j.collapse(false);if(c.compareEndPoints("StartToEnd",j)>
|
||||
-1)b=c=f;else{b=-c.moveStart("character",-f);b+=d.slice(0,b).split("\n").length-1;if(c.compareEndPoints("EndToEnd",j)>-1)c=f;else{c=-c.moveEnd("character",-f);c+=d.slice(0,c).split("\n").length-1}}}return{start:b,end:c,length:c-b,text:a.value.slice(b,c)}};h=function(a,b,c){b=p(a,b,c);c=a.createTextRange();var d=b.start-(a.value.slice(0,b.start).split("\r\n").length-1);c.collapse(true);if(b.start==b.end)c.move("character",d);else{c.moveEnd("character",b.end-(a.value.slice(0,b.end).split("\r\n").length-
|
||||
1));c.moveStart("character",d)}c.select()};m=function(a,b){var c=document.selection.createRange();c.collapse(b);c.select()}}else{k().removeChild(g);window.console&&window.console.log&&window.console.log("TextInputs module for Rangy not supported in your browser. Reason: No means of finding text input caret position");return}k().removeChild(g);l=function(a,b,c,d){var f;if(b!=c){f=a.value;a.value=f.slice(0,b)+f.slice(c)}d&&h(a,b,b)};q=function(a){var b=i(a);l(a,b.start,b.end,true)};u=function(a){var b=
|
||||
i(a),c;if(b.start!=b.end){c=a.value;a.value=c.slice(0,b.start)+c.slice(b.end)}h(a,b.start,b.start);return b.text};r=function(a,b,c,d){var f=a.value;a.value=f.slice(0,c)+b+f.slice(c);if(d){b=c+b.length;h(a,b,b)}};s=function(a,b){var c=i(a),d=a.value;a.value=d.slice(0,c.start)+b+d.slice(c.end);c=c.start+b.length;h(a,c,c)};t=function(a,b,c){var d=i(a),f=a.value;a.value=f.slice(0,d.start)+b+d.text+c+f.slice(d.end);b=d.start+b.length;h(a,b,b+d.length)};n.fn.extend({getSelection:e(i,false),setSelection:e(h,
|
||||
true),collapseSelection:e(m,true),deleteSelectedText:e(q,true),deleteText:e(l,true),extractSelectedText:e(u,false),insertText:e(r,true),replaceSelectedText:e(s,true),surroundSelectedText:e(t,true)})})})(jQuery);
|
||||
@@ -0,0 +1,243 @@
|
||||
/**
|
||||
* Toolbar.js
|
||||
*
|
||||
* @fileoverview jQuery plugin that creates tooltip style toolbars.
|
||||
* @link http://paulkinzett.github.com/toolbar/
|
||||
* @author Paul Kinzett (http://kinzett.co.nz/)
|
||||
* @version 1.0.4
|
||||
* @requires jQuery 1.7+
|
||||
*
|
||||
* @license jQuery Toolbar Plugin v1.0.4
|
||||
* http://paulkinzett.github.com/toolbar/
|
||||
* Copyright 2013 Paul Kinzett (http://kinzett.co.nz/)
|
||||
* Released under the MIT license.
|
||||
* <https://raw.github.com/paulkinzett/toolbar/master/LICENSE.txt>
|
||||
*/
|
||||
|
||||
if ( typeof Object.create !== 'function' ) {
|
||||
Object.create = function( obj ) {
|
||||
function F() {}
|
||||
F.prototype = obj;
|
||||
return new F();
|
||||
};
|
||||
}
|
||||
|
||||
(function( $, window, document, undefined ) {
|
||||
document.oncontextmenu = function() {return false;};
|
||||
|
||||
var ToolBar = {
|
||||
init: function( options, elem ) {
|
||||
var self = this;
|
||||
self.elem = elem;
|
||||
self.$elem = $( elem );
|
||||
self.options = $.extend( {}, $.fn.toolbar.options, options );
|
||||
self.toolbar = $('<div class="tool-container gradient" />')
|
||||
.addClass('tool-'+self.options.position)
|
||||
.addClass('tool-rounded')
|
||||
.append('<div class="tool-items" />')
|
||||
.append('<div class="arrow" />')
|
||||
.appendTo('body')
|
||||
.css('opacity', 0)
|
||||
.hide();
|
||||
self.toolbar_arrow = self.toolbar.find('.arrow');
|
||||
self.initializeToolbar();
|
||||
},
|
||||
|
||||
initializeToolbar: function() {
|
||||
var self = this;
|
||||
self.populateContent();
|
||||
self.setTrigger();
|
||||
self.toolbarWidth = self.toolbar.width();
|
||||
},
|
||||
|
||||
setTrigger: function() {
|
||||
var self = this;
|
||||
|
||||
self.$elem.on('mousedown', function(event) {
|
||||
if(event.button == 2 && !self.toolbar.is(":visible")) {
|
||||
self.show();
|
||||
}
|
||||
else {
|
||||
self.hide();
|
||||
}
|
||||
});
|
||||
|
||||
if (self.options.hideOnClick) {
|
||||
$('html').on("mousedown.toolbar", function ( event ) {
|
||||
if (event.target != self.elem &&
|
||||
self.$elem.has(event.target).length === 0 &&
|
||||
self.toolbar.has(event.target).length === 0 &&
|
||||
self.toolbar.is(":visible")) {
|
||||
self.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(window).resize(function( event ) {
|
||||
event.stopPropagation();
|
||||
if ( self.toolbar.is(":visible") ) {
|
||||
self.toolbarCss = self.getCoordinates(self.options.position, 20);
|
||||
self.collisionDetection();
|
||||
self.toolbar.css( self.toolbarCss );
|
||||
self.toolbar_arrow.css( self.arrowCss );
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
populateContent: function() {
|
||||
var self = this;
|
||||
var location = self.toolbar.find('.tool-items');
|
||||
var content = $(self.options.content).clone( true ).find('a').addClass('tool-item gradient');
|
||||
location.html(content);
|
||||
location.find('.tool-item').on('click', function(event) {
|
||||
event.preventDefault();
|
||||
self.$elem.trigger('toolbarItemClick', this);
|
||||
});
|
||||
},
|
||||
|
||||
calculatePosition: function() {
|
||||
var self = this;
|
||||
self.arrowCss = {};
|
||||
self.toolbarCss = self.getCoordinates(self.options.position, 0);
|
||||
self.toolbarCss.position = 'absolute';
|
||||
self.toolbarCss.zIndex = self.options.zIndex;
|
||||
self.collisionDetection();
|
||||
self.toolbar.css(self.toolbarCss);
|
||||
self.toolbar_arrow.css(self.arrowCss);
|
||||
},
|
||||
|
||||
getCoordinates: function( position, adjustment ) {
|
||||
var self = this;
|
||||
self.coordinates = self.$elem.offset();
|
||||
|
||||
if (self.options.adjustment && self.options.adjustment[self.options.position]) {
|
||||
adjustment = self.options.adjustment[self.options.position];
|
||||
}
|
||||
|
||||
switch(self.options.position) {
|
||||
case 'top':
|
||||
return {
|
||||
left: self.coordinates.left-(self.toolbar.width()/2)+(self.$elem.outerWidth()/2),
|
||||
top: self.coordinates.top-self.$elem.height()-adjustment,
|
||||
right: 'auto'
|
||||
};
|
||||
case 'left':
|
||||
return {
|
||||
left: self.coordinates.left-(self.toolbar.width()/2)-(self.$elem.width()/2)-adjustment,
|
||||
top: self.coordinates.top-(self.toolbar.height()/2)+(self.$elem.outerHeight()/2),
|
||||
right: 'auto'
|
||||
};
|
||||
case 'right':
|
||||
return {
|
||||
left: self.coordinates.left+(self.toolbar.width()/2)+(self.$elem.width()/3)+adjustment,
|
||||
top: self.coordinates.top-(self.toolbar.height()/2)+(self.$elem.outerHeight()/2),
|
||||
right: 'auto'
|
||||
};
|
||||
case 'bottom':
|
||||
return {
|
||||
left: self.coordinates.left-(self.toolbar.width()/2)+(self.$elem.outerWidth()/2),
|
||||
top: self.coordinates.top+self.$elem.height()+adjustment,
|
||||
right: 'auto'
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
collisionDetection: function() {
|
||||
var self = this;
|
||||
var edgeOffset = 20;
|
||||
if(self.options.position == 'top' || self.options.position == 'bottom') {
|
||||
self.arrowCss = {left: '50%', right: '50%'};
|
||||
if( self.toolbarCss.left < edgeOffset ) {
|
||||
self.toolbarCss.left = edgeOffset;
|
||||
self.arrowCss.left = self.$elem.offset().left + self.$elem.width()/2-(edgeOffset);
|
||||
}
|
||||
else if(($(window).width() - (self.toolbarCss.left + self.toolbarWidth)) < edgeOffset) {
|
||||
self.toolbarCss.right = edgeOffset;
|
||||
self.toolbarCss.left = 'auto';
|
||||
self.arrowCss.left = 'auto';
|
||||
self.arrowCss.right = ($(window).width()-self.$elem.offset().left)-(self.$elem.width()/2)-(edgeOffset)-5;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
show: function() {
|
||||
var self = this;
|
||||
var animation = {'opacity': 1};
|
||||
|
||||
self.$elem.addClass('pressed');
|
||||
self.calculatePosition();
|
||||
|
||||
switch(self.options.position) {
|
||||
case 'top':
|
||||
animation.top = '-=20';
|
||||
break;
|
||||
case 'left':
|
||||
animation.left = '-=20';
|
||||
break;
|
||||
case 'right':
|
||||
animation.left = '+=20';
|
||||
break;
|
||||
case 'bottom':
|
||||
animation.top = '+=20';
|
||||
break;
|
||||
}
|
||||
|
||||
self.toolbar.show().animate(animation, 200 );
|
||||
self.$elem.trigger('toolbarShown');
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
var self = this;
|
||||
var animation = {'opacity': 0};
|
||||
|
||||
self.$elem.removeClass('pressed');
|
||||
|
||||
switch(self.options.position) {
|
||||
case 'top':
|
||||
animation.top = '+=20';
|
||||
break;
|
||||
case 'left':
|
||||
animation.left = '+=20';
|
||||
break;
|
||||
case 'right':
|
||||
animation.left = '-=20';
|
||||
break;
|
||||
case 'bottom':
|
||||
animation.top = '-=20';
|
||||
break;
|
||||
}
|
||||
|
||||
self.toolbar.animate(animation, 200, function() {
|
||||
self.toolbar.hide();
|
||||
});
|
||||
|
||||
self.$elem.trigger('toolbarHidden');
|
||||
},
|
||||
|
||||
getToolbarElement: function () {
|
||||
return this.toolbar.find('.tool-items');
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.toolbar = function( options ) {
|
||||
if ($.isPlainObject( options )) {
|
||||
return this.each(function() {
|
||||
var toolbarObj = Object.create( ToolBar );
|
||||
toolbarObj.init( options, this );
|
||||
$(this).data('toolbarObj', toolbarObj);
|
||||
});
|
||||
} else if ( typeof options === 'string' && options.indexOf('_') !== 0 ) {
|
||||
var toolbarObj = $(this).data('toolbarObj');
|
||||
var method = toolbarObj[options];
|
||||
return method.apply(toolbarObj, $.makeArray(arguments).slice(1));
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.toolbar.options = {
|
||||
content: '#myContent',
|
||||
position: 'top',
|
||||
hideOnClick: false,
|
||||
zIndex: 120
|
||||
};
|
||||
|
||||
}) ( jQuery, window, document );
|
||||
@@ -0,0 +1,128 @@
|
||||
var listView = Backbone.View.extend({
|
||||
|
||||
initialize: function(options){
|
||||
var that = this;
|
||||
|
||||
this.viewWindow = $(options["viewWindow"]);
|
||||
that.model = options["model"];
|
||||
(that.model.attributes["views"] = this.model.attributes["views"] || []).push(that);
|
||||
that.$el.attr("data-id", that.model.get("_id"));
|
||||
this.childViews = [];
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
||||
tagName: 'ul',
|
||||
className: 'root subList dd-list',
|
||||
|
||||
render: function(){
|
||||
var that = this;
|
||||
|
||||
that.renderChildren();
|
||||
that.renderPath();
|
||||
|
||||
return that;
|
||||
},
|
||||
|
||||
|
||||
renderPath: function(){
|
||||
var that = this;
|
||||
var pathDiv = "";
|
||||
|
||||
var ancestry = [];
|
||||
var parents = that.model.get("parents");
|
||||
while(parents.length != 0){
|
||||
ancestry.push(parents);
|
||||
parents = nodesCollection.findWhere({_id: parents[0] }).get("parents");
|
||||
//making the assumption/simplification that it's a tree. Not a graph.
|
||||
}
|
||||
|
||||
_.each(ancestry.reverse(), function(parent){
|
||||
var parentModel = nodesCollection.findWhere({_id: parent[0] });
|
||||
pathDiv += "<a class='pathLink' href='#"+ parentModel.get("_id") + "'>" + parentModel.get("text") + "</a>";
|
||||
pathDiv += " -- ";
|
||||
});
|
||||
if(ancestry.length == 0){pathDiv += " "}
|
||||
|
||||
|
||||
$("#pathDiv").html(pathDiv);
|
||||
},
|
||||
|
||||
//identical except for the .$el part at the end.
|
||||
renderChildren: function(){
|
||||
var that = this;
|
||||
|
||||
var childrenIds = that.model.get("children");
|
||||
_.each(childrenIds, function(childId, index){
|
||||
var childModel = nodesCollection.findWhere({_id: childId});
|
||||
console.log("childModelId = " + childId);
|
||||
console.log(childModel);
|
||||
var tempView = new showView({
|
||||
depth: 0,
|
||||
model: childModel //,
|
||||
//nodesCollection: that.nodesCollection
|
||||
});
|
||||
var tempLI = tempView.render().$el;
|
||||
tempLI.children("textarea").textareaAutoExpand();
|
||||
that.$el.append(tempLI);
|
||||
that.childViews.push(tempView);
|
||||
});
|
||||
that.viewWindow.html(that.$el);
|
||||
},
|
||||
|
||||
//adds a CHILD node.
|
||||
addNode: function(newNode, index, cur){
|
||||
var that = this;
|
||||
var newView = new showView({
|
||||
model: newNode,
|
||||
depth: 0
|
||||
});
|
||||
var newLI = newView.render().$el;
|
||||
|
||||
if(index == 0){ //just handles edge case where you're using this for indent
|
||||
that.$el.prepend(newLI);
|
||||
}else{
|
||||
that.$el.children(":nth-child(" + (index) + ")").after(newLI);
|
||||
}
|
||||
//that.$el.children(":nth-child(" + (index) + ")").after(newLI);
|
||||
|
||||
that.childViews.insert(index , newView);
|
||||
cur = true;
|
||||
if(cur){
|
||||
newLI.children().children("textarea").focus();
|
||||
}
|
||||
else{
|
||||
newView.lock();
|
||||
}
|
||||
return newView;
|
||||
},
|
||||
|
||||
|
||||
updateId: function(newId){
|
||||
that.$el.attr("data-id", newId);
|
||||
},
|
||||
|
||||
updateText: function(newText){
|
||||
var that = this;
|
||||
$("#rootTitle").html(that.model.get("text"));
|
||||
},
|
||||
|
||||
lock: function(){
|
||||
console.log("ROOT LOCKED");
|
||||
},
|
||||
unlock: function(){
|
||||
console.log("ROOT UNLOCKED");
|
||||
},
|
||||
|
||||
removeNode: function(index){
|
||||
var that = this;
|
||||
|
||||
console.log(that.childViews);
|
||||
that.childViews[index].remove();
|
||||
that.childViews.remove(index);
|
||||
},
|
||||
pushView: function(view){
|
||||
this.childViews.push(view);
|
||||
this.$el.children().last().after(view.$el);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,141 @@
|
||||
var showView = Backbone.View.extend({
|
||||
initialize: function(options){
|
||||
var that = this;
|
||||
|
||||
this.model = options["model"];
|
||||
this.depth = options["depth"];
|
||||
(that.model.attributes["views"] = this.model.attributes["views"] || []).push(that);
|
||||
that.$el.attr("data-id", that.model.get("_id")); //booya!
|
||||
this.childViews = [];
|
||||
|
||||
},
|
||||
|
||||
tagName: 'li',
|
||||
className: "herez node",
|
||||
|
||||
|
||||
//todo = refactor this function.
|
||||
render: function(){
|
||||
var that = this;
|
||||
that.$el.html("");
|
||||
|
||||
var id = that.model.get("_id");
|
||||
var text = that.model.get("text");
|
||||
|
||||
var html = that.createUIBullet(id, text, that.depth);
|
||||
that.$el.children("ul").addClass("collapsed");
|
||||
that.$el.attr("data-depth", that.depth);
|
||||
that.$el.attr("data-id", id);
|
||||
|
||||
that.$el.html(html);
|
||||
console.log("about to render textarea")
|
||||
|
||||
that.renderChildren();
|
||||
|
||||
return that;
|
||||
},
|
||||
renderChildren: function(){
|
||||
var that = this;
|
||||
var childrenIds = that.model.get("children");
|
||||
|
||||
_.each(childrenIds, function(childId, index){
|
||||
var childModel = nodesCollection.findWhere({_id: childId});
|
||||
var tempView = new showView({
|
||||
depth: 0,
|
||||
model: childModel
|
||||
});
|
||||
that.childViews.push(tempView)
|
||||
that.$el.children("ul").append(tempView.render().$el);
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
unhide: function(){
|
||||
alert("bleh");
|
||||
},
|
||||
|
||||
//Moved to app.js to handle bubbling issues.
|
||||
// collapse: function(){
|
||||
// var that = this;
|
||||
// that.$el.children("ul").slideToggle(110);
|
||||
// that.$el.children(".zoomButton").toggleClass("collapsed");
|
||||
// },
|
||||
|
||||
createUIBullet: function( id , text, depth) {
|
||||
var that = this;
|
||||
var textArea = "<textarea height='10px' class='js-auto-expand content' style='background:none'>" + text + "</textarea>";
|
||||
|
||||
var expandCollapse = "<a class='expandCollapse'>+</a>"
|
||||
// var aButton = "<a href='#/" + id + "'" + "class='nodeLink'>" + "</a>";
|
||||
// var handle = "<span class=\"handle\"><img src=\"img/bullet-8.png\" /></span>"
|
||||
var zoomButton = "<a href='#/" +that.model.get("_id") + "' class='zoomButton handle'></a>"
|
||||
// var buttonHoist = "<a href='#' class='buttonHoist'></a>"
|
||||
|
||||
var subList = "<ul class ='subList dd-list' data-id="+ id + "></ul>"
|
||||
var bullet = expandCollapse + zoomButton + "<span class='hoverWrap content'>" + textArea + "</span>" + subList;
|
||||
return bullet;
|
||||
},
|
||||
|
||||
addNode: function(newNode, index, cur){
|
||||
var that = this;
|
||||
console.log("addNodeText" + newNode.get("text"))
|
||||
var newView = new showView({
|
||||
model: newNode,
|
||||
depth: that.depth +1
|
||||
});
|
||||
|
||||
var newLI = newView.render().$el;
|
||||
|
||||
|
||||
//var empty = (that.$el.children("ul").children().length == 0);
|
||||
if(index == 0){ //just handles edge case where you're using this for indent
|
||||
that.$el.children("ul").prepend(newLI);
|
||||
}else{
|
||||
that.$el.children("ul").children(":nth-child(" + (index) + ")").after(newLI);
|
||||
}
|
||||
|
||||
that.childViews.insert(index , newView);
|
||||
if(cur){
|
||||
newLI.children().children("textarea").focus();
|
||||
}
|
||||
else{
|
||||
newView.lock();
|
||||
}
|
||||
return newView;
|
||||
},
|
||||
|
||||
updateId: function(newId){
|
||||
this.$el.attr("data-id", newId);
|
||||
this.$el.children("ul").attr("data-id", newId);
|
||||
},
|
||||
updateText: function(newText){
|
||||
var that = this;
|
||||
this.$el.children().children("textarea").val(that.model.get("text"));
|
||||
},
|
||||
lock: function(){
|
||||
this.$el.children().children("textarea").attr("readonly", "readonly");
|
||||
this.$el.children().children("textarea").val("editing....")
|
||||
},
|
||||
unlock: function(){
|
||||
this.$el.children().children("textarea").removeAttr("readonly");
|
||||
this.$el.children().children("textarea").val(this.model.get("text"));
|
||||
},
|
||||
removeNode: function(index){
|
||||
var that = this;
|
||||
that.childViews[index].remove();
|
||||
that.childViews.remove(index);
|
||||
},
|
||||
pushView: function(view){
|
||||
this.childViews.push(view);
|
||||
this.$el.children("ul").children().last().after(view.$el);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
@@ -0,0 +1,487 @@
|
||||
/*!
|
||||
* Bootstrap v2.2.2
|
||||
*
|
||||
* Copyright 2012 Twitter, Inc
|
||||
* Licensed under the Apache License v2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Designed and built with all the love in the world @twitter by @mdo and @fat.
|
||||
*/
|
||||
.clearfix {
|
||||
*zoom: 1;
|
||||
}
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
display: table;
|
||||
content: "";
|
||||
line-height: 0;
|
||||
}
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
.hide-text {
|
||||
font: 0/0 a;
|
||||
color: transparent;
|
||||
text-shadow: none;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
.input-block-level {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 30px;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
[class^="icon-"],
|
||||
[class*=" icon-"] {
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
*margin-right: .3em;
|
||||
line-height: 14px;
|
||||
vertical-align: text-top;
|
||||
background-image: url("../img/glyphicons-halflings.png");
|
||||
background-position: 14px 14px;
|
||||
background-repeat: no-repeat;
|
||||
margin-top: 9px;
|
||||
}
|
||||
/* White icons with optional class, or on hover/active states of certain elements */
|
||||
.icon-white,
|
||||
.nav-pills > .active > a > [class^="icon-"],
|
||||
.nav-pills > .active > a > [class*=" icon-"],
|
||||
.nav-list > .active > a > [class^="icon-"],
|
||||
.nav-list > .active > a > [class*=" icon-"],
|
||||
.navbar-inverse .nav > .active > a > [class^="icon-"],
|
||||
.navbar-inverse .nav > .active > a > [class*=" icon-"],
|
||||
.dropdown-menu > li > a:hover > [class^="icon-"],
|
||||
.dropdown-menu > li > a:hover > [class*=" icon-"],
|
||||
.dropdown-menu > .active > a > [class^="icon-"],
|
||||
.dropdown-menu > .active > a > [class*=" icon-"],
|
||||
.dropdown-submenu:hover > a > [class^="icon-"],
|
||||
.dropdown-submenu:hover > a > [class*=" icon-"] {
|
||||
background-image: url("../img/glyphicons-halflings-white.png");
|
||||
}
|
||||
.icon-glass {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icon-music {
|
||||
background-position: -24px 0;
|
||||
}
|
||||
.icon-search {
|
||||
background-position: -48px 0;
|
||||
}
|
||||
.icon-envelope {
|
||||
background-position: -72px 0;
|
||||
}
|
||||
.icon-heart {
|
||||
background-position: -96px 0;
|
||||
}
|
||||
.icon-star {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.icon-star-empty {
|
||||
background-position: -144px 0;
|
||||
}
|
||||
.icon-user {
|
||||
background-position: -168px 0;
|
||||
}
|
||||
.icon-film {
|
||||
background-position: -192px 0;
|
||||
}
|
||||
.icon-th-large {
|
||||
background-position: -216px 0;
|
||||
}
|
||||
.icon-th {
|
||||
background-position: -240px 0;
|
||||
}
|
||||
.icon-th-list {
|
||||
background-position: -264px 0;
|
||||
}
|
||||
.icon-ok {
|
||||
background-position: -288px 0;
|
||||
}
|
||||
.icon-remove {
|
||||
background-position: -312px 0;
|
||||
}
|
||||
.icon-zoom-in {
|
||||
background-position: -336px 0;
|
||||
}
|
||||
.icon-zoom-out {
|
||||
background-position: -360px 0;
|
||||
}
|
||||
.icon-off {
|
||||
background-position: -384px 0;
|
||||
}
|
||||
.icon-signal {
|
||||
background-position: -408px 0;
|
||||
}
|
||||
.icon-cog {
|
||||
background-position: -432px 0;
|
||||
}
|
||||
.icon-trash {
|
||||
background-position: -456px 0;
|
||||
}
|
||||
.icon-home {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
.icon-file {
|
||||
background-position: -24px -24px;
|
||||
}
|
||||
.icon-time {
|
||||
background-position: -48px -24px;
|
||||
}
|
||||
.icon-road {
|
||||
background-position: -72px -24px;
|
||||
}
|
||||
.icon-download-alt {
|
||||
background-position: -96px -24px;
|
||||
}
|
||||
.icon-download {
|
||||
background-position: -120px -24px;
|
||||
}
|
||||
.icon-upload {
|
||||
background-position: -144px -24px;
|
||||
}
|
||||
.icon-inbox {
|
||||
background-position: -168px -24px;
|
||||
}
|
||||
.icon-play-circle {
|
||||
background-position: -192px -24px;
|
||||
}
|
||||
.icon-repeat {
|
||||
background-position: -216px -24px;
|
||||
}
|
||||
.icon-refresh {
|
||||
background-position: -240px -24px;
|
||||
}
|
||||
.icon-list-alt {
|
||||
background-position: -264px -24px;
|
||||
}
|
||||
.icon-lock {
|
||||
background-position: -287px -24px;
|
||||
}
|
||||
.icon-flag {
|
||||
background-position: -312px -24px;
|
||||
}
|
||||
.icon-headphones {
|
||||
background-position: -336px -24px;
|
||||
}
|
||||
.icon-volume-off {
|
||||
background-position: -360px -24px;
|
||||
}
|
||||
.icon-volume-down {
|
||||
background-position: -384px -24px;
|
||||
}
|
||||
.icon-volume-up {
|
||||
background-position: -408px -24px;
|
||||
}
|
||||
.icon-qrcode {
|
||||
background-position: -432px -24px;
|
||||
}
|
||||
.icon-barcode {
|
||||
background-position: -456px -24px;
|
||||
}
|
||||
.icon-tag {
|
||||
background-position: 0 -48px;
|
||||
}
|
||||
.icon-tags {
|
||||
background-position: -25px -48px;
|
||||
}
|
||||
.icon-book {
|
||||
background-position: -48px -48px;
|
||||
}
|
||||
.icon-bookmark {
|
||||
background-position: -72px -48px;
|
||||
}
|
||||
.icon-print {
|
||||
background-position: -96px -48px;
|
||||
}
|
||||
.icon-camera {
|
||||
background-position: -120px -48px;
|
||||
}
|
||||
.icon-font {
|
||||
background-position: -144px -48px;
|
||||
}
|
||||
.icon-bold {
|
||||
background-position: -167px -48px;
|
||||
}
|
||||
.icon-italic {
|
||||
background-position: -192px -48px;
|
||||
}
|
||||
.icon-text-height {
|
||||
background-position: -216px -48px;
|
||||
}
|
||||
.icon-text-width {
|
||||
background-position: -240px -48px;
|
||||
}
|
||||
.icon-align-left {
|
||||
background-position: -264px -48px;
|
||||
}
|
||||
.icon-align-center {
|
||||
background-position: -288px -48px;
|
||||
}
|
||||
.icon-align-right {
|
||||
background-position: -312px -48px;
|
||||
}
|
||||
.icon-align-justify {
|
||||
background-position: -336px -48px;
|
||||
}
|
||||
.icon-list {
|
||||
background-position: -360px -48px;
|
||||
}
|
||||
.icon-indent-left {
|
||||
background-position: -384px -48px;
|
||||
}
|
||||
.icon-indent-right {
|
||||
background-position: -408px -48px;
|
||||
}
|
||||
.icon-facetime-video {
|
||||
background-position: -432px -48px;
|
||||
}
|
||||
.icon-picture {
|
||||
background-position: -456px -48px;
|
||||
}
|
||||
.icon-pencil {
|
||||
background-position: 0 -72px;
|
||||
}
|
||||
.icon-map-marker {
|
||||
background-position: -24px -72px;
|
||||
}
|
||||
.icon-adjust {
|
||||
background-position: -48px -72px;
|
||||
}
|
||||
.icon-tint {
|
||||
background-position: -72px -72px;
|
||||
}
|
||||
.icon-edit {
|
||||
background-position: -96px -72px;
|
||||
}
|
||||
.icon-share {
|
||||
background-position: -120px -72px;
|
||||
}
|
||||
.icon-check {
|
||||
background-position: -144px -72px;
|
||||
}
|
||||
.icon-move {
|
||||
background-position: -168px -72px;
|
||||
}
|
||||
.icon-step-backward {
|
||||
background-position: -192px -72px;
|
||||
}
|
||||
.icon-fast-backward {
|
||||
background-position: -216px -72px;
|
||||
}
|
||||
.icon-backward {
|
||||
background-position: -240px -72px;
|
||||
}
|
||||
.icon-play {
|
||||
background-position: -264px -72px;
|
||||
}
|
||||
.icon-pause {
|
||||
background-position: -288px -72px;
|
||||
}
|
||||
.icon-stop {
|
||||
background-position: -312px -72px;
|
||||
}
|
||||
.icon-forward {
|
||||
background-position: -336px -72px;
|
||||
}
|
||||
.icon-fast-forward {
|
||||
background-position: -360px -72px;
|
||||
}
|
||||
.icon-step-forward {
|
||||
background-position: -384px -72px;
|
||||
}
|
||||
.icon-eject {
|
||||
background-position: -408px -72px;
|
||||
}
|
||||
.icon-chevron-left {
|
||||
background-position: -432px -72px;
|
||||
}
|
||||
.icon-chevron-right {
|
||||
background-position: -456px -72px;
|
||||
}
|
||||
.icon-plus-sign {
|
||||
background-position: 0 -96px;
|
||||
}
|
||||
.icon-minus-sign {
|
||||
background-position: -24px -96px;
|
||||
}
|
||||
.icon-remove-sign {
|
||||
background-position: -48px -96px;
|
||||
}
|
||||
.icon-ok-sign {
|
||||
background-position: -72px -96px;
|
||||
}
|
||||
.icon-question-sign {
|
||||
background-position: -96px -96px;
|
||||
}
|
||||
.icon-info-sign {
|
||||
background-position: -120px -96px;
|
||||
}
|
||||
.icon-screenshot {
|
||||
background-position: -144px -96px;
|
||||
}
|
||||
.icon-remove-circle {
|
||||
background-position: -168px -96px;
|
||||
}
|
||||
.icon-ok-circle {
|
||||
background-position: -192px -96px;
|
||||
}
|
||||
.icon-ban-circle {
|
||||
background-position: -216px -96px;
|
||||
}
|
||||
.icon-arrow-left {
|
||||
background-position: -240px -96px;
|
||||
}
|
||||
.icon-arrow-right {
|
||||
background-position: -264px -96px;
|
||||
}
|
||||
.icon-arrow-up {
|
||||
background-position: -289px -96px;
|
||||
}
|
||||
.icon-arrow-down {
|
||||
background-position: -312px -96px;
|
||||
}
|
||||
.icon-share-alt {
|
||||
background-position: -336px -96px;
|
||||
}
|
||||
.icon-resize-full {
|
||||
background-position: -360px -96px;
|
||||
}
|
||||
.icon-resize-small {
|
||||
background-position: -384px -96px;
|
||||
}
|
||||
.icon-plus {
|
||||
background-position: -408px -96px;
|
||||
}
|
||||
.icon-minus {
|
||||
background-position: -433px -96px;
|
||||
}
|
||||
.icon-asterisk {
|
||||
background-position: -456px -96px;
|
||||
}
|
||||
.icon-exclamation-sign {
|
||||
background-position: 0 -120px;
|
||||
}
|
||||
.icon-gift {
|
||||
background-position: -24px -120px;
|
||||
}
|
||||
.icon-leaf {
|
||||
background-position: -48px -120px;
|
||||
}
|
||||
.icon-fire {
|
||||
background-position: -72px -120px;
|
||||
}
|
||||
.icon-eye-open {
|
||||
background-position: -96px -120px;
|
||||
}
|
||||
.icon-eye-close {
|
||||
background-position: -120px -120px;
|
||||
}
|
||||
.icon-warning-sign {
|
||||
background-position: -144px -120px;
|
||||
}
|
||||
.icon-plane {
|
||||
background-position: -168px -120px;
|
||||
}
|
||||
.icon-calendar {
|
||||
background-position: -192px -120px;
|
||||
}
|
||||
.icon-random {
|
||||
background-position: -216px -120px;
|
||||
width: 16px;
|
||||
}
|
||||
.icon-comment {
|
||||
background-position: -240px -120px;
|
||||
}
|
||||
.icon-magnet {
|
||||
background-position: -264px -120px;
|
||||
}
|
||||
.icon-chevron-up {
|
||||
background-position: -288px -120px;
|
||||
}
|
||||
.icon-chevron-down {
|
||||
background-position: -313px -119px;
|
||||
}
|
||||
.icon-retweet {
|
||||
background-position: -336px -120px;
|
||||
}
|
||||
.icon-shopping-cart {
|
||||
background-position: -360px -120px;
|
||||
}
|
||||
.icon-folder-close {
|
||||
background-position: -384px -120px;
|
||||
}
|
||||
.icon-folder-open {
|
||||
background-position: -408px -120px;
|
||||
width: 16px;
|
||||
}
|
||||
.icon-resize-vertical {
|
||||
background-position: -432px -119px;
|
||||
}
|
||||
.icon-resize-horizontal {
|
||||
background-position: -456px -118px;
|
||||
}
|
||||
.icon-hdd {
|
||||
background-position: 0 -144px;
|
||||
}
|
||||
.icon-bullhorn {
|
||||
background-position: -24px -144px;
|
||||
}
|
||||
.icon-bell {
|
||||
background-position: -48px -144px;
|
||||
}
|
||||
.icon-certificate {
|
||||
background-position: -72px -144px;
|
||||
}
|
||||
.icon-thumbs-up {
|
||||
background-position: -96px -144px;
|
||||
}
|
||||
.icon-thumbs-down {
|
||||
background-position: -120px -144px;
|
||||
}
|
||||
.icon-hand-right {
|
||||
background-position: -144px -144px;
|
||||
}
|
||||
.icon-hand-left {
|
||||
background-position: -168px -144px;
|
||||
}
|
||||
.icon-hand-up {
|
||||
background-position: -192px -144px;
|
||||
}
|
||||
.icon-hand-down {
|
||||
background-position: -216px -144px;
|
||||
}
|
||||
.icon-circle-arrow-right {
|
||||
background-position: -240px -144px;
|
||||
}
|
||||
.icon-circle-arrow-left {
|
||||
background-position: -264px -144px;
|
||||
}
|
||||
.icon-circle-arrow-up {
|
||||
background-position: -288px -144px;
|
||||
}
|
||||
.icon-circle-arrow-down {
|
||||
background-position: -312px -144px;
|
||||
}
|
||||
.icon-globe {
|
||||
background-position: -336px -144px;
|
||||
}
|
||||
.icon-wrench {
|
||||
background-position: -360px -144px;
|
||||
}
|
||||
.icon-tasks {
|
||||
background-position: -384px -144px;
|
||||
}
|
||||
.icon-filter {
|
||||
background-position: -408px -144px;
|
||||
}
|
||||
.icon-briefcase {
|
||||
background-position: -432px -144px;
|
||||
}
|
||||
.icon-fullscreen {
|
||||
background-position: -456px -144px;
|
||||
}
|
||||
@@ -0,0 +1,406 @@
|
||||
/*! normalize.css v2.1.3 | MIT License | git.io/normalize */
|
||||
|
||||
/* ==========================================================================
|
||||
HTML5 display definitions
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Correct `block` display not defined in IE 8/9.
|
||||
*/
|
||||
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
main,
|
||||
nav,
|
||||
section,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct `inline-block` display not defined in IE 8/9.
|
||||
*/
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
video {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent modern browsers from displaying `audio` without controls.
|
||||
* Remove excess height in iOS 5 devices.
|
||||
*/
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `[hidden]` styling not present in IE 8/9.
|
||||
* Hide the `template` element in IE, Safari, and Firefox < 22.
|
||||
*/
|
||||
|
||||
[hidden],
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Base
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Set default font family to sans-serif.
|
||||
* 2. Prevent iOS text size adjust after orientation change, without disabling
|
||||
* user zoom.
|
||||
*/
|
||||
|
||||
html {
|
||||
font-family: sans-serif; /* 1 */
|
||||
-ms-text-size-adjust: 100%; /* 2 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove default margin.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Links
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the gray background color from active links in IE 10.
|
||||
*/
|
||||
|
||||
a {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `outline` inconsistency between Chrome and other browsers.
|
||||
*/
|
||||
|
||||
a:focus {
|
||||
outline: thin dotted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Improve readability when focused and also mouse hovered in all browsers.
|
||||
*/
|
||||
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Typography
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Address variable `h1` font-size and margin within `section` and `article`
|
||||
* contexts in Firefox 4+, Safari 5, and Chrome.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9, Safari 5, and Chrome.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in Safari 5 and Chrome.
|
||||
*/
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address differences between Firefox and other browsers.
|
||||
*/
|
||||
|
||||
hr {
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9.
|
||||
*/
|
||||
|
||||
mark {
|
||||
background: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct font family set oddly in Safari 5 and Chrome.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
samp {
|
||||
font-family: monospace, serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Improve readability of pre-formatted text in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set consistent quote types.
|
||||
*/
|
||||
|
||||
q {
|
||||
quotes: "\201C" "\201D" "\2018" "\2019";
|
||||
}
|
||||
|
||||
/**
|
||||
* Address inconsistent and variable font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove border when inside `a` element in IE 8/9.
|
||||
*/
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct overflow displayed oddly in IE 9.
|
||||
*/
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Figures
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Address margin not present in IE 8/9 and Safari 5.
|
||||
*/
|
||||
|
||||
figure {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Define consistent border, margin, and padding.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
border: 1px solid #c0c0c0;
|
||||
margin: 0 2px;
|
||||
padding: 0.35em 0.625em 0.75em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct `color` not being inherited in IE 8/9.
|
||||
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
|
||||
*/
|
||||
|
||||
legend {
|
||||
border: 0; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct font family not being inherited in all browsers.
|
||||
* 2. Correct font size not being inherited in all browsers.
|
||||
* 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit; /* 1 */
|
||||
font-size: 100%; /* 2 */
|
||||
margin: 0; /* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
|
||||
* the UA stylesheet.
|
||||
*/
|
||||
|
||||
button,
|
||||
input {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address inconsistent `text-transform` inheritance for `button` and `select`.
|
||||
* All other form control elements do not inherit `text-transform` values.
|
||||
* Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
|
||||
* Correct `select` style inheritance in Firefox 4+ and Opera.
|
||||
*/
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
|
||||
* and `video` controls.
|
||||
* 2. Correct inability to style clickable `input` types in iOS.
|
||||
* 3. Improve usability and consistency of cursor style between image-type
|
||||
* `input` and others.
|
||||
*/
|
||||
|
||||
button,
|
||||
html input[type="button"], /* 1 */
|
||||
input[type="reset"],
|
||||
input[type="submit"] {
|
||||
-webkit-appearance: button; /* 2 */
|
||||
cursor: pointer; /* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-set default cursor for disabled elements.
|
||||
*/
|
||||
|
||||
button[disabled],
|
||||
html input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Address box sizing set to `content-box` in IE 8/9/10.
|
||||
* 2. Remove excess padding in IE 8/9/10.
|
||||
*/
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
|
||||
* 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
|
||||
* (include `-moz` to future-proof).
|
||||
*/
|
||||
|
||||
input[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
-moz-box-sizing: content-box;
|
||||
-webkit-box-sizing: content-box; /* 2 */
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inner padding and search cancel button in Safari 5 and Chrome
|
||||
* on OS X.
|
||||
*/
|
||||
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inner padding and border in Firefox 4+.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Remove default vertical scrollbar in IE 8/9.
|
||||
* 2. Improve readability and alignment in all browsers.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto; /* 1 */
|
||||
vertical-align: top; /* 2 */
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Tables
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove most spacing between table cells.
|
||||
*/
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* html5doctor.com Reset Stylesheet v1.6.1 (http://html5doctor.com/html-5-reset-stylesheet/)
|
||||
* Richard Clark (http://richclarkdesign.com)
|
||||
* http://cssreset.com
|
||||
*/
|
||||
html, body, div, span, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
abbr, address, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, samp,
|
||||
small, strong, sub, sup, var,
|
||||
b, i,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin:0;
|
||||
padding:0;
|
||||
border:0;
|
||||
outline:0;
|
||||
font-size:100%;
|
||||
vertical-align:baseline;
|
||||
background:transparent;
|
||||
}
|
||||
body {
|
||||
line-height:1;
|
||||
}
|
||||
article,aside,details,figcaption,figure,
|
||||
footer,header,hgroup,menu,nav,section {
|
||||
display:block;
|
||||
}
|
||||
nav ul {
|
||||
list-style:none;
|
||||
}
|
||||
blockquote, q {
|
||||
quotes:none;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content:'';
|
||||
content:none;
|
||||
}
|
||||
a {
|
||||
margin:0;
|
||||
padding:0;
|
||||
font-size:100%;
|
||||
vertical-align:baseline;
|
||||
background:transparent;
|
||||
}
|
||||
/* change colours to suit your needs */
|
||||
ins {
|
||||
background-color:#ff9;
|
||||
color:#000;
|
||||
text-decoration:none;
|
||||
}
|
||||
/* change colours to suit your needs */
|
||||
mark {
|
||||
background-color:#ff9;
|
||||
color:#000;
|
||||
font-style:italic;
|
||||
font-weight:bold;
|
||||
}
|
||||
del {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
abbr[title], dfn[title] {
|
||||
border-bottom:1px dotted;
|
||||
cursor:help;
|
||||
}
|
||||
table {
|
||||
border-collapse:collapse;
|
||||
border-spacing:0;
|
||||
}
|
||||
/* change border colour to suit your needs */
|
||||
hr {
|
||||
display:block;
|
||||
height:1px;
|
||||
border:0;
|
||||
border-top:1px solid #cccccc;
|
||||
margin:1em 0;
|
||||
padding:0;
|
||||
}
|
||||
input, select {
|
||||
vertical-align:middle;
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
body {
|
||||
background-color: rgb(245, 245, 245)
|
||||
}
|
||||
|
||||
/* Fix for Firefox dotted outline */
|
||||
:focus, :active, :hover {
|
||||
outline:0 none !important;
|
||||
}
|
||||
|
||||
/************** Navbar *****************/
|
||||
.navbar-primary .navbar {
|
||||
border-bottom:none;
|
||||
}
|
||||
.navbar-primary .navbar .navbar-brand {
|
||||
color:#fff;
|
||||
}
|
||||
.navbar-nav.navbar-right:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
/* Navbar-xs */
|
||||
.navbar-xs .navbar-primary .navbar {
|
||||
min-height:36px;
|
||||
}
|
||||
/* Sidebar Link */
|
||||
.navbar-xs a.navbar-left {
|
||||
margin: 7px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.navbar-xs a i {
|
||||
margin: 0;
|
||||
}
|
||||
/* Navbar-Brand */
|
||||
.navbar-xs .navbar-primary .navbar .navbar-brand {
|
||||
padding: 8px 8px;
|
||||
font-size: 16px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.navbar-xs .navbar-brand {
|
||||
margin-top: 2px;
|
||||
}
|
||||
/* Search Form */
|
||||
.navbar-xs .navbar-form {
|
||||
height: 28px;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 0;
|
||||
padding-right: 6px;
|
||||
}
|
||||
.navbar-xs .navbar-form .form-control {
|
||||
height: 28px;
|
||||
/*padding: 0 12px;*/
|
||||
font-size: 14px;
|
||||
line-height: 1.42857;
|
||||
border-radius: 3px;
|
||||
}
|
||||
/* Star Button */
|
||||
.navbar-xs .btn {
|
||||
min-width: 27px;
|
||||
width: 27px;
|
||||
height: 28px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.navbar-xs .btn i {
|
||||
margin-left: -7px;
|
||||
margin-top: -2px;
|
||||
}
|
||||
/* Navbar Nav */
|
||||
.navbar-xs ul {
|
||||
margin: 2px
|
||||
}
|
||||
.navbar-xs .navbar-primary .navbar .navbar-nav > li > a {
|
||||
padding-top: 7px;
|
||||
padding-bottom: 7px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.navbar-xs a img {
|
||||
height: 16px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
/************* End Navbar **************/
|
||||
|
||||
/*************** Sidebar ***************/
|
||||
|
||||
.sidebar .list-group-item {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding-top: 6px;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.sidebar .list-group-icon {
|
||||
position: relative;
|
||||
top: -8px;
|
||||
}
|
||||
|
||||
.sidebar .list-group-icon-tag {
|
||||
position: relative;
|
||||
top: -7px;
|
||||
}
|
||||
|
||||
.sidebar .list-group-item-text {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
/************* End Sidebar *************/
|
||||
|
||||
/**************** Panel ****************/
|
||||
.main-container {
|
||||
margin-top: 60px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.panel {
|
||||
background: none repeat scroll 0% 0% rgb(252, 252, 252);
|
||||
padding: 20px;
|
||||
min-height: 800px;
|
||||
border: 1px solid rgb(217, 217, 217);
|
||||
border-radius: 5px;
|
||||
box-shadow: 0px 0px 3px 3px rgba(0, 0, 0, 0.05);
|
||||
/*box-shadow: h-shadow v-shadow blur spread color inset;*/
|
||||
}
|
||||
.col-sidebar-panel {
|
||||
margin-left: 50px;
|
||||
}
|
||||
.addendum {
|
||||
position:absolute;
|
||||
bottom: 35px;
|
||||
}
|
||||
/**************** Panel ****************/
|
||||
|
||||
/**************** List *****************/
|
||||
ul {
|
||||
margin-left: 20px;
|
||||
padding: 0;
|
||||
}
|
||||
.node {
|
||||
padding: 0;
|
||||
padding-top: 0;
|
||||
margin-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.leaf {
|
||||
margin-left: 20px;
|
||||
}
|
||||
.expand {
|
||||
display: inline-block;
|
||||
height: 22px;
|
||||
width: 16px;
|
||||
}
|
||||
.expand a {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
vertical-align: center;
|
||||
height: 20px;
|
||||
width: 16px;
|
||||
bottom: 3px;
|
||||
font-size: 18px;
|
||||
text-decoration: none;
|
||||
color: rgb(51, 51, 51);
|
||||
}
|
||||
.handle {
|
||||
display: float;
|
||||
height: 22px;
|
||||
width: 16px;
|
||||
}
|
||||
.handle a {
|
||||
height: 24px;
|
||||
width: 16px;
|
||||
}
|
||||
.handle a img {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.node .content {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 85%;
|
||||
}
|
||||
.node p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: auto;
|
||||
font-size: 16px;
|
||||
}
|
||||
.subList {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
/*MINE */
|
||||
|
||||
#pathDiv {
|
||||
border: 1px solid rgb(217, 217, 217);
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
/*
|
||||
#pathDiv{
|
||||
background-color: grey;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
z-index: 900000000;
|
||||
left: -187px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
|
||||
.panelMenu {
|
||||
height: 40px;
|
||||
border: 1px solid rgb(217, 217, 217);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
.root ul {
|
||||
/*padding: 4px !important; */
|
||||
padding-top: 1px !important;
|
||||
margin-right: 0px !important;
|
||||
/*margin-left: 25px !important;*/
|
||||
list-style-type: square;
|
||||
}
|
||||
|
||||
.root li {
|
||||
/*background: brown;*/
|
||||
position: relative;
|
||||
padding: 0;
|
||||
padding-top: 0px;
|
||||
margin: 0;
|
||||
margin-left: 25px;
|
||||
background-repeat: no-repeat;
|
||||
list-style: none;
|
||||
/*background-image: url(smiley.png); */
|
||||
/*background-size: 15px 15px;
|
||||
background-position: -1px 2px;*/
|
||||
}
|
||||
textarea {
|
||||
width: 100%;
|
||||
/*height: 1em;*/
|
||||
height: 22px;
|
||||
margin-left: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
border: none;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
/*textarea {
|
||||
border: none;
|
||||
overflow: auto;
|
||||
outline: none;
|
||||
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}*/
|
||||
|
||||
.expandCollapse{
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -28px;
|
||||
/*margin-top: -23px;*/
|
||||
top: -2px;
|
||||
opacity: 0.001;
|
||||
/*visibility: hidden; */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ul li a.zoomButton{
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -17px;
|
||||
|
||||
height: 11px !important;
|
||||
width: 11px;
|
||||
|
||||
margin-top: 4px;
|
||||
margin-right: 8px;
|
||||
|
||||
/*background: url("smiley.png") no-repeat center; */
|
||||
/*background-color: grey;*/
|
||||
background-size: 140%;
|
||||
|
||||
|
||||
border: 2px solid black;
|
||||
}
|
||||
|
||||
.collapsed{
|
||||
background-color: grey;
|
||||
}
|
||||
|
||||
ul li i{
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 2px;
|
||||
|
||||
}
|
||||
|
||||
textarea:focus {
|
||||
outline: 0px none transparent;
|
||||
}
|
||||
/**************** List *****************/
|
||||
|
||||
/************** Draggable **************/
|
||||
.placeholder {
|
||||
display: block;
|
||||
height: 24px;
|
||||
width: 100%;
|
||||
border: 1px solid rgb(65, 65, 65);
|
||||
list-style: none;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
.ui-tabs {
|
||||
position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
|
||||
padding: .2em;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav {
|
||||
margin: 0;
|
||||
padding: .2em .2em 0;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav li {
|
||||
list-style: none;
|
||||
float: left;
|
||||
position: relative;
|
||||
top: 0;
|
||||
margin: 1px .2em 0 0;
|
||||
border-bottom-width: 0;
|
||||
margin-left: -3px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav li a {
|
||||
float: left;
|
||||
padding: .5em 1em;
|
||||
color: rgb(51, 51, 51);
|
||||
text-decoration: none;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav li.ui-tabs-active {
|
||||
padding-bottom: 1px;
|
||||
border-radius: 5px 5px 0px 0px;
|
||||
background: rgb(217,217,217);
|
||||
}
|
||||
/*.ui-tabs .ui-tabs-nav li.ui-tabs-active a,
|
||||
.ui-tabs .ui-tabs-nav li.ui-state-disabled a,
|
||||
.ui-tabs .ui-tabs-nav li.ui-tabs-loading a {
|
||||
cursor: text;
|
||||
}*/
|
||||
/* first selector in group seems obsolete, but required
|
||||
* to overcome bug in Opera applying cursor: text overall if defined elsewhere...
|
||||
*/
|
||||
.ui-tabs .ui-tabs-nav li a,
|
||||
.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a {
|
||||
cursor: pointer;
|
||||
}
|
||||
.ui-tabs .ui-tabs-panel {
|
||||
display: block;
|
||||
border-width: 0;
|
||||
padding: 1em 1.4em;
|
||||
border-radius: 0px 5px 5px 5px;
|
||||
background: rgb(217,217,217);
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
.tool-container {
|
||||
background-color: #d0cbcb;
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(14%, #d0cbcb), color-stop(100%, #e9e5e5));
|
||||
background: -moz-linear-gradient(top, #d0cbcb 14%, #e9e5e5 100%);
|
||||
background: -ms-linear-gradient(top, #d0cbcb 14%,#e9e5e5 100%);
|
||||
background: linear-gradient(to bottom, #d0cbcb 14%,#e9e5e5 100%);
|
||||
background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIxNCUiIHN0b3AtY29sb3I9IiNkMGNiY2IiIHN0b3Atb3BhY2l0eT0iMSIvPgogICAgPHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjZTllNWU1IiBzdG9wLW9wYWNpdHk9IjEiLz4KICA8L2xpbmVhckdyYWRpZW50PgogIDxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9InVybCgjZ3JhZC11Y2dnLWdlbmVyYXRlZCkiIC8+Cjwvc3ZnPg==);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#d0cbcb', endColorstr='#e9e5e5',GradientType=0 );
|
||||
background-size: 100% 100%;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0px 0px 15px #000;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.tool-container.tool-top, .tool-container.tool-bottom {
|
||||
height: 34px;
|
||||
border-bottom: 1px solid #beb8b8 ; /* #B1A9A9 */
|
||||
}
|
||||
|
||||
.tool-items {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tool-top .tool-item, .tool-bottom .tool-item {
|
||||
float: left;
|
||||
border-right: 1px solid #e2dfdf;
|
||||
border-left: 1px solid #9f9898;
|
||||
}
|
||||
|
||||
.tool-left .tool-item, .tool-right .tool-item {
|
||||
height: 34px;
|
||||
border-top: 1px solid #e2dfdf;
|
||||
border-bottom: 1px solid #9f9898;
|
||||
}
|
||||
|
||||
|
||||
.tool-item {
|
||||
height: 100%;
|
||||
display: block;
|
||||
width: 44px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tool-item:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.tool-left .tool-item:first-child, .tool-right .tool-item:first-child {
|
||||
border-top: 1px solid transparent;
|
||||
}
|
||||
|
||||
.tool-item:last-child {
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.tool-item.selected, .tool-item:hover {
|
||||
background: #a79f9f;
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #a79f9f), color-stop(93%, #e2dfdf));
|
||||
background: -moz-linear-gradient(top, #a79f9f 0%, #e2dfdf 93%);
|
||||
background: -ms-linear-gradient(top, #a79f9f 0%, #e2dfdf 93%);
|
||||
background: linear-gradient(to bottom, #a79f9f 0%, #e2dfdf 93%);
|
||||
background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2E3OWY5ZiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjkzJSIgc3RvcC1jb2xvcj0iI2UyZGZkZiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgPC9saW5lYXJHcmFkaWVudD4KICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSJ1cmwoI2dyYWQtdWNnZy1nZW5lcmF0ZWQpIiAvPgo8L3N2Zz4=);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#a79f9f', endColorstr='#e2dfdf',GradientType=0 );
|
||||
}
|
||||
|
||||
.tool-top .tool-item:last-child:hover, .tool-bottom .tool-item:last-child:hover {
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.tool-top .tool-item:first-child:hover, .tool-bottom .tool-item:first-child:hover {
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
|
||||
.tool-left .tool-item:last-child:hover, .tool-right .tool-item:last-child:hover {
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
|
||||
.tool-left .tool-item:first-child:hover, .tool-right .tool-item:first-child:hover {
|
||||
border-top-right-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
|
||||
.tool-container .arrow {
|
||||
width:0;
|
||||
height:0;
|
||||
position: absolute;
|
||||
border-width:7px;
|
||||
border-style:solid;
|
||||
}
|
||||
|
||||
.tool-container.tool-top .arrow {
|
||||
border-color: #e9e5e5 transparent transparent;
|
||||
left: 50%;
|
||||
bottom: -14px;
|
||||
margin-left: -7px;
|
||||
}
|
||||
|
||||
.tool-container.tool-bottom .arrow {
|
||||
border-color: transparent transparent #e9e5e5;
|
||||
left: 50%;
|
||||
top: -14px;
|
||||
margin-left: -7px;
|
||||
}
|
||||
|
||||
.tool-container.tool-left .arrow {
|
||||
border-color: transparent transparent transparent #E9E5E5;
|
||||
top: 50%;
|
||||
right: -14px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
.tool-container.tool-right .arrow {
|
||||
border-color: transparent #E9E5E5 transparent transparent;
|
||||
top: 50%;
|
||||
left: -14px;
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
||||
.demo-link {
|
||||
color: #89CDE4;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.demo-link:hover {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<link href="stylesheets/reset.css" rel="stylesheet" type="text/css">
|
||||
<link href="stylesheets/normalize.css" rel="stylesheet" type="text/css">
|
||||
<link href="stylesheets/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="stylesheets/toolbar.css" rel="stylesheet" />
|
||||
<link href="stylesheets/bootstrap.icons.css" rel="stylesheet" />
|
||||
<link href="stylesheets/style.css" rel="stylesheet" type="text/css">
|
||||
|
||||
|
||||
<script src="js/libs/externalLibs/jquery-2.0.3.js"></script>
|
||||
<script src="socket.io/socket.io.js"></script>
|
||||
<script src="js/libs/myLib/addNode.js"></script>
|
||||
<script src="js/libs/myLib/removeNode.js"></script>
|
||||
<script src="js/libs/myLib/KeyBoardLogic.js"></script>
|
||||
<script src="js/libs/myLib/moveNode.js"></script>
|
||||
<script src="js/app.js"></script>
|
||||
|
||||
|
||||
|
||||
<!-- <script src="./jquery-sortable.js"></script> -->
|
||||
<script src="js/libs/externalLibs/rangyinputs-jquery-1.1.2.js"></script>
|
||||
|
||||
<script src="js/libs/externalLibs/textarea_auto_expand.js"></script>
|
||||
|
||||
|
||||
|
||||
|
||||
<script src ="js/libs/externalLibs/underscore-min.js"></script>
|
||||
<script src="js/libs/externalLibs/backbone-min.js"></script>
|
||||
|
||||
|
||||
<script src="js/models/node.js"></script>
|
||||
<script src="js/collections/nodesCollection.js"></script>
|
||||
<script src="js/views/listView.js"></script>
|
||||
<script src="js/views/showView.js"></script>
|
||||
<script src="js/router.js"></script>
|
||||
|
||||
|
||||
|
||||
<body>
|
||||
<p><br /><span class="math"><em>x</em><sup>2</sup></span><br /></p>
|
||||
|
||||
<div class="navbar-xs">
|
||||
<div class="navbar-primary">
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-left" href="sidebar.html"><i class="icon-list"></i></a>
|
||||
<a class="navbar-brand" href="index.html">Metablock</a>
|
||||
</div>
|
||||
<form class="navbar-form navbar-left" role="search">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" placeholder="Search">
|
||||
</div>
|
||||
</form>
|
||||
<a class="btn btn-default" href=""><i class="icon-star"></i></a>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a class='transclude'>Transclude/alias</a></li>
|
||||
<!-- <li><a href="index.html"><img src="img/splitscreen.png"></a></li> -->
|
||||
<li><a class='splitScreen'><img src="img/splitscreen.png"></a></li>
|
||||
<li><a href=""><img src="img/undo.png"></a></li>
|
||||
<li><a href=""><img src="img/redo.png"></a></li>
|
||||
<li><a href="">x<sup>2</sup></a></li>
|
||||
<li class="dropdown">
|
||||
<a href="" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="">Action</a></li>
|
||||
<li><a href="">Another action</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="">Separated link</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="main-container">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
|
||||
<!-- Pane 1 -->
|
||||
<div class="col-md-6 col-md-offset-2">
|
||||
<div id="pathDiv">PathDIV</div>
|
||||
<div class='main main1 panel'>
|
||||
<ul id="0" class='root subList dd-list' ></ul>
|
||||
<h4 class="addendum"><small> Make lists. Not war. </small></h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pane 2 -->
|
||||
<!-- <div class="col-md-6">
|
||||
<div class='main2 panel'>
|
||||
<ul id="0" class='root subList dd-list' >
|
||||
<li id='1' class='herez node'>
|
||||
Inentionally Un-editable. (split-screen editing is a pending feature).
|
||||
</ul>
|
||||
<h4 class="addendum"><small> Make lists. Not war. </small></h4>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toolbars
|
||||
<div id="toolbar" hidden>
|
||||
<a href="#"><i class="icon-user"></i></a>
|
||||
<a href="#"><i class="icon-star"></i></a>
|
||||
<a href="#"><i class="icon-edit"></i></a>
|
||||
<a href="#"><i class="icon-trash"></i></a>
|
||||
</div> -->
|
||||
|
||||
<!-- <script src="js/tempFolder/nestable.js"></script> -->
|
||||
<script src="js/tempFolder/toolbar.js"></script>
|
||||
<script src="js/tempFolder/bootstrap.js"></script>
|
||||
<script src="js/tempFolder/startup.js"></script>
|
||||
</body>
|
||||
<script>
|
||||
$(function(){
|
||||
$('textarea').textareaAutoExpand();
|
||||
});
|
||||
</script>
|
||||
|
||||
</html>
|
||||