Clean start

This commit is contained in:
Curtis SerVaas
2014-07-24 15:22:08 -04:00
commit ea4a65ddc9
54 changed files with 47834 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
node_modules/
lib/db.js
+13
View File
@@ -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.
+31
View File
@@ -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`
+55
View File
@@ -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();
}
+25
View File
@@ -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()
}
+172
View File
@@ -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();
}
}
+220
View File
@@ -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);
};
+29
View File
@@ -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');
}
+22
View File
@@ -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"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

+311
View File
@@ -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);
}
+5
View File
@@ -0,0 +1,5 @@
var nodesCollection = Backbone.Collection.extend({
model: NodeModel
});
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -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);
File diff suppressed because one or more lines are too long
+164
View File
@@ -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);
}
+85
View File
@@ -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();
}
+36
View File
@@ -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);
}
}
+42
View File
@@ -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);
});
}
+3
View File
@@ -0,0 +1,3 @@
var NodeModel = Backbone.Model.extend({
});
+191
View File
@@ -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")
// });
+2006
View File
File diff suppressed because it is too large Load Diff
+14972
View File
File diff suppressed because it is too large Load Diff
+8829
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+554
View File
@@ -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);
+13
View File
@@ -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');
}
})
+609
View File
@@ -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)
+40
View File
@@ -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');
// }
// });
});
+60
View File
@@ -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);
}
}
});
+20
View File
@@ -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);
+243
View File
@@ -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 );
+128
View File
@@ -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);
}
});
+141
View File
@@ -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);
}
});
+7118
View File
File diff suppressed because it is too large Load Diff
+487
View File
@@ -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;
}
+406
View File
@@ -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;
}
+86
View File
@@ -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;
}
+319
View File
@@ -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;
}
+49
View File
@@ -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);
}
+133
View File
@@ -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;
}
+132
View File
@@ -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>