poimoe_

nodejs poimoe

Stars
7
Committers
2

Poimoe


[TOC]


[email protected] 2016-06-06 16:29 markdown Poimoepoimoe


B/S SocketCanvasAJAXHTTPComet

**** HTML5 + CSS3 + JavaScript **** Nodejs **** MongoDB

PHP + MySql

**** Mac OS X **** Sublime Text 3 **** Git **** HomebrewNPM MongoDB Node

PoimoeSPA 5


MVVMVuejs + Angularjs Bootstrap Webpack ECMAScriptBabel


RESTful APIrestify MongoDBMongoose

API

RESTful API

TCP/IPSocketComet

**** CentOS ****Nginx + php-fpm

Nginx

  1. Wordpress
  2. PoiVuejsComet
  3. KakuVuejsSocketSocket

Cookie + localStoragedocument.domainpoimoe

Poi

Kaku



Poi


Kaku



  1. /
  2. //
  3. /
  4. /

///


  1. /

/


  1. /

/


  1. /

/

  1. /


  1. /


Webpack


var webpack = require('webpack');

module.exports = {
    entry: './src/index.js',
    output: {
        path: __dirname,
        filename: './dist/build.js'
    },
    module: {
        loaders: [
            { test: /\.vue$/, loader: 'vue' },
            { test: /\.css$/, loader: "style!css" },
            { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' },
            { test: /\.js$/, loader: 'jsx-loader?harmony' },
            { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff" },
            { test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff2" },
            { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream" },
            { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file" },
            { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml" }
        ]
    },
    babel: {
        presets: ['es2015', 'stage-0'],
        plugins: ['transform-runtime']
    },
    resolve: {
        //require
        extensions: ['', '.js', '.json', '.css'],
        //
        alias: {
            vueStrap: './node_modules/vue-strap/dist/vue-strap.min.js',
            bootstrap: './node_modules/bootstrap/dist/css/bootstrap.min.css'
        }
    }
}

if (process.env.NODE_ENV === 'production') {
  module.exports.plugins = [ 
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }   
    }), 
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }   
    }), 
    new webpack.optimize.OccurenceOrderPlugin()
  ]
} else {
  module.exports.devtool = '#source-map'
}


JS/CSS//

npm run dev

.

npm run build

gulp


var args        = require('yargs').argv,
    path        = require('path'),
    flip        = require('css-flip'),
    through     = require('through2'),
    gulp        = require('gulp'),
    $           = require('gulp-load-plugins')(),
    gulpsync    = $.sync(gulp),
    PluginError = $.util.PluginError,
    del         = require('del'),
    connect     = require('gulp-connect');

//---------------
// MAIN TASKS
//---------------

// build for production (minify)
gulp.task('build', gulpsync.sync([
          'prod',
          'vendor',
          'assets'
        ]));

gulp.task('prod', function() { 
  log('Starting production build...');
  isProduction = true; 
});

// build with sourcemaps (no minify)
gulp.task('sourcemaps', ['usesources', 'default']);
gulp.task('usesources', function(){ useSourceMaps = true; });

// default (no minify)
gulp.task('default', gulpsync.sync([
          'vendor',
          'assets',
          'serve',
          'watch'
        ]), function(){

  log('************');
  log('* All Done * You can start editing your code, LiveReload will update your browser after any change..');
  log('************');

});

gulp.task('serve', function () {
  connect.server({
    root: '../',
    livereload: false,
    port: 8080
  });
});

gulp.task('assets',[
  'scripts:app',
  'styles:app',
  'styles:app:rtl',
  'styles:themes',
  'templates:index',
  'templates:views'
]);

jscssscsslessjadehtml/

gulp
gulp build

git + ssh


echo "commit"

read msg 

git add .
git commit -a -m "$msg"
git push -u origin master
rsync -avz -4 --exclude-from "/var/www/poimoe/exclude.md" /var/www/poimoe/ [email protected]:/var/www/poimoe/

github

Node

Supervisor

poikaku:

npm run dev

8080

gulp

8080

APISocketComet

supervisorsupervisorNode

cd /var/www/poimoe/admin/master/ && gulp build
cd /var/www/poimoe/web/kaku && npm run build
cd /var/www/poimoe/web/poi && npm run build
sh p.sh #

supervisorSocketAPI


screen -S poimoe_api && cd /var/www/poimoe/api && supervisor app.js
screen -S poimoe_socket && cd /var/www/poimoe/socket && supervisor app.js

nginx
systemctl start mariadb
systemctl start php-fpm
mongod

kaku


  • tab

. README.md admin app index.html master server vendor api app.js conf controllers models node_modules package.json routes.js sc.sh util build.sh cdn exclude.md image index.php upload.php npm-debug.log p.sh r.sh server.sh socket index.html index.js node_modules package.json util web index kaku poi Poimoe adminapiapiimagesocketweb

p.shgithub r.sh


RESTful API

