├── VERSION ├── .openshift ├── cron │ ├── daily │ │ └── .gitignore │ ├── hourly │ │ └── .gitignore │ ├── minutely │ │ └── .gitignore │ ├── monthly │ │ └── .gitignore │ ├── weekly │ │ ├── chrono.dat │ │ ├── chronograph │ │ ├── jobs.deny │ │ ├── jobs.allow │ │ └── README │ └── README.cron ├── action_hooks │ ├── post_deploy │ ├── pre_build │ ├── deploy │ ├── pre_start_nodejs │ └── build ├── markers │ ├── README │ └── NODEJS_VERSION └── lib │ └── setup_custom_nodejs_env ├── uploads └── .gitignore ├── public ├── attachments │ └── .gitignore ├── images │ ├── add.png │ ├── irc.png │ ├── man.png │ ├── set.png │ ├── ucd.png │ ├── admin.png │ ├── bg-1.png │ ├── devel.png │ ├── lock.png │ ├── logo.png │ ├── sent.png │ ├── 404-img.png │ ├── Calendar.png │ ├── Wrench.png │ ├── bg-grey.png │ ├── bg-white.png │ ├── body-bg.png │ ├── btn-edit.png │ ├── delete.png │ ├── destroy.png │ ├── favicon.ico │ ├── favicon.png │ ├── loading.gif │ ├── member.png │ ├── option.png │ ├── setting.png │ ├── settings.png │ ├── side-bar.png │ ├── unlock.png │ ├── add-2-icon.png │ ├── btn-delete.png │ ├── cantas-all.png │ ├── footprint.png │ ├── icon-owner.png │ ├── icon-time.png │ ├── infomation.png │ ├── red-heart.png │ ├── search-bg.png │ ├── black-heart.png │ ├── cantas-agree.png │ ├── cantas-agree1.png │ ├── cantas-all1.png │ ├── cantas-assign.png │ ├── cantas-check.png │ ├── cantas-login.png │ ├── cantas-none.png │ ├── cantas-none1.png │ ├── cantas-option.png │ ├── cantas-part.png │ ├── cantas-part1.png │ ├── description.png │ ├── footer-logo.png │ ├── icon-archive.png │ ├── icon-invited.png │ ├── information.png │ ├── list-settings.png │ ├── login-header.png │ ├── notification.png │ ├── progressbar.gif │ ├── public-board.png │ ├── stage-server.png │ ├── activetracking.png │ ├── btn-edit-hover.png │ ├── cantas-check-1.png │ ├── cantas-comment.png │ ├── cantas-disabled.png │ ├── cantas-disagree.png │ ├── cantas-due-date.png │ ├── card-setting-1.png │ ├── eso-footer-logo.png │ ├── btn-delete-hover.png │ ├── cantas-agree-badge.png │ ├── cantas-attachment.png │ ├── cantas-checklist.png │ ├── cantas-disagree1.png │ ├── cantas-help-assign.gif │ ├── cantas-help-board.gif │ ├── cantas-help-card.gif │ ├── cantas-help-invite.gif │ ├── cantas-help-list.gif │ ├── cantas-help-activity.gif │ ├── cantas-help-comment.gif │ ├── cantas-help-movecard.gif │ ├── cantas-help-movelist.gif │ ├── cantas-help-private.gif │ ├── list-settings-hover.png │ ├── cantas-help-archivecard.gif │ ├── cantas-help-archivelist.gif │ ├── cantas-help-checklist.gif │ ├── cantas-help-import-trello.gif │ ├── cantas-help-notification.gif │ ├── header-logo-eso-developed.png │ ├── cantas-help-import-bugzilla.gif │ └── header-logo-eso-maintained.png ├── stylesheets │ ├── fonts │ │ ├── droid-sans.woff │ │ ├── overpass-wf.woff │ │ ├── droid-sans-bold.woff │ │ ├── overpass-bold-wf.woff │ │ ├── font-awesome │ │ │ └── font │ │ │ │ ├── FontAwesome.otf │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ └── fontawesome-webfont.woff │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ ├── images │ │ ├── cantas-welcome-board.png │ │ ├── cantas-welcome-card.png │ │ ├── cantas-welcome-list.png │ │ └── cantas-welcome-card-detail.png │ ├── jquery-fileupload-ui.css │ └── style.css └── javascripts │ ├── constants.js │ ├── views │ ├── base.js │ ├── help.js │ ├── accountSettings.js │ ├── dashboard-navigation.js │ ├── app.js │ ├── welcome.js │ ├── dashboard.js │ ├── boardlist.js │ ├── confirmDialog.js │ └── activity.js │ ├── models │ ├── boardMember.js │ ├── visitor.js │ ├── activity.js │ ├── notification.js │ ├── label.js │ ├── vote.js │ ├── attachment.js │ ├── syncConfig.js │ ├── comment.js │ └── checklist.js │ ├── utils │ └── safe_string.js │ ├── vendor │ ├── jquery.ba-cond.js │ └── backbone.iosync.js │ └── application.js ├── docs └── source │ ├── test.rst │ ├── conv.rst │ ├── about.rst │ ├── deploy.rst │ ├── devel.rst │ ├── design.rst │ └── index.rst ├── views ├── backbone │ ├── move-list-item.jade │ ├── notification-item.jade │ ├── dashboard.jade │ ├── card-votes-total.jade │ ├── board-title.jade │ ├── card-checkitem.jade │ ├── card-labels-neonlights.jade │ ├── card-menu.jade │ ├── list-menu.jade │ ├── comment.jade │ ├── notification-menu.jade │ ├── accountSettings.jade │ ├── list.jade │ ├── card-checklist.jade │ ├── card-add.jade │ ├── admin-config.jade │ ├── archived-item.jade │ ├── card-attachment-upload.jade │ ├── label-assign.jade │ ├── card-attachment.jade │ ├── card-list.jade │ ├── quick-search.jade │ ├── archived.jade │ ├── dashboard-navigation.jade │ ├── search.jade │ ├── card-vote.jade │ ├── card-attachment-download.jade │ ├── card-assign.jade │ ├── import-bugzilla.jade │ ├── comment-item.jade │ ├── syncconfig-item-input.jade │ ├── syncconfig-item-edit.jade │ ├── card-due-date.jade │ ├── vote-config.jade │ ├── comment-config.jade │ ├── syncconfig-item.jade │ ├── move-list.jade │ ├── board-list.jade │ ├── card.jade │ └── card-detail.jade └── email │ ├── assign.jade │ ├── comment.jade │ ├── invitation.jade │ ├── editComment.jade │ └── notification.jade ├── CHANGELOG.md ├── .gitignore ├── sockets ├── stdlib.js ├── patch_socket.js ├── crud │ ├── activity.js │ ├── boardMemberRelation.js │ ├── notification.js │ ├── index.js │ ├── cardLabelRelation.js │ ├── checklist.js │ └── checklistItem.js ├── importTrello.js └── signals.js ├── spec ├── javascripts │ ├── fixtures │ │ ├── checklistItem.html │ │ ├── timeout.html │ │ ├── labelNeonlights.html │ │ ├── cardVote.html │ │ ├── adminConfig.html │ │ ├── unselectLabel.html │ │ ├── voteConfig.html │ │ ├── commentConfig.html │ │ ├── cardBadges.html │ │ ├── cardDetail.html │ │ ├── movelist.html │ │ └── boardView.html │ ├── checkEmailAddress.spec.js │ ├── timeout.spec.js │ ├── movelist.spec.js │ ├── voteConfig.spec.js │ ├── commentConfig.spec.js │ ├── unselectLabel.spec.js │ ├── labelNeonlights.spec.js │ ├── sycnCardBadges.spec.js │ └── cardVote.spec.js └── node │ ├── socket-patch-test.js │ ├── dbinit.js │ ├── mail-test.js │ └── invitation-test.js ├── scripts ├── cantas-init.sh ├── lintcheck ├── cantas-migration-to-0.3.sh ├── db_migration_card_add_boardId.js ├── db_migration_checklistItem_add_cardId.js ├── db_migration_card_assignees_changed.js ├── db_init_label_metadata.js └── cantas.rc ├── services ├── sites.js ├── cardHandler.js ├── auth │ └── index.js ├── mail.js ├── activity.js └── integration │ └── bz-API.js ├── models ├── boardMemberStatus.js ├── notificationType.js ├── roles.js ├── group.js ├── organization.js ├── activity.js ├── configStatus.js ├── vote.js ├── label.js ├── comment.js ├── metadata.js ├── notification.js ├── cardLabelRelation.js ├── checklist.js ├── commentSourceRelation.js ├── checklistItem.js ├── cardSourceRelation.js ├── list.js ├── user.js ├── action.js ├── attachment.js ├── syncConfig.js └── permission.js ├── settings.js ├── AUTHORS.md ├── .travis.yml ├── sonar-project.properties ├── package.json ├── LICENSE └── settings.json.example /VERSION: -------------------------------------------------------------------------------- 1 | 1.0.1-dev 2 | -------------------------------------------------------------------------------- /.openshift/cron/daily/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.openshift/cron/hourly/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.openshift/cron/minutely/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.openshift/cron/monthly/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /uploads/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /public/attachments/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /docs/source/test.rst: -------------------------------------------------------------------------------- 1 | .. _test: 2 | 3 | 4 | Testing 5 | ======= 6 | -------------------------------------------------------------------------------- /.openshift/cron/weekly/chrono.dat: -------------------------------------------------------------------------------- 1 | Time And Relative D...n In Execution (Open)Shift! 2 | -------------------------------------------------------------------------------- /docs/source/conv.rst: -------------------------------------------------------------------------------- 1 | .. _conv: 2 | 3 | 4 | Code Convention 5 | =============== 6 | -------------------------------------------------------------------------------- /public/images/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/add.png -------------------------------------------------------------------------------- /public/images/irc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/irc.png -------------------------------------------------------------------------------- /public/images/man.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/man.png -------------------------------------------------------------------------------- /public/images/set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/set.png -------------------------------------------------------------------------------- /public/images/ucd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/ucd.png -------------------------------------------------------------------------------- /public/images/admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/admin.png -------------------------------------------------------------------------------- /public/images/bg-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/bg-1.png -------------------------------------------------------------------------------- /public/images/devel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/devel.png -------------------------------------------------------------------------------- /public/images/lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/lock.png -------------------------------------------------------------------------------- /public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/logo.png -------------------------------------------------------------------------------- /public/images/sent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/sent.png -------------------------------------------------------------------------------- /public/images/404-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/404-img.png -------------------------------------------------------------------------------- /public/images/Calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/Calendar.png -------------------------------------------------------------------------------- /public/images/Wrench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/Wrench.png -------------------------------------------------------------------------------- /public/images/bg-grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/bg-grey.png -------------------------------------------------------------------------------- /public/images/bg-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/bg-white.png -------------------------------------------------------------------------------- /public/images/body-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/body-bg.png -------------------------------------------------------------------------------- /public/images/btn-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/btn-edit.png -------------------------------------------------------------------------------- /public/images/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/delete.png -------------------------------------------------------------------------------- /public/images/destroy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/destroy.png -------------------------------------------------------------------------------- /public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/favicon.ico -------------------------------------------------------------------------------- /public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/favicon.png -------------------------------------------------------------------------------- /public/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/loading.gif -------------------------------------------------------------------------------- /public/images/member.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/member.png -------------------------------------------------------------------------------- /public/images/option.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/option.png -------------------------------------------------------------------------------- /public/images/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/setting.png -------------------------------------------------------------------------------- /public/images/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/settings.png -------------------------------------------------------------------------------- /public/images/side-bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/side-bar.png -------------------------------------------------------------------------------- /public/images/unlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/unlock.png -------------------------------------------------------------------------------- /.openshift/cron/weekly/chronograph: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "`date`: `cat $(dirname \"$0\")/chrono.dat`" 4 | -------------------------------------------------------------------------------- /public/images/add-2-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/add-2-icon.png -------------------------------------------------------------------------------- /public/images/btn-delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/btn-delete.png -------------------------------------------------------------------------------- /public/images/cantas-all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-all.png -------------------------------------------------------------------------------- /public/images/footprint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/footprint.png -------------------------------------------------------------------------------- /public/images/icon-owner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/icon-owner.png -------------------------------------------------------------------------------- /public/images/icon-time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/icon-time.png -------------------------------------------------------------------------------- /public/images/infomation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/infomation.png -------------------------------------------------------------------------------- /public/images/red-heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/red-heart.png -------------------------------------------------------------------------------- /public/images/search-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/search-bg.png -------------------------------------------------------------------------------- /public/images/black-heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/black-heart.png -------------------------------------------------------------------------------- /public/images/cantas-agree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-agree.png -------------------------------------------------------------------------------- /public/images/cantas-agree1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-agree1.png -------------------------------------------------------------------------------- /public/images/cantas-all1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-all1.png -------------------------------------------------------------------------------- /public/images/cantas-assign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-assign.png -------------------------------------------------------------------------------- /public/images/cantas-check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-check.png -------------------------------------------------------------------------------- /public/images/cantas-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-login.png -------------------------------------------------------------------------------- /public/images/cantas-none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-none.png -------------------------------------------------------------------------------- /public/images/cantas-none1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-none1.png -------------------------------------------------------------------------------- /public/images/cantas-option.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-option.png -------------------------------------------------------------------------------- /public/images/cantas-part.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-part.png -------------------------------------------------------------------------------- /public/images/cantas-part1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-part1.png -------------------------------------------------------------------------------- /public/images/description.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/description.png -------------------------------------------------------------------------------- /public/images/footer-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/footer-logo.png -------------------------------------------------------------------------------- /public/images/icon-archive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/icon-archive.png -------------------------------------------------------------------------------- /public/images/icon-invited.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/icon-invited.png -------------------------------------------------------------------------------- /public/images/information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/information.png -------------------------------------------------------------------------------- /public/images/list-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/list-settings.png -------------------------------------------------------------------------------- /public/images/login-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/login-header.png -------------------------------------------------------------------------------- /public/images/notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/notification.png -------------------------------------------------------------------------------- /public/images/progressbar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/progressbar.gif -------------------------------------------------------------------------------- /public/images/public-board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/public-board.png -------------------------------------------------------------------------------- /public/images/stage-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/stage-server.png -------------------------------------------------------------------------------- /public/images/activetracking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/activetracking.png -------------------------------------------------------------------------------- /public/images/btn-edit-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/btn-edit-hover.png -------------------------------------------------------------------------------- /public/images/cantas-check-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-check-1.png -------------------------------------------------------------------------------- /public/images/cantas-comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-comment.png -------------------------------------------------------------------------------- /public/images/cantas-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-disabled.png -------------------------------------------------------------------------------- /public/images/cantas-disagree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-disagree.png -------------------------------------------------------------------------------- /public/images/cantas-due-date.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-due-date.png -------------------------------------------------------------------------------- /public/images/card-setting-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/card-setting-1.png -------------------------------------------------------------------------------- /public/images/eso-footer-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/eso-footer-logo.png -------------------------------------------------------------------------------- /public/images/btn-delete-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/btn-delete-hover.png -------------------------------------------------------------------------------- /public/images/cantas-agree-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-agree-badge.png -------------------------------------------------------------------------------- /public/images/cantas-attachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-attachment.png -------------------------------------------------------------------------------- /public/images/cantas-checklist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-checklist.png -------------------------------------------------------------------------------- /public/images/cantas-disagree1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-disagree1.png -------------------------------------------------------------------------------- /public/images/cantas-help-assign.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-assign.gif -------------------------------------------------------------------------------- /public/images/cantas-help-board.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-board.gif -------------------------------------------------------------------------------- /public/images/cantas-help-card.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-card.gif -------------------------------------------------------------------------------- /public/images/cantas-help-invite.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-invite.gif -------------------------------------------------------------------------------- /public/images/cantas-help-list.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-list.gif -------------------------------------------------------------------------------- /public/images/cantas-help-activity.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-activity.gif -------------------------------------------------------------------------------- /public/images/cantas-help-comment.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-comment.gif -------------------------------------------------------------------------------- /public/images/cantas-help-movecard.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-movecard.gif -------------------------------------------------------------------------------- /public/images/cantas-help-movelist.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-movelist.gif -------------------------------------------------------------------------------- /public/images/cantas-help-private.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-private.gif -------------------------------------------------------------------------------- /public/images/list-settings-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/list-settings-hover.png -------------------------------------------------------------------------------- /public/images/cantas-help-archivecard.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-archivecard.gif -------------------------------------------------------------------------------- /public/images/cantas-help-archivelist.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-archivelist.gif -------------------------------------------------------------------------------- /public/images/cantas-help-checklist.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-checklist.gif -------------------------------------------------------------------------------- /public/stylesheets/fonts/droid-sans.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/fonts/droid-sans.woff -------------------------------------------------------------------------------- /public/stylesheets/fonts/overpass-wf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/fonts/overpass-wf.woff -------------------------------------------------------------------------------- /public/images/cantas-help-import-trello.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-import-trello.gif -------------------------------------------------------------------------------- /public/images/cantas-help-notification.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-notification.gif -------------------------------------------------------------------------------- /public/images/header-logo-eso-developed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/header-logo-eso-developed.png -------------------------------------------------------------------------------- /public/images/cantas-help-import-bugzilla.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/cantas-help-import-bugzilla.gif -------------------------------------------------------------------------------- /public/images/header-logo-eso-maintained.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/images/header-logo-eso-maintained.png -------------------------------------------------------------------------------- /public/stylesheets/fonts/droid-sans-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/fonts/droid-sans-bold.woff -------------------------------------------------------------------------------- /public/stylesheets/fonts/overpass-bold-wf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/fonts/overpass-bold-wf.woff -------------------------------------------------------------------------------- /public/stylesheets/images/cantas-welcome-board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/images/cantas-welcome-board.png -------------------------------------------------------------------------------- /public/stylesheets/images/cantas-welcome-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/images/cantas-welcome-card.png -------------------------------------------------------------------------------- /public/stylesheets/images/cantas-welcome-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/images/cantas-welcome-list.png -------------------------------------------------------------------------------- /public/stylesheets/images/cantas-welcome-card-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/images/cantas-welcome-card-detail.png -------------------------------------------------------------------------------- /public/stylesheets/fonts/font-awesome/font/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/fonts/font-awesome/font/FontAwesome.otf -------------------------------------------------------------------------------- /public/stylesheets/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/stylesheets/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/stylesheets/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /views/backbone/move-list-item.jade: -------------------------------------------------------------------------------- 1 | script#template-move-list-item(type="text/template") 2 | |a(data-itemid= data._id, data-label= data.title)= data.title 3 | |span › 4 | -------------------------------------------------------------------------------- /views/backbone/notification-item.jade: -------------------------------------------------------------------------------- 1 | script#template-notification-item-view(type="text/template") 2 | |span(href="javascript: void(0)") \!{message} [\#{created}] 3 | -------------------------------------------------------------------------------- /public/stylesheets/fonts/font-awesome/font/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/fonts/font-awesome/font/fontawesome-webfont.eot -------------------------------------------------------------------------------- /public/stylesheets/fonts/font-awesome/font/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/fonts/font-awesome/font/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /.openshift/cron/weekly/jobs.deny: -------------------------------------------------------------------------------- 1 | # 2 | # Any script or job files listed in here (one entry per line) will NOT be 3 | # executed (read as ignored by run-parts). 4 | # 5 | 6 | README 7 | 8 | -------------------------------------------------------------------------------- /public/stylesheets/fonts/font-awesome/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaods/nodejs-cantas/HEAD/public/stylesheets/fonts/font-awesome/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /views/backbone/dashboard.jade: -------------------------------------------------------------------------------- 1 | script#template-dashboard-layout-view(type="text/template") 2 | |div.row-fluid.dashboard-layout 3 | | div.span2.dashboard-navigation 4 | | div.span10.dashboard-content -------------------------------------------------------------------------------- /views/backbone/card-votes-total.jade: -------------------------------------------------------------------------------- 1 | script#template-card-votes-total-view(type="text/template") 2 | |span.vote-agree-num= voteYes 3 | |span.agree 4 | |span.vote-disagree-num= voteNo 5 | |span.disagree 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.1 (2014-09-02) 4 | 5 | + support login with google auth2 6 | + add mycards panels to home page 7 | + support cards filter 8 | + upload file to card, support image cover on card face 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .idea 4 | *.rdb 5 | npm-debug.log 6 | _SpecRunner.html 7 | *~ 8 | *.swp 9 | public/javascripts/dist/*.js 10 | public/stylesheets/*.min.css 11 | .grunt 12 | redhat 13 | settings.json -------------------------------------------------------------------------------- /.openshift/action_hooks/post_deploy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This is a simple post deploy hook executed after your application 3 | # is deployed and started. This script gets executed directly, so 4 | # it could be python, php, ruby, etc. 5 | -------------------------------------------------------------------------------- /sockets/stdlib.js: -------------------------------------------------------------------------------- 1 | 2 | (function(module) { 3 | 4 | "use strict"; 5 | 6 | var definition = { 7 | RESP_SUCCESS: 0, 8 | RESP_FAILURE: 1 9 | }; 10 | 11 | module.exports = definition; 12 | 13 | }(module)); 14 | -------------------------------------------------------------------------------- /spec/javascripts/fixtures/checklistItem.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/source/about.rst: -------------------------------------------------------------------------------- 1 | .. _about: 2 | 3 | About Cantas 4 | =============== 5 | 6 | See https://github.com/onepiecejs/nodejs-cantas/ 7 | 8 | Key features 9 | ------------ 10 | 11 | 12 | A brief history 13 | --------------- 14 | 15 | -------------------------------------------------------------------------------- /spec/javascripts/fixtures/timeout.html: -------------------------------------------------------------------------------- 1 |
7 | -------------------------------------------------------------------------------- /views/backbone/board-title.jade: -------------------------------------------------------------------------------- 1 | script#template-board-title-view(type="text/template") 2 | |div#board-edit-title.edit-title 3 | | input#board-title-input(type="text") 4 | | button#board-title-save.btn(href="javascript:void(0)") Save 5 | -------------------------------------------------------------------------------- /views/email/assign.jade: -------------------------------------------------------------------------------- 1 | extends notification 2 | 3 | block content 4 | h4 Hi #{assignee}, 5 | p 6 | | #{assigner} assign card #{cardTitle} to you. 7 | p Regards, 8 | p Cantas 9 | 10 | -------------------------------------------------------------------------------- /docs/source/deploy.rst: -------------------------------------------------------------------------------- 1 | .. _deploy: 2 | 3 | 4 | Package&Deployment 5 | ================== 6 | 7 | 8 | Getting to know Jekins 9 | ---------------------- 10 | 11 | 12 | Package 13 | ------- 14 | 15 | 16 | Deployment 17 | ---------- 18 | -------------------------------------------------------------------------------- /views/backbone/card-checkitem.jade: -------------------------------------------------------------------------------- 1 | script#template-card-checkitem(type="text/template") 2 | |p.js-check-item-text(title="Edit Content")= cantas.utils.safeString(content) 3 | |div.checkbox.js-item-checkbox 4 | | span 5 | |a.delete.delete-item.js-item-delete 6 | -------------------------------------------------------------------------------- /scripts/cantas-init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Initial Script 4 | # Now initial collection of label 5 | 6 | NODE=`which node` 7 | NODE_MODULES_PATH=/usr/lib/node_modules/cantas/scripts 8 | 9 | ${NODE} ${NODE_MODULES_PATH}/db_init_label_metadata.js 10 | 11 | -------------------------------------------------------------------------------- /views/backbone/card-labels-neonlights.jade: -------------------------------------------------------------------------------- 1 | script#template-card-labels-neonlights(type="text/template") 2 | |each relation in relations 3 | | if relation.selected 4 | | div(title=relation.labelId.title, style="background-color: " + relation.labelId.color).clabel 5 | -------------------------------------------------------------------------------- /.openshift/markers/README: -------------------------------------------------------------------------------- 1 | Markers 2 | =========== 3 | 4 | Adding marker files to this directory will have the following effects: 5 | 6 | force_clean_build - Will remove any previously installed npm modules and 7 | re-install all the required modules from scratch 8 | -------------------------------------------------------------------------------- /services/sites.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | var settings = require("../settings"); 4 | 5 | module.exports.currentSite = function() { 6 | var currentPhase = settings.sites.currentPhase; 7 | return settings.sites.phases[currentPhase]; 8 | }; 9 | 10 | }(module)); 11 | -------------------------------------------------------------------------------- /spec/javascripts/fixtures/labelNeonlights.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /views/backbone/card-menu.jade: -------------------------------------------------------------------------------- 1 | div#card-menu.modal.card-menu.menu.hide(style="display:none") 2 | header.modal-header 3 | h4 Card Options 4 | div.modal-body 5 | ul 6 | li.js-archive-card 7 | a Archive this card 8 | li.js-move-card 9 | a Move Card 10 | -------------------------------------------------------------------------------- /views/email/comment.jade: -------------------------------------------------------------------------------- 1 | extends notification 2 | 3 | block content 4 | h4 Hi #{receiver}, 5 | p 6 | | #{sender} added a comment in card #{cardTitle}. 7 | | content:
8 | | #{comment}
9 | p Regards,
10 | p Cantas
11 |
12 |
--------------------------------------------------------------------------------
/views/email/invitation.jade:
--------------------------------------------------------------------------------
1 | extends notification
2 |
3 | block content
4 | h4 Hi #{inviteeName},
5 | p
6 | | You are invited by #{inviterName} to join board #{boardTitle}.
7 | | Click #{boardUrl} to join.
8 | p Regards,
9 | p Cantas
10 |
11 |
--------------------------------------------------------------------------------
/models/boardMemberStatus.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Board member status.
3 | */
4 |
5 | (function (module) {
6 |
7 | "use strict";
8 |
9 | module.exports = {
10 | unknown: "unknown",
11 | available: "available",
12 | inviting: "inviting",
13 | kickedOff: "kickedOff"
14 | };
15 |
16 | }(module));
17 |
--------------------------------------------------------------------------------
/.openshift/markers/NODEJS_VERSION:
--------------------------------------------------------------------------------
1 | # Uncomment one of the version lines to select the node version to use.
2 | # The last "non-blank" version line is the one picked up by the code in
3 | # .openshift/lib/utils
4 | # Default: 0.10.25
5 | #
6 | # 0.8.24
7 | # 0.9.1
8 | # 0.10.25
9 | # 0.11.11
10 | 0.10.28
11 |
12 |
--------------------------------------------------------------------------------
/models/notificationType.js:
--------------------------------------------------------------------------------
1 | /*
2 | * definition of notification types.
3 | */
4 |
5 | (function (module) {
6 |
7 | "use strict";
8 |
9 | module.exports = {
10 | invitation: "invitation",
11 | subscription: "subscription",
12 | mentioned: "mentioned",
13 | information: "information"
14 | };
15 |
16 | }(module));
17 |
--------------------------------------------------------------------------------
/public/javascripts/constants.js:
--------------------------------------------------------------------------------
1 |
2 | (function() {
3 |
4 | "use strict";
5 |
6 | var cantas = window.cantas || {};
7 |
8 | cantas.KEY_CODES = {
9 | SPACE: 32,
10 | COMMA: 188,
11 | ENTER: 13,
12 | BACKSPACE: 8,
13 | LEFT_ARROW: 37,
14 | RIGHT_ARROW: 39,
15 | };
16 |
17 | window.cantas = cantas;
18 |
19 | }());
--------------------------------------------------------------------------------
/docs/source/devel.rst:
--------------------------------------------------------------------------------
1 | .. _devel:
2 |
3 |
4 | Development
5 | ===========
6 |
7 |
8 | Code repos
9 | --------------------------
10 |
11 |
12 | Dependencies
13 | ------------
14 |
15 |
16 | Dev environment
17 | ---------------------
18 |
19 |
20 | Code structure
21 | --------------
22 |
23 |
24 | Debug tools
25 | -----------
26 |
27 |
28 | Workflow
29 | --------
30 |
--------------------------------------------------------------------------------
/views/email/editComment.jade:
--------------------------------------------------------------------------------
1 | extends notification
2 |
3 | block content
4 | h4 Hi #{receiver},
5 | p
6 | | #{sender} edited a comment in card #{cardTitle}.
7 | | original content:
8 | | #{originComment}
9 | | current content:
10 | | #{currentComment}
11 | p Regards,
12 | p Cantas
13 |
14 |
--------------------------------------------------------------------------------
/docs/source/design.rst:
--------------------------------------------------------------------------------
1 | .. _design:
2 |
3 |
4 | Dive Into Cantas
5 | ================
6 |
7 |
8 | System architecture
9 | -------------------
10 |
11 |
12 | Technical introduction
13 | ----------------------
14 |
15 |
16 | Data schema
17 | -----------
18 |
19 |
20 | Server
21 | ------
22 |
23 |
24 | Client
25 | ------
26 |
27 |
28 | System integration
29 | ------------------
30 |
--------------------------------------------------------------------------------
/settings.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Settings module
3 | *
4 | * settings.json maintains all settings. All modules that require settings
5 | * just need load this module by calling require.
6 | *
7 | * Module exports a settings object to client.
8 | */
9 |
10 | (function(module) {
11 |
12 | "use strict";
13 |
14 | module.exports = require(__dirname + "/settings.json");
15 |
16 | }(module));
17 |
--------------------------------------------------------------------------------
/spec/javascripts/fixtures/cardVote.html:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/spec/javascripts/checkEmailAddress.spec.js:
--------------------------------------------------------------------------------
1 | describe( "validate email address", function () {
2 | var checkEmail = cantas.utils.checkEmail;
3 |
4 | it("It's a valid email address", function () {
5 | expect(checkEmail("example@redhat.com")).toBe(true);
6 | });
7 |
8 | it("It's an invalid email address", function () {
9 | expect(checkEmail("eaample@redhatcom")).toBe(false);
10 | });
11 | });
--------------------------------------------------------------------------------
/views/backbone/list-menu.jade:
--------------------------------------------------------------------------------
1 | div#list-menu.modal.list-menu.menu(style="display:none")
2 | header.modal-header
3 | h4 List Options
4 | div.modal-body
5 | ul
6 | li.js-add-card
7 | a Add Card
8 | li.js-archive-list
9 | a Archive This List
10 | li.js-archive-all-cards
11 | a Archive All Cards in This List
12 | li.js-move-list
13 | a Move List
14 |
--------------------------------------------------------------------------------
/views/backbone/comment.jade:
--------------------------------------------------------------------------------
1 | script#template-comment-view(type="text/template")
2 | |h4 Comment
3 | | a.new-item(href="http://daringfireball.net/projects/markdown/syntax") Markdown Syntax
4 | |textarea.js-add-comment-input(placeholder="Add comment")
5 | |div.js-comment-controls.hide.comment-button
6 | | button.btn.btn-primary.js-save-comment Save
7 | | button.btn.js-cancel-comment Cancel
8 | |div.comment-list
9 |
--------------------------------------------------------------------------------
/models/roles.js:
--------------------------------------------------------------------------------
1 | (function(module) {
2 |
3 | "use strict";
4 |
5 | var mongoose = require('mongoose');
6 | var Schema = mongoose.Schema;
7 | var ObjectId = Schema.ObjectId;
8 | var RoleSchema;
9 |
10 | RoleSchema = new Schema({
11 | name: { type: String, required: true },
12 | perms: [ String ]
13 | });
14 |
15 | module.exports = mongoose.model('Role', RoleSchema);
16 |
17 | }(module));
18 |
19 |
--------------------------------------------------------------------------------
/public/javascripts/views/base.js:
--------------------------------------------------------------------------------
1 | (function ($, _, Backbone) {
2 |
3 | "use strict";
4 |
5 | /*
6 | * View to render each section to show an Activity log
7 | */
8 | cantas.views.BaseView = Backbone.View.extend({
9 | close: function() {
10 | if (this.model) {
11 | this.model.dispose();
12 | }
13 |
14 | this.remove();
15 | }
16 | });
17 |
18 |
19 | }(jQuery, _, Backbone));
20 |
--------------------------------------------------------------------------------
/views/backbone/notification-menu.jade:
--------------------------------------------------------------------------------
1 | script#template-notification-menu-view(type="text/template").
2 | a(class="dropdown-toggle js-dropdown-toggle",data-toggle="dropdown") Notification
3 | a(class="reminder") 1
4 | ul(class="dropdown-menu dropdown-notification")
5 | li.all-read
6 | a.js-all-read Mark All as Read
7 | ul.dropdown-notification-content.js-dropdown-content
8 | li.show-more
9 | a.js-show-more Show More
--------------------------------------------------------------------------------
/views/backbone/accountSettings.jade:
--------------------------------------------------------------------------------
1 | script#template-account-settings-view(type="text/template")
2 | |div.board-ul-title
3 | | h3= header
4 | |div.settings-container
5 | | form(role="form")
6 | | div.form-group
7 | | label.control-label Username
8 | | input#userName(type="text", value=username)
9 | | label.control-label Password
10 | | input#userPassword(type="password", placeholder="Password")
11 |
--------------------------------------------------------------------------------
/views/backbone/list.jade:
--------------------------------------------------------------------------------
1 | script#template-list-view(type="text/template")
2 | |header.list-header.handle
3 | | div.list-header-title
4 | | h4.js-list-title
5 | | strong.js-list-title-text(title= title)= title
6 | | span.js-card-quantity(title="Total")
7 | | a.list-setting.setting.js-list-setting
8 | |section.list-content.droptrue.move.ui-state-default.connectedSortable.js-list-content
9 | |footer.add-plugin.js-add-card Add a card
10 |
11 |
--------------------------------------------------------------------------------
/AUTHORS.md:
--------------------------------------------------------------------------------
1 | Product Owner
2 | -------------
3 | * Ren Yang
").replace(/ /g, " ");
26 | };
27 |
28 | cantas.utils = utils;
29 |
30 | }(jQuery, _, Backbone));
31 |
--------------------------------------------------------------------------------
/views/backbone/card-attachment-download.jade:
--------------------------------------------------------------------------------
1 | script#template-attachment-download-view(type="text/template").
2 | td.download-cover
3 | if fileType === 'picture'
4 | div.checkbox.js-download-cover
5 | span
6 | td.download-preview
7 | if thumbnail
8 | img(src= thumbnail)
9 | if isBoardMember
10 | td.download-name
11 | a(href=url, target='_blank')= fileName
12 | else
13 | td.download-name= fileName
14 | td.download-size= size
15 | td.download-uploader= uploaderId.username
16 | td.download-createdOn= createdOn
17 | td.download-control
18 | if isBoardAdmin || (isBoardMember && isUploader)
19 | button.btn.btn-danger.download-delete.js-download-delete Delete
--------------------------------------------------------------------------------
/public/javascripts/views/help.js:
--------------------------------------------------------------------------------
1 | // Help View
2 |
3 | (function ($, _, Backbone) {
4 | "use strict";
5 |
6 | cantas.views.HelpView = Backbone.View.extend({
7 | el: '.content',
8 |
9 | events: {
10 | },
11 |
12 | template: jade.compile($("#template-help-view").text()),
13 |
14 | close: function() {
15 | this.remove();
16 | },
17 |
18 | remove: function() {
19 | this.undelegateEvents();
20 | this.$el.empty();
21 | this.stopListening();
22 | return this;
23 | },
24 |
25 | render: function(context) {
26 | this.$el.html(this.template());
27 | cantas.setTitle(context.title);
28 | }
29 | });
30 |
31 | }(jQuery, _, Backbone));
32 |
33 |
--------------------------------------------------------------------------------
/views/backbone/card-assign.jade:
--------------------------------------------------------------------------------
1 | script#template-card-assign-view(type="text/template")
2 | |header.modal-header
3 | | button#close-board-edit.close.js-close-assign-window ×
4 | | h3 Assign
5 | |div.modal-body
6 | | ul.assignee
7 | | each member in members
8 | | if member.checked
9 | | li.js-select-assignee.checked(data-uid= member.userId._id)= member.userId.username
10 | | span
11 | | else
12 | | li.js-select-assignee(data-uid= member.userId._id)= member.userId.username
13 | | span
14 | |footer.modal-footer
15 | | button#save-board-edit.btn.btn-primary.js-save-assignee Save
16 | | button#cancel-board-edit.btn.js-cancel-assign-window Cancel
17 |
--------------------------------------------------------------------------------
/views/backbone/import-bugzilla.jade:
--------------------------------------------------------------------------------
1 | script#template-import-bugzilla-view(type="text/template").
2 | div
3 | div.modal-header
4 | button(type="button",class="close",data-dismiss="modal",aria-hidden="true")×
5 | h2.window-title-text Import Bugs From Bugzilla
6 | div.mapping-config
7 | div.row-fluid
8 | div.span2
9 | button.btn.btn-primary.js-add-mapping Add Mapping
10 | div.span2
11 | button.btn.btn-primary.js-sync-all Sync All
12 | div.modal-body.mapping-body
13 | div.window_module
14 | div.mapping-list.hide.mapping-add
15 | footer.modal-footer
16 | button.btn(data-dismiss="modal") Close
17 |
--------------------------------------------------------------------------------
/views/backbone/comment-item.jade:
--------------------------------------------------------------------------------
1 | script#template-comment-item-view(type="text/template")
2 | |dt
3 | | span.speanker= authorId.username
4 | |dd
5 | | span.speaker-detail!= content
6 | | div.comment-option
7 | | div.item-time= "Creation: " + cantas.utils.formatDate(createdOn)
8 | | if typeof updatedOn !== 'undefined'
9 | | div.item-time= " Last Modified: " + cantas.utils.formatDate(updatedOn)
10 | | if authorId._id === cantas.utils.getCurrentUser().id
11 | | a.edit-comment.js-edit-comment(data-cid= _id) Edit
12 |
13 | script#template-comment-item-edit-view(type="text/template")
14 | |textarea.js-comment-input
15 | |button.btn.btn-primary.js-save-comment Save
16 | |button.btn.js-cancel-comment Cancel
--------------------------------------------------------------------------------
/views/backbone/syncconfig-item-input.jade:
--------------------------------------------------------------------------------
1 | script#template-syncconfig-item-input-view(type="text/template").
2 | div.row-fluid
3 | div.span1
4 | div.span6
5 | label Input bugzilla link
6 | input(placeholder="Input a Bugzilla link").js-query-url
7 | div.js-alert.alert.hide Loading...
8 | div.span5
9 | label Put bugs in List
10 | a.js-specify-list New List
11 | select.js-list-name
12 | option(value="") ----
13 | each list, i in lists
14 | option(value=list.id)= list.name
15 | input(placeholder="Input New List Name").hide.js-list-name
16 | div.mapping-submit
17 | button.btn.btn-primary.js-syncconfig-add Save
18 | button.btn.js-syncconfig-cancel Cancel
19 |
--------------------------------------------------------------------------------
/views/backbone/syncconfig-item-edit.jade:
--------------------------------------------------------------------------------
1 | script#template-syncconfig-item-edit-view(type="text/template").
2 | div.span1
3 | div.span6
4 | label Input bugzilla link
5 | input(value=queryUrl).js-query-url
6 | div.js-alert.alert.hide Loading...
7 | div.span5
8 | label Put bugs in List
9 | a.js-specify-list New List
10 | select.js-list-name
11 | each list, i in lists
12 | if list.id === listId._id
13 | option(value=list.id, selected="selected")= list.name
14 | else
15 | option(value=list.id)= list.name
16 | input(placeholder="Input New List Name").hide.js-list-name
17 | div.mapping-submit
18 | button.btn.btn-primary.js-syncconfig-save Save
19 | button.btn.js-syncconfig-cancel Cancel
20 |
--------------------------------------------------------------------------------
/.openshift/action_hooks/pre_build:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # This is a simple script and will be executed on your CI system if
3 | # available. Otherwise it will execute while your application is stopped
4 | # before the build step. This script gets executed directly, so it
5 | # could be python, php, ruby, etc.
6 |
7 |
8 | # Source utility functions.
9 | source "$OPENSHIFT_REPO_DIR/.openshift/lib/utils"
10 |
11 | # Ensure custom node version if not installed.
12 | echo ""
13 | ensure_node_is_installed
14 |
15 |
16 | # We need to move the package.json file out of the way in pre_build, so
17 | # that the OpenShift git post-receive hook doesn't try and use the old
18 | # npm version to install the dependencies.
19 | mv "${OPENSHIFT_REPO_DIR}/package.json" "$(get_node_tmp_dir)"
--------------------------------------------------------------------------------
/views/backbone/card-due-date.jade:
--------------------------------------------------------------------------------
1 | script#template-card-due-date-view(type="text/template")
2 | |header.modal-header
3 | | button#close-board-edit.close.js-close ×
4 | | h3 Due Date
5 | |div.modal-body
6 | | form(id="form-due-date")
7 | | div.due-date-inputs
8 | | div.field-date
9 | | label Date
10 | | input(type="text", value=dueDate, class="input-due-date js-due-date", name="due-date")
11 | | div.field-time
12 | | label Time
13 | | input(type="text", value=dueTime, class="input-due-time js-due-time", name="due-time")
14 | | div.js-datepicker
15 | | div.js-timepicker
16 | |footer.modal-footer
17 | | button.btn.btn-primary.js-save Save
18 | | button.btn.btn-danger.js-delete Remove
19 | | button.btn.js-close Cancel
--------------------------------------------------------------------------------
/.openshift/action_hooks/deploy:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # This deploy hook gets executed after dependencies are resolved and the
3 | # build hook has been run but before the application has been started back
4 | # up again. This script gets executed directly, so it could be python, php,
5 | # ruby, etc.
6 |
7 |
8 | # Source utility functions.
9 | source "$OPENSHIFT_REPO_DIR/.openshift/lib/utils"
10 |
11 |
12 | # On slave/serving gears, need to do the install as part of deploy
13 | # so check if its needed. Just ensure the custom Node[.js] version is
14 | # installed.
15 | ensure_node_is_installed
16 |
17 |
18 | # Setup the settings.json file
19 | node "$OPENSHIFT_REPO_DIR/.openshift/lib/init_settings"
20 |
21 |
22 | # Seed the label metadata
23 | node "$OPENSHIFT_REPO_DIR/scripts/db_init_label_metadata.js"
--------------------------------------------------------------------------------
/models/cardLabelRelation.js:
--------------------------------------------------------------------------------
1 | (function (module) {
2 |
3 | "use strict";
4 |
5 | var mongoose = require('mongoose');
6 | var Schema = mongoose.Schema;
7 | var ObjectId = Schema.ObjectId;
8 |
9 | var CardLabelRelationSchema = new Schema({
10 | boardId: { type: ObjectId, required: true, ref: 'Board', index: true },
11 | cardId: { type: ObjectId, required: true, ref: 'Card', index: true },
12 | labelId: { type: ObjectId, required: true, ref: 'Label', index: true },
13 | selected: { type: Boolean, default: false},
14 | createdOn: { type: Date, default: Date.now },
15 | updatedOn: { type: Date, default: Date.now }
16 | });
17 |
18 | module.exports = mongoose.model('CardLabelRelation',
19 | CardLabelRelationSchema);
20 |
21 | }(module));
22 |
--------------------------------------------------------------------------------
/models/checklist.js:
--------------------------------------------------------------------------------
1 | (function(module) {
2 |
3 | "use strict";
4 |
5 | var mongoose = require("mongoose");
6 | var Schema = mongoose.Schema;
7 | var ObjectId = Schema.ObjectId;
8 |
9 | var ChecklistSchema = new Schema({
10 | title: {type: String, default: "New Checklist"},
11 | cardId: {type: ObjectId, required: true, ref: "Card", index: true},
12 | authorId: {type: ObjectId, required: true, ref: "User", index: true},
13 | createdOn: {type: Date, default: Date.now},
14 | updatedOn: {type: Date, default: Date.now}
15 | });
16 |
17 | ChecklistSchema.statics.getById = function(id, callback) {
18 | this.findById({_id: id}).populate("cardId", "authorId").exec(callback);
19 | };
20 |
21 | module.exports = mongoose.model("Checklist", ChecklistSchema);
22 |
23 | }(module));
24 |
--------------------------------------------------------------------------------
/.openshift/cron/weekly/README:
--------------------------------------------------------------------------------
1 | Run scripts or jobs on a weekly basis
2 | =====================================
3 | Any scripts or jobs added to this directory will be run on a scheduled basis
4 | (weekly) using run-parts.
5 |
6 | run-parts ignores any files that are hidden or dotfiles (.*) or backup
7 | files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} and handles
8 | the files named jobs.deny and jobs.allow specially.
9 |
10 | In this specific example, the chronograph script is the only script or job file
11 | executed on a weekly basis (due to white-listing it in jobs.allow). And the
12 | README and chrono.dat file are ignored either as a result of being black-listed
13 | in jobs.deny or because they are NOT white-listed in the jobs.allow file.
14 |
15 | For more details, please see ../README.cron file.
16 |
17 |
--------------------------------------------------------------------------------
/public/javascripts/models/activity.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Models for displaying Activity logs.
3 | */
4 |
5 | (function ($, _, Backbone) {
6 |
7 | "use strict";
8 |
9 | cantas.models.Activity = cantas.models.BaseModel.extend({
10 | idAttribute: "_id",
11 | socket: cantas.socket,
12 | urlRoot: "activity",
13 |
14 | url: function () {
15 | return "/activity/" + this.id;
16 | }
17 |
18 | });
19 |
20 | cantas.models.ActivityCollection = cantas.models.BaseCollection.extend({
21 | /*
22 | * With this url, collection responds all events whose name match
23 | * activities:[action]
24 | */
25 | url: "/activity",
26 | model: cantas.models.Activity,
27 |
28 | comparator: function (activity) {
29 | return activity.get("createdOn");
30 | }
31 | });
32 |
33 | }(jQuery, _, Backbone));
34 |
--------------------------------------------------------------------------------
/spec/javascripts/fixtures/voteConfig.html:
--------------------------------------------------------------------------------
1 |
37 |
--------------------------------------------------------------------------------
/views/email/notification.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html
3 | head
4 | style.
5 | .mail{
6 | background: #333;
7 | padding: 50px;
8 | }
9 | .mail-label{
10 | background: blue;
11 | }
12 | .mail-card{
13 | margin: 0 auto;
14 | color: #000000;
15 | font-size: 13px;
16 | min-width: 80%;
17 | padding: 9px 18px;
18 | z-index: 0;
19 | border-radius: 3px;
20 | border-bottom-right-radius: 95px 15px;
21 | background: #FCDF71;
22 | }
23 | span{
24 | font-style: italic;
25 | }
26 |
27 | body
28 | div.mail
29 | div.mail-label
30 | div.mail-card
31 | block content
32 | h4 Hi #{username},
33 | p !{message}
34 | p Regards,
35 | p Cantas
36 |
37 |
--------------------------------------------------------------------------------
/spec/javascripts/movelist.spec.js:
--------------------------------------------------------------------------------
1 | describe('MoveListToView',function(){
2 | var view;
3 |
4 | beforeEach(function(){
5 | $('').appendTo('body');
6 | loadFixtures('movelist.html');
7 | view = new cantas.views.MoveListToView({
8 | title: 'Move List',
9 | listId: "5195d6bc07eec66c36000014",
10 | boardId: "51b97050240934cf2f000005"
11 | });
12 |
13 | view.template = jade.compile($("#template-move-to").text());
14 | view.render();
15 | });
16 |
17 | afterEach(function() {
18 | $('.window-overlay').empty();
19 | });
20 |
21 | it('should showing move listTo view', function(){
22 | expect($('body').find('.window-overlay')).not.toBeHidden();
23 | expect($('body').find('.window-overlay').find('.modal-header > h3')).toHaveText("Move To");
24 | });
25 |
26 | });
27 |
--------------------------------------------------------------------------------
/models/commentSourceRelation.js:
--------------------------------------------------------------------------------
1 | (function (module) {
2 |
3 | "use strict";
4 |
5 | var mongoose = require('mongoose');
6 | var Schema = mongoose.Schema;
7 | var ObjectId = Schema.ObjectId;
8 |
9 | /*
10 | * CommentSourceRelation schema is designed to record comment which
11 | * is from external system like bug comment from bugzilla.
12 | */
13 |
14 | var CommentSourceRelationSchema = new Schema({
15 | commentId: { type: ObjectId, required: true, ref: 'Comment', index: true },
16 | cardId: { type: ObjectId, required: true, ref: 'Card', index: true },
17 | sourceId: { type: String, require: true },
18 | sourceType: { type: String, require: true },
19 | lastSyncTime: { type: Date, default: Date.now }
20 |
21 | });
22 |
23 | module.exports = mongoose.model('CommentSourceRelation', CommentSourceRelationSchema);
24 |
25 | }(module));
26 |
--------------------------------------------------------------------------------
/spec/javascripts/fixtures/commentConfig.html:
--------------------------------------------------------------------------------
1 |
37 |
--------------------------------------------------------------------------------
/services/cardHandler.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Service for managing cards
3 | */
4 | (function(exports) {
5 |
6 | var mongoose = require('mongoose'),
7 | Card = require('./../models/card'),
8 | async = require('async');
9 |
10 |
11 | /**
12 | * Get all cards created by the provided user
13 | *
14 | * @param {User} user
15 | * @param {Function} callback
16 | * @return {void}
17 | */
18 | exports.listMyCards = function(user, callback) {
19 |
20 | Card.find({
21 | isArchived: false,
22 | creatorId: user._id
23 | })
24 | .populate({
25 | path: 'boardId',
26 | select: '_id title isPublic isClosed'
27 | })
28 | .populate({
29 | path: 'listId',
30 | select: '_id title isArchived'
31 | })
32 | .sort('-created')
33 | .exec(function(err, cards) {
34 | callback(err, cards);
35 | });
36 |
37 | };
38 |
39 |
40 | }(exports));
--------------------------------------------------------------------------------
/views/backbone/vote-config.jade:
--------------------------------------------------------------------------------
1 | script#template-vote-config-view(type="text/template")
2 | |dt
3 | | h3 Vote
4 | |dd
5 | | if voteStatus == 'opened'
6 | | a.checked.js-open-vote.all
7 | | span
8 | | span
9 | | span Public for Every User
10 | | else
11 | | a.js-open-vote.all
12 | | span
13 | | span
14 | | span Public for Every User
15 | | if voteStatus == 'enabled'
16 | | a.checked.js-enable-vote.part
17 | | span
18 | | span
19 | | span Public for Board Member
20 | | else
21 | | a.js-enable-vote.part
22 | | span
23 | | span
24 | | span Public for Board Member
25 | | if voteStatus == 'disabled'
26 | | a.checked.js-disable-vote.none
27 | | span
28 | | span
29 | | span Disable
30 | | else
31 | | a.js-disable-vote.none
32 | | span
33 | | span
34 | | span Disable
35 | |dd
36 |
--------------------------------------------------------------------------------
/spec/node/socket-patch-test.js:
--------------------------------------------------------------------------------
1 |
2 | "use strict";
3 |
4 | var assert = require("assert");
5 | var SocketPatch = require("../../sockets/patch_socket");
6 |
7 | describe("Test socket patch", function() {
8 |
9 | var socket = null;
10 |
11 | beforeEach(function() {
12 | var Socket = function() {
13 | this.handshake = {
14 | user: {username: "socket user"}
15 | };
16 | };
17 | socket = new Socket();
18 | });
19 |
20 | afterEach(function() {
21 | socket = null;
22 | });
23 |
24 | it("Test patch getCurrentUser", function() {
25 | // SocketPatch.patch(socket);
26 |
27 | // var getCurrentUser = socket.getCurrentUser;
28 | // assert.notEqual(getCurrentUser, undefined,
29 | // "getCurrentUser method should exist.");
30 | // assert.equal(socket.handshake.user.username, getCurrentUser().username,
31 | // "User's username does not equal to the one within socket.");
32 | });
33 |
34 | });
35 |
--------------------------------------------------------------------------------
/docs/source/index.rst:
--------------------------------------------------------------------------------
1 | .. cantas documentation master file, created by
2 | sphinx-quickstart on Sun Jun 9 15:19:42 2013.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 | .. _index:
6 |
7 | Cantas Developer Guide
8 | ==================================
9 |
10 | Cantas is a flexible real-time collaboration tools. It can help u
11 | arrange&share your ideas with some aids(board, list, card). It provide a
12 | platform to share information and track their changes with each other.
13 |
14 |
15 | Support
16 | -------
17 |
18 | mailing list: cantas-dev-list@redhat.com
19 | IRC: #cantas
20 |
21 |
22 | Contents
23 | --------
24 |
25 | .. toctree::
26 | :maxdepth: 2
27 |
28 | about
29 | design
30 | devel
31 | test
32 | deploy
33 | conv
34 |
35 |
36 | Indices and tables
37 | ------------------
38 |
39 | * :ref:`genindex`
40 | * :ref:`modindex`
41 | * :ref:`search`
42 |
43 |
--------------------------------------------------------------------------------
/views/backbone/comment-config.jade:
--------------------------------------------------------------------------------
1 | script#template-comment-config-view(type="text/template")
2 | |dt
3 | | h3 Comment
4 | |dd
5 | | if commentStatus == 'opened'
6 | | a.checked.js-open-comment.all
7 | | span
8 | | span
9 | | span Public for Every User
10 | | else
11 | | a.js-open-comment.all
12 | | span
13 | | span
14 | | span Public for Every User
15 | | if commentStatus == 'enabled'
16 | | a.checked.js-enable-comment.part
17 | | span
18 | | span
19 | | span Public for Board Member
20 | | else
21 | | a.js-enable-comment.part
22 | | span
23 | | span
24 | | span Public for Board Member
25 | | if commentStatus == 'disabled'
26 | | a.checked.js-disable-comment.none
27 | | span
28 | | span
29 | | span Disable
30 | | else
31 | | a.js-disable-comment.none
32 | | span
33 | | span
34 | | span Disable
35 | |dd
36 |
--------------------------------------------------------------------------------
/public/javascripts/vendor/jquery.ba-cond.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * cond - v0.1 - 6/10/2009
3 | * http://benalman.com/projects/jquery-cond-plugin/
4 | *
5 | * Copyright (c) 2009 "Cowboy" Ben Alman
6 | * Licensed under the MIT license
7 | * http://benalman.com/about/license/
8 | *
9 | * Based on suggestions and sample code by Stephen Band and DBJDBJ in the
10 | * jquery-dev Google group: http://bit.ly/jqba1
11 | */
12 |
13 | jQuery.fn.cond = function() {
14 | var undefined,
15 | args = arguments,
16 | i = 0,
17 | test,
18 | callback,
19 | result;
20 |
21 | while ( !test && i < args.length ) {
22 | test = args[ i++ ];
23 | callback = args[ i++ ];
24 |
25 | test = jQuery.isFunction( test ) ? test.call( this ) : test;
26 |
27 | result = !callback ? test
28 | : test ? callback.call( this, test )
29 | : undefined;
30 | }
31 |
32 | return result !== undefined ? result : this;
33 | };
34 |
35 |
--------------------------------------------------------------------------------
/public/javascripts/views/accountSettings.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Page view for viewing / changing settings of current account
3 | */
4 |
5 | (function ($, _, Backbone) {
6 |
7 | "use strict";
8 |
9 | cantas.views.accountSettingsView = cantas.views.BaseView.extend({
10 | events: {
11 | },
12 |
13 | template: jade.compile($("#template-account-settings-view").text()),
14 |
15 | initialize: function () {
16 | },
17 |
18 | render: function (context) {
19 | cantas.setTitle(this.options.title);
20 |
21 | this.$el.html(this.template({
22 | header: this.options.title,
23 | username: cantas.user.username
24 | }));
25 |
26 | return this;
27 | },
28 |
29 | close: function() {
30 | this.remove();
31 | },
32 |
33 |
34 | remove: function() {
35 | this.undelegateEvents();
36 | this.$el.empty();
37 | this.stopListening();
38 | return this;
39 | }
40 | });
41 |
42 | }(jQuery, _, Backbone));
--------------------------------------------------------------------------------
/models/checklistItem.js:
--------------------------------------------------------------------------------
1 | (function(module) {
2 |
3 | "use strict";
4 |
5 | var mongoose = require("mongoose");
6 | var Schema = mongoose.Schema;
7 | var ObjectId = Schema.ObjectId;
8 |
9 | var ChecklistItemSchema = new Schema({
10 | content: {type: String, required: true},
11 | checked: {type: Boolean, default: false},
12 | order: {type: Number, default: 1},
13 | checklistId: {type: ObjectId, required: true, ref: "Checklist", index: true},
14 | cardId: {type: ObjectId, required: true, ref: "Card", index: true},
15 | authorId: {type: ObjectId, required: true, ref: "User", index: true},
16 | createdOn: {type: Date, default: Date.now},
17 | updatedOn: {type: Date, default: Date.now}
18 | });
19 |
20 | ChecklistItemSchema.static.getById = function(id, callback) {
21 | this.findById({_id: id}).populate("checklistId", "authorId").exec(callback);
22 | };
23 |
24 | module.exports = mongoose.model("ChecklistItem", ChecklistItemSchema);
25 |
26 | }(module));
27 |
--------------------------------------------------------------------------------
/sockets/crud/notification.js:
--------------------------------------------------------------------------------
1 |
2 | (function(module) {
3 |
4 | "use strict";
5 |
6 | var util = require("util");
7 | var BaseCRUD = require("./base");
8 |
9 | function NotificationCRUD(options) {
10 | BaseCRUD.call(this, options);
11 |
12 | this.modelClass = require("../../models/notification");
13 | this.key = this.modelClass.modelName.toLowerCase();
14 | }
15 |
16 | util.inherits(NotificationCRUD, BaseCRUD);
17 |
18 | NotificationCRUD.prototype._patch = function(data, callback) {
19 | var self = this;
20 | var _id = data._id || data.id;
21 | var name = '/' + this.key + '/' + _id + ':update';
22 | delete data._id; // _id is not modifiable
23 |
24 | this.modelClass.findByIdAndUpdate(_id, data, function (err, updatedData) {
25 | if (err) {
26 | callback(err, updatedData);
27 | } else {
28 | self.emitMessage(name, updatedData);
29 | }
30 | });
31 | };
32 |
33 | module.exports = NotificationCRUD;
34 |
35 | }(module));
36 |
--------------------------------------------------------------------------------
/models/cardSourceRelation.js:
--------------------------------------------------------------------------------
1 | (function (module) {
2 |
3 | "use strict";
4 |
5 | var mongoose = require('mongoose');
6 | var Schema = mongoose.Schema;
7 | var ObjectId = Schema.ObjectId;
8 |
9 | /*
10 | * CardSourceRelation schema is designed to record the relationship
11 | * between card and external source like bug id from bugzilla,
12 | * issue id from jira.
13 | */
14 |
15 | var CardSourceRelationSchema = new Schema({
16 | syncConfigId: { type: ObjectId, required: true, ref: 'SyncConfig', index: true },
17 | cardId: { type: ObjectId, required: true, ref: 'Card', index: true },
18 | // External source id like bug id from bugzilla, issue id from jira
19 | sourceId: { type: String, require: true },
20 |
21 | // External system name
22 | sourceType: { type: String, require: true },
23 | lastSyncTime: { type: Date, default: Date.now }
24 | });
25 |
26 | module.exports = mongoose.model('CardSourceRelation', CardSourceRelationSchema);
27 |
28 | }(module));
29 |
--------------------------------------------------------------------------------
/sockets/crud/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Load all CRUD modules.
3 | */
4 |
5 | (function(module) {
6 |
7 | "use strict";
8 |
9 | var fs = require("fs");
10 | var path = require("path");
11 |
12 | var _crudObjects = {};
13 |
14 | module.exports.crudObjects = _crudObjects;
15 |
16 | module.exports.setUp = function(socket, handshake) {
17 | var crudModules = fs.readdirSync(__dirname);
18 | // Do not import these modules, which are used internally.
19 | var excludeNames = ['index', 'base'];
20 | var i;
21 | for (i = 0; i < crudModules.length; i++) {
22 | if (path.extname(crudModules[i]) === ".js") {
23 | var cleanName = path.basename(crudModules[i], ".js");
24 | if (excludeNames.indexOf(cleanName) < 0) {
25 | var Class = require("./" + cleanName);
26 | var obj = new Class({ socket: socket, handshake: handshake });
27 | obj.listen();
28 | _crudObjects[obj.modelClass.modelName] = obj;
29 | }
30 | }
31 | }
32 | };
33 |
34 | }(module));
35 |
--------------------------------------------------------------------------------
/.openshift/action_hooks/pre_start_nodejs:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # The pre_start_cartridge and pre_stop_cartridge hooks are *SOURCED*
4 | # immediately before (re)starting or stopping the specified cartridge.
5 | # They are able to make any desired environment variable changes as
6 | # well as other adjustments to the application environment.
7 |
8 | # The post_start_cartridge and post_stop_cartridge hooks are executed
9 | # immediately after (re)starting or stopping the specified cartridge.
10 |
11 | # Exercise caution when adding commands to these hooks. They can
12 | # prevent your application from stopping cleanly or starting at all.
13 | # Application start and stop is subject to different timeouts
14 | # throughout the system.
15 |
16 |
17 | # Source utility functions.
18 | source "$OPENSHIFT_REPO_DIR/.openshift/lib/utils"
19 |
20 | # Setup path to include the custom Node[.js] version.
21 | ver=$(get_node_version)
22 | echo ""
23 | echo " - pre_start_nodejs: Adding Node.js version $ver binaries to path"
24 | _SHOW_SETUP_PATH_MESSAGES="true" setup_path_for_custom_node_version
--------------------------------------------------------------------------------
/models/list.js:
--------------------------------------------------------------------------------
1 | (function (module) {
2 |
3 | "use strict";
4 |
5 | var mongoose = require('mongoose');
6 | var Schema = mongoose.Schema;
7 | var ObjectId = Schema.ObjectId;
8 | var Card = require('./card');
9 | var ListSchema;
10 |
11 | ListSchema = new Schema({
12 | title: { type: String, required: true },
13 | isArchived: { type: Boolean, default: false },
14 | created: { type: Date, default: Date.now },
15 | creatorId: { type: ObjectId, required: true, index: true },
16 | order: { type: Number, default: -1},
17 | boardId: { type: ObjectId, required: true, index: true },
18 | perms: {
19 | delete: {
20 | users: [ ObjectId ],
21 | roles: [ ObjectId ]
22 | },
23 | update: {
24 | users: [ ObjectId ],
25 | roles: [ ObjectId ]
26 | }
27 | }
28 | });
29 |
30 | ListSchema.post('remove', function (list) {
31 | // Also remove its cards.
32 | Card.remove({listId: list._id}).exec();
33 | });
34 |
35 | module.exports = mongoose.model('List', ListSchema);
36 |
37 | }(module));
38 |
--------------------------------------------------------------------------------
/public/javascripts/models/notification.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Models for displaying Activity logs.
3 | */
4 |
5 | (function ($, _, Backbone) {
6 |
7 | "use strict";
8 |
9 | cantas.models.Notification = cantas.models.BaseModel.extend({
10 | idAttribute: "_id",
11 | socket: cantas.socket,
12 | urlRoot: "notification",
13 |
14 | url: function() {
15 | return "/notification/" + this.id;
16 | }
17 |
18 | });
19 |
20 | cantas.models.NotificationCollection = cantas.models.BaseCollection.extend({
21 | /*
22 | * With this url, collection responds all events whose name match
23 | * notification:[action]
24 | */
25 | url: "/notification",
26 | model: cantas.models.Notification,
27 |
28 | // sort notifications by 'created' in descending order
29 | comparator: function(a, b) {
30 | if (a.get('created') > b.get('created')) {
31 | return -1;
32 | }
33 | if (a.get('created') < b.get('created')) {
34 | return 1;
35 | }
36 | return 0;
37 | }
38 | });
39 |
40 | }(jQuery, _, Backbone));
41 |
--------------------------------------------------------------------------------
/public/javascripts/views/dashboard-navigation.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Layout for the dashboard navigation
3 | */
4 | (function ($, _, Backbone) {
5 | "use strict";
6 |
7 | cantas.views.DashboardNavigationView = cantas.views.BaseView.extend({
8 |
9 | events: {
10 | 'click a': 'openDashboard'
11 | },
12 |
13 | template: jade.compile($("#template-dashboard-navigation-view").text()),
14 |
15 | initialize: function() {},
16 |
17 | setActive: function(className) {
18 | this.$el.find('a.active').removeClass('active');
19 | this.$el.find('a.' + className).parents('li').addClass("active");
20 | return this;
21 | },
22 |
23 | render: function(context) {
24 | this.$el.html(this.template());
25 | return this;
26 | },
27 |
28 | openDashboard: function(e) {
29 | e.preventDefault();
30 | cantas.navigateTo($(e.target).attr('href'));
31 | },
32 |
33 | remove: function() {
34 | this.undelegateEvents();
35 | this.$el.empty();
36 | this.stopListening();
37 | return this;
38 | }
39 |
40 | });
41 |
42 | }(jQuery, _, Backbone));
--------------------------------------------------------------------------------
/spec/javascripts/fixtures/cardBadges.html:
--------------------------------------------------------------------------------
1 |
31 |
--------------------------------------------------------------------------------
/sockets/importTrello.js:
--------------------------------------------------------------------------------
1 | (function(exports) {
2 | "use strict";
3 |
4 | // expose variable
5 | var async = require("async");
6 | var util = require("util");
7 | var stdlib = require("./stdlib");
8 | var mongoose = require('mongoose');
9 | var User = require("../models/user");
10 | var Board = require("../models/board");
11 | var List = require("../models/list");
12 | var Card = require("../models/card");
13 | var LogActivity = require("../services/activity").Activity;
14 |
15 | exports.init = function(socket) {
16 |
17 | socket.on('import-trello-complete', function(data) {
18 | var eventRoomName = "board:" + data.boardId;
19 | var eventName = 'alert-import-trello-complete';
20 | var user = socket.getCurrentUser();
21 | // record import action into activity log
22 | var content = user.username + ' has imported new content to this board.';
23 | var activity = new LogActivity({socket: socket, exceptMe: false});
24 | activity.log({
25 | 'content': content,
26 | 'creatorId': user.id,
27 | 'boardId': data.boardId
28 | });
29 | socket.broadcast.to(eventRoomName).emit(eventName, {});
30 | });
31 | };
32 |
33 | }(exports));
34 |
--------------------------------------------------------------------------------
/.openshift/cron/README.cron:
--------------------------------------------------------------------------------
1 | Run scripts or jobs on a periodic basis
2 | =======================================
3 | Any scripts or jobs added to the minutely, hourly, daily, weekly or monthly
4 | directories will be run on a scheduled basis (frequency is as indicated by the
5 | name of the directory) using run-parts.
6 |
7 | run-parts ignores any files that are hidden or dotfiles (.*) or backup
8 | files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved}
9 |
10 | The presence of two specially named files jobs.deny and jobs.allow controls
11 | how run-parts executes your scripts/jobs.
12 | jobs.deny ===> Prevents specific scripts or jobs from being executed.
13 | jobs.allow ===> Only execute the named scripts or jobs (all other/non-named
14 | scripts that exist in this directory are ignored).
15 |
16 | The principles of jobs.deny and jobs.allow are the same as those of cron.deny
17 | and cron.allow and are described in detail at:
18 | http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/ch-Automating_System_Tasks.html#s2-autotasks-cron-access
19 |
20 | See: man crontab or above link for more details and see the the weekly/
21 | directory for an example.
22 |
23 |
--------------------------------------------------------------------------------
/views/backbone/syncconfig-item.jade:
--------------------------------------------------------------------------------
1 | script#template-syncconfig-item-view(type="text/template").
2 | a.delete.mapping-delete.js-syncconfig-delete
3 | div.row-fluid
4 | div.span1
5 | if isActive
6 | span.enabled.js-is-active(title="Click to disable this mapping")
7 | else
8 | span.disabled.js-is-active(title="Click to enable this mapping")
9 | div.span5
10 | label Input bugzilla link
11 | div.js-queryurl-wrapper(title="Click to Eidt Query URL")
12 | span.glyphicon.glyphicon-link
13 | p= queryUrl
14 | div.span5
15 | label Put bugs in List
16 | div.js-listname-wrapper(title="Click to Change List")
17 | span.glyphicon.glyphicon-list-alt
18 | p= listName
19 | div.mapping-loading.js-sync-status
20 | div.process-loading
21 | div.loader
22 | div.top
23 | div.bar
24 | div.bar
25 | div.bar
26 | div.bar
27 | div.bar
28 | div.bottom
29 | div.bar
30 | div.bar
31 | div.bar
32 | div.bar
33 | div.bar
34 | div.span1
35 | if isBoardMember && isActive
36 | button.btn.btn-primary.js-mapping-sync Sync
37 |
--------------------------------------------------------------------------------
/models/user.js:
--------------------------------------------------------------------------------
1 | (function(module) {
2 |
3 | "use strict";
4 |
5 | var mongoose = require('mongoose');
6 | var Schema = mongoose.Schema;
7 | var ObjectId = Schema.ObjectId;
8 | var UserSchema;
9 |
10 | UserSchema = new Schema({
11 | username: { type: String, required: true, lowercase: true, unique: true },
12 | fullname: { type: String, default: '' },
13 | password: { type: String, default: '', select: false },
14 | email: { type: String, required: true, lowercase: true, unique: true },
15 | joined: { type: Date, default: Date.now },
16 | roles: [ ObjectId ],
17 | isFirstLogin: { type: Boolean, default: true }
18 | });
19 |
20 | // static method
21 |
22 | UserSchema.statics.getByUsername = function(identity, callback) {
23 | var condition = { username: identity };
24 | this.findOne(condition, callback);
25 | };
26 |
27 | UserSchema.statics.exists = function(identity, callback) {
28 | var conditions = { $or: [{ username: identity }, { email: identity }] };
29 | this.findOne(conditions, "username", function(err, user) {
30 | callback(user !== undefined && user !== null);
31 | });
32 | };
33 |
34 | module.exports = mongoose.model('User', UserSchema);
35 |
36 | }(module));
37 |
38 |
--------------------------------------------------------------------------------
/spec/node/dbinit.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var mongoose = require('mongoose');
4 | var dbURI = 'mongodb://localhost/cantas_test';
5 | var async = require('async');
6 |
7 | beforeEach(function (done) {
8 |
9 | function clearDB() {
10 | async.series([
11 | function(callback){
12 | for (var i in mongoose.connection.collections) {
13 | mongoose.connection.collections[i].remove(function() {});
14 | }
15 | callback(null);
16 | },
17 | function(callback){
18 | for (var i in mongoose.connection.collections) {
19 | mongoose.connection.collections[i].dropAllIndexes(function() {});
20 | }
21 | callback(null);
22 | }
23 | ],
24 | function(err, results){
25 | if(err || !results) throw err;
26 | done();
27 | });
28 | }
29 |
30 | if (mongoose.connection.readyState === 0) {
31 | mongoose.connect(dbURI, function (err) {
32 | if (err) {
33 | throw err;
34 | }
35 | return clearDB();
36 | });
37 | mongoose.set('debug', true);
38 | } else {
39 | return clearDB();
40 | }
41 | });
42 |
43 | afterEach(function (done) {
44 | setTimeout(function(){
45 | mongoose.connection.close();
46 | done();
47 | },0);
48 | });
49 |
--------------------------------------------------------------------------------
/models/action.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Module Action
3 | *
4 | * idMemberCreator
5 | * data
6 | * type
7 | * created
8 | *
9 | * REF: https://trello.com/docs/api/board/index.html#get-1-boards-board-id-actions
10 | *
11 | * [{
12 | * "idMemberCreator": "4ee7deffe582acdec80000ac",
13 | * "data": {
14 | * "card": {
15 | * "id": "4eea522c91e31d174600027e",
16 | * "name": "Figure out how to read a user's board list"
17 | * },
18 | * "board": {
19 | * "id": "4eea4ffc91e31d1746000046",
20 | * "name": "Example Board"
21 | * },
22 | * "idMember": "4ee7df74e582acdec80000b6"
23 | * },
24 | * "type": "addMemberToCard",
25 | * "created": "2011-12-15T20:01:59.688Z"
26 | * ]
27 | *
28 | */
29 |
30 | (function(module) {
31 |
32 | "use strict";
33 |
34 | var mongoose = require('mongoose');
35 | var Schema = mongoose.Schema;
36 | var ObjectId = Schema.ObjectId;
37 | var ActionSchema;
38 |
39 | ActionSchema = new Schema({
40 | idMemberCreator: ObjectId,
41 | data: { type: {}, default: {} },
42 | type: { type: String },
43 | created: { type: Date, default: Date.now }
44 | });
45 |
46 | module.exports = mongoose.model('Action', ActionSchema);
47 |
48 | }(module));
49 |
--------------------------------------------------------------------------------
/spec/javascripts/voteConfig.spec.js:
--------------------------------------------------------------------------------
1 | describe('Vote configuration Test', function() {
2 | var boardModel;
3 | var voteConfig;
4 |
5 | beforeEach(function() {
6 | $('').appendTo('body');
7 | boardModel = new cantas.models.Board({ voteStatus: 'enabled' });
8 | voteConfig = new cantas.views.VoteConfig({
9 | el: 'dl.js-vote',
10 | model: boardModel
11 | });
12 |
13 | loadFixtures('voteConfig.html');
14 | voteConfig.template = jade.compile($('#template-vote-config-view').text());
15 | voteConfig.render();
16 |
17 | spyOn(boardModel, 'patch').and.callFake(function() {});
18 | });
19 |
20 | afterEach(function() {
21 | voteConfig.close();
22 | });
23 |
24 | it("default vote status should be enabled", function() {
25 | expect($('.js-enable-vote')).toHaveClass('checked');
26 | });
27 |
28 | it('Should call patch method when disable vote', function() {
29 | voteConfig.$('.js-disable-vote span:last').trigger('click');
30 | expect(boardModel.patch).toHaveBeenCalled;
31 | });
32 |
33 | it("Should call patch method when open vote", function() {
34 | voteConfig.$('.js-open-vote span:last').trigger('click');
35 | expect(boardModel.patch).toHaveBeenCalled;
36 | });
37 |
38 |
39 | });
40 |
--------------------------------------------------------------------------------
/views/backbone/move-list.jade:
--------------------------------------------------------------------------------
1 | script#template-move-list(type="text/template")
2 | |div.modal-backdrop.fade.in
3 | | div#movement.modal.fade.in
4 | | div.modal-header
5 | | button.close(data-dismiss="modal") ×
6 | | h3= data.title
7 | | div.modal-body
8 | | div.choose-position
9 | | ul
10 | | li
11 | | h4 Choose Board
12 | | li
13 | | input(class="js-move-search", type="text", placeholder="Search")
14 | | li
15 | | ul.js-move-items
16 | | ul.hide
17 | | li
18 | | h4 Choose List
19 | | li
20 | | input(class="js-move-search",type="text", placeholder="Search")
21 | | li
22 | | ul.js-move-items
23 | | ul.hide
24 | | li
25 | | h4 Set Position
26 | | li.specific
27 | | a.js-set-position(data-position="top") Top
28 | | a.js-set-position(data-position="middle") Middle
29 | | a.js-set-position(data-position="bottom") Bottom
30 | | li
31 | | ul.js-move-position
32 | | footer.modal-footer
33 | | button.js-move.btn.btn-primary Move
34 | | button.btn(data-dismiss="modal") Cancel
35 |
--------------------------------------------------------------------------------
/.openshift/lib/setup_custom_nodejs_env:
--------------------------------------------------------------------------------
1 | # Utility functions for bash session - sourced in via the user's
2 | # bash profile ($OPENSHIFT_DATA_DIR/.bash_profile).
3 |
4 | # Source utility functions.
5 | source $OPENSHIFT_REPO_DIR/.openshift/lib/utils
6 |
7 |
8 | # Internal function to setup path and remove the wrappers.
9 | function _setup_path_and_remove_wrappers() {
10 | # First invocation of npm or node, so setup the custom path and
11 | # unset the wrappers. Add the custom node binaries to the PATH.
12 | [ -z "$ZDEBUG" ] || echo "Setting path to include custom Node version"
13 | setup_path_for_custom_node_version
14 | unset node
15 | unset npm
16 | unset _setup_path_and_remove_wrappers
17 |
18 | } # End of function _setup_path_and_remove_wrappers.
19 |
20 |
21 | # Temporary wrapper function to setup path before invoking npm.
22 | function npm() {
23 | # Setup path, remove wrappers and reinvoke npm.
24 | _setup_path_and_remove_wrappers
25 | npm "$@"
26 |
27 | } # End of function npm.
28 |
29 |
30 | # Temporary wrapper function to setup path before invoking node.
31 | function node() {
32 | # Setup path, remove wrappers and reinvoke node.
33 | _setup_path_and_remove_wrappers
34 | node "$@"
35 |
36 | } # End of function node.
37 |
38 |
39 | #
40 | # EOF
41 |
--------------------------------------------------------------------------------
/spec/javascripts/commentConfig.spec.js:
--------------------------------------------------------------------------------
1 | describe('Comment configuration test', function() {
2 | var boardModel;
3 | var commentConfig;
4 |
5 | beforeEach(function() {
6 | $('
').appendTo('body');
7 | boardModel = new cantas.models.Board({ commentStatus: 'enabled' });
8 | commentConfig = new cantas.views.CommentConfig({
9 | el: 'dl.js-comment',
10 | model: boardModel
11 | });
12 |
13 | loadFixtures('commentConfig.html');
14 | commentConfig.template = jade.compile($('#template-comment-config-view').text());
15 | commentConfig.render();
16 |
17 | spyOn(boardModel, 'patch').and.callFake(function() {});
18 | });
19 |
20 | afterEach(function() {
21 | commentConfig.close();
22 | });
23 |
24 | it("default comment status should be enabled", function() {
25 | expect($('.js-enable-comment')).toHaveClass('checked');
26 | });
27 |
28 | it('Should call patch method when disable comment', function() {
29 | commentConfig.$('.js-disable-comment span:last').trigger('click');
30 | expect(boardModel.patch).toHaveBeenCalled;
31 | });
32 |
33 | it("Should call patch method when open comment", function() {
34 | commentConfig.$('.js-open-comment span:last').trigger('click');
35 | expect(boardModel.patch).toHaveBeenCalled;
36 | });
37 |
38 |
39 | });
40 |
--------------------------------------------------------------------------------
/views/backbone/board-list.jade:
--------------------------------------------------------------------------------
1 | script#template-board-list-view(type="text/template")
2 | |div.board-ul-title
3 | | h3= h3Header
4 | | a.btn.btn-warning.new-board(type="text", onclick="cantas.navigateTo('boards/new')") New Board
5 | |div.board-ul-wapper
6 | | div.clearfix.board-ul-header
7 | | span.owner.board-name Board Name
8 | | span Creation Time
9 | | span Owner
10 | |ul.board-ul
11 | | each board in boards
12 | | if board.isClosed == true
13 | | li(class=(highlighted === board._id) ? 'board-close highlighted' : 'board-close')
14 | | div.owner.board-name= board.title
15 | | div.board-meta
16 | | span= cantas.utils.formatDate(board.created)
17 | | span= board.creatorId.username
18 | | if isCreator(board)
19 | | a.js-open-board.reopen.board-list-status(data-board= board._id, title="Open this board")
20 | | else
21 | | li(class=(highlighted === board._id) ? 'highlighted' : '')
22 | | a.owner.board-name.js-view-board(href="/board/\#{board._id}")= board.title
23 | | div.board-meta
24 | | span= cantas.utils.formatDate(board.created)
25 | | span= board.creatorId.username
26 | | if isCreator(board)
27 | | a.js-close-board.delete.board-list-status(data-board= board._id, title="Close this board")
--------------------------------------------------------------------------------
/models/attachment.js:
--------------------------------------------------------------------------------
1 | (function (module) {
2 |
3 | "use strict";
4 |
5 | var mongoose = require('mongoose'),
6 | Schema = mongoose.Schema,
7 | ObjectId = Schema.ObjectId,
8 | AttachmentSchema;
9 |
10 | AttachmentSchema = new Schema({
11 | cardId: {type: ObjectId, required: true, ref: 'Card', index: true},
12 | uploaderId: {type: ObjectId, required: true, ref: 'User', index: true},
13 | name: {type: String, required: true},
14 | size: {type: Number, required: true},
15 | // fileType field includes picture, video, audio and other
16 | fileType: {type: String, default: 'other'},
17 | path: {type: String, required: true},
18 | // boolean falg to indicate if this attachment is used as cover for the card
19 | isCover: {type: Boolean, default: false},
20 | // path of the thumbnail which is used in the card view
21 | cardThumbPath: {type: String, default: ''},
22 | // path of the thumbnail which is used in the card details view
23 | cardDetailThumbPath: {type: String, default: ''},
24 | createdOn: {type: Date, default: Date.now}
25 | });
26 |
27 | AttachmentSchema.statics.getById = function (id, callback) {
28 | this.findById({_id: id}).populate("cardId", "uploaderId").exec(callback);
29 | };
30 |
31 | module.exports = mongoose.model('Attachment', AttachmentSchema);
32 |
33 | }(module));
34 |
--------------------------------------------------------------------------------
/public/javascripts/models/label.js:
--------------------------------------------------------------------------------
1 | (function ($, _, Backbone) {
2 |
3 | "use strict";
4 |
5 | var BaseModel = cantas.models.BaseModel;
6 | var BaseCollection = cantas.models.BaseCollection;
7 |
8 | cantas.models.Label = BaseModel.extend({
9 | urlRoot: 'label'
10 | });
11 |
12 | cantas.models.LabelCollection = BaseCollection.extend({
13 | model: cantas.models.Label,
14 | url: '/label',
15 |
16 | initialize: function(models, options) {
17 | _.bindAll(this, "serverCreate");
18 | if (!this.noIoBind) {
19 | this.ioBind("create", this.socket, this.serverCreate, this);
20 | }
21 | }
22 | });
23 |
24 | cantas.models.CardLabelRelation = BaseModel.extend({
25 | urlRoot: 'cardlabelrelation'
26 | });
27 |
28 | cantas.models.CardLabelRelationCollection = BaseCollection.extend({
29 | model: cantas.models.CardLabelRelation,
30 | url: 'cardlabelrelation',
31 |
32 | /*
33 | * Due to the number of labels of a card is fixed, we don't need listen to
34 | * create event. So, override this function to disable default behavior,
35 | * and add other possible actions.
36 | */
37 | initialize: function(models, options) {
38 | },
39 |
40 | comparator: function(relation) {
41 | return relation.get('cardId').order;
42 | }
43 | });
44 |
45 | }(jQuery, _, Backbone));
46 |
--------------------------------------------------------------------------------
/public/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // Provide top-level namespaces for our javascript.
2 | $(function ($, _, Backbone) {
3 |
4 | "use strict";
5 |
6 | window.cantas = window.cantas || {};
7 | cantas.models = {};
8 | var ioPort = (window.cantas.settings) ? window.cantas.settings.socketIO.port : 80;
9 | cantas.socket = io.connect("" +
10 | document.location.protocol +
11 | "//" + document.location.hostname +
12 | ":" + ioPort, {
13 | "reconnect": true,
14 | "max reconnection attempts": 100,
15 | "max reconnection delay": 32000,
16 | "reconnection delay": cantas.utils.randomWait(100,1000)
17 | });
18 | cantas.views = {};
19 |
20 | cantas.setTitle = function(title) {
21 | window.document.title = "Cantas | " + title;
22 | };
23 |
24 | moment.lang('en', {
25 | calendar : {
26 | lastDay: '[Yesterday at] LT',
27 | sameDay: '[Today at] LT',
28 | nextDay: '[Tomorrow at] LT',
29 | lastWeek: '[last] dddd [at] LT',
30 | nextWeek: 'dddd [at] LT',
31 | sameElse: 'DD/MM/YYYY'
32 | }
33 | });
34 |
35 | _.mixin({
36 | compactObject : function(object) {
37 | var clone = _.clone(object);
38 | _.each(clone, function(value, key){
39 | if(!value) {
40 | delete clone[key];
41 | }
42 | });
43 | return clone;
44 | }
45 | });
46 |
47 | }(jQuery, _, Backbone));
48 |
--------------------------------------------------------------------------------
/services/auth/index.js:
--------------------------------------------------------------------------------
1 |
2 | (function(module) {
3 |
4 | 'use strict';
5 |
6 | var passport = require('passport');
7 | var mongoose = require('mongoose');
8 | var User = require('../../models/user');
9 | var strategies = require('./strategies');
10 |
11 | function findUserById(id, fn) {
12 | var ObjectId = mongoose.Types.ObjectId;
13 | User.findById({ _id: new ObjectId(id) }, function(err, user) {
14 | if (err || user === null) {
15 | fn(new Error('User ' + id + ' does not exist'));
16 | }
17 |
18 | fn(null, user);
19 | });
20 | }
21 |
22 | // Passport session setup.
23 | // To support persistent login sessions, Passport needs to be able to
24 | // serialize users into and deserialize users out of the session. Typically,
25 | // this will be as simple as storing the user ID when serializing, and finding
26 | // the user by ID when deserializing.
27 | passport.serializeUser(function(user, done) {
28 | done(null, user.id);
29 | });
30 |
31 | passport.deserializeUser(function(id, done) {
32 | findUserById(id, function (err, user) {
33 | done(err, user);
34 | });
35 | });
36 |
37 | // Set strategies for authentication.
38 | var key;
39 | for (key in strategies) {
40 | if (strategies.hasOwnProperty(key)) {
41 | passport.use(strategies[key]);
42 | }
43 | }
44 |
45 | module.exports = passport;
46 |
47 | }(module));
48 |
--------------------------------------------------------------------------------
/models/syncConfig.js:
--------------------------------------------------------------------------------
1 | (function (module) {
2 |
3 | "use strict";
4 |
5 | var mongoose = require('mongoose');
6 | var Schema = mongoose.Schema;
7 | var ObjectId = Schema.ObjectId;
8 |
9 | /*
10 | * SyncConfig schema is designed to record the mapping and
11 | * related settings between list and query url.
12 | * User can config several mappings in a board
13 | */
14 |
15 | var SyncConfigSchema = new Schema({
16 | boardId: { type: ObjectId, required: true, ref: 'Board', index: true },
17 | listId: { type: ObjectId, ref: 'List', index: true },
18 |
19 | // QueryUrl is used for querying bug/issue info
20 | // from external system like bugzilla or jira through API
21 | queryUrl: { type: String },
22 |
23 | // External system name
24 | queryType: { type: String, required: true },
25 |
26 | // If sync external systems based on sync config automatically
27 | isActive: { type: Boolean, default: true },
28 |
29 | // Set the interval time when cantas sync external
30 | // systems automatically, default is 8 hours once
31 | intervalTime: { type: Number, default: 8 },
32 |
33 | creatorId: { type: ObjectId, required: true, ref: 'User', index: true },
34 | createdOn: { type: Date, default: Date.now },
35 | updatedOn: { type: Date, default: Date.now }
36 | });
37 |
38 | module.exports = mongoose.model('SyncConfig', SyncConfigSchema);
39 |
40 | }(module));
41 |
--------------------------------------------------------------------------------
/public/javascripts/models/vote.js:
--------------------------------------------------------------------------------
1 | //model vote
2 |
3 | (function ($, _, Backbone) {
4 | "use strict";
5 | var BaseModel = cantas.models.BaseModel;
6 | var BaseCollection = cantas.models.BaseCollection;
7 |
8 | cantas.models.Vote = BaseModel.extend({
9 | urlRoot: 'vote',
10 |
11 | initialize: function () {
12 | this.on('modelCleanup', this.modelCleanup, this);
13 | if (!this.noIoBind) {
14 | this.ioBind('update', this.serverChange, this);
15 | this.ioBind('delete', this.serverDelete, this);
16 | }
17 | },
18 |
19 | serverChange: function (data) {
20 | this.set(data);
21 | },
22 |
23 | serverDelete: function (data) {
24 | if (typeof this.collection === 'object') {
25 | this.collection.remove(this);
26 | } else {
27 | this.trigger('remove', this);
28 | }
29 | },
30 |
31 | modelCleanup: function () {
32 | this.ioUnbindAll();
33 | return this;
34 | }
35 |
36 | });
37 |
38 | cantas.models.VoteCollection = cantas.models.BaseCollection.extend({
39 | model: cantas.models.Vote,
40 | url: '/vote',
41 |
42 | initialize: function(models, options) {
43 | _.bindAll(this, "serverCreate");
44 | this.socket.removeAllListeners("/vote:create");
45 | if (!this.noIoBind) {
46 | this.socket.on('/vote:create', this.serverCreate, this);
47 | }
48 | }
49 |
50 | });
51 |
52 | }(jQuery, _, Backbone));
53 |
--------------------------------------------------------------------------------
/sockets/signals.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Prdefined signals
3 | */
4 |
5 | (function(module) {
6 |
7 | "use strict";
8 |
9 | var Signal = require("../services/signal");
10 |
11 | /*
12 | * Emit after CRUD function create executes successfully.
13 | *
14 | * Arguments:
15 | * - instance: the newly created object.
16 | * - socket: client socket.
17 | */
18 | module.exports.post_create = new Signal(["instance", "socket"]);
19 |
20 | /*
21 | * Emit after CRUD function delete executes successfully.
22 | *
23 | * Arguments:
24 | * - instance: the deleted object.
25 | * - socket: client socket.
26 | */
27 | module.exports.post_delete = new Signal(["instance", "socket"]);
28 |
29 | /*
30 | * Emit after CRUD function patch executes successfully.
31 | *
32 | * Arguments:
33 | * - instance: the just updated object.
34 | * - socket: client socket.
35 | */
36 | module.exports.post_patch = new Signal(["instance", "socket"]);
37 |
38 | /*
39 | * Emit after CRUD function read executes successfully.
40 | *
41 | * Arguments:
42 | * - instances: objects returned back to client.
43 | * - socket: client socket.
44 | */
45 | module.exports.post_read = new Signal(["instances", "socket"]);
46 |
47 | /*
48 | * Emit after CRUD function read executes successfully.
49 | *
50 | * Arguments:
51 | * - instance: the updated object.
52 | * - socket: client socket.
53 | */
54 | module.exports.post_update = new Signal(["instance", "socket"]);
55 |
56 | }(module));
57 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "HSS-IED-BJ",
3 | "description": "cantas is a real-time collaborative application.",
4 | "dependencies": {
5 | "async": "*",
6 | "connect-redis": "~1.4.x",
7 | "express": "~2.5.x",
8 | "jade": "*",
9 | "markdown": "*",
10 | "moment": "*",
11 | "mongoose": "3.6.13",
12 | "node-krb5": "*",
13 | "nodemailer": "~0.7.1",
14 | "passport": "*",
15 | "passport-local": "*",
16 | "passport-google-oauth": "~0.1.5",
17 | "redis": "*",
18 | "socket.io": "~0.9.x",
19 | "xmlrpc": "~1.1.0",
20 | "easyimage": "^1.0.2",
21 | "requestify": "*",
22 | "lodash": "*",
23 | "piwik-tracker": "^0.1.1"
24 | },
25 | "devDependencies": {
26 | "expect.js": "*",
27 | "grunt": "~0.4.5",
28 | "grunt-contrib-concat": "*",
29 | "grunt-contrib-cssmin": "~0.6.1",
30 | "grunt-contrib-jasmine": "0.6.x",
31 | "grunt-contrib-uglify": "*",
32 | "grunt-contrib-watch": "~0.4.3",
33 | "grunt-simple-mocha": "~0.4.0",
34 | "mongoose-fakery": "*",
35 | "nodelint": "*",
36 | "optimist": "~0.6.0",
37 | "sinon": "*",
38 | "supertest": "*"
39 | },
40 | "engines": {
41 | "node": "0.10.26",
42 | "npm": "1.4.7"
43 | },
44 | "name": "cantas",
45 | "private": true,
46 | "scripts": {
47 | "lintcheck": "scripts/lintcheck",
48 | "start": "node app"
49 | },
50 | "main": "app.js",
51 | "version": "1.0.0",
52 | "repository": {
53 | "type": "git",
54 | "url": "https://github.com/onepiecejs/nodejs-cantas.git"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/.openshift/action_hooks/build:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # This is a simple build script and will be executed on your CI system if
3 | # available. Otherwise it will execute while your application is stopped
4 | # before the deploy step. This script gets executed directly, so it
5 | # could be python, php, ruby, etc.
6 |
7 |
8 | # Source utility functions.
9 | source "$OPENSHIFT_REPO_DIR/.openshift/lib/utils"
10 |
11 | # Setup path to include the custom Node[.js] version.
12 | _SHOW_SETUP_PATH_MESSAGES="true" setup_path_for_custom_node_version
13 |
14 |
15 | # we moved the package.json file out of the way in pre_build,
16 | # so that the OpenShift git post-receive hook doesn't try and use the
17 | # old npm version to install the dependencies. Move it back in.
18 | tmp_package_json="$(get_node_tmp_dir)/package.json"
19 | if [ -f "$tmp_package_json" ]; then
20 | # Only overlay it if there is no current package.json file.
21 | [ -f "${OPENSHIFT_REPO_DIR}/package.json" ] || \
22 | mv "$tmp_package_json" "${OPENSHIFT_REPO_DIR}/package.json"
23 | fi
24 |
25 |
26 | # Do npm install with the new npm binary.
27 | if [ -f "${OPENSHIFT_REPO_DIR}"/package.json ]; then
28 | echo " - Installing dependencies w/ new version of npm ... "
29 | echo
30 | (cd "${OPENSHIFT_REPO_DIR}"; export TMPDIR="/tmp"; npm install -d)
31 | fi
32 |
33 | # Do grunt css and js minified.
34 | if [ -f "${OPENSHIFT_REPO_DIR}"/package.json ]; then
35 | echo " - Minified css js files ... "
36 | echo
37 | (cd "${OPENSHIFT_REPO_DIR}"; export TMPDIR="/tmp"; npm install -g grunt-cli; grunt)
38 | fi
--------------------------------------------------------------------------------
/public/javascripts/views/app.js:
--------------------------------------------------------------------------------
1 | (function ($, _, Backbone) {
2 |
3 | "use strict";
4 |
5 | cantas.views.AppView = cantas.views.BaseView.extend({
6 |
7 | el: 'body',
8 |
9 | events: {
10 | 'keyup .js-search-form': 'searchAction',
11 | 'submit .js-search-form': 'searchAction',
12 | 'focus .js-search-form': 'searchAction',
13 | 'click .quick-search': function(e) {
14 | e.stopPropagation();
15 | }
16 | },
17 |
18 | initialize: function() {
19 | this.initNofiticationView();
20 | this.initQuickSearchView();
21 | },
22 |
23 |
24 | initNofiticationView: function() {
25 | this.notificationView = new cantas.views.NotificationView();
26 |
27 | cantas.socket.on('/notification:create', function(data) {
28 | var obj = new cantas.models.Notification(data);
29 | this.notificationView.notificationCollection.add(data);
30 | }.bind(this));
31 | },
32 |
33 |
34 | initQuickSearchView: function() {
35 | this.quickSearchView = new cantas.views.QuickSearchView({
36 | el: this.$('.quick-search-content')
37 | });
38 | },
39 |
40 |
41 | searchAction: function(e) {
42 | var code = e.keyCode || e.which;
43 |
44 | // Don't search if the user pressed esc or enter
45 | if (code === 27 || code === 13) {
46 | return;
47 | }
48 |
49 | e.preventDefault();
50 | var q = this.$('.js-search-form [name="query"]').val();
51 | this.quickSearchView.search(q);
52 | }
53 |
54 |
55 | });
56 |
57 |
58 | }(jQuery, _, Backbone));
--------------------------------------------------------------------------------
/scripts/db_migration_card_add_boardId.js:
--------------------------------------------------------------------------------
1 | // add boardId to card schema
2 |
3 | var async = require('async');
4 | var util = require('util');
5 | var mongoose = require('mongoose');
6 | var settings = require('../settings');
7 | var List = require('../models/list');
8 | var Card = require('../models/card');
9 |
10 | mongoose.connect(
11 | settings.mongodb.host,
12 | settings.mongodb.name,
13 | settings.mongodb.port,
14 | {
15 | user: settings.mongodb.user,
16 | pass: settings.mongodb.pass
17 | }
18 | );
19 |
20 | Card.find().populate('listId').exec(function(err, cards) {
21 | var processed = 0;
22 | var updated = 0;
23 | cards.forEach(function(card) {
24 | if (card.boardId && card.boardId.toString() === card.listId.boardId.toString()) {
25 | processed++;
26 | } else {
27 | var boardId = card.listId.boardId;
28 | card.update({$set: {boardId: boardId}}, function(err) {
29 | if (err) {
30 | console.log("Error: card %s : %s", card.id, err);
31 | } else {
32 | updated++;
33 | }
34 | processed++;
35 | });
36 | }
37 | });
38 |
39 | async.until(
40 | function() {
41 | return cards.length === processed;
42 | },
43 | function(callback) {
44 | setTimeout(callback, 1000);
45 | },
46 | function(err) {
47 | console.log(util.format("%d of %d cards proceessed.", processed, cards.length));
48 | console.log(util.format("%d of %d cards updated.", updated, cards.length));
49 | console.log("finished.");
50 | process.exit();
51 | }
52 | );
53 | });
54 |
--------------------------------------------------------------------------------
/scripts/db_migration_checklistItem_add_cardId.js:
--------------------------------------------------------------------------------
1 | // add boardId to card schema
2 |
3 | var async = require('async');
4 | var util = require('util');
5 | var mongoose = require('mongoose');
6 | var settings = require('../settings');
7 | var ChecklistItem = require('../models/checklistItem');
8 | var Checklist = require('../models/checklist');
9 |
10 | mongoose.connect(
11 | settings.mongodb.host,
12 | settings.mongodb.name,
13 | settings.mongodb.port,
14 | {
15 | user: settings.mongodb.user,
16 | pass: settings.mongodb.pass
17 | }
18 | );
19 |
20 | ChecklistItem.find().populate('checklistId').exec(function(err, items) {
21 | var total = items.length;
22 | var processed = 0;
23 | var updated = 0;
24 | items.forEach(function(item) {
25 | if (item.cardId && item.cardId.toString() === item.checklistId.cardId.toString()) {
26 | processed++;
27 | } else {
28 | item.update({$set: {cardId: item.checklistId.cardId}}, function(err) {
29 | if (err) {
30 | console.log("Error: checklist item %s : %s", item.id, err);
31 | } else {
32 | updated++;
33 | }
34 | processed++;
35 | });
36 | }
37 | });
38 |
39 | async.until(
40 | function() {
41 | return total === processed;
42 | },
43 | function(callback) {
44 | setTimeout(callback, 1000);
45 | },
46 | function(err) {
47 | console.log(util.format("%d of %d checklist items proceessed.", processed, total));
48 | console.log(util.format("%d of %d checklist items updated.", updated, total));
49 | console.log("finished.");
50 | process.exit();
51 | }
52 | );
53 | });
54 |
--------------------------------------------------------------------------------
/spec/javascripts/unselectLabel.spec.js:
--------------------------------------------------------------------------------
1 | describe('unselectLabel',function(){
2 | var labelAssignView;
3 | var template_data;
4 | var relation;
5 | beforeEach(function(){
6 | $('').appendTo('body');
7 |
8 | labelAssignView = new cantas.views.LabelAssignView({
9 | collection: new cantas.models.CardLabelRelationCollection,
10 | card: new cantas.models.Card({
11 | title: 'good luck',
12 | creatorId: '516f593cbd645e7306000001',
13 | listId: '51cb97495bffe9ba08000003',
14 | boardId: '51cb97495bffe9ba08000001'
15 | })
16 | });
17 |
18 | loadFixtures('unselectLabel.html');
19 | labelAssignView.template = jade.compile($('#template-label-assign-view').text());
20 | template_data = {relations: [{
21 | _id: '51cb974c5bffe9ba08000011',
22 | color: '#E7BAB6',
23 | selected: true
24 | }]};
25 |
26 | labelAssignView.$el.html(labelAssignView.template(template_data)).appendTo('body');
27 |
28 | relation = new cantas.models.CardLabelRelation({
29 | _id: '51cb974c5bffe9ba08000011',
30 | boardId: '51cb97495bffe9ba08000001',
31 | cardId: '51cb974c5bffe9ba0800000f',
32 | labelId: '51cb97495bffe9ba08000007',
33 | selected: true
34 | });
35 |
36 | labelAssignView.collection = new cantas.models.CardLabelRelationCollection([relation]);
37 |
38 | spyOn(relation, "patch").and.callFake(function() {});
39 | });
40 |
41 | it('should unselect the label by click the lable with √', function(){
42 | labelAssignView.$('ul.label-items').children().eq(0).trigger('click');
43 | expect(relation.patch).toHaveBeenCalled();
44 | });
45 |
46 | });
--------------------------------------------------------------------------------
/services/mail.js:
--------------------------------------------------------------------------------
1 | var nodemailer = require("nodemailer");
2 | var wellknown = require("nodemailer/lib/wellknown");
3 | var settings = require("../settings");
4 |
5 | /*
6 | * Add Zimbra to wellknown mail service so that Nodemailer recognizes it.
7 | */
8 | wellknown.Zimbra = settings.mailServices.Zimbra;
9 |
10 | function mailer() {}
11 |
12 | /*
13 | * Send mail to recipients.
14 | *
15 | * All mail options, such as sender, recipients, subject and body, is contained
16 | * in options argument.
17 | *
18 | * Arguments:
19 | * - options.from: a string, address of sender
20 | * - options.to: a string or an array, addresses of recipients
21 | * - options.subject: a string, subject of the mail
22 | * - options.body: a string, body of mail that recipients can read
23 | * - options.html: a boolean, indicate whether the body is formatted in HTML
24 | */
25 | mailer.prototype.sendmail = function(options, callback) {
26 | var recipients = options.to;
27 | if (typeof recipients === "object" && recipients.join !== undefined) {
28 | recipients = recipients.join(", ");
29 | }
30 | var mailOptions = {
31 | from: options.from,
32 | to: recipients,
33 | subject: options.subject
34 | };
35 | mailOptions[options.html ? "html" : "text"] = options.body;
36 | var smtpTransport = nodemailer.createTransport("SMTP", {
37 | service: "Zimbra",
38 | });
39 | smtpTransport.sendMail(mailOptions, function(error, response) {
40 | callback(error, response);
41 | });
42 | };
43 |
44 | mailer.prototype.sendmailFromNoReply = function(options, callback) {
45 | options.from = "noreply@redhat.com";
46 | this.sendmail(options, callback);
47 | };
48 |
49 | module.exports = mailer;
50 |
--------------------------------------------------------------------------------
/views/backbone/card.jade:
--------------------------------------------------------------------------------
1 | script#template-card-view(type="text/template")
2 | |div.card-container.ui-state-default.card-title
3 | | div.card.clearfix
4 | | a.setting.card-setting
5 | | p= title
6 | | if typeof cover === 'string'
7 | | if cover
8 | | if coverURL.indexOf('thumb-card') > -1
9 | | div.card-cover(style='background-image:\#{coverURL};')
10 | | else
11 | | div.card-cover.original-size(style='background-image:\#{coverURL};')
12 | | else
13 | | div.card-cover.hide
14 | | section.card-items
15 | | each assignee in assignees
16 | | span.card-assignee(title="Assignee: "+assignee.username + "")= assignee.username
17 | | if typeof badges === "object"
18 | | if badges.comments !== 0
19 | | span.card-comment(title="\#{badges.comments} comment(s).")= badges.comments
20 | | if badges.checkitems !== 0
21 | | span.card-checklist(title=" \#{checkitemsProgress} checklist items completed.")= checkitemsProgress
22 | | if (badges.votesYes + badges.votesNo) !== 0
23 | | span.card-vote(title=" \#{badges.votesYes} agree, \#{badges.votesNo} disagree.")= badgesVotes
24 | | if badges.attachments !== 0
25 | | span.card-attachment(title=" \#{badges.attachments} attachment(s).")= badges.attachments
26 | | if dueDateDisplay
27 | | span.card-due-date= "Due " + dueDateDisplay
28 | | if typeof index !== "undefined"
29 | | div.card-index(title="Card Position")
30 | | span.order-number= index
31 | | div.card-filter.clearfix
32 |
33 | script#template-card-meta-view(type="text/template")
34 | |div.card-meta!= meta
--------------------------------------------------------------------------------
/public/javascripts/views/welcome.js:
--------------------------------------------------------------------------------
1 | // Welcome View
2 |
3 | (function ($, _, Backbone) {
4 |
5 | "use strict";
6 |
7 | cantas.views.WelcomeView = Backbone.View.extend({
8 |
9 | el: '.content',
10 |
11 | events: {
12 | },
13 |
14 | template: jade.compile($("#template-welcome-view").text()),
15 |
16 | close: function() {
17 | // this.$el.empty();
18 | // this.undelegateEvents();
19 | // this.stopListening();
20 |
21 | return this;
22 | },
23 |
24 | render: function(context) {
25 | this.$el.html(this.template());
26 | cantas.setTitle(context.title);
27 |
28 | var $navArrows = $('#nav-arrows');
29 | var $nav = $('#nav-dots > span');
30 |
31 | var slitslider = $('#slider').slitslider({
32 | onBeforeChange: function(slide, pos) {
33 | $nav.removeClass('nav-dot-current');
34 | $nav.eq(pos).addClass('nav-dot-current');
35 | }
36 | });
37 |
38 | $navArrows.children(':last').on('click', function() {
39 | slitslider.next();
40 | return false;
41 | });
42 |
43 | $navArrows.children(':first').on('click', function() {
44 | slitslider.previous();
45 | return false;
46 | });
47 |
48 | $nav.each(function(i) {
49 | $(this).on('click',
50 | function(event) {
51 | var $dot = $(this);
52 | if (!slitslider.isActive()) {
53 | $nav.removeClass('nav-dot-current');
54 | $dot.addClass('nav-dot-current');
55 | }
56 |
57 | slitslider.jump(i + 1);
58 | return false;
59 | });
60 | });
61 | }
62 |
63 | });
64 |
65 | }(jQuery, _, Backbone));
66 |
--------------------------------------------------------------------------------
/public/stylesheets/jquery-fileupload-ui.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 | /*
3 | * jQuery File Upload UI Plugin CSS 8.1
4 | * https://github.com/blueimp/jQuery-File-Upload
5 | *
6 | * Copyright 2010, Sebastian Tschan
7 | * https://blueimp.net
8 | *
9 | * Licensed under the MIT license:
10 | * http://www.opensource.org/licenses/MIT
11 | */
12 | .fileinput-button {
13 | position: relative;
14 | overflow: hidden;
15 | }
16 | .fileinput-button input {
17 | position: absolute;
18 | top: 0;
19 | right: 0;
20 | margin: 0;
21 | opacity: 0;
22 | filter: alpha(opacity=0);
23 | transform: translate(-300px, 0) scale(4);
24 | font-size: 23px;
25 | direction: ltr;
26 | cursor: pointer;
27 | }
28 | .fileupload-buttonbar .btn,
29 | .fileupload-buttonbar .toggle {
30 | margin-bottom: 5px;
31 | margin-right: 9px;
32 | }
33 |
34 | .progress-animated .bar {
35 | background: url(../images/progressbar.gif) !important;
36 | filter: none;
37 | }
38 | .fileupload-loading {
39 | float: right;
40 | width: 32px;
41 | height: 32px;
42 | background: url(../images/loading.gif) center no-repeat;
43 | background-size: contain;
44 | display: none;
45 | }
46 | .fileupload-processing .fileupload-loading {
47 | display: block;
48 | }
49 | .files audio,
50 | .files video {
51 | max-width: 300px;
52 | }
53 |
54 | @media (max-width: 767px) {
55 | .fileupload-buttonbar .toggle,
56 | .files .toggle,
57 | .files .btn span {
58 | display: none;
59 | }
60 | .files .name {
61 | width: 80px;
62 | word-wrap: break-word;
63 | }
64 | .files audio,
65 | .files video {
66 | max-width: 80px;
67 | }
68 | }
69 | .template-upload td {
70 | text-align: center;
71 | width: 24%;
72 | }
73 | .template-download td {
74 | text-align: center;
75 | }
--------------------------------------------------------------------------------
/sockets/crud/cardLabelRelation.js:
--------------------------------------------------------------------------------
1 |
2 | (function(module) {
3 |
4 | "use strict";
5 |
6 | var util = require("util");
7 | var BaseCRUD = require("./base");
8 | var signals = require("../signals");
9 |
10 | function CardLabelRelationCRUD(options) {
11 | BaseCRUD.call(this, options);
12 |
13 | this.createEnabled = false;
14 | this.updateEnabled = false;
15 |
16 | this.modelClass = require("../../models/cardLabelRelation");
17 | this.key = this.modelClass.modelName.toLowerCase();
18 | }
19 |
20 | util.inherits(CardLabelRelationCRUD, BaseCRUD);
21 |
22 | CardLabelRelationCRUD.prototype._read = function(data, callback) {
23 | if (data) {
24 | this.modelClass
25 | .find(data)
26 | .populate('labelId')
27 | .exec(function (err, result) {
28 | callback(err, result);
29 | });
30 | } else {
31 | this.modelClass.find({}, callback);
32 | }
33 | };
34 |
35 | CardLabelRelationCRUD.prototype._patch = function(data, callback) {
36 | var self = this;
37 | var _id = data._id || data.id;
38 | var name = '/' + this.key + '/' + _id + ':update';
39 | delete data._id; // _id is not modifiable
40 |
41 | this.modelClass.findByIdAndUpdate(_id, data)
42 | .populate("boardId cardId labelId")
43 | .exec(function (err, updatedData) {
44 | if (err) {
45 | callback(err, updatedData);
46 | } else {
47 | self.emitMessage(name, updatedData);
48 |
49 | signals.post_patch.send(updatedData, {
50 | instance: updatedData,
51 | socket: self.socket
52 | }, function(err, result) {});
53 |
54 | }
55 | });
56 | };
57 |
58 | module.exports = CardLabelRelationCRUD;
59 |
60 | }(module));
61 |
--------------------------------------------------------------------------------
/spec/javascripts/fixtures/cardDetail.html:
--------------------------------------------------------------------------------
1 |
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright © 2013 Cantas Team
Delete Option
' + '' +
11 | '