diff --git a/app/assets/images/menber-pic.png b/app/assets/images/menber-pic.png
index 3e53af70d..f0493974c 100644
Binary files a/app/assets/images/menber-pic.png and b/app/assets/images/menber-pic.png differ
diff --git a/app/assets/images/sign-in-logo.png b/app/assets/images/sign-in-logo.png
index 53756c7c3..91020300e 100644
Binary files a/app/assets/images/sign-in-logo.png and b/app/assets/images/sign-in-logo.png differ
diff --git a/app/assets/javascripts/lib/checkbox.card.js b/app/assets/javascripts/lib/checkbox.card.js
new file mode 100644
index 000000000..78f2ff260
--- /dev/null
+++ b/app/assets/javascripts/lib/checkbox.card.js
@@ -0,0 +1,23 @@
+!function ($) {
+ $.fn.cardCheck = function(param) {
+ _defaultSettings = {
+ check: '',
+ };
+ _set = $.extend(_defaultSettings, param);
+ $card = $(this);
+ $check = _set.check;
+ $check.each(function(){
+ if($(this).attr('checked')) {
+ $(this).parent($card).addClass("active");
+ }
+ });
+ $card.on('click', function() {
+ $(this).toggleClass('active')
+ });
+ }
+}(window.jQuery);
+$(function(){
+ $('.checkbox-card > li').cardCheck({
+ check: $('.checkbox-card > li input[type="checkbox"]'),
+ });
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/lib/jquery.nanoscroller.js b/app/assets/javascripts/lib/jquery.nanoscroller.js
new file mode 100644
index 000000000..e7f53cc3f
--- /dev/null
+++ b/app/assets/javascripts/lib/jquery.nanoscroller.js
@@ -0,0 +1,752 @@
+/*! nanoScrollerJS - v0.7.2
+* http://jamesflorentino.github.com/nanoScrollerJS/
+* Copyright (c) 2013 James Florentino; Licensed MIT */
+
+
+(function($, window, document) {
+ "use strict";
+
+ var BROWSER_IS_IE7, BROWSER_SCROLLBAR_WIDTH, DOMSCROLL, DOWN, DRAG, KEYDOWN, KEYUP, MOUSEDOWN, MOUSEMOVE, MOUSEUP, MOUSEWHEEL, NanoScroll, PANEDOWN, RESIZE, SCROLL, SCROLLBAR, TOUCHMOVE, UP, WHEEL, defaults, getBrowserScrollbarWidth;
+ defaults = {
+ /**
+ a classname for the pane element.
+ @property paneClass
+ @type String
+ @default 'pane'
+ */
+
+ paneClass: 'pane',
+ /**
+ a classname for the slider element.
+ @property sliderClass
+ @type String
+ @default 'slider'
+ */
+
+ sliderClass: 'slider',
+ /**
+ a classname for the content element.
+ @property contentClass
+ @type String
+ @default 'content'
+ */
+
+ contentClass: 'content',
+ /**
+ a setting to enable native scrolling in iOS devices.
+ @property iOSNativeScrolling
+ @type Boolean
+ @default false
+ */
+
+ iOSNativeScrolling: false,
+ /**
+ a setting to prevent the rest of the page being
+ scrolled when user scrolls the `.content` element.
+ @property preventPageScrolling
+ @type Boolean
+ @default false
+ */
+
+ preventPageScrolling: false,
+ /**
+ a setting to disable binding to the resize event.
+ @property disableResize
+ @type Boolean
+ @default false
+ */
+
+ disableResize: false,
+ /**
+ a setting to make the scrollbar always visible.
+ @property alwaysVisible
+ @type Boolean
+ @default false
+ */
+
+ alwaysVisible: false,
+ /**
+ a default timeout for the `flash()` method.
+ @property flashDelay
+ @type Number
+ @default 1500
+ */
+
+ flashDelay: 1500,
+ /**
+ a minimum height for the `.slider` element.
+ @property sliderMinHeight
+ @type Number
+ @default 20
+ */
+
+ sliderMinHeight: 20,
+ /**
+ a maximum height for the `.slider` element.
+ @property sliderMaxHeight
+ @type Number
+ @default null
+ */
+
+ sliderMaxHeight: null
+ };
+ /**
+ @property SCROLLBAR
+ @type String
+ @static
+ @final
+ @private
+ */
+
+ SCROLLBAR = 'scrollbar';
+ /**
+ @property SCROLL
+ @type String
+ @static
+ @final
+ @private
+ */
+
+ SCROLL = 'scroll';
+ /**
+ @property MOUSEDOWN
+ @type String
+ @final
+ @private
+ */
+
+ MOUSEDOWN = 'mousedown';
+ /**
+ @property MOUSEMOVE
+ @type String
+ @static
+ @final
+ @private
+ */
+
+ MOUSEMOVE = 'mousemove';
+ /**
+ @property MOUSEWHEEL
+ @type String
+ @final
+ @private
+ */
+
+ MOUSEWHEEL = 'mousewheel';
+ /**
+ @property MOUSEUP
+ @type String
+ @static
+ @final
+ @private
+ */
+
+ MOUSEUP = 'mouseup';
+ /**
+ @property RESIZE
+ @type String
+ @final
+ @private
+ */
+
+ RESIZE = 'resize';
+ /**
+ @property DRAG
+ @type String
+ @static
+ @final
+ @private
+ */
+
+ DRAG = 'drag';
+ /**
+ @property UP
+ @type String
+ @static
+ @final
+ @private
+ */
+
+ UP = 'up';
+ /**
+ @property PANEDOWN
+ @type String
+ @static
+ @final
+ @private
+ */
+
+ PANEDOWN = 'panedown';
+ /**
+ @property DOMSCROLL
+ @type String
+ @static
+ @final
+ @private
+ */
+
+ DOMSCROLL = 'DOMMouseScroll';
+ /**
+ @property DOWN
+ @type String
+ @static
+ @final
+ @private
+ */
+
+ DOWN = 'down';
+ /**
+ @property WHEEL
+ @type String
+ @static
+ @final
+ @private
+ */
+
+ WHEEL = 'wheel';
+ /**
+ @property KEYDOWN
+ @type String
+ @static
+ @final
+ @private
+ */
+
+ KEYDOWN = 'keydown';
+ /**
+ @property KEYUP
+ @type String
+ @static
+ @final
+ @private
+ */
+
+ KEYUP = 'keyup';
+ /**
+ @property TOUCHMOVE
+ @type String
+ @static
+ @final
+ @private
+ */
+
+ TOUCHMOVE = 'touchmove';
+ /**
+ @property BROWSER_IS_IE7
+ @type Boolean
+ @static
+ @final
+ @private
+ */
+
+ BROWSER_IS_IE7 = window.navigator.appName === 'Microsoft Internet Explorer' && /msie 7./i.test(window.navigator.appVersion) && window.ActiveXObject;
+ /**
+ @property BROWSER_SCROLLBAR_WIDTH
+ @type Number
+ @static
+ @default null
+ @private
+ */
+
+ BROWSER_SCROLLBAR_WIDTH = null;
+ /**
+ Returns browser's native scrollbar width
+ @method getBrowserScrollbarWidth
+ @return {Number} the scrollbar width in pixels
+ @static
+ @private
+ */
+
+ getBrowserScrollbarWidth = function() {
+ var outer, outerStyle, scrollbarWidth;
+ outer = document.createElement('div');
+ outerStyle = outer.style;
+ outerStyle.position = 'absolute';
+ outerStyle.width = '100px';
+ outerStyle.height = '100px';
+ outerStyle.overflow = SCROLL;
+ outerStyle.top = '-9999px';
+ document.body.appendChild(outer);
+ scrollbarWidth = outer.offsetWidth - outer.clientWidth;
+ document.body.removeChild(outer);
+ return scrollbarWidth;
+ };
+ /**
+ @class NanoScroll
+ @param element {HTMLElement|Node} the main element
+ @param options {Object} nanoScroller's options
+ @constructor
+ */
+
+ NanoScroll = (function() {
+
+ function NanoScroll(el, options) {
+ this.el = el;
+ this.options = options;
+ BROWSER_SCROLLBAR_WIDTH || (BROWSER_SCROLLBAR_WIDTH = getBrowserScrollbarWidth());
+ this.$el = $(this.el);
+ this.doc = $(document);
+ this.win = $(window);
+ this.$content = this.$el.children("." + options.contentClass);
+ this.$content.attr('tabindex', 0);
+ this.content = this.$content[0];
+ if (this.options.iOSNativeScrolling && (this.el.style.WebkitOverflowScrolling != null)) {
+ this.nativeScrolling();
+ } else {
+ this.generate();
+ }
+ this.createEvents();
+ this.addEvents();
+ this.reset();
+ }
+
+ /**
+ Prevents the rest of the page being scrolled
+ when user scrolls the `.content` element.
+ @method preventScrolling
+ @param event {Event}
+ @param direction {String} Scroll direction (up or down)
+ @private
+ */
+
+
+ NanoScroll.prototype.preventScrolling = function(e, direction) {
+ if (!this.isActive) {
+ return;
+ }
+ if (e.type === DOMSCROLL) {
+ if (direction === DOWN && e.originalEvent.detail > 0 || direction === UP && e.originalEvent.detail < 0) {
+ e.preventDefault();
+ }
+ } else if (e.type === MOUSEWHEEL) {
+ if (!e.originalEvent || !e.originalEvent.wheelDelta) {
+ return;
+ }
+ if (direction === DOWN && e.originalEvent.wheelDelta < 0 || direction === UP && e.originalEvent.wheelDelta > 0) {
+ e.preventDefault();
+ }
+ }
+ };
+
+ /**
+ Enable iOS native scrolling
+ */
+
+
+ NanoScroll.prototype.nativeScrolling = function() {
+ this.$content.css({
+ WebkitOverflowScrolling: 'touch'
+ });
+ this.iOSNativeScrolling = true;
+ this.isActive = true;
+ };
+
+ /**
+ Updates those nanoScroller properties that
+ are related to current scrollbar position.
+ @method updateScrollValues
+ @private
+ */
+
+
+ NanoScroll.prototype.updateScrollValues = function() {
+ var content;
+ content = this.content;
+ this.maxScrollTop = content.scrollHeight - content.clientHeight;
+ this.contentScrollTop = content.scrollTop;
+ if (!this.iOSNativeScrolling) {
+ this.maxSliderTop = this.paneHeight - this.sliderHeight;
+ this.sliderTop = this.contentScrollTop * this.maxSliderTop / this.maxScrollTop;
+ }
+ };
+
+ /**
+ Creates event related methods
+ @method createEvents
+ @private
+ */
+
+
+ NanoScroll.prototype.createEvents = function() {
+ var _this = this;
+ this.events = {
+ down: function(e) {
+ _this.isBeingDragged = true;
+ _this.offsetY = e.pageY - _this.slider.offset().top;
+ _this.pane.addClass('active');
+ _this.doc.bind(MOUSEMOVE, _this.events[DRAG]).bind(MOUSEUP, _this.events[UP]);
+ return false;
+ },
+ drag: function(e) {
+ _this.sliderY = e.pageY - _this.$el.offset().top - _this.offsetY;
+ _this.scroll();
+ _this.updateScrollValues();
+ if (_this.contentScrollTop >= _this.maxScrollTop) {
+ _this.$el.trigger('scrollend');
+ } else if (_this.contentScrollTop === 0) {
+ _this.$el.trigger('scrolltop');
+ }
+ return false;
+ },
+ up: function(e) {
+ _this.isBeingDragged = false;
+ _this.pane.removeClass('active');
+ _this.doc.unbind(MOUSEMOVE, _this.events[DRAG]).unbind(MOUSEUP, _this.events[UP]);
+ return false;
+ },
+ resize: function(e) {
+ _this.reset();
+ },
+ panedown: function(e) {
+ _this.sliderY = (e.offsetY || e.originalEvent.layerY) - (_this.sliderHeight * 0.5);
+ _this.scroll();
+ _this.events.down(e);
+ return false;
+ },
+ scroll: function(e) {
+ if (_this.isBeingDragged) {
+ return;
+ }
+ _this.updateScrollValues();
+ if (!_this.iOSNativeScrolling) {
+ _this.sliderY = _this.sliderTop;
+ _this.slider.css({
+ top: _this.sliderTop
+ });
+ }
+ if (e == null) {
+ return;
+ }
+ if (_this.contentScrollTop >= _this.maxScrollTop) {
+ if (_this.options.preventPageScrolling) {
+ _this.preventScrolling(e, DOWN);
+ }
+ _this.$el.trigger('scrollend');
+ } else if (_this.contentScrollTop === 0) {
+ if (_this.options.preventPageScrolling) {
+ _this.preventScrolling(e, UP);
+ }
+ _this.$el.trigger('scrolltop');
+ }
+ },
+ wheel: function(e) {
+ if (e == null) {
+ return;
+ }
+ _this.sliderY += -e.wheelDeltaY || -e.delta;
+ _this.scroll();
+ return false;
+ }
+ };
+ };
+
+ /**
+ Adds event listeners with jQuery.
+ @method addEvents
+ @private
+ */
+
+
+ NanoScroll.prototype.addEvents = function() {
+ var events;
+ this.removeEvents();
+ events = this.events;
+ if (!this.options.disableResize) {
+ this.win.bind(RESIZE, events[RESIZE]);
+ }
+ if (!this.iOSNativeScrolling) {
+ this.slider.bind(MOUSEDOWN, events[DOWN]);
+ this.pane.bind(MOUSEDOWN, events[PANEDOWN]).bind("" + MOUSEWHEEL + " " + DOMSCROLL, events[WHEEL]);
+ }
+ this.$content.bind("" + SCROLL + " " + MOUSEWHEEL + " " + DOMSCROLL + " " + TOUCHMOVE, events[SCROLL]);
+ };
+
+ /**
+ Removes event listeners with jQuery.
+ @method removeEvents
+ @private
+ */
+
+
+ NanoScroll.prototype.removeEvents = function() {
+ var events;
+ events = this.events;
+ this.win.unbind(RESIZE, events[RESIZE]);
+ if (!this.iOSNativeScrolling) {
+ this.slider.unbind();
+ this.pane.unbind();
+ }
+ this.$content.unbind("" + SCROLL + " " + MOUSEWHEEL + " " + DOMSCROLL + " " + TOUCHMOVE, events[SCROLL]);
+ };
+
+ /**
+ Generates nanoScroller's scrollbar and elements for it.
+ @method generate
+ @chainable
+ @private
+ */
+
+
+ NanoScroll.prototype.generate = function() {
+ var contentClass, cssRule, options, paneClass, sliderClass;
+ options = this.options;
+ paneClass = options.paneClass, sliderClass = options.sliderClass, contentClass = options.contentClass;
+ if (!this.$el.find("" + paneClass).length && !this.$el.find("" + sliderClass).length) {
+ this.$el.append("
");
+ }
+ this.pane = this.$el.children("." + paneClass);
+ this.slider = this.pane.find("." + sliderClass);
+ if (BROWSER_SCROLLBAR_WIDTH) {
+ cssRule = this.$el.css('direction') === 'rtl' ? {
+ left: -BROWSER_SCROLLBAR_WIDTH
+ } : {
+ right: -BROWSER_SCROLLBAR_WIDTH
+ };
+ this.$el.addClass('has-scrollbar');
+ }
+ if (cssRule != null) {
+ this.$content.css(cssRule);
+ }
+ return this;
+ };
+
+ /**
+ @method restore
+ @private
+ */
+
+
+ NanoScroll.prototype.restore = function() {
+ this.stopped = false;
+ this.pane.show();
+ this.addEvents();
+ };
+
+ /**
+ Resets nanoScroller's scrollbar.
+ @method reset
+ @chainable
+ @example
+ $(".nano").nanoScroller();
+ */
+
+
+ NanoScroll.prototype.reset = function() {
+ var content, contentHeight, contentStyle, contentStyleOverflowY, paneBottom, paneHeight, paneOuterHeight, paneTop, sliderHeight;
+ if (this.iOSNativeScrolling) {
+ this.contentHeight = this.content.scrollHeight;
+ return;
+ }
+ if (!this.$el.find("." + this.options.paneClass).length) {
+ this.generate().stop();
+ }
+ if (this.stopped) {
+ this.restore();
+ }
+ content = this.content;
+ contentStyle = content.style;
+ contentStyleOverflowY = contentStyle.overflowY;
+ if (BROWSER_IS_IE7) {
+ this.$content.css({
+ height: this.$content.height()
+ });
+ }
+ contentHeight = content.scrollHeight + BROWSER_SCROLLBAR_WIDTH;
+ paneHeight = this.pane.outerHeight();
+ paneTop = parseInt(this.pane.css('top'), 10);
+ paneBottom = parseInt(this.pane.css('bottom'), 10);
+ paneOuterHeight = paneHeight + paneTop + paneBottom;
+ sliderHeight = Math.round(paneOuterHeight / contentHeight * paneOuterHeight);
+ if (sliderHeight < this.options.sliderMinHeight) {
+ sliderHeight = this.options.sliderMinHeight;
+ } else if ((this.options.sliderMaxHeight != null) && sliderHeight > this.options.sliderMaxHeight) {
+ sliderHeight = this.options.sliderMaxHeight;
+ }
+ if (contentStyleOverflowY === SCROLL && contentStyle.overflowX !== SCROLL) {
+ sliderHeight += BROWSER_SCROLLBAR_WIDTH;
+ }
+ this.maxSliderTop = paneOuterHeight - sliderHeight;
+ this.contentHeight = contentHeight;
+ this.paneHeight = paneHeight;
+ this.paneOuterHeight = paneOuterHeight;
+ this.sliderHeight = sliderHeight;
+ this.slider.height(sliderHeight);
+ this.events.scroll();
+ this.pane.show();
+ this.isActive = true;
+ if ((content.scrollHeight === content.clientHeight) || (this.pane.outerHeight(true) >= content.scrollHeight && contentStyleOverflowY !== SCROLL)) {
+ this.pane.hide();
+ this.isActive = false;
+ } else if (this.el.clientHeight === content.scrollHeight && contentStyleOverflowY === SCROLL) {
+ this.slider.hide();
+ } else {
+ this.slider.show();
+ }
+ this.pane.css({
+ opacity: (this.options.alwaysVisible ? 1 : ''),
+ visibility: (this.options.alwaysVisible ? 'visible' : '')
+ });
+ return this;
+ };
+
+ /**
+ @method scroll
+ @private
+ @example
+ $(".nano").nanoScroller({ scroll: 'top' });
+ */
+
+
+ NanoScroll.prototype.scroll = function() {
+ if (!this.isActive) {
+ return;
+ }
+ this.sliderY = Math.max(0, this.sliderY);
+ this.sliderY = Math.min(this.maxSliderTop, this.sliderY);
+ this.$content.scrollTop((this.paneHeight - this.contentHeight + BROWSER_SCROLLBAR_WIDTH) * this.sliderY / this.maxSliderTop * -1);
+ if (!this.iOSNativeScrolling) {
+ this.slider.css({
+ top: this.sliderY
+ });
+ }
+ return this;
+ };
+
+ /**
+ Scroll at the bottom with an offset value
+ @method scrollBottom
+ @param offsetY {Number}
+ @chainable
+ @example
+ $(".nano").nanoScroller({ scrollBottom: value });
+ */
+
+
+ NanoScroll.prototype.scrollBottom = function(offsetY) {
+ if (!this.isActive) {
+ return;
+ }
+ this.reset();
+ this.$content.scrollTop(this.contentHeight - this.$content.height() - offsetY).trigger(MOUSEWHEEL);
+ return this;
+ };
+
+ /**
+ Scroll at the top with an offset value
+ @method scrollTop
+ @param offsetY {Number}
+ @chainable
+ @example
+ $(".nano").nanoScroller({ scrollTop: value });
+ */
+
+
+ NanoScroll.prototype.scrollTop = function(offsetY) {
+ if (!this.isActive) {
+ return;
+ }
+ this.reset();
+ this.$content.scrollTop(+offsetY).trigger(MOUSEWHEEL);
+ return this;
+ };
+
+ /**
+ Scroll to an element
+ @method scrollTo
+ @param node {Node} A node to scroll to.
+ @chainable
+ @example
+ $(".nano").nanoScroller({ scrollTo: $('#a_node') });
+ */
+
+
+ NanoScroll.prototype.scrollTo = function(node) {
+ if (!this.isActive) {
+ return;
+ }
+ this.reset();
+ this.scrollTop($(node).get(0).offsetTop);
+ return this;
+ };
+
+ /**
+ To stop the operation.
+ This option will tell the plugin to disable all event bindings and hide the gadget scrollbar from the UI.
+ @method stop
+ @chainable
+ @example
+ $(".nano").nanoScroller({ stop: true });
+ */
+
+
+ NanoScroll.prototype.stop = function() {
+ this.stopped = true;
+ this.removeEvents();
+ this.pane.hide();
+ return this;
+ };
+
+ /**
+ To flash the scrollbar gadget for an amount of time defined in plugin settings (defaults to 1,5s).
+ Useful if you want to show the user (e.g. on pageload) that there is more content waiting for him.
+ @method flash
+ @chainable
+ @example
+ $(".nano").nanoScroller({ flash: true });
+ */
+
+
+ NanoScroll.prototype.flash = function() {
+ var _this = this;
+ if (!this.isActive) {
+ return;
+ }
+ this.reset();
+ this.pane.addClass('flashed');
+ setTimeout(function() {
+ _this.pane.removeClass('flashed');
+ }, this.options.flashDelay);
+ return this;
+ };
+
+ return NanoScroll;
+
+ })();
+ $.fn.nanoScroller = function(settings) {
+ return this.each(function() {
+ var options, scrollbar;
+ if (!(scrollbar = this.nanoscroller)) {
+ options = $.extend({}, defaults, settings);
+ this.nanoscroller = scrollbar = new NanoScroll(this, options);
+ }
+ if (settings && typeof settings === "object") {
+ $.extend(scrollbar.options, settings);
+ if (settings.scrollBottom) {
+ return scrollbar.scrollBottom(settings.scrollBottom);
+ }
+ if (settings.scrollTop) {
+ return scrollbar.scrollTop(settings.scrollTop);
+ }
+ if (settings.scrollTo) {
+ return scrollbar.scrollTo(settings.scrollTo);
+ }
+ if (settings.scroll === 'bottom') {
+ return scrollbar.scrollBottom(0);
+ }
+ if (settings.scroll === 'top') {
+ return scrollbar.scrollTop(0);
+ }
+ if (settings.scroll && settings.scroll instanceof $) {
+ return scrollbar.scrollTo(settings.scroll);
+ }
+ if (settings.stop) {
+ return scrollbar.stop();
+ }
+ if (settings.flash) {
+ return scrollbar.flash();
+ }
+ }
+ return scrollbar.reset();
+ });
+ };
+})(jQuery, window, document);
diff --git a/app/assets/javascripts/member-selection.js b/app/assets/javascripts/member-selection.js
new file mode 100644
index 000000000..8ea7c34dd
--- /dev/null
+++ b/app/assets/javascripts/member-selection.js
@@ -0,0 +1,25 @@
+$(document).ready(function() {
+ $(".select_user_modal").on('click', function(){
+ var ids = [];
+ var users = $(this).siblings('#selected_users').children('span.selected_user');
+ users.each(function(i) {
+ ids.push(users.eq(i).attr('user_id'));
+ });
+ $("#main-wrap").after("");
+ $.ajax({
+ type: 'GET',
+ url: $(this).attr("rel"),
+ dataType: 'script',
+ data: {field: $(this).attr("field"), ids: ids},
+ success: function (msg) {
+ $("#select_user_modal").modal('show'); },
+ error: function(){
+ alert("ERROR");
+ }
+ });
+ return false;
+ });
+ $(document).on('click', ".remove_user", function(){
+ $(this).parent().remove();
+ });
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/tinymce_orbit.js.erb b/app/assets/javascripts/tinymce_orbit.js.erb
index d73d77682..51d7ffe62 100644
--- a/app/assets/javascripts/tinymce_orbit.js.erb
+++ b/app/assets/javascripts/tinymce_orbit.js.erb
@@ -9,7 +9,7 @@ function load_tinymce() {
// Theme options
theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontselect,fontsizeselect",
theme_advanced_buttons2 : "cut,copy,paste,pastetext,pasteword,|,bullist,numlist,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,forecolor,backcolor",
- theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,fullscreen",
+ theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,fullscreen,|,template",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
@@ -20,7 +20,7 @@ function load_tinymce() {
skin_variant : "silver",
font_size_style_values : "xx-small,x-small,small,medium,large,x-large,xx-large",
// Drop lists for link/image/media/template dialogs
- template_external_list_url : "js/template_list.js",
+ template_external_list_url : "/tinymce/lists/template_list.js",
// external_link_list_url : "js/link_list.js",
// external_image_list_url : "js/image_list.js",
// media_external_list_url : "js/media_list.js"
diff --git a/app/assets/stylesheets/member_select.css b/app/assets/stylesheets/member_select.css
new file mode 100644
index 000000000..891a4f336
--- /dev/null
+++ b/app/assets/stylesheets/member_select.css
@@ -0,0 +1,230 @@
+/* Member Filter */
+#select_user #select_user_modal.modal {
+ width: 80%;
+ margin-left: -40%;
+}
+#select_user #select_user_modal .modal-body {
+ max-height: 425px;
+}
+#select_user #select_user_modal .modal-body form {
+ margin-bottom: 0px;
+}
+#select_user #select_user_modal .modal-body form fieldset {
+ min-height: 360px;
+}
+#select_user #select_user_modal .modal-body .radio.inline,
+#select_user #select_user_modal .modal-body .checkbox.inline {
+ display: inline-block;
+ padding-top: 5px;
+ margin-bottom: 0;
+ vertical-align: middle;
+ min-width: 100px;
+ margin-left: 0;
+}
+#select_user #select_user_modal .modal-body .form-actions {
+ margin: 20px 0 0;
+ padding: 10px 0 0;
+ background-color: transparent;
+ text-align: right;
+}
+#select_user #select_user_modal .modal-body .tabs-left > .nano {
+ width: 160px;
+ min-height: 425px;
+ float: left;
+}
+#select_user #select_user_modal .modal-body .tabs-left > .nano .pane {
+ right: 6px;
+}
+#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs {
+ width: 140px;
+ float: left;
+ margin-bottom: 0;
+ margin-right: 0;
+ border-right: 1px solid #ddd;
+ border-bottom: none;
+}
+#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs > li {
+ float: none;
+}
+#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs > li > a {
+ min-width: 74px;
+ margin-right: 0;
+ margin-bottom: 3px;
+}
+#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs > li > a {
+ margin-right: -1px;
+ -webkit-border-radius: 4px 0 0 4px;
+ -moz-border-radius: 4px 0 0 4px;
+ border-radius: 4px 0 0 4px;
+}
+#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs > li > a:hover {
+ border-color: #eeeeee #dddddd #eeeeee #eeeeee;
+}
+#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs .active > a,
+#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs .active > a:hover {
+ border-color: #ddd transparent #ddd #ddd;
+ *border-right-color: #ffffff;
+}
+#select_user #select_user_modal .member-filter-options {
+ float: left;
+ display: inline-block;
+ width: 175px;
+ min-height: 425px;
+ margin-right: 10px;
+ padding: 0 10px 0 0;
+}
+#select_user #select_user_modal .member-filter-options select {
+ width: 165px;
+}
+#select_user #select_user_modal .member-filter-options .btn {
+ display: block;
+}
+#select_user #select_user_modal .member-filter-result {
+ padding-left: 15px;
+ min-height: 360px;
+ width: auto;
+}
+
+
+/* Check Box Card */
+.checkbox-card {
+ margin: 0;
+}
+.checkbox-card li {
+ position: relative;
+ list-style: none;
+ color: #FFFFFF;
+ width: 180px;
+ height: 40px;
+ margin: 0 10px 10px 0;
+ float: left;
+ display: inline-block;
+ background-color: #cccccc;
+ overflow: hidden;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-transition: all .2s linear;
+ -moz-transition: all .2s linear;
+ -o-transition: all .2s linear;
+ transition: all .2s linear;
+}
+.checkbox-card li.mark {
+ width: 0;
+ height: 0;
+ padding: 0;
+ margin: 0;
+ -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
+ filter: alpha(opacity=0);
+ opacity: 0;
+ visibility: hidden;
+}
+.checkbox-card li:hover {
+ background-color: #0088cc;
+}
+.checkbox-card li:after {
+ content: "";
+ display: block;
+ clear: both;
+ height: 0;
+ visibility: hidden;
+}
+.checkbox-card li.active:before {
+ -webkit-text-size-adjust : none;
+ font-family: FontAwesome;
+ font-weight: normal;
+ font-style: normal;
+ color: #FFF;
+ text-decoration: inherit;
+ content: "\f00c";
+ position: absolute;
+ right: 0px;
+ top: 0px;
+ line-height: 14px;
+ text-indent: 10px;
+ font-size: 10px;
+ width: 0px;
+ height: 0px;
+ border-style: solid;
+ border-width: 0 22px 22px 0;
+ border-color: transparent #51a351 transparent transparent;
+}
+.checkbox-card li.active label {
+}
+.checkbox-card li label {
+ margin-bottom: 0px;
+ overflow: hidden;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+.checkbox-card li input {
+ opacity: 0;
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ margin: 0;
+ z-index: 10;
+}
+.checkbox-card li label span {
+ -webkit-text-size-adjust : none;
+ font-size: 10px;
+ display: block;
+ width: 130px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ color: #666666;
+ margin-top: -3px;
+}
+.checkbox-card li:hover label span,
+.checkbox-card li:hover label span.user-name {
+ color: #FFFFFF;
+}
+.checkbox-card li label span.user-name {
+ font-size: 12px;
+ color: #363636;
+ padding: 2px 0 0;
+ margin-top: 0;
+}
+.checkbox-card li .user-pic {
+ float: left;
+ margin-right: 5px;
+ width: 40px;
+ height: 40px;
+}
+#selected_users .selected_user {
+ display: block;
+ margin-bottom: 5px;
+}
+#selected_users .selected_user .remove_user {
+ font-size: 15px;
+}
+/*
+.promoter {
+ border-color: #CCCCCC;
+ border-style: solid;
+ border-width: 0 1px;
+ padding: 0 10px 5px 10px;
+}
+.promoter > div {
+ border-bottom: 1px solid #CCCCCC;
+}
+.promoter > div:after {
+ content: "";
+ clear: both;
+ display: block;
+ visibility: hidden;
+}
+.promoter > div > span {
+ display: block;
+ margin-left: 70px;
+ padding-bottom: 5px;
+}
+.promoter p {
+ width: 70px;
+ float: left;
+ text-align:right;
+}*/
\ No newline at end of file
diff --git a/app/assets/stylesheets/style.css.erb b/app/assets/stylesheets/style.css.erb
index d28c86e1c..f238f3497 100644
--- a/app/assets/stylesheets/style.css.erb
+++ b/app/assets/stylesheets/style.css.erb
@@ -1,5 +1,7 @@
/*style*/
-
+* {
+ outline: none;
+}
@font-face{
font-family: 'WebSymbolsRegular';
src: url(<%= asset_path 'websymbols-regular-webfont.eot' %>);
diff --git a/app/controllers/admin/member_selects_controller.rb b/app/controllers/admin/member_selects_controller.rb
index 9d7e6643d..40bb6dd90 100644
--- a/app/controllers/admin/member_selects_controller.rb
+++ b/app/controllers/admin/member_selects_controller.rb
@@ -70,4 +70,30 @@ class Admin::MemberSelectsController < OrbitBackendController
end
+ def select_members
+ selected_users = User.find(params[:ids]) rescue []
+ @field = params[:field]
+ roles = Role.all
+ @sorted_users = roles.inject({}) do |users, role|
+ users[role] = role.users.where(:email.not => /guest|rulingcom/) - selected_users
+ users
+ end
+ end
+
+ def set_roles
+ roles = Role.find(params[:role_ids]) rescue []
+ @field = params[:field]
+ @users = roles.inject([]) do |users, role|
+ users += role.users.where(:email.not => /guest|rulingcom/).entries
+ users
+ end
+ render 'admin/member_selects/update_selected_users'
+ end
+
+ def set_users
+ @users = User.find(params[:user_ids]) rescue []
+ @field = params[:field]
+ render 'admin/member_selects/update_selected_users'
+ end
+
end
diff --git a/app/controllers/saml_logins_controller.rb b/app/controllers/saml_logins_controller.rb
new file mode 100644
index 000000000..23ecd8191
--- /dev/null
+++ b/app/controllers/saml_logins_controller.rb
@@ -0,0 +1,36 @@
+class SamlLoginsController < ApplicationController
+
+ require "net/http"
+ require "uri"
+ require 'rexml/document'
+ include REXML
+
+ def index
+
+ if params[:wa] == "wsignoutcleanup1.0" #logout
+
+ redirect_to :root
+
+ else #login
+
+
+ @wresult = params[:wresult]
+ @wctx = params[:wctx]
+
+ @main_url = LIST[:sites][@wctx]['url']
+ @main_public_key = LIST[:sites][@wctx]['key']
+
+ @doc = REXML::Document.new @wresult
+
+ @main_public_key = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzKawlFWAMzA/uV/kcewd\nmtj8PcqxosmnSh7ZzJ0DumG2ieeP9oDBicqbqIEaeJVvrRzYJD2a+u8x5KKMKB8J\nHbMUpCBFlIpkDMjU/oZVMcYT9pcH51QWNvCgHG7prVykSGFz1JRvjSP6cwuZKBFd\nFFneOViETqoMIO1DbRLXsGfPvMOJY9C1xDwv1dLv0Wbj7M9N6eNz06a50bu3I4gl\nMumxWnZUabXL3G62S/Si4NM7J2jOUnkEOxJWOhcAX/iiqS9T8AHu84um2+mLQpfB\nJJFFIWCIAtU78VnIN5JSWwjFU5TsiSyCFYpGXKxUFD25cFmt3SfG0gwmrFis5Pdn\nhwIDAQAB\n-----END PUBLIC KEY-----\n"
+
+ public_key = OpenSSL::PKey::RSA.new(@main_public_key)
+ encrypted_data = public_key.public_encrypt(@doc.elements["//saml:AttributeValue"].text)
+
+ redirect_to "http://#{@main_url}/user_login?" + { :wresult => encrypted_data }.to_param
+
+ end
+
+ end
+
+end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
new file mode 100644
index 000000000..927719bc2
--- /dev/null
+++ b/app/controllers/sessions_controller.rb
@@ -0,0 +1,40 @@
+# encoding: utf-8
+
+class SessionsController < Devise::SessionsController
+ prepend_before_filter :require_no_authentication, :only => [ :new, :create ]
+
+
+ def create
+ @site = Site.first
+
+ private_key = OpenSSL::PKey::RSA.new(@site.private_key)
+ wresult = private_key.private_decrypt(request.params['wresult'])
+
+ @ids = wresult.split("@")
+
+ login_uid = @ids[0]
+
+ resource = User.first(conditions:{user_id: login_uid})
+
+ if !resource.blank?
+ resource_name = resource.class.to_s.downcase
+ sign_in(resource_name, resource)
+ session[:user_id_type] = "myntu"
+ redirect_to after_sign_in_path_for(resource)
+ else
+ flash[:error] = "很抱歉,您無此權限或帳號登入本站,請洽本站管理員
Sorry, you don't have the account or authority to login. Please contact the website administrator."
+ redirect_to :root
+ end
+ end
+
+ def destroy
+ @user_id_type = session[:user_id_type]
+ sign_out
+ if @user_id_type == "myntu"
+ redirect_to "https://adfs.ntu.edu.tw/adfs/ls/?wa=wsignout1.0&wreply=https://galogin.ntu.edu.tw"
+ else
+ redirect_to root_path
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 4f52935fa..0d2d48d7c 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -303,7 +303,7 @@ module ApplicationHelper
# NTU link
def get_link(site_number)
- "http://#{request.host}:2#{site_number}00"
+ "http://#{site_number}.#{request.domain(3)}"
end
def sortable(column, title = nil, options = {})
diff --git a/app/models/user/role.rb b/app/models/user/role.rb
index e1e50d9aa..74b2839b3 100644
--- a/app/models/user/role.rb
+++ b/app/models/user/role.rb
@@ -10,7 +10,7 @@ class Role < Attribute
field :title, localize: true
has_many :sub_roles, :autosave => true, :dependent => :destroy
- has_many :users
+ has_and_belongs_to_many :users
# has_many :statuses, :autosave => true, :dependent => :destroy
# has_many :attribute_fields, :autosave => true, :dependent => :destroy
has_many :role_statuses, :autosave => true, :dependent => :destroy
diff --git a/app/views/admin/member_selects/_modal_select.html.erb b/app/views/admin/member_selects/_modal_select.html.erb
new file mode 100644
index 000000000..4616f0b1e
--- /dev/null
+++ b/app/views/admin/member_selects/_modal_select.html.erb
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+ <%= form_tag set_roles_admin_member_selects_path(field: @field), remote: true do %>
+
+
+
+ <%= submit_tag t(:submit), class: "btn btn-primary" %>
+
+ <% end %>
+
+ <% @sorted_users.each do |role, users| %>
+
+ <%= form_tag set_users_admin_member_selects_path(field: @field), remote: true do %>
+
+ <% end %>
+
+ <% end %>
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/views/admin/member_selects/_promoter_front.html.erb b/app/views/admin/member_selects/_promoter_front.html.erb
new file mode 100644
index 000000000..f8bec0fb6
--- /dev/null
+++ b/app/views/admin/member_selects/_promoter_front.html.erb
@@ -0,0 +1,14 @@
+<% unless users.blank? %>
+
+<% end %>
\ No newline at end of file
diff --git a/app/views/admin/member_selects/_selection_box.html.erb b/app/views/admin/member_selects/_selection_box.html.erb
new file mode 100644
index 000000000..c54929aa7
--- /dev/null
+++ b/app/views/admin/member_selects/_selection_box.html.erb
@@ -0,0 +1,16 @@
+<% content_for :page_specific_javascript do -%>
+ <%= javascript_include_tag "member-selection" %>
+ <%= javascript_include_tag "lib/jquery.nanoscroller" %>
+ <%= javascript_include_tag "lib/checkbox.card" %>
+<% end -%>
+<% content_for :page_specific_css do -%>
+ <%= stylesheet_link_tag "member_select" %>
+<% end %>
+
+
+
+ <%= render partial: 'admin/member_selects/user', collection: users, locals: {field: field} %>
+ <%= hidden_field_tag field %>
+
+ <%= link_to t(:add), '#', class: 'btn btn-primary btn-small select_user_modal', rel: select_members_admin_member_selects_path, field: field %>
+
\ No newline at end of file
diff --git a/app/views/admin/member_selects/_user.html.erb b/app/views/admin/member_selects/_user.html.erb
new file mode 100644
index 000000000..827c5c75b
--- /dev/null
+++ b/app/views/admin/member_selects/_user.html.erb
@@ -0,0 +1,5 @@
+
+ <%= user.name %>
+ <%= hidden_field_tag field, user.id %>
+ <%= content_tag :span, '×', class: 'close remove_user' %>
+
\ No newline at end of file
diff --git a/app/views/admin/member_selects/select_members.js.erb b/app/views/admin/member_selects/select_members.js.erb
new file mode 100644
index 000000000..62d7607d7
--- /dev/null
+++ b/app/views/admin/member_selects/select_members.js.erb
@@ -0,0 +1,2 @@
+$("#select_user").html("<%= j render partial: 'admin/member_selects/modal_select', locals: {field: 'bulletin[user_ids][]'} %>");
+$("#select_user_modal").modal();
\ No newline at end of file
diff --git a/app/views/admin/member_selects/update_selected_users.js.erb b/app/views/admin/member_selects/update_selected_users.js.erb
new file mode 100644
index 000000000..d69be303e
--- /dev/null
+++ b/app/views/admin/member_selects/update_selected_users.js.erb
@@ -0,0 +1,2 @@
+$("#selected_users").append("<%= j render partial: 'user', collection: @users, locals: {field: @field} %>");
+$("#select_user_modal").modal('hide');
\ No newline at end of file
diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb
index 71bd12f46..8a4b8b3eb 100644
--- a/app/views/devise/sessions/new.html.erb
+++ b/app/views/devise/sessions/new.html.erb
@@ -9,15 +9,20 @@
<%= content_tag :span, msg, :class => [key, "notice label label-warning"] %>
<% end %>
You need to sign in or sign up before continuing.
+ <% @request_hosts = request.host_with_port.split(".") %>
+ 使用計中帳號登入
+
+ 或使用本站帳號登入
+
<%= f.label :user_id ,t("users.user_id")%>
- <%= f.text_field :user_id, :placeholder => t("users.user_id"), :style => "width: 330px;" %>
+ <%= f.text_field :user_id, :placeholder => t("users.user_id"), :style => "width: 326px;" %>
Please correct the error
<%= f.label :password,t("password") %>
- <%= f.password_field :password, :placeholder => t(:dots), :style => "width: 330px;" %>
+ <%= f.password_field :password, :placeholder => t(:dots), :style => "width: 326px;" %>
Please correct the error
<%= link_to t(:forgot_password), new_user_password_path, :class => 'pull-right forgot hide' %>
diff --git a/app/views/layouts/_orbit_bar.html.erb b/app/views/layouts/_orbit_bar.html.erb
index 52deb8e7e..ef1a87bcd 100644
--- a/app/views/layouts/_orbit_bar.html.erb
+++ b/app/views/layouts/_orbit_bar.html.erb
@@ -10,19 +10,10 @@
-
+
-
+
+
-
+
+
+
+
+
-
@@ -53,7 +55,7 @@