. app.js conf controllers models node_modules package.json routes.js sc.sh util

apiAPI

app.js api conf controllers models node_modules nodejs routes.js api sc.sh util

API

API


var restify = require('restify');
var mongoose = require('mongoose');
var routes = require('./routes');
var dbconf = require('./conf/db');
var conf = require('./conf/conf');
var models = require('./models/index');

//mongodb
mongoose.connect('mongodb://' + dbconf.mongo.host + '/' + dbconf.mongo.database);

var db = mongoose.connection;
var Schema = mongoose.Schema;

db.on('error', console.error.bind(console,'connection error'));

db.once('open', function(callback) {

});

//restify
var server = restify.createServer({
	name: 'poimoe'
});

restify.CORS.ALLOW_HEADERS.push('authorization');

server.use(restify.authorizationParser());
server.use(restify.bodyParser());
server.use(restify.queryParser());
server.use(restify.CORS());

//
routes.init(server, mongoose, restify);

//
server.listen(2333, function() {
  console.log('%s listening at %s', server.name, server.url);
});


supervisor app.js

CORS

JavaScriptCORSCORS

    server.pre(function(req, res, next) {
    	res.charSet('utf-8');
        res.setHeader('Allow', 'GET, POST, OPTIONS, PUT, DELETE');
        res.setHeader('Access-Control-Allow-Origin', '*');
        res.setHeader('Access-Control-Allow-Headers', 'Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, Api-Version, Authorization');
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE');
        res.setHeader('Access-Control-Allow-Credentials', 'true');
    	return next();
    });

restify

restify

server.use(ctrl.userCtrl.auth);

userauthauth

  auth: function(req, res, next) {

    var reqRoute = req.route.path;
    var routesNoneAuth = [
      '/themes/hot', '/tags/select/hotTags', 
      '/user/recommended', '/user/register/:email/:password', 
      '/user/login/:email/:password', '/themes/select/:tid', 
      '/user/profile/get/:uid', '/site/search/:val/:page/:count', '/timeline/message/personal/count/:uid',
      '/timeline/message/index/count/:uid', '/timeline/message/index/count/:uid',
      '/kaku/room/all/:page/:count'
    ];

    if(req.username == 'anonymous') {

      var reqRouteList = reqRoute.split('/');

      var isHasNoneAuthRoute = false;

      for (var i = routesNoneAuth.length - 1; i >= 0; i--) {
        var currRoute = routesNoneAuth[i];
        if(currRoute == reqRoute) {
          isHasNoneAuthRoute = true;
          break;
        }
      };

      //  

      if(!isHasNoneAuthRoute) {
        res.send(util.retMsg(4001, ""));         
      }else {
        return next();
      }

    }else {
      var User = ctrlInitial.models.User();
      User.findByAccessToken(req.authorization.credentials, function(err, u) {

        if(err) {
          res.send(util.retMsg(400, err.toString()));
        }

        if(u.length === 0) {
          res.send(util.retMsg(4001, "access_token"));
        }

        if(u[0].tokenCreatedAt == undefined || u[0].tokenDestoriedAt == undefined) {
          res.send(util.retMsg(4001, "access_token"));
        }

        var currentTimestamp = Date.now();
        if(currentTimestamp > u[0].tokenDestoriedAt) {
          res.send(util.retMsg(4001, "access_token"));
        }

        if(u[0].isBlocked === true) {
          res.send(util.retMsg(400, "" + thisEmail + " "));
        }

        if(u[0].isDeleted === true) {
          res.send(util.retMsg(400, "" + thisEmail + " "));
        }

        global.currentUserId = u[0]._id;

        var group = u[0].group;

        if(group.length === 0) {
          res.send(util.retMsg(401, ""));
        }

        var group = group[0];

        if(group.name == 'root' && group.code == 100) {
          //root
          next();
        }else {

          var ug = ctrlInitial.models.UserGroups();

          ug.findById(group._id, function(err, auth) {

            if(err) {
              res.send(util.retMsg(400, err.toString()));
            }

            if(auth.length === 0) {
              res.send(util.retMsg(401, ""));
            }else {

              var authList = auth[0].rightsList;

              var hadAuth = false;
              var AuthName = '';

              for (var i = 0; i < authList.length; i++) {
                var currentAuth = authList[i];
                var router = currentAuth.router;

                if(router == reqRoute) {
                  hadAuth  = true;
                  break;
                }
              };

              if(!hadAuth) {
                res.send(util.retMsg(401, ""));
              }else {
                next();
              }

            }

          });

        }

      });
    }

  },

OAuth

PoimoeOAuthAccessTokentokenauth

Poimoe

root


json


  applyAuthority: function(req, res, next) {

    var rights = req.params.rights;
    var id = req.params.id;

    if(rights == undefined || rights == '') {
      res.send(util.retMsg(401, ""));
    }

    if(id == undefined || id == '') {
      res.send(util.retMsg(401, "id"));
    }

    if(rights.length === 0) {
      res.send(util.retMsg(401, ""));
    }

    var UG = ctrlInitial.models.UserGroups();

    UG.findById(id, function(err, ug) {

      if(err) {
        res.send(util.retMsg(401, err.toString()));
      }

      if(ug.length === 0) {
        res.send(util.retMsg(401, ''));
      }

      ug = ug[0];

      if(ug.code == '100') {
        // res.send(util.retMsg(401, ''));
      }

      UG.update(id, {
        rightsList: rights
      }, function(err, ug) {

        if(err) {
          res.send(util.retMsg(401, err.toString()));
        }

        res.send(util.retMsg(200, '', ug));

      });

    });

  },

  applyToUser: function(req, res, next) {

    var aid = req.params.aid;
    var uid = req.params.uid;

    if(uid == undefined || uid == '') {
      res.send(util.retMsg(401, "id"));
    }

    if(aid == undefined || aid == '') {
      res.send(util.retMsg(401, "id"));
    }

    var UG = ctrlInitial.models.UserGroups();

    UG.findById(aid, function(err, ug) {

      if(err) {
        res.send(util.retMsg(401, err.toString()));
      }

      if(ug.length === 0) {
        res.send(util.retMsg(401, ''));
      }

      ug = ug[0];

      var User = ctrlInitial.models.User();

      User.updateGroup(aid, uid, function(err, user) {

        if(err) {
          res.send(util.retMsg(401, err.toString()));
        }

        res.send(util.retMsg(200, '', user));

      });

    });

  }

Comet

CGCGCGCGCGAJAXComet

PoimoeComet

TimelinePoimoe

PoimoeTimeline

      personalMessageQueue: [{
        operator: {
          type: Schema.Types.ObjectId,
          ref: 'users'
        },
        targetUser: {
          type: Schema.Types.ObjectId,
          ref: 'users'
        },
        targetTheme: {
          type: Schema.Types.ObjectId,
          ref: 'themes'
        },
        did: {
          type: String,
          default: 'repost' //repost || favourite
        },
        createdAt: {
          type: Date,
          default: Date.now
        }
      }]

ididCG id


      messageQueue: [{
        type: Schema.Types.ObjectId,
        ref: 'themes'
      }],


  getMessageCount: function(req, res, next) {

    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');

    res.writeHead(200, {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
      "Connection": "keep-alive"
    });

    var count = 0;

    var loadMessageCount = function() {
      
      var uid = req.params.uid;

      if(uid == '' || uid == undefined) {
        res.write(util.retESMsg(401, 'id'));
      }

      var User = ctrlInitial.models.User();

      var Timeline = ctrlInitial.models.Timeline();

      Timeline.findMessageCount(uid, function(err, tl_messageCount) {

        if(err) {
          res.write(util.retESMsg(401, err.toString()));        
        }

        if(tl_messageCount == null) {

          var tline = new Timeline({
            user_id: uid
          });

          tline.save(function(err, new_tl) {

            if(err) {
              res.write(util.retESMsg(401, err.toString()));
            }

            res.write(util.retESMsg(200, new_tl.messageCount));

          });

        }else {
          res.write(util.retESMsg(200, tl_messageCount.messageCount));
        }

      });

    };

    console.log('user start index message count comet service');

    global.currentCountInterval = setInterval(function() {
      loadMessageCount();
    }, 500);

    res.connection.on('end', function(){
      console.log('user exit index message count comet service');
      clearInterval(currentCountInterval);
    });

  },

CometHTTP header

content-typetext/event-stream

EventSourceComet

CometHTML5EventSource


startIndexTimelineComet: function() {
	var _this = this;

	var es = new EventSource('http://api.poimoe.com//timeline/message/index/count/' + localStorage._id);

	es.onmessage = function(e) {
		_this.indexMesssageCount = JSON.parse(e.data).message;
		console.log(_this.indexMesssageCount);
	};

	es.onerror = function(e) {
		util.handleError('comet');
	};

	es.onopen = function(e) {}
}


. index.html index.js node_modules express express-mongoose mongoose request socket.io package.json util index.js

  1. socketididaccessToken

  2. enter chatting room succeedenter chatting room failed

  3. UI

  4. UIUI

enterRoom: function(id) {

	var _this = this;

    var chatSocket = io('ws://socket.poimoe.com/chat');
	chatSocket.emit('enter chatting room', {
		people: localStorage._id,
		roomId: id,
		passport: sessionStorage[id],
		username: localStorage.username,
		accessToken: localStorage.accessToken
	});

	window.chatSocket = chatSocket;

	chatSocket.on('enter chatting room succeed', function(res) {

		var code = res.code;
        var data = res.message;

        if(code != 200) {
            util.messageBox(data);
            router.go('/index');
            return false;
        }

        _this.room = data[0];

        _this.room.chatting.reverse();

        if(_this.room.paint != null) {
            _this.paint = _this.room.paint;

            // falsetruefalsetrue
            for(var key in _this.paint) {

            	_this.paint[key] = _this.paint[key] == 'false' ? false : (_this.paint[key] == 'true' ? true : _this.paint[key]);

            	if(key == 'layer' || key == 'currentLayer') {
        			if(typeof _this.paint[key].length == 'number') {

        				for (var i = 0; i < _this.paint[key].length; i++) {
        					var curr = _this.paint[key][i];
        					for(var k in curr) {
        						_this.paint[key][i][k] = _this.paint[key][i] == 'false' ? false : ( _this.paint[key][i][k] == 'true' ? true : _this.paint[key][i][k] );
        					}
        				};

        			}
            	}

            }

            //
            // toggleLayer(key, layer.id, paint.currentLayer.index);

            _this.paint.x = [];
            _this.paint.y = [];
            _this.paint.clickDrag = [];
        }
        // _this.paintUI = _this.room.paintUI;

        setTimeout(function() {
            _this.initPaint();
            _this.initBasePaint();

            //

            //dataURLtoDataURL

            _this.drawImageOnCanvas(_this.paint.dataURL, _this.paint.baseCxt);
            _this.drawImageOnCanvas(_this.paint.dataURL, _this.paint.cxt);

            var activeLayerIndex = _this.paint.currentLayer.index;
            var activeLayerId = _this.paint.layer[activeLayerIndex].id;
            var activeLayer = {
            	cxt: '',
            	url: ''
            };

            for (var i = 0; i < _this.paint.layer.length; i++) {
            	var currentLayer = _this.paint.layer[i];
            	var tmpCxt = document.getElementById(currentLayer.id).getContext('2d');
            	if(currentLayer.dataURL != '') {
            		console.log(currentLayer.dataURL);
                	_this.drawImageOnCanvas(currentLayer.dataURL, tmpCxt);
                	if(activeLayerId == currentLayer.id) {
                		activeLayer.cxt = tmpCxt;
                		activeLayer.url = currentLayer.dataURL;
                	}
            	}
            };

            // //dataURL
            // console.log(activeLayer);
        	// _this.drawImageOnCanvas(activeLayer.url, activeLayer.cxt);

            _this.isLoaded = true;

            setTimeout(function() {
	        	common.adjustUI();
            }, 400);

			_this.initKakuMQSocket();
			_this.initKakuInstantSavingThread();

        }, 10);

        //// _this.initKakuSocket(id);

	});

	chatSocket.on('enter chatting room failed', function(msg) {
		util.handleError(msg, 'socket');
	});

	chatSocket.on('leave room failed', function(msg) {
		util.handleError(msg, 'socket');
	});

	chatSocket.on('leave room succeed', function(msg) {
		console.log(msg);
	});

	chatSocket.on('sys', function(msg) {
		util.handleError(msg, 'socket');
	});

    chatSocket.on('chat message', function(msg) {

		if(typeof msg === 'string') {
			msg = JSON.parse(msg);
		}

		var code = msg.code;
		var data = msg.message;

		if(code != 200) {
			util.messageBox(data);
			return false;
		}

		_this.room.chatting.push(data.chatting[0]);
		_this.message = '';
	});
},

chatSocket.emit('leave', {
	leaver: localStorage._id,
	roomId: router._currentRoute.params.id,
	accessToken: localStorage.accessToken
});

var dataURL = this.paint.baseCanvas.toDataURL();

PoimoebaseCanvas

  1. base64png

toDataURL

cloneObject: function(original, ignoreList) {

	ignoreList = ignoreList || false;

	var tmp = {};

	for(var key in original) {
		if(ignoreList) {
			if(ignoreList.indexOf(key) === -1) {
				tmp[key] = original[key];
			}
		}else {
			tmp[key] = original[key];
		}
	}

	return tmp;

},

Poimoe

getLayerDataURL: function(canvas) {
	var cxt = canvas.getContext('2d');
	var oldData = cxt.getImageData(0, 0, canvas.width, canvas.height);
	var newCanvas = document.createElement("canvas");
	newCanvas.width = canvas.width;
	newCanvas.height = canvas.height;
	newCanvas.id = "tmpLayer";
	document.body.appendChild(newCanvas);
	var newCxt = newCanvas.getContext("2d");
	newCxt.putImageData(oldData, 0 ,0);
	var data = newCanvas.toDataURL();
	newCanvas.parentNode.removeChild(newCanvas);
	return data;
}

canvascxt.getImageDatacanvascanvascanvasPoimoegetImageDatatoDataURL

CGPoi

shareThisCG: function(obj, cb) {

	var navToPoi;

	if(obj != undefined) {
		navToPoi = obj.navToPoi == false ? obj.navToPoi : true;
	}else {
		navToPoi = true;
		obj = {
			isLayer: false,
			nodel: 'no'
		}
	}

	var _this = this;

	//
	//cookie
	//poiCG
	var base64 = obj.base64 || this.paint.baseCanvas.toDataURL();

	var requestParams = navToPoi ? localStorage._id + '/roomCG/' + this.room._id + '/sharing' : localStorage._id + '/roomCG/' + this.room._id + '/painting';

	requestParams = obj.isLayer ? requestParams + '/layers' : requestParams;

	services.KakuService.uploadBase64ToServer({
		uid: requestParams,
		nodel: obj.nodel || 'no'
	}, {
		base64Image: base64
	}).then(function(res) {

        var code = res.data.status;
        var data = res.data.message;

        if(code != 200) {
            util.messageBox(data, true);
            return false;
        }

        var imageUrl = data.origin;

        if(navToPoi) {
        	var split = imageUrl.split('/');
        	var name = split[split.length - 1];
            window.location.href = 'http://poi.poimoe.com/#!/cg/new/' + _this.room._id + '/' + name;
        }else {
        	cb(imageUrl);
        }

	}, function(err) {
		util.handleError(err);
	});
},

canvasbase64postbase64

/

toggleSyncPaintingStatus: function() {
	if(this.instantSaving.startInstantSavingThread) {
		clearInterval(this.instantSaving.instantSavingThreadFlag);
		this.instantSaving.tips = '';
		util.messageBox('');
		this.instantSaving.startInstantSavingThread = false;
	}else {
		util.messageBox('');
		_this.instantSaving.tips = '';
		this.instantSaving.startInstantSavingThread = true;
		this.initKakuInstantSavingThread();
	}
}

myId: localStorage._id,

room: {},
message: '',

isLoaded: false,

paint: {
	x: [], //x
	y: [], //y
	lock: false, //
	isEraser: false,
	eraserRadius: 15,
	isColorPicker: false,
	canvas: '',
	cxt: '',
	baseCanvas: '',
	baseCxt: '',
	lineWidth: 5,
	strokeStyle: 'rgba(0, 0, 0, 0)',
	width: 0,
	height: 0,

	clickDrag: [],

	touch: ('createTouch' in document),
	startEvent: this.touch ? 'touchstart' : 'mousedown',
	moveEvent: this.touch ? 'touchmove' : 'mousemove',
	endEvent: this.touch ? 'touchend' : 'mouseup',

	layer: [{
		name: '',
		opacity: 100,
		display: 'block',
		zindex: 1,
		id: 'layer-bg',
		active: true,
		editable: false,
		marginTop: 0,
		dataURL: ''
	}],

	currentLayer: {
		id: 'layer-bg',
		index: 0
	},

	picData: '',
	dataURL: ''
},

paintUI: {
	colorPickerCursorPosition: '',
	colorPicker: {}
},

instantSaving: {
	instantSavingThreadFlag: 0,
	startInstantSavingThread: false,
	tips: ''
}

myId:id room message isLoaded paint paint.xx paint.yy paint.lock paint.isEraser paint.eraserRadius paint.canvas paint.cxtcanvas paint.baseCanvascanvas paint.baseCxt paint.lineWidth paint.strokeStyle paint.width paint.height paint.clickDrag paint.touchtouch paint.startEvent paint.moveEvent paint.endEvent paint.layer paint.currentLayer paint.picData

canvascanvas

layer: [{
	name: '',
	opacity: 100,
	display: 'block',
	zindex: 1,
	id: 'layer-bg',
	active: true,
	editable: false,
	marginTop: 0,
	dataURL: ''
}],

currentLayer: {
	id: 'layer-bg',
	index: 0
}

layer.name layer.opacity layer.displaydisplay layer.zindex layer.idcanvasdomid layer.active layer.editable layer.marginTop layer.dataURL

addNewLayer: function(layer, noSocket) {
	noSocket = noSocket || false;

	var thisPaint = this.paint;
	var thisPaintLayer = thisPaint.layer;

	var currentLayerIndex = thisPaint.currentLayer.index;

	thisPaintLayer[currentLayerIndex].active = false;
	thisPaintLayer[currentLayerIndex].zindex = -1;

	var layerId = 'LAYER' + util.randomString(8);
	var layerCount = thisPaintLayer.length;
	var layer = layer || {
		name: '' + layerCount,
		opacity: 100,
		display: 'block',
		zindex: 1,
		id: layerId,
		active: true,
		editable: false,
		marginTop: '-800px',
		dataURL: ''
	};
	thisPaintLayer.push(layer);

	this.toggleLayer(layerCount, layerId, currentLayerIndex);

	layer.people = localStorage._id;

	if(!noSocket) {
		chatSocket.emit('new layer', layer);        			
	}
},
removeThisLayer: function(index, noSocket) {
	noSocket = noSocket || false;

	var thisPaint = this.paint;
	var thisPaintLayer = thisPaint.layer;
	var currentLayer = thisPaint.currentLayer;

	var currentLayerIndex = index || currentLayer.index;
	var tmpIndex = currentLayerIndex;

	if(currentLayerIndex === 0) {
		util.messageBox('');
		return false;
	}

	thisPaintLayer.splice(currentLayerIndex);

	this.toggleLayer(currentLayerIndex - 1, thisPaintLayer[currentLayerIndex - 1].id);

	if(!noSocket) {
		chatSocket.emit('remove layer', {
			index: tmpIndex,
			people: localStorage._id
		});        			
	}
},

toggleLayer: function(activeIndex, activeId, unactiveIndex, noSocket) {
	if(activeIndex == unactiveIndex) {
		return false;
	}

	noSocket = noSocket || false;

	var thisPaint = this.paint;
	var thisPaintLayer = thisPaint.layer;
	var currentLayer = thisPaint.currentLayer;

	currentLayer.index = activeIndex;
	currentLayer.id = activeId;
	thisPaintLayer[activeIndex].active = true;
	thisPaintLayer[activeIndex].zindex = 1;
	if(typeof unactiveIndex != 'undefined') {
		thisPaintLayer[unactiveIndex].active = false;
		thisPaintLayer[unactiveIndex].zindex = -1;  			
	}
	this.initPaintInterval(activeId);
	if(!noSocket) {
		chatSocket.emit('toggle layer', {
			activeIndex: activeIndex,
			activeId: activeId,
			unactiveIndex: unactiveIndex,
			people: localStorage._id
		});
	}
},
showThisLayer: function(id, noSocket) {
	noSocket = noSocket || false;
	this.paint.layer[id].display = 'block';
	if(!noSocket) {
		chatSocket.emit('show layer', {
			index: id,
			people: localStorage._id
		});        			
	}
},

hideThisLayer: function(id, noSocket) {
	noSocket = noSocket || false;
	this.paint.layer[id].display = 'none';
	if(!noSocket) {
		chatSocket.emit('hide layer', {
			index: id,
			people: localStorage._id
		});        			
	}
},
makeThisLayerEditable: function(id, makeFalse) {
	makeFalse = makeFalse || true;
	this.paint.layer[id].editable = !this.paint.layer[id].editable;
	if(!makeFalse) {
		setTimeout(function() {
			this.paint.layer[id].editable = false;        				
		}, 10);
	}
},
confirmEditThisLayerName: function(index, name) {
	this.paint.layer[index].editable = false;
	var layer = this.paint.layer[index];
	layer.people = localStorage._id;
	layer.index = index;
	chatSocket.emit('modify layer', layer);
},

MVVMthis.paint.lineWidthdomDOMslider

canvasColorPicker

kaku/src/commons/scripts/ColorPicker.js

_this.colorPicker = ColorPicker.init({
	onColorChange: function(color) {
		_this.paint.strokeStyle = color;

		chatSocket.emit('color change', {
			people: localStorage._id,
			color: _this.paint.strokeStyle
		});

	},
	defaultColor: 'rgba(0, 0, 0, 255)'
});
var panel = _this.colorPicker.getPanel();
document.getElementById('color-picker-area').appendChild(panel);

resetErase: function(_x, _y, touch) {
	var t = this.paint;
	var cxt = t.cxt;
	for (var i = 0; i < 2; i++) {
		if(i === 1) {
			cxt = t.baseCxt;
		}
		cxt.globalCompositeOperation = "destination-out";
        cxt.beginPath();
        cxt.arc(_x, _y, t.eraserRadius, 0, Math.PI * 2);
        cxt.strokeStyle = "rgba(250,250,250,0)";
        cxt.fill();
        cxt.globalCompositeOperation = "source-over";
	};
}

Canvas

HTMLFileReadercanvas

getPicFile: function() {

	var file = document.getElementById('upfile');

    var reader = new FileReader();

    var _this = this;

    reader.readAsDataURL(file.files[0]);  
    reader.onload = function(e){
    	_this.drawImage(this.result);
    };

    reader.onerror = function(e) {
    	console.log(e);
    };

    reader.onabort = function(e) {
    	console.log(e);
    };
}

drawImagecanvas

canvasdataURL

window.open(this.paint.baseCanvas.toDataURL());

Socket

Socket.io expresssocket

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var mongoose = require('mongoose');
var request = require('request');
var lib = require('./util/index.js');

app.get('/', function(req, res){
  res.send('welcome to poimoe socket server');
});

var chat = io.of('/chat');
var kaku = io.of('/kaku');

Socketchat message

socket.on('chat message', function(msg){
	console.log('msg reveived: ');

	if(!roomInfo[roomId]) {
		roomInfo[roomId] = [];
	}

	if (roomInfo[roomId].indexOfA(user) === -1) {  
      return false;
    }

	request.post({
	        url: 'http://api.poimoe.com/kaku/room/chat/send',
	        encoding: 'utf8',
	        headers: {
	        	'Authorization': 'Basic ' + msg.accessToken 
	        },
	        form: msg
	    },
	    function(error, response, body){
	        if(!error && response.statusCode == 200){
	            console.log(body);
			    chat.to(roomId).emit('chat message', body);
	        }else{
	            console.log(response.statusCode);
        	    chat.to(roomId).emit('chat message', {
        	    	code: response.statusCode,
        	    	message: response.body,
        	    	error: error,
        	    	headers: response.headers,
        	    	request: response.request
        	    });
	        }
	    }
	);
});
confirmToSendChattingMessage: function() {
	var _this = this;

	if(_this.message == '') {
		util.messageBox('');
		return false;
	}

	var chatMessage = {
		sender: localStorage._id,
		roomId: _this.room._id,
		message: _this.message,
		accessToken: localStorage.accessToken
	};
	chatSocket.emit('chat message', chatMessage);
},

ididaccessToken

chatSocket.on('chat message', function(msg) {

	if(typeof msg === 'string') {
		msg = JSON.parse(msg);
	}

	var code = msg.code;
	var data = msg.message;

	if(code != 200) {
		util.messageBox(data);
		return false;
	}

	_this.room.chatting.push(data.chatting[0]);
	_this.message = '';
});

Socket

socketstart draw kaku

socket.on('start draw kaku', function(msg) {

	if(!roomInfo[roomId]) {
		roomInfo[roomId] = [];
	}

	if (roomInfo[roomId].indexOfA(user) === -1) {  
      return false;
    }

    chat.to(roomId).emit('get kaku path', msg);

});

emitget kaku path

chatSocket.emit('start draw kaku', {
	x: t.x,
	y: t.y,
	strokeStyle: t.strokeStyle,
	clickDrag: t.clickDrag,
	lineWidth: t.lineWidth,
	eraserRadius: t.eraserRadius,
	people: localStorage._id
});

xyid

chatSocket.on('get kaku path', function(data) {
	if(!(data.people.toString() == localStorage._id)) {
		_this.paint.strokeStyle = data.strokeStyle;
		_this.paint.lineWidth = data.lineWidth;
		_this.paint.x = data.x;
		_this.paint.y = data.y;
		_this.paint.clickDrag = data.clickDrag;
		_this.paint.eraserRadius = data.eraserRadius;
		_this.drawPoint();
		_this.drawPoint(false, _this.paint.baseCxt);
	}
});

idid

drawPoint

drawPoint: function(sendSocket, cxt) {

	sendSocket = sendSocket || false;

	var t = this.paint;
	var cxt = cxt || t.cxt;
	cxt.fillStyle = "#000000";

	if(sendSocket) {
		chatSocket.emit('start draw kaku', {
			x: t.x,
			y: t.y,
			strokeStyle: t.strokeStyle,
			clickDrag: t.clickDrag,
			lineWidth: t.lineWidth,
			eraserRadius: t.eraserRadius,
			people: localStorage._id
		});
	}

	for(var i=0; i < t.x.length; i++) {   
        cxt.beginPath();//context.beginPath() , 	                
        if(t.clickDrag[i] && i){//i!=0
            cxt.moveTo(t.x[i-1], t.y[i-1]);//context.moveTo(x, y) , 
        }else{
            cxt.moveTo(t.x[i] - 1, t.y[i]);
        }

        cxt.lineTo(t.x[i], t.y[i]);//context.lineTo(x, y) , 
        cxt.closePath();//context.closePath() , 
        cxt.stroke();//context.stroke() , 
    }

    cxt.save();
}

socket


Poi

. 448c34a56d699c29117adc64c43affeb.woff2 89889688147bd7575d6327160d64e760.svg README.md dist e18bbf611f2a2e43afc071aa2f4e1512.ttf f4769f9bdb7466be65088239c12046d1.eot fa2772327f55d8198301fdb8bcfc8158.woff index.html node_modules package.json remove.sh src upload.html webpack.config.js


Poikaku****MVVMVueJS

src

. 404.vue app.vue commons components config.js filters index.js npm-debug.log routes.js services

app.vue 404.vue commons jscssimages components filters index.js routes.js services api

iframe

upload.html

<script type="text/javascript">
	
	function getQueryString(name) {
	    var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
	    var r = window.location.search.substr(1).match(reg);
	    if (r != null) {
	        return unescape(r[2]);
	    }
	    return null;
	}

	localStorage.pictureUploadedJSON = getQueryString('data');

	document.write(localStorage.pictureUploadedJSON);

</script>

DOM

<div @click="uploadCG()" class="timeline-new-section-outer" id="my-cg-viewer">
	<h1 v-show="isCGShow === false" style="line-height: 14">CG</h1>
	<div id="cg-outer">
		<img style="display:none" id="sharing-viewer" class="cg-viewer" width="100" height="100" border="0">
	</div>
	<form style="display:none" enctype="multipart/form-data" method="post" target="upload" v-bind:action="cgUploadAction" > 
		<input type="file" id="cg-source" name="upfile" v-on:change="previewImage()"/>
		<input id="submit-cg-btn" type="submit" /> 
	</form>
	<iframe style="display:none" id="ifr" name="upload"></iframe>
</div>

uploadCG

document.getElementById("cg-source").click();

formpreviewImage

previewImage: function() {

	var width = document.getElementById('my-cg-viewer').style.width;
	var height = document.getElementById('my-cg-viewer').offsetHeight - 2;

	util.previewImage('cg-source', 'cg-outer', 'cg-viewer', '', 'width:100%;height:' + height + 'px;');
	this.isCGShow = true;

	var _this = this;

	util.syncUploadPic('submit-cg-btn', 'ifr', function(picJSON) {
    	_this.cg.image = picJSON.message.preview;
	});
}

11

syncUploadPic: function(submitBtnId, ifrId, cb) {
	document.getElementById(submitBtnId).click();

	var _this = this;

    var getJSON = function() {
    	var picJSON = JSON.parse(localStorage.pictureUploadedJSON);

    	if(picJSON.status != 200) {
    		_this.messageBox('');
    		return false;
    	}

    	cb(picJSON);
    };

    var oFrm = document.getElementById(ifrId);

	oFrm.onload = oFrm.onreadystatechange = function() {
	     if (this.readyState && this.readyState != 'complete') {
	     	return false;
	     }
	     else {
	         getJSON();
	     }
	}
},

formsubmitiframeurl

php

if(!$cors) {

        returnMessage(200, array('origin' => 'http://image.poimoe.com/'.$destination_folder.$fname, 'preview' => 'http://image.poimoe.com/'.$destination));

}else {

        header('Location:'.$corsurl.'?data='.returnMessage(200, array('origin' => 'http://image.poimoe.com/'.$destination_folder.$fname, 'preview' => 'http://image.poimoe.com/'.$destination), true));
        
    }

components

. error nodata.vue favourites index.vue footer.vue header.vue index.vue loading loading.vue search search.vue search.vue timeline index.vue personal.vue public.vue users login.vue notifications.vue profile.vue relations signin.vue works index.vue new.vue view.vue

error favourites cg footer header loading ajax search timeline uses works workwork

poicometapi

. index.php upload.php

PHPNginx + php-fpmCORS

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, Api-Version, Authorization');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE');
header('Access-Control-Allow-Credentials: true');
header("Content-type: text/html; charset=utf-8");

. app css documentation i18n img js vendor views index.html master bower.json bower_components gulpfile.js jade js less node_modules package.json sass vendor.base.json vendor.json server sidebar-menu.json vendor angular-datatables angular-ui-map datatables fontawesome modernizr simple-line-icons weather-icons

angularjsjadehtmllesscss

master

// START widgets box
.row(ng-controller="DashboardController as dash")
  .col-lg-3.col-sm-6
    // START widget
    .panel.widget.bg-primary
      .row.row-table
        .col-xs-4.text-center.bg-primary-dark.pv-lg
          em.icon-user.fa-3x
        .col-xs-8.pv-lg
          .h2.mt0 {{dash.dashboardInfo.usersAddedToday}}
          .text-uppercase 
  .col-lg-3.col-sm-6
    // START widget
    .panel.widget.bg-purple
      .row.row-table
        .col-xs-4.text-center.bg-purple-dark.pv-lg
          em.icon-users.fa-3x
        .col-xs-8.pv-lg
          .h2.mt0 {{dash.dashboardInfo.usersCount}}
          .text-uppercase 
  .col-lg-3.col-md-6.col-sm-12
    // START widget
    .panel.widget.bg-green
      .row.row-table
        .col-xs-4.text-center.bg-green-dark.pv-lg
          em.icon-bubbles.fa-3x
        .col-xs-8.pv-lg
          .h2.mt0 {{dash.dashboardInfo.themesCount}}
          .text-uppercase 
  .col-lg-3.col-md-6.col-sm-12
    // START date widget
    .panel.widget
      .row.row-table
        .col-xs-4.text-center.bg-green.pv-lg
          // See formats: https://docs.angularjs.org/api/ng/filter/date
          em.icon-tag.fa-3x
        .col-xs-8.pv-lg
          .h2.mt0 {{dash.dashboardInfo.tagsCount}}
          .text-uppercase 
    // END date widget    
// END widgets box
UserService.getAll(1, 1000)
.success(function(res, status, headers, config) {
    if(res.code != 200) {
        var toast = $mdToast.simple()
              .content(res.message)
              .action('')
              .highlightAction(false)
              .position('top right');
        $mdToast.show(toast).then(function() {
        });
    }
    vm.usersList = res.message;
})
.error(function(res, status, headers, config) {
    var toast = $mdToast.simple()
          .content('' + status)
          .action('')
          .highlightAction(false)
          .position('top right');
    $mdToast.show(toast).then(function() {
    });
});

javascriptpromisegulp