Create Custom Announcement plugin.

This commit is contained in:
BoHung Chiu 2021-06-17 18:52:39 +08:00
commit ddf868fb2f
191 changed files with 13554 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
.bundle/
log/*.log
pkg/
test/dummy/db/*.sqlite3
test/dummy/db/*.sqlite3-journal
test/dummy/log/*.log
test/dummy/tmp/
test/dummy/.sass-cache

14
Gemfile Normal file
View File

@ -0,0 +1,14 @@
source "https://rubygems.org"
# Declare your gem's dependencies in custom_bulletin.gemspec.
# Bundler will treat runtime dependencies like base dependencies, and
# development dependencies will be added by default to the :development group.
gemspec
# Declare any dependencies that are still in development here instead of in
# your gemspec. These might include edge Rails or gems from your path or
# Git. Remember to move these dependencies to your gemspec before releasing
# your gem to rubygems.org.
# To use debugger
# gem 'debugger'

106
Gemfile.lock Normal file
View File

@ -0,0 +1,106 @@
PATH
remote: .
specs:
custom_announcement (0.0.1)
mongoid (= 4.0.0.beta1)
rails (~> 4.1.0.rc2)
GEM
remote: https://rubygems.org/
specs:
actionmailer (4.1.0.rc2)
actionpack (= 4.1.0.rc2)
actionview (= 4.1.0.rc2)
mail (~> 2.5.4)
actionpack (4.1.0.rc2)
actionview (= 4.1.0.rc2)
activesupport (= 4.1.0.rc2)
rack (~> 1.5.2)
rack-test (~> 0.6.2)
actionview (4.1.0.rc2)
activesupport (= 4.1.0.rc2)
builder (~> 3.1)
erubis (~> 2.7.0)
activemodel (4.1.0.rc2)
activesupport (= 4.1.0.rc2)
builder (~> 3.1)
activerecord (4.1.0.rc2)
activemodel (= 4.1.0.rc2)
activesupport (= 4.1.0.rc2)
arel (~> 5.0.0)
activesupport (4.1.0.rc2)
i18n (~> 0.6, >= 0.6.9)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.1)
tzinfo (~> 1.1)
arel (5.0.0)
atomic (1.1.16)
bson (2.2.1)
builder (3.2.2)
connection_pool (2.0.0)
erubis (2.7.0)
hike (1.2.3)
i18n (0.6.9)
json (1.8.1)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mime-types (1.25.1)
minitest (5.3.1)
mongoid (4.0.0.beta1)
activemodel (>= 4.0.0)
moped (~> 2.0.beta6)
origin (~> 2.1)
tzinfo (>= 0.3.37)
moped (2.0.0.rc1)
bson (~> 2.2)
connection_pool (~> 2.0)
optionable (~> 0.2.0)
multi_json (1.9.2)
optionable (0.2.0)
origin (2.1.1)
polyglot (0.3.4)
rack (1.5.2)
rack-test (0.6.2)
rack (>= 1.0)
rails (4.1.0.rc2)
actionmailer (= 4.1.0.rc2)
actionpack (= 4.1.0.rc2)
actionview (= 4.1.0.rc2)
activemodel (= 4.1.0.rc2)
activerecord (= 4.1.0.rc2)
activesupport (= 4.1.0.rc2)
bundler (>= 1.3.0, < 2.0)
railties (= 4.1.0.rc2)
sprockets-rails (~> 2.0.0)
railties (4.1.0.rc2)
actionpack (= 4.1.0.rc2)
activesupport (= 4.1.0.rc2)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (10.2.2)
sprockets (2.12.0)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.0.1)
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (~> 2.8)
thor (0.19.1)
thread_safe (0.3.1)
atomic (>= 1.1.7, < 2)
tilt (1.4.1)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
tzinfo (1.1.0)
thread_safe (~> 0.1)
PLATFORMS
ruby
DEPENDENCIES
custom_announcement!

20
MIT-LICENSE Normal file
View File

@ -0,0 +1,20 @@
Copyright 2014 YOURNAME
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
README.rdoc Normal file
View File

@ -0,0 +1,3 @@
= CustomBulletin
This project rocks and uses MIT-LICENSE.

32
Rakefile Normal file
View File

@ -0,0 +1,32 @@
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end
require 'rdoc/task'
RDoc::Task.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'CustomAnnouncement'
rdoc.options << '--line-numbers'
rdoc.rdoc_files.include('README.rdoc')
rdoc.rdoc_files.include('lib/**/*.rb')
end
Bundler::GemHelper.install_tasks
require 'rake/testtask'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = false
end
task default: :test

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

View File

@ -0,0 +1,2 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -0,0 +1,9 @@
( function( $ ) {
'use strict';
$( document ).on( 'ready', function() {
var $settings = wpexAnimsition;
$settings.inDuration = parseInt( $settings.inDuration );
$settings.outDuration = parseInt( $settings.outDuration );
$( 'body' ).animsition( $settings );
} );
} ) ( jQuery );

View File

@ -0,0 +1,115 @@
/*!
* animsition v4.0.2
* A simple and easy jQuery plugin for CSS animated page transitions.
* http://blivesta.github.io/animsition
* License : MIT
* Author : blivesta (http://blivesta.com/)
*/
!function (t) {
"use strict";
"function" == typeof define && define.amd ? define(["jquery"], t) : "object" == typeof exports ? module.exports = t(require("jquery")) : t(jQuery)
}(function (t) {
"use strict";
var n = "animsition",
i = {
init: function (a) {
a = t.extend({ inClass: "fade-in",
outClass: "fade-out",
inDuration: 1500,
outDuration: 800,
linkElement: ".animsition-link",
loading: !0,
loadingParentElement: "body",
loadingClass: "animsition-loading",
loadingInner: "",
timeout: !1,
timeoutCountdown: 5e3,
onLoadEvent: !0,
browser: ["animation-duration", "-webkit-animation-duration"],
overlay: !1,
overlayClass: "animsition-overlay-slide",
overlayParentElement: "body",
transition: function (t) { window.location.href = t } }, a),
i.settings = { timer: !1,
data: { inClass: "animsition-in-class",
inDuration: "animsition-in-duration",
outClass: "animsition-out-class",
outDuration: "animsition-out-duration", overlay: "animsition-overlay"
},
events: { inStart: "animsition.inStart",
inEnd: "animsition.inEnd",
outStart: "animsition.outStart",
outEnd: "animsition.outEnd"
}
};
var o = i.supportCheck.call(this, a);
if (!o && a.browser.length > 0 && (!o || !this.length))
return "console" in window || (window.console = {}, window.console.log = function (t) { return t }), this.length || console.log("Animsition: Element does not exist on page."), o || console.log("Animsition: Does not support this browser."), i.destroy.call(this); var e = i.optionCheck.call(this, a); return e && t("." + a.overlayClass).length <= 0 && i.addOverlay.call(this, a), a.loading && t("." + a.loadingClass).length <= 0 && i.addLoading.call(this, a), this.each(function () { var o = this, e = t(this), s = t(window), r = t(document), l = e.data(n); l || (a = t.extend({}, a), e.data(n, { options: a }), a.timeout && i.addTimer.call(o), a.onLoadEvent && s.on("load." + n, function () { i.settings.timer && clearTimeout(i.settings.timer), i["in"].call(o) }), s.on("pageshow." + n, function (t) { t.originalEvent.persisted && i["in"].call(o) }), s.on("unload." + n, function () { }), r.on("click." + n, a.linkElement, function (n) { n.preventDefault(); var a = t(this), e = a.attr("href"); 2 === n.which || n.metaKey || n.shiftKey || -1 !== navigator.platform.toUpperCase().indexOf("WIN") && n.ctrlKey ? window.open(e, "_blank") : i.out.call(o, a, e) })) })
}, addOverlay: function (n) {
t(n.overlayParentElement).prepend('<div class="' + n.overlayClass + '"></div>')
}, addLoading: function (n) {
t(n.loadingParentElement).append('<div class="' + n.loadingClass + '">' + n.loadingInner + "</div>")
}, removeLoading: function () {
var i = t(this), a = i.data(n).options, o = t(a.loadingParentElement).children("." + a.loadingClass);
o.fadeOut().remove()
}, addTimer: function () {
var a = this, o = t(this),
e = o.data(n).options;
i.settings.timer = setTimeout(function () {
i["in"].call(a), t(window).off("load." + n) }, e.timeoutCountdown)
}, supportCheck: function (n) {
var i = t(this), a = n.browser, o = a.length, e = !1;
0 === o && (e = !0);
for (var s = 0; o > s; s++)
if ("string" == typeof i.css(a[s])) {
e = !0; break
}
return e
}, optionCheck: function (n) {
var a, o = t(this);
return a = n.overlay || o.data(i.settings.data.overlay) ? !0 : !1
}, animationCheck: function (i, a, o) {
var e = t(this), s = e.data(n).options,
r = typeof i, l = !a && "number" === r,
d = a && "string" === r && i.length > 0;
return l || d ? i = i : a && o ? i = s.inClass : !a && o ? i = s.inDuration : a && !o ? i = s.outClass : a || o || (i = s.outDuration), i
}, "in": function () {
var a = this, o = t(this), e = o.data(n).options,
s = o.data(i.settings.data.inDuration), r = o.data(i.settings.data.inClass),
l = i.animationCheck.call(a, s, !1, !0), d = i.animationCheck.call(a, r, !0, !0),
u = i.optionCheck.call(a, e), c = o.data(n).outClass;
e.loading && i.removeLoading.call(a), c && o.removeClass(c), u ? i.inOverlay.call(a, d, l) : i.inDefault.call(a, d, l)
}, inDefault: function (n, a) {
var o = t(this); o.css({ "animation-duration": a + "ms" }).addClass(n).trigger(i.settings.events.inStart).animateCallback(function () { o.removeClass(n).css({ opacity: 1 }).trigger(i.settings.events.inEnd) })
}, inOverlay: function (a, o) {
var e = t(this), s = e.data(n).options;
e.css({ opacity: 1 }).trigger(i.settings.events.inStart),
t(s.overlayParentElement).children("." + s.overlayClass).css({ "animation-duration": o + "ms" }).addClass(a).animateCallback(function () { e.trigger(i.settings.events.inEnd) })
}, out: function (a, o) {
var e = this, s = t(this), r = s.data(n).options, l = a.data(i.settings.data.outClass), d = s.data(i.settings.data.outClass), u = a.data(i.settings.data.outDuration), c = s.data(i.settings.data.outDuration), m = l ? l : d, g = u ? u : c, f = i.animationCheck.call(e, m, !0, !1), v = i.animationCheck.call(e, g, !1, !1), h = i.optionCheck.call(e, r); s.data(n).outClass = f, h ? i.outOverlay.call(e, f, v, o) : i.outDefault.call(e, f, v, o)
}, outDefault: function (a, o, e) {
var s = t(this), r = s.data(n).options;
s.css({ "animation-duration": o + 1 + "ms" }).addClass(a).trigger(i.settings.events.outStart).animateCallback(function () {
s.trigger(i.settings.events.outEnd), r.transition(e)
})
}, outOverlay: function (a, o, e) {
var s = this, r = t(this), l = r.data(n).options,
d = r.data(i.settings.data.inClass), u = i.animationCheck.call(s, d, !0, !0);
t(l.overlayParentElement).children("." + l.overlayClass).css({ "animation-duration": o + 1 + "ms" }).removeClass(u).addClass(a).trigger(i.settings.events.outStart).animateCallback(function () {
r.trigger(i.settings.events.outEnd), l.transition(e) })
}, destroy: function () {
return this.each(function () {
var i = t(this); t(window).off("." + n), i.css({ opacity: 1 }).removeData(n)
})
}
};
t.fn.animateCallback = function (n) {
var i = "animationend webkitAnimationEnd";
return this.each(function () {
var a = t(this); a.on(i, function () { return a.off(i), n.call(this) })
})
},
t.fn.animsition = function (a) {
return i[a] ? i[a].apply(this, Array.prototype.slice.call(arguments, 1)) : "object" != typeof a && a ? void t.error("Method " + a + " does not exist on jQuery." + n) : i.init.apply(this, arguments)
}
});

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,21 @@
$(document).ready(function() {
var config = {}
config.autoGrow_minHeight = 50;
config.allowedContent = false;
config.disallowedContent = 'img';
config.toolbar = [
{ name: 'clipboard', items: [ 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo' ] },
{ name: 'editing', items: [ 'Find', 'Replace', '-', 'SelectAll', '-', 'Scayt' ] },
{ name: 'basicstyles', items: [ 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'CopyFormatting', 'RemoveFormat' ] },
'/',
{ name: 'insert', items: [ 'SpecialChar'] },
{ name: 'styles', items: [ 'Font' ] },
{ name: 'colors', items: [ 'TextColor', 'BGColor' ] }
];
var ckeditor_reduce = $('.ckeditor_reduce')
ckeditor_reduce.each(function(i,v){
CKEDITOR.replace(v,config);
})
});

View File

@ -0,0 +1,7 @@
/*
Place all the styles related to the matching controller here.
They will automatically be included in application.css.
*/
.table .expired{
color: #BE2E2E;
}

View File

@ -0,0 +1,947 @@
//
// Mixins
// --------------------------------------------------
// Utilities
// -------------------------
// Clearfix
// Source: http://nicolasgallagher.com/micro-clearfix-hack/
//
// For modern browsers
// 1. The space content is one way to avoid an Opera bug when the
// contenteditable attribute is included anywhere else in the document.
// Otherwise it causes space to appear at the top and bottom of elements
// that are clearfixed.
// 2. The use of `table` rather than `block` is only necessary if using
// `:before` to contain the top-margins of child elements.
@mixin clearfix() {
&:before,
&:after {
content: " "; // 1
display: table; // 2
}
&:after {
clear: both;
}
}
// WebKit-style focus
@mixin tab-focus() {
// Default
outline: thin dotted;
// WebKit
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
// Center-align a block level element
@mixin center-block() {
display: block;
margin-left: auto;
margin-right: auto;
}
// Sizing shortcuts
@mixin size($width, $height) {
width: $width;
height: $height;
}
@mixin square($size) {
@include size($size, $size);
}
// Placeholder text
@mixin placeholder($color: $input-color-placeholder) {
&::-moz-placeholder { color: $color; // Firefox
opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526
&:-ms-input-placeholder { color: $color; } // Internet Explorer 10+
&::-webkit-input-placeholder { color: $color; } // Safari and Chrome
}
// Text overflow
// Requires inline-block or block for proper styling
@mixin text-overflow() {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
// CSS image replacement
//
// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for
// mixins being reused as classes with the same name, this doesn't hold up. As
// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. Note
// that we cannot chain the mixins together in Less, so they are repeated.
//
// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757
// Deprecated as of v3.0.1 (will be removed in v4)
@mixin hide-text() {
font: #{0/0} a;
color: transparent;
text-shadow: none;
background-color: transparent;
border: 0;
}
// New mixin to use as of v3.0.1
@mixin text-hide() {
@include hide-text();
}
// CSS3 PROPERTIES
// --------------------------------------------------
// Single side border-radius
@mixin border-top-radius($radius) {
border-top-right-radius: $radius;
border-top-left-radius: $radius;
}
@mixin border-right-radius($radius) {
border-bottom-right-radius: $radius;
border-top-right-radius: $radius;
}
@mixin border-bottom-radius($radius) {
border-bottom-right-radius: $radius;
border-bottom-left-radius: $radius;
}
@mixin border-left-radius($radius) {
border-bottom-left-radius: $radius;
border-top-left-radius: $radius;
}
// Drop shadows
//
// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's
// supported browsers that have box shadow capabilities now support the
// standard `box-shadow` property.
@mixin box-shadow($shadow...) {
-webkit-box-shadow: $shadow; // iOS <4.3 & Android <4.1
box-shadow: $shadow;
}
// Transitions
@mixin transition($transition...) {
-webkit-transition: $transition;
transition: $transition;
}
@mixin transition-property($transition-property...) {
-webkit-transition-property: $transition-property;
transition-property: $transition-property;
}
@mixin transition-delay($transition-delay) {
-webkit-transition-delay: $transition-delay;
transition-delay: $transition-delay;
}
@mixin transition-duration($transition-duration...) {
-webkit-transition-duration: $transition-duration;
transition-duration: $transition-duration;
}
@mixin transition-transform($transition...) {
-webkit-transition: -webkit-transform $transition;
-moz-transition: -moz-transform $transition;
-o-transition: -o-transform $transition;
transition: transform $transition;
}
// Transformations
@mixin rotate($degrees) {
-webkit-transform: rotate($degrees);
-ms-transform: rotate($degrees); // IE9 only
transform: rotate($degrees);
}
@mixin scale($scale-args...) {
-webkit-transform: scale($scale-args);
-ms-transform: scale($scale-args); // IE9 only
transform: scale($scale-args);
}
@mixin translate($x, $y) {
-webkit-transform: translate($x, $y);
-ms-transform: translate($x, $y); // IE9 only
transform: translate($x, $y);
}
@mixin skew($x, $y) {
-webkit-transform: skew($x, $y);
-ms-transform: skewX($x) skewY($y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+
transform: skew($x, $y);
}
@mixin translate3d($x, $y, $z) {
-webkit-transform: translate3d($x, $y, $z);
transform: translate3d($x, $y, $z);
}
@mixin rotateX($degrees) {
-webkit-transform: rotateX($degrees);
-ms-transform: rotateX($degrees); // IE9 only
transform: rotateX($degrees);
}
@mixin rotateY($degrees) {
-webkit-transform: rotateY($degrees);
-ms-transform: rotateY($degrees); // IE9 only
transform: rotateY($degrees);
}
@mixin perspective($perspective) {
-webkit-perspective: $perspective;
-moz-perspective: $perspective;
perspective: $perspective;
}
@mixin perspective-origin($perspective) {
-webkit-perspective-origin: $perspective;
-moz-perspective-origin: $perspective;
perspective-origin: $perspective;
}
@mixin transform-origin($origin) {
-webkit-transform-origin: $origin;
-moz-transform-origin: $origin;
-ms-transform-origin: $origin; // IE9 only
transform-origin: $origin;
}
// Animations
@mixin animation($animation) {
-webkit-animation: $animation;
animation: $animation;
}
@mixin animation-name($name) {
-webkit-animation-name: $name;
animation-name: $name;
}
@mixin animation-duration($duration) {
-webkit-animation-duration: $duration;
animation-duration: $duration;
}
@mixin animation-timing-function($timing-function) {
-webkit-animation-timing-function: $timing-function;
animation-timing-function: $timing-function;
}
@mixin animation-delay($delay) {
-webkit-animation-delay: $delay;
animation-delay: $delay;
}
@mixin animation-iteration-count($iteration-count) {
-webkit-animation-iteration-count: $iteration-count;
animation-iteration-count: $iteration-count;
}
@mixin animation-direction($direction) {
-webkit-animation-direction: $direction;
animation-direction: $direction;
}
// Backface visibility
// Prevent browsers from flickering when using CSS 3D transforms.
// Default value is `visible`, but can be changed to `hidden`
@mixin backface-visibility($visibility){
-webkit-backface-visibility: $visibility;
-moz-backface-visibility: $visibility;
backface-visibility: $visibility;
}
// Box sizing
@mixin box-sizing($boxmodel) {
-webkit-box-sizing: $boxmodel;
-moz-box-sizing: $boxmodel;
box-sizing: $boxmodel;
}
// User select
// For selecting text on the page
@mixin user-select($select) {
-webkit-user-select: $select;
-moz-user-select: $select;
-ms-user-select: $select; // IE10+
user-select: $select;
}
// Resize anything
@mixin resizable($direction) {
resize: $direction; // Options: horizontal, vertical, both
overflow: auto; // Safari fix
}
// CSS3 Content Columns
@mixin content-columns($column-count, $column-gap: $grid-gutter-width) {
-webkit-column-count: $column-count;
-moz-column-count: $column-count;
column-count: $column-count;
-webkit-column-gap: $column-gap;
-moz-column-gap: $column-gap;
column-gap: $column-gap;
}
// Optional hyphenation
@mixin hyphens($mode: auto) {
word-wrap: break-word;
-webkit-hyphens: $mode;
-moz-hyphens: $mode;
-ms-hyphens: $mode; // IE10+
-o-hyphens: $mode;
hyphens: $mode;
}
// Opacity
@mixin opacity($opacity) {
opacity: $opacity;
// IE8 filter
$opacity-ie: ($opacity * 100);
filter: #{alpha(opacity=$opacity-ie)};
}
// GRADIENTS
// --------------------------------------------------
// Horizontal gradient, from left to right
//
// Creates two color stops, start and end, by specifying a color and position for each color stop.
// Color stops are not available in IE9 and below.
@mixin gradient-horizontal($start-color: #555, $end-color: #333, $start-percent: 0%, $end-percent: 100%) {
background-image: -webkit-linear-gradient(left, color-stop($start-color $start-percent), color-stop($end-color $end-percent)); // Safari 5.1-6, Chrome 10+
background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=1); // IE9 and down
}
// Vertical gradient, from top to bottom
//
// Creates two color stops, start and end, by specifying a color and position for each color stop.
// Color stops are not available in IE9 and below.
@mixin gradient-vertical($start-color: #555, $end-color: #333, $start-percent: 0%, $end-percent: 100%) {
background-image: -webkit-linear-gradient(top, $start-color $start-percent, $end-color $end-percent); // Safari 5.1-6, Chrome 10+
background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=0); // IE9 and down
}
@mixin gradient-directional($start-color: #555, $end-color: #333, $deg: 45deg) {
background-repeat: repeat-x;
background-image: -webkit-linear-gradient($deg, $start-color, $end-color); // Safari 5.1-6, Chrome 10+
background-image: linear-gradient($deg, $start-color, $end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
}
@mixin gradient-horizontal-three-colors($start-color: #00b3ee, $mid-color: #7a43b6, $color-stop: 50%, $end-color: #c3325f) {
background-image: -webkit-linear-gradient(left, $start-color, $mid-color $color-stop, $end-color);
background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color);
background-repeat: no-repeat;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=1); // IE9 and down, gets no color-stop at all for proper fallback
}
@mixin gradient-vertical-three-colors($start-color: #00b3ee, $mid-color: #7a43b6, $color-stop: 50%, $end-color: #c3325f) {
background-image: -webkit-linear-gradient($start-color, $mid-color $color-stop, $end-color);
background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color);
background-repeat: no-repeat;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=0); // IE9 and down, gets no color-stop at all for proper fallback
}
@mixin gradient-radial($inner-color: #555, $outer-color: #333) {
background-image: -webkit-radial-gradient(circle, $inner-color, $outer-color);
background-image: radial-gradient(circle, $inner-color, $outer-color);
background-repeat: no-repeat;
}
@mixin gradient-striped($color: rgba(255,255,255,.15), $angle: 45deg) {
background-image: -webkit-linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent);
background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent);
}
// Reset filters for IE
//
// When you need to remove a gradient background, do not forget to use this to reset
// the IE filter for IE9 and below.
@mixin reset-filter() {
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
}
// Retina images
//
// Short retina mixin for setting background-image and -size
@mixin img-retina($file-1x, $file-2x, $width-1x, $height-1x) {
background-image: url(if($bootstrap-sass-asset-helper, twbs-image-path("#{$file-1x}"), "#{$file-1x}"));
@media
only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and ( min--moz-device-pixel-ratio: 2),
only screen and ( -o-min-device-pixel-ratio: 2/1),
only screen and ( min-device-pixel-ratio: 2),
only screen and ( min-resolution: 192dpi),
only screen and ( min-resolution: 2dppx) {
background-image: url(if($bootstrap-sass-asset-helper, twbs-image-path("#{$file-2x}"), "#{$file-2x}"));
background-size: $width-1x $height-1x;
}
}
// Responsive image
//
// Keep images from scaling beyond the width of their parents.
@mixin img-responsive($display: block) {
display: $display;
max-width: 100%; // Part 1: Set a maximum relative to the parent
height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching
}
// COMPONENT MIXINS
// --------------------------------------------------
// Horizontal dividers
// -------------------------
// Dividers (basically an hr) within dropdowns and nav lists
@mixin nav-divider($color: #e5e5e5) {
height: 1px;
margin: (($line-height-computed / 2) - 1) 0;
overflow: hidden;
background-color: $color;
}
// Panels
// -------------------------
@mixin panel-variant($border, $heading-text-color, $heading-bg-color, $heading-border) {
border-color: $border;
& > .panel-heading {
color: $heading-text-color;
background-color: $heading-bg-color;
border-color: $heading-border;
+ .panel-collapse .panel-body {
border-top-color: $border;
}
}
& > .panel-footer {
+ .panel-collapse .panel-body {
border-bottom-color: $border;
}
}
}
// Alerts
// -------------------------
@mixin alert-variant($background, $border, $text-color) {
background-color: $background;
border-color: $border;
color: $text-color;
hr {
border-top-color: darken($border, 5%);
}
.alert-link {
color: darken($text-color, 10%);
}
}
// Tables
// -------------------------
@mixin table-row-variant($state, $background) {
// Exact selectors below required to override `.table-striped` and prevent
// inheritance to nested tables.
.table > thead > tr,
.table > tbody > tr,
.table > tfoot > tr {
> td.#{$state},
> th.#{$state},
&.#{$state} > td,
&.#{$state} > th {
background-color: $background;
}
}
// Hover states for `.table-hover`
// Note: this is not available for cells or rows within `thead` or `tfoot`.
.table-hover > tbody > tr {
> td.#{$state}:hover,
> th.#{$state}:hover,
&.#{$state}:hover > td,
&.#{$state}:hover > th {
background-color: darken($background, 5%);
}
}
}
// List Groups
// -------------------------
@mixin list-group-item-variant($state, $background, $color) {
.list-group-item-#{$state} {
color: $color;
background-color: $background;
// [converter] extracted a& to a.list-group-item-#{$state}
}
a.list-group-item-#{$state} {
color: $color;
.list-group-item-heading { color: inherit; }
&:hover,
&:focus {
color: $color;
background-color: darken($background, 5%);
}
&.active,
&.active:hover,
&.active:focus {
color: #fff;
background-color: $color;
border-color: $color;
}
}
}
// Button variants
// -------------------------
// Easily pump out default styles, as well as :hover, :focus, :active,
// and disabled options for all buttons
@mixin button-variant($color, $background, $border) {
color: $color;
background-color: $background;
border-color: $border;
&:hover,
&:focus,
&:active,
&.active {
color: $color;
background-color: darken($background, 8%);
border-color: darken($border, 12%);
}
.open & { &.dropdown-toggle {
color: $color;
background-color: darken($background, 8%);
border-color: darken($border, 12%);
} }
&:active,
&.active {
background-image: none;
}
.open & { &.dropdown-toggle {
background-image: none;
} }
&.disabled,
&[disabled],
fieldset[disabled] & {
&,
&:hover,
&:focus,
&:active,
&.active {
background-color: $background;
border-color: $border;
}
}
.badge {
color: $background;
background-color: $color;
}
}
// Button sizes
// -------------------------
@mixin button-size($padding-vertical, $padding-horizontal, $font-size, $line-height, $border-radius) {
padding: $padding-vertical $padding-horizontal;
font-size: $font-size;
line-height: $line-height;
border-radius: $border-radius;
}
// Pagination
// -------------------------
@mixin pagination-size($padding-vertical, $padding-horizontal, $font-size, $border-radius) {
> li {
> a,
> span {
padding: $padding-vertical $padding-horizontal;
font-size: $font-size;
}
&:first-child {
> a,
> span {
@include border-left-radius($border-radius);
}
}
&:last-child {
> a,
> span {
@include border-right-radius($border-radius);
}
}
}
}
// Labels
// -------------------------
@mixin label-variant($color) {
background-color: $color;
&[href] {
&:hover,
&:focus {
background-color: darken($color, 10%);
}
}
}
// Contextual backgrounds
// -------------------------
// [converter] $parent hack
@mixin bg-variant($parent, $color) {
#{$parent} {
background-color: $color;
}
a#{$parent}:hover {
background-color: darken($color, 10%);
}
}
// Typography
// -------------------------
// [converter] $parent hack
@mixin text-emphasis-variant($parent, $color) {
#{$parent} {
color: $color;
}
a#{$parent}:hover {
color: darken($color, 10%);
}
}
// Navbar vertical align
// -------------------------
// Vertically center elements in the navbar.
// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.
@mixin navbar-vertical-align($element-height) {
margin-top: (($navbar-height - $element-height) / 2);
margin-bottom: (($navbar-height - $element-height) / 2);
}
// Progress bars
// -------------------------
@mixin progress-bar-variant($color) {
background-color: $color;
.progress-striped & {
@include gradient-striped();
}
}
// Responsive utilities
// -------------------------
// More easily include all the states for responsive-utilities.less.
// [converter] $parent hack
@mixin responsive-visibility($parent) {
#{$parent} {
display: block !important;
}
table#{$parent} { display: table; }
tr#{$parent} { display: table-row !important; }
th#{$parent},
td#{$parent} { display: table-cell !important; }
}
// [converter] $parent hack
@mixin responsive-invisibility($parent) {
#{$parent} {
display: none !important;
}
}
// Grid System
// -----------
// Centered container element
@mixin container-fixed() {
margin-right: auto;
margin-left: auto;
padding-left: ($grid-gutter-width / 2);
padding-right: ($grid-gutter-width / 2);
@include clearfix();
}
// Creates a wrapper for a series of columns
@mixin make-row($gutter: $grid-gutter-width) {
margin-left: ($gutter / -2);
margin-right: ($gutter / -2);
@include clearfix();
}
// Generate the extra small columns
@mixin make-xs-column($columns, $gutter: $grid-gutter-width) {
position: relative;
float: left;
width: percentage(($columns / $grid-columns));
min-height: 1px;
padding-left: ($gutter / 2);
padding-right: ($gutter / 2);
}
@mixin make-xs-column-offset($columns) {
@media (min-width: $screen-xs-min) {
margin-left: percentage(($columns / $grid-columns));
}
}
@mixin make-xs-column-push($columns) {
@media (min-width: $screen-xs-min) {
left: percentage(($columns / $grid-columns));
}
}
@mixin make-xs-column-pull($columns) {
@media (min-width: $screen-xs-min) {
right: percentage(($columns / $grid-columns));
}
}
// Generate the small columns
@mixin make-sm-column($columns, $gutter: $grid-gutter-width) {
position: relative;
min-height: 1px;
padding-left: ($gutter / 2);
padding-right: ($gutter / 2);
@media (min-width: $screen-sm-min) {
float: left;
width: percentage(($columns / $grid-columns));
}
}
@mixin make-sm-column-offset($columns) {
@media (min-width: $screen-sm-min) {
margin-left: percentage(($columns / $grid-columns));
}
}
@mixin make-sm-column-push($columns) {
@media (min-width: $screen-sm-min) {
left: percentage(($columns / $grid-columns));
}
}
@mixin make-sm-column-pull($columns) {
@media (min-width: $screen-sm-min) {
right: percentage(($columns / $grid-columns));
}
}
// Generate the medium columns
@mixin make-md-column($columns, $gutter: $grid-gutter-width) {
position: relative;
min-height: 1px;
padding-left: ($gutter / 2);
padding-right: ($gutter / 2);
@media (min-width: $screen-md-min) {
float: left;
width: percentage(($columns / $grid-columns));
}
}
@mixin make-md-column-offset($columns) {
@media (min-width: $screen-md-min) {
margin-left: percentage(($columns / $grid-columns));
}
}
@mixin make-md-column-push($columns) {
@media (min-width: $screen-md-min) {
left: percentage(($columns / $grid-columns));
}
}
@mixin make-md-column-pull($columns) {
@media (min-width: $screen-md-min) {
right: percentage(($columns / $grid-columns));
}
}
// Generate the large columns
@mixin make-lg-column($columns, $gutter: $grid-gutter-width) {
position: relative;
min-height: 1px;
padding-left: ($gutter / 2);
padding-right: ($gutter / 2);
@media (min-width: $screen-lg-min) {
float: left;
width: percentage(($columns / $grid-columns));
}
}
@mixin make-lg-column-offset($columns) {
@media (min-width: $screen-lg-min) {
margin-left: percentage(($columns / $grid-columns));
}
}
@mixin make-lg-column-push($columns) {
@media (min-width: $screen-lg-min) {
left: percentage(($columns / $grid-columns));
}
}
@mixin make-lg-column-pull($columns) {
@media (min-width: $screen-lg-min) {
right: percentage(($columns / $grid-columns));
}
}
// Framework grid generation
//
// Used only by Bootstrap to generate the correct number of grid classes given
// any value of `$grid-columns`.
// [converter] This is defined recursively in LESS, but Sass supports real loops
@mixin make-grid-columns() {
$list: '';
$i: 1;
$list: ".col-xs-#{$i}, .col-sm-#{$i}, .col-md-#{$i}, .col-lg-#{$i}";
@for $i from (1 + 1) through $grid-columns {
$list: "#{$list}, .col-xs-#{$i}, .col-sm-#{$i}, .col-md-#{$i}, .col-lg-#{$i}";
}
#{$list} {
position: relative;
// Prevent columns from collapsing when empty
min-height: 1px;
// Inner gutter via padding
padding-left: ($grid-gutter-width / 2);
padding-right: ($grid-gutter-width / 2);
}
}
// [converter] This is defined recursively in LESS, but Sass supports real loops
@mixin float-grid-columns($class) {
$list: '';
$i: 1;
$list: ".col-#{$class}-#{$i}";
@for $i from (1 + 1) through $grid-columns {
$list: "#{$list}, .col-#{$class}-#{$i}";
}
#{$list} {
float: left;
}
}
@mixin calc-grid-column($index, $class, $type) {
@if ($type == width) and ($index > 0) {
.col-#{$class}-#{$index} {
width: percentage(($index / $grid-columns));
}
}
@if ($type == push) {
.col-#{$class}-push-#{$index} {
left: percentage(($index / $grid-columns));
}
}
@if ($type == pull) {
.col-#{$class}-pull-#{$index} {
right: percentage(($index / $grid-columns));
}
}
@if ($type == offset) {
.col-#{$class}-offset-#{$index} {
margin-left: percentage(($index / $grid-columns));
}
}
}
// [converter] This is defined recursively in LESS, but Sass supports real loops
@mixin loop-grid-columns($columns, $class, $type) {
@for $i from 0 through $columns {
@include calc-grid-column($i, $class, $type);
}
}
// Create grid for specific class
@mixin make-grid($class) {
@include float-grid-columns($class);
@include loop-grid-columns($grid-columns, $class, width);
@include loop-grid-columns($grid-columns, $class, pull);
@include loop-grid-columns($grid-columns, $class, push);
@include loop-grid-columns($grid-columns, $class, offset);
}
// Form validation states
//
// Used in forms.less to generate the form validation CSS for warnings, errors,
// and successes.
@mixin form-control-validation($text-color: #555, $border-color: #ccc, $background-color: #f5f5f5) {
// Color the label and help text
.help-block,
.control-label,
.radio,
.checkbox,
.radio-inline,
.checkbox-inline {
color: $text-color;
}
// Set the border and box shadow on specific inputs to match
.form-control {
border-color: $border-color;
@include box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work
&:focus {
border-color: darken($border-color, 10%);
$shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten($border-color, 20%);
@include box-shadow($shadow);
}
}
// Set validation states also for addons
.input-group-addon {
color: $text-color;
border-color: $border-color;
background-color: $background-color;
}
// Optional feedback icon
.form-control-feedback {
color: $text-color;
}
}
// Form control focus state
//
// Generate a customized focus state and for any input with the specified color,
// which defaults to the `$input-focus-border` variable.
//
// We highly encourage you to not customize the default value, but instead use
// this to tweak colors on an as-needed basis. This aesthetic change is based on
// WebKit's default styles, but applicable to a wider range of browsers. Its
// usability and accessibility should be taken into account with any change.
//
// Example usage: change the default blue border and shadow to white for better
// contrast against a dark gray background.
@mixin form-control-focus($color: $input-border-focus) {
$color-rgba: rgba(red($color), green($color), blue($color), .6);
&:focus {
border-color: $color;
outline: 0;
@include box-shadow(inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px $color-rgba);
}
}
// Form control sizing
//
// Relative text size, padding, and border-radii changes for form controls. For
// horizontal sizing, wrap controls in the predefined grid classes. `<select>`
// element gets special love because it's special, and that's a fact!
// [converter] $parent hack
@mixin input-size($parent, $input-height, $padding-vertical, $padding-horizontal, $font-size, $line-height, $border-radius) {
#{$parent} {
height: $input-height;
padding: $padding-vertical $padding-horizontal;
font-size: $font-size;
line-height: $line-height;
border-radius: $border-radius;
}
select#{$parent} {
height: $input-height;
line-height: $input-height;
}
textarea#{$parent},
select[multiple]#{$parent} {
height: auto;
}
}

View File

@ -0,0 +1,833 @@
// a flag to toggle asset pipeline / compass integration
// defaults to true if twbs-font-path function is present (no function => twbs-font-path('') parsed as string == right side)
// in Sass 3.3 this can be improved with: function-exists(twbs-font-path)
$bootstrap-sass-asset-helper: (twbs-font-path("") != unquote('twbs-font-path("")')) !default;
//
// Variables
// --------------------------------------------------
//== Colors
//
//## Gray and brand colors for use across Bootstrap.
$gray-darker: lighten(#000, 13.5%) !default; // #222
$gray-dark: lighten(#000, 20%) !default; // #333
$gray: lighten(#000, 33.5%) !default; // #555
$gray-light: lighten(#000, 60%) !default; // #999
$gray-lighter: lighten(#000, 93.5%) !default; // #eee
$brand-primary: #47bab5 !default;
$brand-success: #5cb85c !default;
$brand-info: #5bc0de !default;
$brand-warning: #f0ad4e !default;
$brand-danger: #ed4c43 !default;
//== Scaffolding
//
// ## Settings for some of the most global styles.
//** Background color for `<body>`.
$body-bg: #fff !default;
//** Global text color on `<body>`.
$text-color: $gray-dark !default;
//** Global textual link color.
$link-color: $brand-primary !default;
//** Link hover color set via `darken()` function.
$link-hover-color: darken($link-color, 15%) !default;
//== Typography
//
//## Font, line-height, and color for body text, headings, and more.
$font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif !default;
$font-family-serif: Georgia, "Times New Roman", Times, serif !default;
//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
$font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace !default;
$font-family-base: $font-family-sans-serif !default;
$font-size-base: 14px !default;
$font-size-large: ceil(($font-size-base * 1.25)) !default; // ~18px
$font-size-small: ceil(($font-size-base * 0.85)) !default; // ~12px
$font-size-h1: floor(($font-size-base * 2.6)) !default; // ~36px
$font-size-h2: floor(($font-size-base * 2.15)) !default; // ~30px
$font-size-h3: ceil(($font-size-base * 1.7)) !default; // ~24px
$font-size-h4: ceil(($font-size-base * 1.25)) !default; // ~18px
$font-size-h5: $font-size-base !default;
$font-size-h6: ceil(($font-size-base * 0.85)) !default; // ~12px
//** Unit-less `line-height` for use in components like buttons.
$line-height-base: 1.428571429 !default; // 20/14
//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
$line-height-computed: floor(($font-size-base * $line-height-base)) !default; // ~20px
//** By default, this inherits from the `<body>`.
$headings-font-family: inherit !default;
$headings-font-weight: 500 !default;
$headings-line-height: 1.1 !default;
$headings-color: inherit !default;
//-- Iconography
//
//## Specify custom locations of the include Glyphicons icon font. Useful for those including Bootstrap via Bower.
$icon-font-path: "bootstrap/" !default;
$icon-font-name: "glyphicons-halflings-regular" !default;
$icon-font-svg-id: "glyphicons_halflingsregular" !default;
//== Components
//
//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
$padding-base-vertical: 6px !default;
$padding-base-horizontal: 12px !default;
$padding-large-vertical: 10px !default;
$padding-large-horizontal: 16px !default;
$padding-small-vertical: 5px !default;
$padding-small-horizontal: 10px !default;
$padding-xs-vertical: 1px !default;
$padding-xs-horizontal: 5px !default;
$line-height-large: 1.33 !default;
$line-height-small: 1.5 !default;
$border-radius-base: 4px !default;
$border-radius-large: 6px !default;
$border-radius-small: 3px !default;
//** Global color for active items (e.g., navs or dropdowns).
$component-active-color: #fff !default;
//** Global background color for active items (e.g., navs or dropdowns).
$component-active-bg: $brand-primary !default;
//** Width of the `border` for generating carets that indicator dropdowns.
$caret-width-base: 4px !default;
//** Carets increase slightly in size for larger components.
$caret-width-large: 5px !default;
//== Tables
//
//## Customizes the `.table` component with basic values, each used across all table variations.
//** Padding for `<th>`s and `<td>`s.
$table-cell-padding: 8px !default;
//** Padding for cells in `.table-condensed`.
$table-condensed-cell-padding: 5px !default;
//** Default background color used for all tables.
$table-bg: transparent !default;
//** Background color used for `.table-striped`.
$table-bg-accent: #f9f9f9 !default;
//** Background color used for `.table-hover`.
$table-bg-hover: #f5f5f5 !default;
$table-bg-active: $table-bg-hover !default;
//** Border color for table and cell borders.
$table-border-color: #ddd !default;
//== Buttons
//
//## For each of Bootstrap's buttons, define text, background and border color.
$btn-font-weight: normal !default;
$btn-default-color: #333 !default;
$btn-default-bg: #fff !default;
$btn-default-border: #ccc !default;
$btn-primary-color: #fff !default;
$btn-primary-bg: $brand-primary !default;
$btn-primary-border: darken($btn-primary-bg, 5%) !default;
$btn-success-color: #fff !default;
$btn-success-bg: $brand-success !default;
$btn-success-border: darken($btn-success-bg, 5%) !default;
$btn-info-color: #fff !default;
$btn-info-bg: $brand-info !default;
$btn-info-border: darken($btn-info-bg, 5%) !default;
$btn-warning-color: #fff !default;
$btn-warning-bg: $brand-warning !default;
$btn-warning-border: darken($btn-warning-bg, 5%) !default;
$btn-danger-color: #fff !default;
$btn-danger-bg: $brand-danger !default;
$btn-danger-border: darken($btn-danger-bg, 5%) !default;
$btn-link-disabled-color: $gray-light !default;
//== Forms
//
//##
//** `<input>` background color
$input-bg: #fff !default;
//** `<input disabled>` background color
$input-bg-disabled: $gray-lighter !default;
//** Text color for `<input>`s
$input-color: $gray !default;
//** `<input>` border color
$input-border: #ccc !default;
//** `<input>` border radius
$input-border-radius: $border-radius-base !default;
//** Border color for inputs on focus
$input-border-focus: #66afe9 !default;
//** Placeholder text color
$input-color-placeholder: $gray-light !default;
//** Default `.form-control` height
$input-height-base: ($line-height-computed + ($padding-base-vertical * 2) + 2) !default;
//** Large `.form-control` height
$input-height-large: (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2) !default;
//** Small `.form-control` height
$input-height-small: (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2) !default;
$legend-color: $gray-dark !default;
$legend-border-color: #e5e5e5 !default;
//** Background color for textual input addons
$input-group-addon-bg: $gray-lighter !default;
//** Border color for textual input addons
$input-group-addon-border-color: $input-border !default;
//== Dropdowns
//
//## Dropdown menu container and contents.
//** Background for the dropdown menu.
$dropdown-bg: #fff !default;
//** Dropdown menu `border-color`.
$dropdown-border: rgba(0,0,0,.15) !default;
//** Dropdown menu `border-color` **for IE8**.
$dropdown-fallback-border: #ccc !default;
//** Divider color for between dropdown items.
$dropdown-divider-bg: #e5e5e5 !default;
//** Dropdown link text color.
$dropdown-link-color: $gray-dark !default;
//** Hover color for dropdown links.
$dropdown-link-hover-color: darken($gray-dark, 5%) !default;
//** Hover background for dropdown links.
$dropdown-link-hover-bg: #f5f5f5 !default;
//** Active dropdown menu item text color.
$dropdown-link-active-color: $component-active-color !default;
//** Active dropdown menu item background color.
$dropdown-link-active-bg: $component-active-bg !default;
//** Disabled dropdown menu item background color.
$dropdown-link-disabled-color: $gray-light !default;
//** Text color for headers within dropdown menus.
$dropdown-header-color: $gray-light !default;
// Note: Deprecated $dropdown-caret-color as of v3.1.0
$dropdown-caret-color: #000 !default;
//-- Z-index master list
//
// Warning: Avoid customizing these values. They're used for a bird's eye view
// of components dependent on the z-axis and are designed to all work together.
//
// Note: These variables are not generated into the Customizer.
$zindex-navbar: 1000 !default;
$zindex-dropdown: 1000 !default;
$zindex-popover: 1010 !default;
$zindex-tooltip: 1030 !default;
$zindex-navbar-fixed: 1030 !default;
$zindex-modal-background: 1040 !default;
$zindex-modal: 1050 !default;
//== Media queries breakpoints
//
//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
// Extra small screen / phone
// Note: Deprecated $screen-xs and $screen-phone as of v3.0.1
$screen-xs: 480px !default;
$screen-xs-min: $screen-xs !default;
$screen-phone: $screen-xs-min !default;
// Small screen / tablet
// Note: Deprecated $screen-sm and $screen-tablet as of v3.0.1
$screen-sm: 768px !default;
$screen-sm-min: $screen-sm !default;
$screen-tablet: $screen-sm-min !default;
// Medium screen / desktop
// Note: Deprecated $screen-md and $screen-desktop as of v3.0.1
$screen-md: 992px !default;
$screen-md-min: $screen-md !default;
$screen-desktop: $screen-md-min !default;
// Large screen / wide desktop
// Note: Deprecated $screen-lg and $screen-lg-desktop as of v3.0.1
$screen-lg: 1200px !default;
$screen-lg-min: $screen-lg !default;
$screen-lg-desktop: $screen-lg-min !default;
// So media queries don't overlap when required, provide a maximum
$screen-xs-max: ($screen-sm-min - 1) !default;
$screen-sm-max: ($screen-md-min - 1) !default;
$screen-md-max: ($screen-lg-min - 1) !default;
//== Grid system
//
//## Define your custom responsive grid.
//** Number of columns in the grid.
$grid-columns: 12 !default;
//** Padding between columns. Gets divided in half for the left and right.
$grid-gutter-width: 30px !default;
// Navbar collapse
//** Point at which the navbar becomes uncollapsed.
$grid-float-breakpoint: $screen-sm-min !default;
//** Point at which the navbar begins collapsing.
$grid-float-breakpoint-max: ($grid-float-breakpoint - 1) !default;
//== Container sizes
//
//## Define the maximum width of `.container` for different screen sizes.
// Small screen / tablet
$container-tablet: ((720px + $grid-gutter-width)) !default;
//** For `$screen-sm-min` and up.
$container-sm: $container-tablet !default;
// Medium screen / desktop
$container-desktop: ((940px + $grid-gutter-width)) !default;
//** For `$screen-md-min` and up.
$container-md: $container-desktop !default;
// Large screen / wide desktop
$container-large-desktop: ((1140px + $grid-gutter-width)) !default;
//** For `$screen-lg-min` and up.
$container-lg: $container-large-desktop !default;
//== Navbar
//
//##
// Basics of a navbar
$navbar-height: 50px !default;
$navbar-margin-bottom: $line-height-computed !default;
$navbar-border-radius: $border-radius-base !default;
$navbar-padding-horizontal: floor(($grid-gutter-width / 2)) !default;
$navbar-padding-vertical: (($navbar-height - $line-height-computed) / 2) !default;
$navbar-collapse-max-height: 340px !default;
$navbar-default-color: #777 !default;
$navbar-default-bg: #f8f8f8 !default;
$navbar-default-border: darken($navbar-default-bg, 6.5%) !default;
// Navbar links
$navbar-default-link-color: #777 !default;
$navbar-default-link-hover-color: #333 !default;
$navbar-default-link-hover-bg: transparent !default;
$navbar-default-link-active-color: #555 !default;
$navbar-default-link-active-bg: darken($navbar-default-bg, 6.5%) !default;
$navbar-default-link-disabled-color: #ccc !default;
$navbar-default-link-disabled-bg: transparent !default;
// Navbar brand label
$navbar-default-brand-color: $navbar-default-link-color !default;
$navbar-default-brand-hover-color: darken($navbar-default-brand-color, 10%) !default;
$navbar-default-brand-hover-bg: transparent !default;
// Navbar toggle
$navbar-default-toggle-hover-bg: #ddd !default;
$navbar-default-toggle-icon-bar-bg: #888 !default;
$navbar-default-toggle-border-color: #ddd !default;
// Inverted navbar
// Reset inverted navbar basics
$navbar-inverse-color: $gray-light !default;
$navbar-inverse-bg: #222 !default;
$navbar-inverse-border: darken($navbar-inverse-bg, 10%) !default;
// Inverted navbar links
$navbar-inverse-link-color: $gray-light !default;
$navbar-inverse-link-hover-color: #fff !default;
$navbar-inverse-link-hover-bg: transparent !default;
$navbar-inverse-link-active-color: $navbar-inverse-link-hover-color !default;
$navbar-inverse-link-active-bg: darken($navbar-inverse-bg, 10%) !default;
$navbar-inverse-link-disabled-color: #444 !default;
$navbar-inverse-link-disabled-bg: transparent !default;
// Inverted navbar brand label
$navbar-inverse-brand-color: $navbar-inverse-link-color !default;
$navbar-inverse-brand-hover-color: #fff !default;
$navbar-inverse-brand-hover-bg: transparent !default;
// Inverted navbar toggle
$navbar-inverse-toggle-hover-bg: #333 !default;
$navbar-inverse-toggle-icon-bar-bg: #fff !default;
$navbar-inverse-toggle-border-color: #333 !default;
//== Navs
//
//##
//=== Shared nav styles
$nav-link-padding: 10px 15px !default;
$nav-link-hover-bg: $gray-lighter !default;
$nav-disabled-link-color: $gray-light !default;
$nav-disabled-link-hover-color: $gray-light !default;
$nav-open-link-hover-color: #fff !default;
//== Tabs
$nav-tabs-border-color: #ddd !default;
$nav-tabs-link-hover-border-color: $gray-lighter !default;
$nav-tabs-active-link-hover-bg: $body-bg !default;
$nav-tabs-active-link-hover-color: $gray !default;
$nav-tabs-active-link-hover-border-color: #ddd !default;
$nav-tabs-justified-link-border-color: #ddd !default;
$nav-tabs-justified-active-link-border-color: $body-bg !default;
//== Pills
$nav-pills-border-radius: $border-radius-base !default;
$nav-pills-active-link-hover-bg: $component-active-bg !default;
$nav-pills-active-link-hover-color: $component-active-color !default;
//== Pagination
//
//##
$pagination-color: $link-color !default;
$pagination-bg: #fff !default;
$pagination-border: #ddd !default;
$pagination-hover-color: $link-hover-color !default;
$pagination-hover-bg: $gray-lighter !default;
$pagination-hover-border: #ddd !default;
$pagination-active-color: #fff !default;
$pagination-active-bg: $brand-primary !default;
$pagination-active-border: $brand-primary !default;
$pagination-disabled-color: $gray-light !default;
$pagination-disabled-bg: #fff !default;
$pagination-disabled-border: #ddd !default;
//== Pager
//
//##
$pager-bg: $pagination-bg !default;
$pager-border: $pagination-border !default;
$pager-border-radius: 15px !default;
$pager-hover-bg: $pagination-hover-bg !default;
$pager-active-bg: $pagination-active-bg !default;
$pager-active-color: $pagination-active-color !default;
$pager-disabled-color: $pagination-disabled-color !default;
//== Jumbotron
//
//##
$jumbotron-padding: 30px !default;
$jumbotron-color: inherit !default;
$jumbotron-bg: $gray-lighter !default;
$jumbotron-heading-color: inherit !default;
$jumbotron-font-size: ceil(($font-size-base * 1.5)) !default;
//== Form states and alerts
//
//## Define colors for form feedback states and, by default, alerts.
$state-success-text: #3c763d !default;
$state-success-bg: #dff0d8 !default;
$state-success-border: darken(adjust-hue($state-success-bg, -10), 5%) !default;
$state-info-text: #31708f !default;
$state-info-bg: #d9edf7 !default;
$state-info-border: darken(adjust-hue($state-info-bg, -10), 7%) !default;
$state-warning-text: #8a6d3b !default;
$state-warning-bg: #fcf8e3 !default;
$state-warning-border: darken(adjust-hue($state-warning-bg, -10), 5%) !default;
$state-danger-text: #a94442 !default;
$state-danger-bg: #f2dede !default;
$state-danger-border: darken(adjust-hue($state-danger-bg, -10), 5%) !default;
//== Tooltips
//
//##
//** Tooltip max width
$tooltip-max-width: 200px !default;
//** Tooltip text color
$tooltip-color: #fff !default;
//** Tooltip background color
$tooltip-bg: #000 !default;
$tooltip-opacity: .9 !default;
//** Tooltip arrow width
$tooltip-arrow-width: 5px !default;
//** Tooltip arrow color
$tooltip-arrow-color: $tooltip-bg !default;
//== Popovers
//
//##
//** Popover body background color
$popover-bg: #fff !default;
//** Popover maximum width
$popover-max-width: 276px !default;
//** Popover border color
$popover-border-color: rgba(0,0,0,.2) !default;
//** Popover fallback border color
$popover-fallback-border-color: #ccc !default;
//** Popover title background color
$popover-title-bg: darken($popover-bg, 3%) !default;
//** Popover arrow width
$popover-arrow-width: 10px !default;
//** Popover arrow color
$popover-arrow-color: #fff !default;
//** Popover outer arrow width
$popover-arrow-outer-width: ($popover-arrow-width + 1) !default;
//** Popover outer arrow color
$popover-arrow-outer-color: fadein($popover-border-color, 5%) !default;
//** Popover outer arrow fallback color
$popover-arrow-outer-fallback-color: darken($popover-fallback-border-color, 20%) !default;
//== Labels
//
//##
//** Default label background color
$label-default-bg: $gray-light !default;
//** Primary label background color
$label-primary-bg: $brand-primary !default;
//** Success label background color
$label-success-bg: $brand-success !default;
//** Info label background color
$label-info-bg: $brand-info !default;
//** Warning label background color
$label-warning-bg: $brand-warning !default;
//** Danger label background color
$label-danger-bg: $brand-danger !default;
//** Default label text color
$label-color: #fff !default;
//** Default text color of a linked label
$label-link-hover-color: #fff !default;
//== Modals
//
//##
//** Padding applied to the modal body
$modal-inner-padding: 20px !default;
//** Padding applied to the modal title
$modal-title-padding: 15px !default;
//** Modal title line-height
$modal-title-line-height: $line-height-base !default;
//** Background color of modal content area
$modal-content-bg: #fff !default;
//** Modal content border color
$modal-content-border-color: rgba(0,0,0,.2) !default;
//** Modal content border color **for IE8**
$modal-content-fallback-border-color: #999 !default;
//** Modal backdrop background color
$modal-backdrop-bg: #000 !default;
//** Modal backdrop opacity
$modal-backdrop-opacity: .5 !default;
//** Modal header border color
$modal-header-border-color: #e5e5e5 !default;
//** Modal footer border color
$modal-footer-border-color: $modal-header-border-color !default;
$modal-lg: 900px !default;
$modal-md: 600px !default;
$modal-sm: 300px !default;
//== Alerts
//
//## Define alert colors, border radius, and padding.
$alert-padding: 15px !default;
$alert-border-radius: $border-radius-base !default;
$alert-link-font-weight: bold !default;
$alert-success-bg: $state-success-bg !default;
$alert-success-text: $state-success-text !default;
$alert-success-border: $state-success-border !default;
$alert-info-bg: $state-info-bg !default;
$alert-info-text: $state-info-text !default;
$alert-info-border: $state-info-border !default;
$alert-warning-bg: $state-warning-bg !default;
$alert-warning-text: $state-warning-text !default;
$alert-warning-border: $state-warning-border !default;
$alert-danger-bg: $state-danger-bg !default;
$alert-danger-text: $state-danger-text !default;
$alert-danger-border: $state-danger-border !default;
//== Progress bars
//
//##
//** Background color of the whole progress component
$progress-bg: #f5f5f5 !default;
//** Progress bar text color
$progress-bar-color: #fff !default;
//** Default progress bar color
$progress-bar-bg: $brand-primary !default;
//** Success progress bar color
$progress-bar-success-bg: $brand-success !default;
//** Warning progress bar color
$progress-bar-warning-bg: $brand-warning !default;
//** Danger progress bar color
$progress-bar-danger-bg: $brand-danger !default;
//** Info progress bar color
$progress-bar-info-bg: $brand-info !default;
//== List group
//
//##
//** Background color on `.list-group-item`
$list-group-bg: #fff !default;
//** `.list-group-item` border color
$list-group-border: #ddd !default;
//** List group border radius
$list-group-border-radius: $border-radius-base !default;
//** Background color of single list elements on hover
$list-group-hover-bg: #f5f5f5 !default;
//** Text color of active list elements
$list-group-active-color: $component-active-color !default;
//** Background color of active list elements
$list-group-active-bg: $component-active-bg !default;
//** Border color of active list elements
$list-group-active-border: $list-group-active-bg !default;
$list-group-active-text-color: lighten($list-group-active-bg, 40%) !default;
$list-group-link-color: #555 !default;
$list-group-link-heading-color: #333 !default;
//== Panels
//
//##
$panel-bg: #fff !default;
$panel-body-padding: 15px !default;
$panel-border-radius: $border-radius-base !default;
//** Border color for elements within panels
$panel-inner-border: #ddd !default;
$panel-footer-bg: #f5f5f5 !default;
$panel-default-text: $gray-dark !default;
$panel-default-border: #ddd !default;
$panel-default-heading-bg: #f5f5f5 !default;
$panel-primary-text: #fff !default;
$panel-primary-border: $brand-primary !default;
$panel-primary-heading-bg: $brand-primary !default;
$panel-success-text: $state-success-text !default;
$panel-success-border: $state-success-border !default;
$panel-success-heading-bg: $state-success-bg !default;
$panel-info-text: $state-info-text !default;
$panel-info-border: $state-info-border !default;
$panel-info-heading-bg: $state-info-bg !default;
$panel-warning-text: $state-warning-text !default;
$panel-warning-border: $state-warning-border !default;
$panel-warning-heading-bg: $state-warning-bg !default;
$panel-danger-text: $state-danger-text !default;
$panel-danger-border: $state-danger-border !default;
$panel-danger-heading-bg: $state-danger-bg !default;
//== Thumbnails
//
//##
//** Padding around the thumbnail image
$thumbnail-padding: 4px !default;
//** Thumbnail background color
$thumbnail-bg: $body-bg !default;
//** Thumbnail border color
$thumbnail-border: #ddd !default;
//** Thumbnail border radius
$thumbnail-border-radius: $border-radius-base !default;
//** Custom text color for thumbnail captions
$thumbnail-caption-color: $text-color !default;
//** Padding around the thumbnail caption
$thumbnail-caption-padding: 9px !default;
//== Wells
//
//##
$well-bg: #f5f5f5 !default;
$well-border: darken($well-bg, 7%) !default;
//== Badges
//
//##
$badge-color: #fff !default;
//** Linked badge text color on hover
$badge-link-hover-color: #fff !default;
$badge-bg: $gray-light !default;
//** Badge text color in active nav link
$badge-active-color: $link-color !default;
//** Badge background color in active nav link
$badge-active-bg: #fff !default;
$badge-font-weight: bold !default;
$badge-line-height: 1 !default;
$badge-border-radius: 10px !default;
//== Breadcrumbs
//
//##
$breadcrumb-padding-vertical: 8px !default;
$breadcrumb-padding-horizontal: 15px !default;
//** Breadcrumb background color
$breadcrumb-bg: #f5f5f5 !default;
//** Breadcrumb text color
$breadcrumb-color: #ccc !default;
//** Text color of current page in the breadcrumb
$breadcrumb-active-color: $gray-light !default;
//** Textual separator for between breadcrumb elements
$breadcrumb-separator: "/" !default;
//== Carousel
//
//##
$carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6) !default;
$carousel-control-color: #fff !default;
$carousel-control-width: 15% !default;
$carousel-control-opacity: .5 !default;
$carousel-control-font-size: 20px !default;
$carousel-indicator-active-bg: #fff !default;
$carousel-indicator-border-color: #fff !default;
$carousel-caption-color: #fff !default;
//== Close
//
//##
$close-font-weight: bold !default;
$close-color: #000 !default;
$close-text-shadow: 0 1px 0 #fff !default;
//== Code
//
//##
$code-color: #c7254e !default;
$code-bg: #f9f2f4 !default;
$kbd-color: #fff !default;
$kbd-bg: #333 !default;
$pre-bg: #f5f5f5 !default;
$pre-color: $gray-dark !default;
$pre-border-color: #ccc !default;
$pre-scrollable-max-height: 340px !default;
//== Type
//
//##
//** Text muted color
$text-muted: $gray-light !default;
//** Abbreviations and acronyms border color
$abbr-border-color: $gray-light !default;
//** Headings small color
$headings-small-color: $gray-light !default;
//** Blockquote small color
$blockquote-small-color: $gray-light !default;
//** Blockquote font size
$blockquote-font-size: ($font-size-base * 1.25) !default;
//** Blockquote border color
$blockquote-border-color: $gray-lighter !default;
//** Page header border color
$page-header-border-color: $gray-lighter !default;
//== Miscellaneous
//
//##
//** Horizontal line color.
$hr-border: $gray-lighter !default;
//** Horizontal offset for forms and lists.
$component-offset-horizontal: 180px !default;

File diff suppressed because one or more lines are too long

0
app/controllers/.keep Normal file
View File

View File

@ -0,0 +1,554 @@
# encoding: utf-8
require 'rubyXL'
class Admin::CustomAnnouncementsController < OrbitAdminController
include Admin::CustomAnnouncementsHelper
before_action ->(module_app = @app_title) { set_variables module_app }
before_action :set_custom_bulletin, only: [:edit, :destroy, :comment]
before_action :load_access_level, :load_settings
before_action :set_module_pages, only: [:edit,:new]
def set_module_pages
@module_pages = Page.where(:module => 'custom_announcement').collect{|p| [p.name,p.id] }
end
def initialize
super
@app_title = "custom_announcement"
end
def comment_hidden
b = CustomBulletinComment.find(params[:id]) rescue nil
if !b.nil?
b.is_hidden = !b.is_hidden
b.save
@table_feed_fields = ["custom_announcement.time", "custom_announcement.comment", "custom_announcement.account","ip","is_hidden"]
@comments = b.custom_bulletin.custom_bulletin_comments.reverse rescue []
render partial: 'comment'
end
end
def comment
@table_feed_fields = ["custom_announcement.time", "custom_announcement.comment", "custom_announcement.account","ip","is_hidden"]
@comments = @custom_bulletin.custom_bulletin_comments.reverse rescue []
end
def index
@custom_bulletin_configs = CustomBulletinConfig.all
CustomBulletin.remove_expired_status
@tags = @module_app.tags
@table_fields = [:status, :category, :title, :start_date, :end_date, "custom_announcement.comment", :last_modified]
@current_user = current_user
if CustomAnnouncementSetting.first.is_display_edit_only && !current_user.is_admin? && !current_user.is_manager?(@module_app)
current_user_is_sub_manager = !current_user.is_manager?(@module_app) && (current_user.is_sub_manager?(@module_app) || current_user.is_sub_manager_with_role?(@module_app)) rescue false
if current_user_is_sub_manager
@categories = current_user.approved_categories.select{|c| c.module_app_id == @module_app.id} rescue []
@filter_fields = filter_fields(@categories, @tags)
@custom_bulletins = CustomBulletin.where(:create_user_id=>current_user.id,:title.ne => "",:is_preview.in=>[false,nil])
.order_by(sort)
.with_categories(filters("category"))
.with_tags(filters("tag"))
.with_status(filters("status"))
else
@custom_bulletins = CustomBulletin.where(:uid=>nil)
@categories = @module_app.categories.enabled
@filter_fields = filter_fields(@categories, @tags)
end
else
@categories = @module_app.categories.enabled
@filter_fields = filter_fields(@categories, @tags)
@custom_bulletins = CustomBulletin.where(:title.ne => "",:is_preview.in=>[false,nil])
.order_by(sort)
.with_categories(filters("category"))
.with_tags(filters("tag"))
.with_status(filters("status"))
end
if params[:custom_module].present?
@custom_bulletins = @custom_bulletins.where(:custom_module=>params[:custom_module])
end
if params[:bind_uid].present?
@custom_bulletins = @custom_bulletins.where(:bind_uid=>params[:bind_uid])
end
@custom_bulletins = search_data(@custom_bulletins,[:title]).page(params[:page]).per(10)
if request.xhr?
render :partial => "index"
elsif params[:custom_module].blank? || params[:bind_uid].blank?
render "display_enable_modules"
end
end
def feed
@table_feed_fields = ["custom_announcement.feed_name", :tags, "custom_announcement.rssfeed", "custom_announcement.jsonfeed"]
@feeds = CustomBulletinFeed.all.asc(:created_at)
end
def generate_iframe_url
iframe_params = params.require(:iframe).permit!
uids = iframe_params['member_ids'].to_a.map{|m_id| MemberProfile.find(m_id).uid rescue nil}.select{|uid| !uid.nil?}
url_params = iframe_params.except(:member_ids)
url_params['uids'] = uids if uids != []
render :text => '/xhr/panel/custom_announcement/widget/sync_data?'+url_params.to_param
end
def settings
@setting = @custom_announcement_setting
roles = Role.all
@sorted_members = roles.inject({}) do |members,role|
members_for_role = role.member_profiles.select{|m| (m.user.nil? ? false : m.user.approved)}
members[role] = members_for_role
members
end
@sorted_members['no_role'] = MemberProfile.any_in(:role_ids=>[nil,[]]).select{|m| (m.user.nil? ? false : m.user.approved)}
@unapproved_members = User.where(:approved => false).map{|u| u.member_profile}
end
def import
end
def excel_format
respond_to do |format|
format.xlsx {
response.headers['Content-Disposition'] = 'attachment; filename="custom_announcement_import_format.xlsx"'
}
end
end
def export_excel
@custom_announcements = CustomBulletin.all.desc(:created_at)
respond_to do |format|
format.xlsx {
response.headers['Content-Disposition'] = 'attachment; filename="custom_announcement_export.xlsx"'
}
end
end
def import_from_xml
download_tmp_xml params["import_xml"]
import_from_tmp_xml File.read(File.join(Rails.root, "tmp", "ann_cc_ntu.xml"))
redirect_to admin_custom_announcements_path
end
def import
end
def import_from_wp
import_from_wordpress params["import_xml"].tempfile
redirect_to admin_custom_announcements_path
end
def importcustom_anns
workbook = RubyXL::Parser.parse(params["import_file"].tempfile)
categories = @module_app.categories.asc(:created_at).to_a
tags = @module_app.tags.asc(:created_at).to_a
sheet = workbook[0]
if sheet.count <= 503
sheet.each_with_index do |row, i|
next if i < 3
v = row.cells.first.value rescue nil
next if v.blank?
import_this_custom_announcement(row, categories, tags)
end
redirect_to admin_custom_announcements_path
else
redirect_to admin_custom_announcements_path(:error => "1")
end
end
def createsettings
setting = CustomAnnouncementSetting.new(settings_params)
setting.save
redirect_to admin_custom_announcement_settings_path
end
def updatesettings
setting = @custom_announcement_setting
ids = params['custom_announcement_setting']['custom_anns_status_settings'].to_a.collect do |i,v|
v['_id']
end.compact
CustomAnnsStatusSetting.where(:id.nin=>ids).destroy
setting.update_attributes(settings_params)
setting.save
redirect_to admin_custom_announcement_settings_path
end
def feedform
if params[:type] == "new"
@custom_announcement_feed = CustomBulletinFeed.new
render :partial => "feed_form"
else params[:type] == "edit"
@custom_announcement_feed = CustomBulletinFeed.find(params[:id])
render :partial => "edit_feed_form"
end
end
def createfeed
custom_announcement_feed = CustomBulletinFeed.new(feed_params)
custom_announcement_feed.save
create_feed_cache(nil,custom_announcement_feed)
feeds = CustomBulletinFeed.all.asc(:created_at)
render :partial => "feed", :collection => feeds
end
def updatefeed
ann_feed = CustomBulletinFeed.find(params[:id])
ann_feed.update_attributes(feed_params)
ann_feed.save
create_feed_cache(nil,ann_feed)
feeds = CustomBulletinFeed.all.asc(:created_at)
render :partial => "feed", :collection => feeds
end
def deletefeed
ann_feed = CustomBulletinFeed.find(params[:id])
ann_feed.destroy
feeds = CustomBulletinFeed.all.asc(:created_at)
render :partial => "feed", :collection => feeds
end
def new
@tags = @module_app.tags
@statuses = []
@custom_bulletin = CustomBulletin.new
@custom_bulletin.email_sentdate = Time.now
@reach_limit = @custom_bulletin.check_status_limit(current_user,true)
if defined? Calendar
categories = user_authenticated_categories rescue ['all']
if categories.first == "all"
@calendar_categories = CalendarType.all
else
@calendar_categories = CalendarType.where(:category_id.in => categories) rescue []
end
end
end
def create
bps = custom_bulletin_params
custom_bulletin = CustomBulletin.new(bps)
if !bps['custom_bulletin_links_attributes'].nil?
bps['custom_bulletin_links_attributes'].each do |idx,link|
bps['custom_bulletin_links_attributes'].delete(idx.to_s) if link['url'].blank?
end
end
if((!CustomAnnouncementSetting.first.only_manager_can_edit_status) || (CustomAnnouncementSetting.first.only_manager_can_edit_status && (@current_user.is_admin? || @current_user.is_manager?(@module_app))) )
if bps[:is_top] == "1" && !CustomAnnouncementSetting.check_limit_for_user(custom_bulletin.create_user_id, custom_bulletin.id)
bps[:is_top] = "0"
bps[:top_end_date] = nil
end
else
bps[:is_top] = false
bps[:is_hot] = false
bps[:is_hidden] = false
end
if !defined?(Calendar).nil?
bps = update_calendar(bps,custom_bulletin)
end
custom_bulletin.create_user_id = current_user.id
custom_bulletin.update_user_id = current_user.id
if CustomAnnouncementSetting.is_pro?
if user_can_approve?
custom_bulletin.approved = true
else
send_notification_mail_to_managers(custom_bulletin,"approval",I18n.locale)
end
else
custom_bulletin.approved = true
end
custom_bulletin.save
build_email(custom_bulletin,I18n.locale)
create_feed_cache(custom_bulletin)
if bps[:custom_module].present?
redirect_to admin_custom_announcements_path + "/#{bps[:custom_module]}#{bps[:bind_uid].present? ? ('-'+bps[:bind_uid]) : ''}"
else
redirect_to admin_custom_announcements_path
end
end
def approve_custom_bulletin
id = params[:id]
custom_bulletin = CustomBulletin.find(id)
if params["approved"] == "true"
custom_bulletin.approved = true
custom_bulletin.rejected = false
custom_bulletin.reapproval = false
else
custom_bulletin.rejected = true
custom_bulletin.reapproval = false
custom_bulletin.rejection_reason = params["reason"]
send_rejection_email(custom_bulletin,I18n.locale)
end
custom_bulletin.save
create_feed_cache(custom_bulletin)
redirect_to admin_custom_announcements_path
end
def edit
if can_edit_or_delete?(@custom_bulletin)
@reach_limit = @custom_bulletin.check_status_limit(current_user,true)
@tags = @module_app.tags
@categories = @module_app.categories.enabled
if defined? Calendar
categories = user_authenticated_categories rescue ['all']
if categories.first == "all"
@calendar_categories = CalendarType.all
else
@calendar_categories = CalendarType.where(:category_id.in => categories) rescue []
end
end
@statuses = []
@custom_bulletin.email_sentdate = Time.now if @custom_bulletin.email_sent == false
else
render_401
end
end
def update
uid = params[:id].split('-').last
custom_bulletin = CustomBulletin.find_by(:uid=>uid)
bps = custom_bulletin_params
bps[:tags] = bps[:tags].blank? ? [] : bps[:tags]
bps[:email_member_ids] = bps[:email_member_ids].blank? ? [] : bps[:email_member_ids]
if !bps['custom_bulletin_links_attributes'].nil?
bps['custom_bulletin_links_attributes'].each do |idx,link|
bps['custom_bulletin_links_attributes'].delete(idx.to_s) if link['url'].blank?
end
end
if((!CustomAnnouncementSetting.first.only_manager_can_edit_status) || (CustomAnnouncementSetting.first.only_manager_can_edit_status && (@current_user.is_admin? || @current_user.is_manager?(@module_app))) )
if bps[:is_top] == "1" && !CustomAnnouncementSetting.check_limit_for_user(custom_bulletin.create_user_id, custom_bulletin.id)
bps[:is_top] = "0"
bps[:top_end_date] = nil
end
else
bps[:is_top] = custom_bulletin.is_top
bps[:is_hot] = custom_bulletin.is_hot
bps[:is_hidden] = custom_bulletin.is_hidden
end
if !defined?(Calendar).nil?
bps = update_calendar(bps,custom_bulletin)
end
custom_bulletin.update_attributes(bps)
custom_bulletin.update_user_id = current_user.id
if custom_bulletin.rejected
custom_bulletin.reapproval = true
custom_bulletin.save
send_notification_mail_to_managers(custom_bulletin,"reapproval",I18n.locale)
else
custom_bulletin.save
end
build_email(custom_bulletin,I18n.locale)
create_feed_cache(custom_bulletin)
custom_module = custom_bulletin.custom_module
now_custom_bulletin_page = CustomBulletin.where(:custom_module=>custom_module,:title.ne => "",:is_preview.in=>[false,nil])
.order_by(sort).map(&:id).map.with_index.select{|v,i| v==custom_bulletin.id}[0][1] rescue nil
now_custom_bulletin_page = now_custom_bulletin_page.nil? ? 0 : ((now_custom_bulletin_page+1).to_f/10).ceil
bind_uid = custom_bulletin.bind_uid
if custom_module.present?
redirect_to admin_custom_announcements_path + "/#{custom_module}#{bind_uid.present? ? ('-'+bind_uid) : ''}?page=#{now_custom_bulletin_page}"
else
redirect_to admin_custom_announcements_path(:page=>now_custom_bulletin_page)
end
end
def destroy
custom_module = @custom_bulletin.custom_module
bind_uid = @custom_bulletin.bind_uid
@custom_bulletin.destroy
if custom_module.present?
redirect_to admin_custom_announcements_path + "/#{custom_module}#{bind_uid.present? ? ('-'+bind_uid) : ''}"
else
redirect_to admin_custom_announcements_path
end
end
def delete
if params[:ids]
CustomBulletin.any_in(:uid => params[:ids]).destroy_all
end
redirect_to admin_custom_announcements_path
end
def preview
if params['preview_type'].eql?('edit')
custom_bulletin_data = custom_bulletin_params
org_custom_bulletin = CustomBulletin.find(params['custom_bulletin_id'])
custom_bulletin = org_custom_bulletin.clone
custom_bulletin.generate_uid
custom_bulletin.custom_bulletin_files = []
custom_bulletin.custom_bulletin_links = []
if custom_bulletin_data['image'].blank?
custom_bulletin.image = org_custom_bulletin.image
end
if !custom_bulletin_data['custom_bulletin_files_attributes'].blank?
custom_bulletin_data['custom_bulletin_files_attributes'].each do |key, custom_bulletin_file|
next if !custom_bulletin_file['_destroy'].blank?
file = nil
if custom_bulletin_file['id'].blank?
file = CustomBulletinFile.new(custom_bulletin_file)
file.custom_bulletin_id = custom_bulletin.id
file.save
else
org_file = CustomBulletinFile.find(custom_bulletin_file['id'])
file = org_file.clone
file.custom_bulletin_id = custom_bulletin.id
file.file = org_file.file
custom_bulletin_file.delete('id')
custom_bulletin_file.delete('_destroy')
file.update_attributes(custom_bulletin_file)
end
file.save
custom_bulletin.custom_bulletin_files << file
end
end
if !custom_bulletin_data['custom_bulletin_links_attributes'].blank?
custom_bulletin_data['custom_bulletin_links_attributes'].each do |key, custom_bulletin_link|
next if !custom_bulletin_link['_destroy'].blank?
if custom_bulletin_link['id'].blank?
link = CustomBulletinLink.new(custom_bulletin_link)
link.custom_bulletin_id = custom_bulletin.id
else
link = CustomBulletinLink.find(custom_bulletin_link['id']).clone
link.custom_bulletin_id = custom_bulletin.id
custom_bulletin_link.delete('id')
custom_bulletin_link.delete('_destroy')
link.update_attributes(custom_bulletin_link)
end
link.save
custom_bulletin.custom_bulletin_links << link
end
end
custom_bulletin_data.delete('custom_bulletin_files_attributes')
custom_bulletin_data.delete('custom_bulletin_links_attributes')
custom_bulletin.update_attributes(custom_bulletin_data)
else
custom_bulletin = CustomBulletin.new(custom_bulletin_params)
end
custom_bulletin.is_preview = true
custom_bulletin.save
create_feed_cache(custom_bulletin)
render :text=>page_for_custom_bulletin(custom_bulletin) + "?preview=true"
end
def destroy_preview
custom_bulletin = CustomBulletin.find_by(:uid=>params['uid'])
if custom_bulletin.is_preview
custom_bulletin.destroy
end
render :json=>{'destroy'=>custom_bulletin.id.to_s}
end
def build_email(custom_bulletin,locale)
if custom_bulletin.email_sent and !custom_bulletin.email_addresses.blank?
if custom_bulletin.email.nil?
email = Email.new
email.save
email.deliver rescue nil
custom_bulletin.email_id = email.id
custom_bulletin.save
end
is_sent = custom_bulletin.email.is_sent
is_sent = !params[:resend_mail].eql?("true") if !params[:resend_mail].blank?
doc = Nokogiri::HTML(custom_bulletin.title_translations[locale])
title = doc.text.empty? ? 'no content' : doc.text
custom_bulletin.email.update_attributes(
:create_user=>current_user,
:mail_sentdate=>custom_bulletin.email_sentdate,
:module_app=>@module_app,
:mail_lang => locale,
:mail_to=>custom_bulletin.email_addresses,
:mail_subject=>title,
:template=>'custom_announcements/email',
:template_data=>{
"host" => request.host_with_port,
"title" => title,
"url" => page_for_custom_bulletin(custom_bulletin)
},
:is_sent=>is_sent
)
custom_bulletin.email.deliver
else
custom_bulletin.email.destroy if !custom_bulletin.email.nil?
end
end
private
def load_settings
@custom_announcement_setting = CustomAnnouncementSetting.first rescue nil
if @custom_announcement_setting.nil?
@custom_announcement_setting = CustomAnnouncementSetting.create
end
end
def set_custom_bulletin
@custom_bulletin = CustomBulletin.find(params[:id])
end
def custom_bulletin_config_params
params.require(:custom_bulletin_config).permit!
end
def custom_bulletin_params
params[:custom_bulletin][:email_sent] = params[:custom_bulletin][:email_sent].nil? ? 0 : params[:custom_bulletin][:email_sent]
params.require(:custom_bulletin).permit!
end
def feed_params
params.require(:custom_bulletin_feed).permit!
end
def settings_params
params.require(:custom_announcement_setting).permit!
end
def update_calendar(bps,custom_bulletin)
if bps[:add_to_calendar] == '0' && !bps[:event_id].blank?
Event.find(bps[:event_id]).destroy rescue nil
bps[:event_id] = nil
elsif bps[:add_to_calendar] == '1'
event = Event.find(bps[:event_id]) rescue Event.new(create_user_id: current_user.id)
e_start = bps[:calendar_start_date].blank? ? bps[:postdate] : bps[:calendar_start_date]
e_start = Time.now.to_datetime if e_start.blank?
e_end = bps[:calendar_end_date].blank? ? bps[:deadline] : bps[:calendar_end_date]
#e_end = Time.now.to_datetime + 1.year if e_end.blank?
event.update_attributes(model_class: 'CustomBulletin',
module_key: 'custom_announcement',
model_cat: bps[:category_id],
model_tags: bps[:tags],
model_page_id: bps[:page_id],
model_id: custom_bulletin.id,start: e_start,
end: e_end,update_user_id: current_user.id,
all_day: bps[:calendar_all_day],
calendar_type_id: bps[:calendar_type_id],
title_translations: bps[:title_translations],
note_translations: bps[:subtitle_translations])
bps[:event_id] = event.id
end
bps
end
def create_feed_cache(custom_bulletin=nil,custom_bulletin_feed=nil)
if !custom_bulletin.nil?
CustomBulletinFeed.where(:tag_ids.in => Array(custom_bulletin.tag_ids).collect{|v| v.to_s}).each do |custom_bulletin_feed|
uid = custom_bulletin_feed.uid
uri = URI(request.protocol + request.host_with_port + "/xhr/custom_announcements/feed/#{uid}.json")
Thread.new do
res_net = Net::HTTP.start(uri.host, uri.port,:use_ssl => uri.scheme == 'https',open_timeout: 60,read_timeout: 60) do |http|
req = Net::HTTP::Get.new(uri)
http.request(req)
end
end
end
elsif !custom_bulletin_feed.nil?
uid = custom_bulletin_feed.uid
uri = URI(request.protocol + request.host_with_port + "/xhr/custom_announcements/feed/#{uid}.json")
Thread.new do
res_net = Net::HTTP.start(uri.host, uri.port,:use_ssl => uri.scheme == 'https',open_timeout: 60,read_timeout: 60) do |http|
req = Net::HTTP::Get.new(uri)
http.request(req)
end
end
end
end
end

View File

@ -0,0 +1,159 @@
require "rss"
class CustomAnnouncementFeedsController < ApplicationController
include Admin::CustomAnnouncementsHelper
def feed
uid = params[:uid]
feed_cache = CustomBulletinFeedCache.where(uid: uid).first
custom_anns = ''
if feed_cache.nil?
CustomBulletinFeedCache.create(uid: uid,content: '')
Thread.new do
custom_anns = get_custom_announcements(uid).to_json
feed_cache = CustomBulletinFeedCache.where(uid: uid).first
if !feed_cache.nil?
feed_cache.update_attributes(content: custom_anns)
end
end
else
custom_anns = feed_cache.content
end
render :json => custom_anns
end
def rssfeed
uid = params[:uid]
@bf = CustomBulletinFeed.find_by(:uid => uid) rescue nil
if !@bf.nil?
tags = @bf.tag_ids
if !tags.empty?
@custom_announcements = CustomBulletin.can_display_and_sorted.is_approved.filter_by_tags(tags)
end
end
respond_to do |format|
format.html {redirect_to "/xhr/custom_announcements/rssfeed/#{@bf.uid}.rss"}
format.rss
end
end
def feeds
feeds = []
CustomBulletinFeed.all.each do |bf|
feed = {}
feed["title_translations"] = bf.title_translations
feed["uid"] = bf.uid
feed["url"] = "#{request.base_url}/xhr/custom_announcements/feed/#{bf.uid}"
feed["xml_url"] = "#{request.base_url}/xhr/custom_announcements/rssfeed/#{bf.uid}.rss"
feed["tags"] = []
bf.tag_ids.each do |t|
tag = Tag.find(t)
d = {}
d["name_translations"] = tag.name_translations
feed["tags"] << d
end
feeds << feed
end
render :json => {"feeds" => feeds}.to_json
end
private
def smart_convertor(text)
html_string = text
url = request.protocol + request.host_with_port
html_string = html_string.gsub(/img.*?src="(?=\/)(.*?)|a.*?href="(?=\/)(.*?)/i){|w| w+url}
html_string = html_string.gsub(/img.*?src="\.\.(?=\/)(.*?)|a.*?href="\.\.(?=\/)(.*?)/i){|w| w[0...-2]+url}
return html_string
end
def get_custom_announcements(uid)
bf = CustomBulletinFeed.find_by(:uid => uid) rescue nil
startdt = params[:start]
enddt = params[:end]
dt = params[:date]
if !bf.nil?
tags = bf.tag_ids
if !tags.empty?
if !dt.nil?
dt = DateTime.parse(dt)
dtt = dt + 1.day
custom_announcements = CustomBulletin.where(:postdate.gt => dt, :postdate.lt => dtt).can_display_and_sorted.is_approved.filter_by_tags(tags)
elsif !startdt.nil? && enddt.nil?
startdt = DateTime.parse(startdt)
enddt = DateTime.now
custom_announcements = CustomBulletin.where(:postdate.gt => startdt, :postdate.lt => enddt).can_display_and_sorted.is_approved.filter_by_tags(tags)
elsif !startdt.nil? && !enddt.nil?
startdt = DateTime.parse(startdt)
enddt = DateTime.parse(enddt) + 1.day
custom_announcements = CustomBulletin.where(:postdate.gt => startdt, :postdate.lt => enddt).can_display_and_sorted.is_approved.filter_by_tags(tags)
else
custom_announcements = CustomBulletin.all.can_display_and_sorted.is_approved.filter_by_tags(tags)
end
else
custom_announcements = []
end
end
all_custom_anns = []
tag_names = []
tag_ids = []
custom_announcements.each do |custom_anns|
user = User.find(custom_anns.create_user_id) rescue nil
if !user.nil?
author = user.member_profile && user.member_profile.name == "" ? user.user_name : user.member_profile.name
else
author = ""
end
a = {}
a["id"] = custom_anns.uid
a["title_translations"] = custom_anns.title_translations
a["subtitle_translations"] = custom_anns.subtitle_translations
a["text_translations"] = {}
a["text_translations"]["en"] = smart_convertor(custom_anns.text_translations["en"]) if !custom_anns.text_translations["en"].blank?
a["text_translations"]["zh_tw"] = smart_convertor(custom_anns.text_translations["zh_tw"]) if !custom_anns.text_translations["zh_tw"].blank?
a["postdate"] = custom_anns.postdate
a["image_description_translations"] = custom_anns.image_description_translations
a["image"] = {}
a["display_img"] = custom_anns.display_img
a["image"]["original"] = ("#{request.base_url}" + custom_anns.image.url rescue "")
a["image"]["thumb"] = ("#{request.base_url}" + custom_anns.image.thumb.url rescue "")
a["image"]["mobile"] = ("#{request.base_url}" + custom_anns.image.mobile.url rescue "")
a["tags"] = []
a["author"] = author
a["params"] = custom_anns.to_param
a["subtitle_ann"] = custom_anns.subtitle if custom_anns.display_subtitle?
a["custom_bulletin_links"] = []
a["custom_bulletin_files"] = []
a["custom_bulletin_carousel_images"] = custom_anns.custom_bulletin_carousel_images.map{|image| {"src"=>"#{request.base_url}" + image.file.url,"description"=>image.description.to_s,"description_text"=>image.description_text }}
custom_anns.tags.each do |tag|
if !tag_ids.include?(tag.id.to_s)
tag_ids << tag.id.to_s
tag_names << {"name_translations" => tag.name_translations}
end
a["tags"] << {"name_translations" => tag.name_translations}
end
custom_anns.custom_bulletin_links.each do |bl|
b = {}
b["url"] = bl.url
b["title_translations"] = bl.title_translations
a["custom_bulletin_links"] << b
end
custom_anns.custom_bulletin_files.each do |bf|
b = {}
b["description_translations"] = bf.description_translations
b["title_translations"] = bf.title_translations
b["url"] = ("#{request.base_url}" + bf.file.url rescue "")
a["custom_bulletin_files"] << b
end
all_custom_anns << a
end
{
"custom_announcements" => all_custom_anns,
"tags" => tag_names
}
end
end

View File

@ -0,0 +1,809 @@
class CustomAnnouncementsController < ApplicationController
include CustomAnnouncementsHelper
def comment
@custom_bulletin = CustomBulletin.where(:uid=>params[:uid]).first
comment_val = params['comment']
if !@custom_bulletin.nil? && @custom_bulletin.open_comment_for_user(OrbitHelper.current_user) && !comment_val.blank?
account_id = OrbitHelper.current_user.member_profile.id.to_s rescue 'visitor'
b = CustomBulletinComment.new(ip: request.remote_ip,comment: comment_val,account_id: account_id)
b.custom_bulletin_id = @custom_bulletin.id
b.save
render :json => {}
end
end
def index
CustomBulletin.remove_expired_status
sorted,total_pages = get_sorted_annc
sorted = [] if sorted.nil?
custom_anns = sorted.collect do |a|
if a["source-site"].blank?
statuses = a.statuses_with_classname.collect do |status|
{
"status" => status["name"],
"status-class" => "status-#{status['classname']}"
}
end
locale = OrbitHelper.get_site_locale.to_s
files = a.custom_bulletin_files.map{|file| { "file_url" => file.file.url + "\" title=\"#{file.file_title}", "file_title" => (file.title.blank? ? File.basename(file.file.path) : file.title rescue '') } if file.enabled_for?(locale) } rescue []
files.delete(nil)
links = a.custom_bulletin_links.map{|link| { "link_url" => link.url, "link_title" => (link.title.blank? ? link.url : link.title) } } rescue []
author = User.find(a.create_user_id).member_profile.name rescue ""
desc = a.image_description
desc = (desc.blank? ? "custom_announcement image" : desc)
link_to_show = a.is_external_link ? a.external_link : OrbitHelper.url_to_show(a.to_param)
target = a.is_external_link ? "_blank" : "_self"
doc = Nokogiri::HTML(a.title)
title = doc.text.empty? ? 'no content' : doc.text
{
"department" => author,
"custom_bulletin_links" => links,
"custom_bulletin_files" => files,
"title" => a.title,
"source-site" => "",
"source-site-title" => "",
"source-site-link" => "",
"subtitle" => a.subtitle,
"statuses" => statuses,
"category" => (a.category.title rescue ''),
"postdate" => a.postdate,
"author" => author,
"is_top" => (a.is_top? ? 1 : 0),
"link_to_show" => link_to_show+"\" title=\"#{title}\"",
"target" => target,
"img_src" => a.image.thumb.url || "/assets/custom_announcement-default.jpg",
"img_description" => desc,
"more" => t(:more_plus),
"view_count" => a.view_count
}
else
a
end
end
#If no data , hide title&table
if sorted.count == 0
display = "hide"
end
# custom_anns = custom_anns.concat(feeds_custom_anns)
# total_pages = custom_announcements.total_pages
params = OrbitHelper.params
page = Page.where(url:params['url']).first
@annc_page_title = nil
if (params['category'] != page.categories rescue true)
@annc_page_title = Category.find(Array(params['category']).first).title rescue nil
end
if (params["tags"] != page.tags && !params["tags"].blank? && params["tags"].count == 1 && params["tags"][0] != "all" rescue true)
@annc_page_title = Tag.find(Array(params['tags']).first).name rescue nil
end
{
"custom_announcements" => custom_anns,
"extras" => {
"widget-title" =>t('custom_announcement.custom_announcement'),
"title-head" => t('custom_announcement.table.title'),
"date-head" => t('custom_announcement.table.date'),
"status-head" => t('custom_announcement.table.status'),
"author-head" => t('custom_announcement.table.author'),
"subtitle-head" => t('custom_announcement.table.sub_title'),
"category-head" => t('custom_announcement.table.category'),
"link-head" => t('custom_announcement.table.link'),
"file-head" => t('custom_announcement.table.file'),
"view-count-head" => t('custom_announcement.table.view_count'),
"display" => display,
"department-head" => t('custom_announcement.table.department'),
"page-title" => @annc_page_title
},
"total_pages" => total_pages
}
end
def self.custom_widget_data
@custom_configs = CustomBulletinConfig.all.to_a
ac = ActionController::Base.new
ac.render_to_string("custom_announcements/custom_widget_data",:locals=>{:@custom_data_field=>@custom_data_field,:@custom_configs=>@custom_configs,:@field_name=>@field_name})
end
def random_custom_announcement_widget
pack_data(true)
end
def widget
pack_data()
end
def tag_cloud
ma = ModuleApp.where(:key => "custom_announcement").first
temp = []
ma.tags.each do |tag|
t1 = tag.taggings.collect{|t| t.taggable_id.to_s}
count = CustomBulletin.where(:id.in => t1).can_display_and_sorted.count
temp << {
"tag-name" => tag.name,
"count" => count,
"tag-url" => OrbitHelper.widget_more_url + "?tags[]=" + tag.id.to_s
}
end
max = temp.max_by{|t| t["count"]}["count"]
tags = []
temp.each do |tag|
if tag["count"] > 0
percent = (tag["count"] * 100) / max
font_size = ((percent / 10).round) + 16
tag["font-size"] = font_size
tags << tag
end
end
{
"tags" => tags,
"extras" => {}
}
end
def pack_data(is_random=false)
cats = OrbitHelper.widget_categories || []
tags = OrbitHelper.widget_tags || []
subpart = OrbitHelper.get_current_widget
custom_data_field = subpart.custom_data_field
get_tabs_option
custom_anns = []
use_tag = false
if @tab_option == 0
custom_anns = get_anncs_for_pack_data(cats,tags,nil,is_random)
else
if cats.count != 1 || tags == ["all"]
cats.each do |cat|
custom_anns = custom_anns + get_anncs_for_pack_data([cat],tags,'')
end
else
tags.each do |tag|
custom_anns = custom_anns + get_anncs_for_pack_data(cats,[tag],tag)
end
use_tag = true
end
end
mp = (custom_anns[0]["img_src"] rescue "")
mpd = (custom_anns[0]["img_description"] rescue "")
if @tab_option == 1
if use_tag
tags = ["all"] + tags
else
cats = ["all"] + cats
end
custom_anns = custom_anns.sort{|v1,v2| v2["postdate"]<=>v1["postdate"]}
end
cats = cats.uniq
tags = tags.uniq
tags_translations = tags.map{|tag_id|
if tag_id == "all"
t = I18n.t(:all)
else
t = Tag.find(tag_id).name rescue ""
end
[tag_id,t]
}.to_h
cats_translations = cats.map{|cat_id|
if cat_id == "all"
t = I18n.t(:all)
else
t = Category.find(cat_id).title rescue ""
end
[cat_id,t]
}.to_h
cats_relations = cats_translations.map{|cat_id,t|
if cat_id == "all"
t = "all"
end
[cat_id,t]
}.to_h
page = OrbitHelper.page.find_page(:page_id=> subpart.read_more_page_id).first rescue nil
page = OrbitHelper.page.find_page(:module => "custom_announcement").first rescue nil if page.nil?
all_cats = cats.dup
all_cats.delete "all"
if all_cats.count == 0
all_cats = ["all"]
end
all_tags = tags.dup
all_tags.delete "all"
if all_tags.count == 0
all_tags = ["all"]
end
max_all_count = [OrbitHelper.widget_data_count,custom_anns.count].min
if @tab_option != 0
OrbitHelper.set_widget_title(OrbitHelper.widget_title +
"<div style=\"clear: both;\"></div>" +
"<ul class=\"nav_tabs_filter\">" +
(use_tag ? tags.map.with_index{|tag,i|
read_more_url = "/#{I18n.locale.to_s + page.url}" rescue ""
read_more_url = read_more_url + "?" + {"category"=>all_cats,"tags"=>(tag == 'all' ? all_tags : [tag])}.to_param if read_more_url != ""
read_more_text = I18n.t("custom_announcement.more")
if tag != "all"
begin
read_more_text = I18n.t("custom_announcement.more_") + tags_translations[tag]
rescue
nil
end
end
"<li class=\"filter_tab#{i == 0 ? ' active' : ''}\" #{(tag == 'all' && @all_setting_option == 0) ? "data-count_limit=\"#{max_all_count}\"" : ''} data-read_more_text=\"#{read_more_text}\" data-read_more=\"#{read_more_url}\" data-tags=\"#{tag}\">#{tags_translations[tag]}</li>"
}.join("") : cats.map.with_index{|cat,i|
read_more_url = "/#{I18n.locale.to_s + page.url}" rescue ""
read_more_url = read_more_url + "?" + {"category"=>(cat == 'all' ? all_cats : cat)}.to_param if read_more_url != ""
read_more_text = I18n.t("custom_announcement.more")
if cat != "all"
begin
read_more_text = I18n.t("custom_announcement.more_") + cats_translations[cat]
rescue
nil
end
end
"<li class=\"filter_tab#{i == 0 ? ' active' : ''}\" #{(cat == 'all' && @all_setting_option == 0) ? "data-count_limit=\"#{max_all_count}\"" : ''} data-read_more_text=\"#{read_more_text}\" data-read_more=\"#{read_more_url}\" data-category=\"#{cats_relations[cat]}\">#{cats_translations[cat]}</li>"
}.join("")) +
"</ul>"
)
filter_attr = (use_tag ? 'data-tags' : 'data-category')
extra_html = '
<script>
if(typeof(wpexAnimsition) == "undefined"){
var wpexAnimsition = {
"loading":"1",
"inDuration":"400",
"outDuration":"400",
"inClass":"fade-in",
"outClass":"fade-out",
"need_fix_containers":".widget-custom_announcement-4,.widget-custom_announcement-15",
"linkElement": "[data-list=\"custom_announcements\"] > *",
"children_text_block": ".w-annc__content-wrap",
"container_block": "[data-subpart-id=\"'+subpart.id.to_s+'\"] [data-list=\"custom_announcements\"]:not(tbody)",
"parent_block": "[data-subpart-id=\"'+subpart.id.to_s+'\"]",
"filter_bar": ".nav_tabs_filter",
"filter_option": "li.filter_tab",
"filter_attr": "'+filter_attr+'",
"filter_target_attr": "class",
"use_attr_filter": true,
"equal_height": false
};
}else{
var filter_attr = "'+filter_attr+'";
wpexAnimsition.parent_block = wpexAnimsition.parent_block + ", [data-subpart-id=\"'+subpart.id.to_s+'\"]";
wpexAnimsition.container_block = wpexAnimsition.container_block + ", [data-subpart-id=\"'+subpart.id.to_s+'\"] [data-list=\"custom_announcements\"]:not(tbody)";
if( wpexAnimsition.filter_attr.indexOf(filter_attr) == -1 ){
wpexAnimsition.filter_attr += ("," + filter_attr);
}
}
var wpexLocalize = {
"lightboxType": "iLightbox",
"iLightbox": { "auto": false, "skin": "minimal", "path": "horizontal",
"infinite": false, "maxScale": 1, "minScale": 0, "width": 1400, "height": "",
"slideshow": { "pauseTime": 3000, "startPaused": true },
"effects": { "reposition": true, "repositionSpeed": 200, "switchSpeed": 300,
"loadedFadeSpeed": 50, "fadeSpeed": 500
},
"show": { "title": true, "speed": 200 },
"hide": { "speed": 200 },
"overlay": { "blur": true, "opacity": "0.9" },
"slideShow": "Slideshow", "next": "Next", "previous": "Previous" ,
"thumbnails": { "maxWidth": 120, "maxHeight": 80 }
}
};
$(document).ready(function(){
var first_filter_tab = $("[data-subpart-id=\"'+subpart.id.to_s+'\"] .filter_tab").eq(0);
var read_more_url = first_filter_tab.data("read_more");
if(read_more_url.length != 0){
$("[data-subpart-id=\"'+subpart.id.to_s+'\"] .w-annc__more").attr("href",read_more_url);
$("[data-subpart-id=\"'+subpart.id.to_s+'\"] .w-annc__more").text(first_filter_tab.data("read_more_text"));
}
$("[data-subpart-id=\"'+subpart.id.to_s+'\"] .filter_tab").click(function(){
var read_more_url = $(this).data("read_more");
if(read_more_url.length != 0){
$("[data-subpart-id=\"'+subpart.id.to_s+'\"] .w-annc__more").attr("href",read_more_url);
$("[data-subpart-id=\"'+subpart.id.to_s+'\"] .w-annc__more").text($(this).data("read_more_text"));
}
})
})
</script>
<script src="/assets/custom_bulletin/wpex.min.js"></script>
<style>
[data-list="custom_announcements"] {
position: relative;
}
</style>
'
else
read_more_text = I18n.t("custom_announcement.more")
if cats.count == 1 && cats[0] != "all"
begin
read_more_text = I18n.t("custom_announcement.more_") + ((all_tags.count == 1 && all_tags[0] != 'all') ? tags_translations[tags[0]] : cats_translations[cats[0]])
rescue
nil
end
end
extra_html = "
<script>
$(document).ready(function(){
$(\"[data-subpart-id=\\\"#{subpart.id}\\\"] .w-annc__more\").text(\"#{read_more_text}\");
})
</script>
"
end
if (@read_more_option != 0 rescue false)
extra_html += "
<script>
$(document).ready(function(){
var read_more_position = #{@read_more_option};
var read_more_block = $(\"[data-subpart-id=\\\"#{subpart.id}\\\"] .w-annc__more\");
if(read_more_position == 1 || read_more_position == 2){
read_more_block.addClass(\"pull-left\");
}else{
read_more_block.addClass(\"pull-right\");
}
if(read_more_position == 1 || read_more_position == 3){
var first_element = $(\"[data-subpart-id=\\\"#{subpart.id}\\\"] > *:eq(0)\");
var div_clearfix = $('<div class=\"clearfix\"></div>')
if(first_element.height() == 0){
read_more_block.appendTo(div_clearfix);
}else{
div_clearfix = read_more_block;
}
first_element.before(div_clearfix);
}else{
var div_clearfix = $('<div class=\"clearfix\"></div>');
read_more_block.appendTo(div_clearfix);
$(\"[data-subpart-id=\\\"#{subpart.id}\\\"] > *:eq(-1)\").after(div_clearfix);
}
})
</script>
"
end
extra_after_html = ""
if @all_setting_option == 0 && @tab_option == 1
extra_after_html = "
<script>
$(\"[data-subpart-id=\\\"#{subpart.id}\\\"] [data-list] [data-category]\").css(\"display\",\"none\");
$(\"[data-subpart-id=\\\"#{subpart.id}\\\"] [data-list] [data-category]:lt(#{max_all_count})\").css(\"display\",\"\");
</script>
"
end
if @tab_option == 0
read_more_url = "/#{I18n.locale.to_s + page.get_url}" rescue ""
read_more_url = read_more_url + "?" + {"category"=>all_cats,"tags"=>all_tags}.to_param if read_more_url != ""
extra_after_html += "
<script>
$(\"[data-subpart-id=\\\"#{subpart.id}\\\"] .w-annc__more\").attr(\"href\",\"#{read_more_url}\");
</script>
"
end
{
"custom_announcements" => custom_anns,
"extras" => {
"more_url"=>OrbitHelper.widget_more_url,
"main_picture" => mp,
"main_picture_description" => mpd,
"title-head" => t('custom_announcement.table.title'),
"date-head" => t('custom_announcement.table.date'),
"author-head" => t('custom_announcement.table.author'),
"status-head" => t('custom_announcement.table.status'),
"subtitle-head" => t('custom_announcement.table.sub_title'),
"category-head" => t('custom_announcement.table.category'),
"link-head" => t('custom_announcement.table.link'),
"file-head" => t('custom_announcement.table.file'),
"read_more" => read_more_url,
"read_more_text" => "read more",
"extra_brefore_html" => extra_html,
"extra_after_html" => extra_after_html
}
}
end
def get_tabs_option
subpart = OrbitHelper.get_current_widget
tab_options = ["not_enable_tabs","enable_tabs_with_categories_include_all","enable_tabs_with_categories"]
read_more_options = ['default','upper_left','lower_left','upper_right','lower_right']
all_setting_options = ['the_same_as_data_count','display_all_in_other_tabs']
@tab_option = 0
@read_more_option = 0
@all_setting_option = 0
if subpart.methods.include? 'select_options'.to_sym
ModuleApp.all.select{|tmp| tmp.key.to_s=='custom_announcement'}.each do |modile_app|
@show_options = modile_app.show_options rescue nil
end
subpart.select_options.each do |select_option|
if !(@show_options.nil?) && select_option.field_name == @show_options.keys[1].to_s
value = YAML.load(select_option.value)
tmp = value[:en]
I18n.with_locale(:en) do
tab_options.each_with_index do |option,i|
if tmp == t("custom_announcement.#{option}")
@tab_option = i
break
end
end
end
end
if !(@show_options.nil?) && select_option.field_name == @show_options.keys[2].to_s
value = YAML.load(select_option.value)
tmp = value[:en]
I18n.with_locale(:en) do
read_more_options.each_with_index do |option,i|
if tmp == t("custom_announcement.#{option}")
@read_more_option = i
break
end
end
end
end
if !(@show_options.nil?) && select_option.field_name == @show_options.keys[3].to_s
value = YAML.load(select_option.value)
tmp = value[:en]
I18n.with_locale(:en) do
all_setting_options.each_with_index do |option,i|
if tmp == t("custom_announcement.#{option}")
@all_setting_option = i
break
end
end
end
end
end
end
end
def get_anncs_for_pack_data(cats,tags,set_tags=nil,is_random = false)
subpart = OrbitHelper.get_current_widget
custom_data_field = subpart.custom_data_field
widget_data_count = OrbitHelper.widget_data_count
custom_anns_cache = CustomAnnsCache.where(parent_id: subpart.id.to_s + cats.to_s + tags.to_s + custom_data_field.to_s + widget_data_count.to_s,locale: I18n.locale.to_s)
set_image_version_for_widget()
devide_flag = (!(defined? SiteFeed).nil?)
if custom_anns_cache.count != 1 || is_random
CustomBulletin.remove_expired_status
uid = OrbitHelper.params[:uid] rescue ""
sorted_custom_anns = CustomBulletin.where(:title.nin => ["",nil],:is_preview.in=>[false,nil], :uid.ne => uid)
.can_display_and_sorted.is_approved
.filter_by_widget_categories(cats,false).filter_by_tags(tags)
if custom_data_field
if (custom_data_field[:bind_module_app] rescue false)
sorted_custom_anns = sorted_custom_anns.where(:custom_module=>custom_data_field[:bind_module_app])
end
if (custom_data_field[:bind_uid] rescue false)
sorted_custom_anns = sorted_custom_anns.where(:bind_uid=>custom_data_field[:bind_uid])
end
end
if !is_random
sorted_custom_anns = sorted_custom_anns.limit(widget_data_count)
if custom_anns_cache.count > 1
custom_anns_cache.destroy
end
if devide_flag
now_custom_anns = sorted_custom_anns.to_a
top_custom_anns = now_custom_anns.select{|v| v.is_top}.map{|v| data_to_human_type(v,set_tags)}
not_top_custom_anns = now_custom_anns.select{|v| !v.is_top}.map{|v| data_to_human_type(v,set_tags)}
CustomAnnsCache.create(parent_id: subpart.id.to_s + cats.to_s + tags.to_s + custom_data_field.to_s + widget_data_count.to_s,locale: I18n.locale.to_s,filter_result: {top: top_custom_anns,not_top: not_top_custom_anns})
else
custom_anns = sorted_custom_anns.map{|v| data_to_human_type(v,set_tags)}
CustomAnnsCache.create(parent_id: subpart.id.to_s + cats.to_s + tags.to_s + custom_data_field.to_s + widget_data_count.to_s,locale: I18n.locale.to_s,filter_result: custom_anns)
end
else
if devide_flag
custom_anns = sorted_custom_anns.sample(widget_data_count)
top_custom_anns = custom_anns.select{|v| v.is_top}.map{|v| data_to_human_type(v,set_tags)}
not_top_custom_anns = custom_anns.select{|v| !v.is_top}.map{|v| data_to_human_type(v,set_tags)}
else
custom_anns = sorted_custom_anns.sample(widget_data_count).map{|v| data_to_human_type(v,set_tags)}
end
end
elsif devide_flag
now_custom_anns = custom_anns_cache.first.filter_result
top_custom_anns = now_custom_anns[:top]
not_top_custom_anns = now_custom_anns[:not_top]
else
custom_anns = custom_anns_cache.first.filter_result
end
if devide_flag
rest_count = widget_data_count - top_custom_anns.count
if rest_count <= 0
custom_anns = top_custom_anns
else
feeds_custom_anns = get_feed_custom_announcements("widget")
top_custom_anns = top_custom_anns + feeds_custom_anns.select{|v| v['is_top']}
top_custom_anns = top_custom_anns.sort{|v1,v2| v2["postdate"]<=>v1["postdate"]}
rest_all_custom_anns = feeds_custom_anns.select{|v| v['is_top'] != true} + not_top_custom_anns.take(rest_count)
rest_custom_anns = rest_all_custom_anns.sort{|v1,v2| v2["postdate"]<=>v1["postdate"]}.take(rest_count)
custom_anns = (top_custom_anns + rest_custom_anns).take(widget_data_count)
end
end
custom_anns.each{|a| a["postdate"] = a["postdate"].in_time_zone(Time.zone.utc_offset / 3600).strftime('%Y-%m-%d %H:%M') rescue nil }
custom_anns
end
def get_file
@url = request.path
begin
file = CustomBulletinFile.find(params[:id])
@url = file.file.url
if file.can_access?(OrbitHelper.current_user)
@path = file.file.path rescue ""
@filename = @path.split("/").last
@ext = @path.split("/").last.to_s.split(".").last
if @ext == "png" || @ext == "jpg" || @ext == "bmp" || @ext == "pdf"
render "archives/download_file.html",:layout=>false
else
send_file(@path)
end
else
render :file => "#{Rails.root}/app/views/errors/403.html", :layout => false, :status => :not_found, :content_type => 'text/html'
end
rescue
render :file => "#{Rails.root}/app/views/errors/404.html", :layout => false, :status => :not_found, :content_type => 'text/html'
end
end
def show_local_custom_announcement(uid, is_preview)
locale = OrbitHelper.get_site_locale.to_s
if is_preview
custom_announcement = CustomBulletin.where(:uid => uid).first
else
custom_announcement = CustomBulletin.can_display_and_sorted.where(:uid => uid).first
end
@custom_bulletin = custom_announcement
custom_announcement = CustomBulletin.where(:uid => uid).first if custom_announcement.nil?
url_to_edit = OrbitHelper.user_can_edit?(custom_announcement) ? "/admin/custom_announcements/#{custom_announcement.id.to_s}/edit" : ""
access_level = OrbitHelper.user_access_level?
if !custom_announcement.approved && (access_level != "manager" && access_level != "admin")
if CustomAnnouncementSetting.is_pro?
if !(access_level == "sub_manager" && CustomAnnouncementSetting.first.approvers.include?(OrbitHelper.current_user.id.to_s))
return {}
end
elsif access_level != "sub_manager"
return {}
end
end
return {} if (custom_announcement.category.disable rescue false)
tags = custom_announcement.tags.map{|tag| {
"tag" => tag.name ,
"url" => OrbitHelper.page_for_tag(tag)
} } rescue []
files = custom_announcement.custom_bulletin_files.map do |file|
{ "file_url" => "/xhr/custom_announcements/file/#{file.id}/#{file['file']}" + "\" title=\"#{file.file_title}",
"file_title" => (file.title.blank? ? URI.unescape(File.basename(file.file.path)) : file.title rescue '') } rescue nil if file.enabled_for?(locale)
end rescue []
files.delete(nil)
files.each do |file|
if file["file_url"] =="" || file["file_url"] == nil
files.delete(file)
end
end
links = custom_announcement.custom_bulletin_links.map{|link| { "link_url" => link.url, "link_title" => (link.title.blank? ? link.url : link.title) } } rescue []
update_user = custom_announcement.update_user.member_profile.name rescue ""
desc = custom_announcement.image_description
desc = (desc.nil? || desc == "" ? "custom_announcement image" : desc)
request = OrbitHelper.request
meta_desc = custom_announcement.subtitle.nil? || custom_announcement.subtitle == "" ? custom_announcement.text[0..200] : custom_announcement.subtitle
OrbitHelper.render_meta_tags([{"property" => "og:title", "content" => custom_announcement.title},{"property" => "og:site_name", "content" => Site.first.title},{"property" => "og:url", "content" => request.original_url.split("?").first},{"property" => "og:description", "content" => meta_desc},{"property" => "og:image", "content" => "#{request.base_url}#{custom_announcement.image.url}"},{"property" => "og:type", "content" => "Article"}])
subtitle_ann = nil
img_src = nil
img_description = nil
subtitle_ann = custom_announcement.subtitle if custom_announcement.display_subtitle?
img_src = (custom_announcement.image.thumb.url || "/assets/custom_announcement-default.jpg") if custom_announcement.display_img?
img_description = custom_announcement.image_description if (custom_announcement.image_description.present?) && (custom_announcement.display_img?)
show_comment_flag = custom_announcement.open_comment_for_user(OrbitHelper.current_user)
custom_bulletin_carousel_images = custom_announcement.custom_bulletin_carousel_images.map{|image| {"src"=>image.file.url,"description"=>image.description.to_s,"description_text"=>image.description_text }}
resume_btn_title = (I18n.locale.to_s =="zh_tw") ? "繼續播放" : "resume"
pause_btn_title = (I18n.locale.to_s =="zh_tw") ? "暫停播放" : "pause"
prev_btn_title = (I18n.locale.to_s =="zh_tw") ? "上一張" : "prev"
next_btn_title = (I18n.locale.to_s =="zh_tw") ? "下一張" : "next"
{
"tags" => tags,
"custom_bulletin_files" => files,
"custom_bulletin_links" => links,
"custom_bulletin_carousel_images" => custom_bulletin_carousel_images,
"data" => {
"title" => custom_announcement.title,
"subtitle_ann" => subtitle_ann,
"update_user" => update_user,
"updated_at" => (custom_announcement.postdate.in_time_zone(Time.zone.utc_offset / 3600).strftime('%Y-%m-%d %H:%M') rescue ""),
"body" =>custom_announcement.text,
"image" => custom_announcement.image.url,
"img_src" => img_src,
"img_description" => img_description,
"hide_class" => custom_announcement.display_img? ? custom_announcement.image_display_class : ' hide',
"alt_title" => desc,
"resume_btn_title" => resume_btn_title,
"pause_btn_title" => pause_btn_title,
"prev_btn_title" => prev_btn_title,
"next_btn_title" => next_btn_title,
"carousel_display_style" => (custom_bulletin_carousel_images.count == 0 ? 'display: none' : 'width: 50%;margin: auto;'),
"carousel_count" => custom_bulletin_carousel_images.count
},
"comments" => custom_announcement.comments,
"show_comment_flag" => show_comment_flag,
"impressionist" => (custom_announcement.is_preview ? nil : custom_announcement),
"url_to_edit"=>url_to_edit
}
end
def show_feed_custom_announcement(uid)
custom_announcement = OrbitHelper.get_from_feed(uid)
locale = OrbitHelper.get_site_locale.to_s
url_to_edit = "#"
return {} if custom_announcement.blank?
tags = []
custom_announcement["tags"].each{|tag|
t = Tag.where(:name => tag["name_translations"][locale]).first rescue nil
if t.nil?
I18n.locale = (locale == "en" ? :zh_tw : :en)
t = Tag.where(:name => tag["name_translations"][locale]).first rescue nil
I18n.locale = locale.to_sym
end
tags << {
"tag" => tag["name_translations"][locale],
"url" => (t.nil? ? "#" : OrbitHelper.page_for_tag(t))
}
}
files = custom_announcement["custom_bulletin_files"].map{|file| { "file_url" => file["url"], "file_title" => (file["title_translations"][locale] == "" ? URI.unescape(File.basename(file["url"])) : file["title_translations"][locale] rescue '') } } rescue []
files.each do |file|
if file["file_url"] =="" || file["file_url"] == nil
files.delete(file)
end
end
links = custom_announcement["custom_bulletin_links"].map{|link| { "link_url" => link["url"], "link_title" => (link["title_translations"][locale] == "" ? link["url"] : link["title_translations"][locale]) } } rescue []
update_user = custom_announcement["author"]
desc = custom_announcement["image_description_translations"][locale] rescue ""
desc = (desc.nil? || desc == "" ? "custom_announcement image" : desc)
img_description = nil
img_description = custom_announcement["image_description_translations"][I18n.locale] if custom_announcement['display_img']
img_src = nil
img_src = (custom_announcement['image']['thumb'] || "/assets/custom_announcement-default.jpg") if custom_announcement['display_img']
subtitle_ann = custom_announcement['subtitle_ann']
request = OrbitHelper.request
if custom_announcement["subtitle_translations"].present?
meta_desc = custom_announcement["subtitle_translations"][locale] != "" ? custom_announcement["subtitle_translations"][locale] : custom_announcement["text_translations"][locale][0..200] rescue ""
else
meta_desc = ""
end
OrbitHelper.render_meta_tags([{"property" => "og:title", "content" => custom_announcement["title_translations"][locale]},{"property" => "og:site_name", "content" => Site.first.title},{"property" => "og:url", "content" => request.original_url.split("?").first},{"property" => "og:description", "content" => meta_desc},{"property" => "og:image", "content" => custom_announcement["image"]["original"]},{"property" => "og:type", "content" => "Article"}])
datetime = DateTime.parse(custom_announcement["postdate"])
custom_bulletin_carousel_images = Array(custom_announcement["custom_bulletin_carousel_images"])
resume_btn_title = (I18n.locale.to_s =="zh_tw") ? "繼續播放" : "resume"
pause_btn_title = (I18n.locale.to_s =="zh_tw") ? "暫停播放" : "pause"
prev_btn_title = (I18n.locale.to_s =="zh_tw") ? "上一張" : "prev"
next_btn_title = (I18n.locale.to_s =="zh_tw") ? "下一張" : "next"
{
"tags" => tags,
"custom_bulletin_files" => files,
"custom_bulletin_links" => links,
"custom_bulletin_carousel_images" => custom_bulletin_carousel_images,
"data" => {
"title" => custom_announcement["title_translations"][locale],
"subtitle_ann" => subtitle_ann,
"update_user" => update_user,
"updated_at" => (datetime.in_time_zone(Time.zone.utc_offset / 3600).strftime('%Y-%m-%d %H:%M') rescue ""),
"body" => custom_announcement["text_translations"][locale],
"image" => custom_announcement["image"]["original"],
"img_src" => img_src,
"img_description" => img_description,
"hide_class" => custom_announcement["display_img"] ? '' : ' hide',
"alt_title" => desc,
"resume_btn_title" => resume_btn_title,
"pause_btn_title" => pause_btn_title,
"prev_btn_title" => prev_btn_title,
"next_btn_title" => next_btn_title,
"carousel_display_style" => (custom_bulletin_carousel_images.count == 0 ? 'display: none' : 'width: 50%;margin: auto;'),
"carousel_count" => custom_bulletin_carousel_images.count
},
"comments" => [],
"show_comment_flag" => false,
"impressionist" => nil,
"url_to_edit" => url_to_edit
}
end
def show
params = OrbitHelper.params
uid = params[:uid]
if OrbitHelper.is_object_from_feed?(uid)
show_feed_custom_announcement(uid)
else
show_local_custom_announcement(uid, (params["preview"] == "true" ? true : false))
end
end
def show_widget
@type = "show_widget"
@show_page = params[:show_page]
if params[:tags].nil?
@tags = ['all']
else
@tags = params[:tags]
end
if params[:categories].nil?
@categories = ['all']
else
@categories = params[:categories]
end
OrbitHelper.set_site_locale(I18n.locale)
OrbitHelper.set_current_widget_module("custom_announcement")
OrbitHelper.set_params(params,current_user)
CustomBulletin.remove_expired_status
OrbitHelper.set_page_number(params[:page_no].to_i)
OrbitHelper.set_page_data_count((params[:data_count].blank? ? 10 : params[:data_count].to_i))
sorted,total_pages = get_sorted_annc
custom_anns = sorted.collect do |a|
if a["source-site"].blank?
statuses = a.statuses_with_classname.collect do |status|
{
"status" => status["name"],
"status-class" => "status-#{status['classname']}"
}
end
locale = I18n.locale.to_s
files = a.custom_bulletin_files.map{|file| { "file_url" => file.file.url + "\" title=\"#{file.file_title}", "file_title" => (file.title.blank? ? File.basename(file.file.path) : file.title rescue '') } if file.enabled_for?(locale) } rescue []
files.delete(nil)
links = a.custom_bulletin_links.map{|link| { "link_url" => link.url, "link_title" => (link.title.blank? ? link.url : link.title) } } rescue []
author = User.find(a.create_user_id).member_profile.name rescue ""
desc = a.image_description
desc = (desc.blank? ? "custom_announcement image" : desc)
link_to_show = (a.is_external_link ? a.external_link : OrbitHelper.url_to_show(a.to_param)) rescue ""
target = a.is_external_link ? "_blank" : "_self"
doc = Nokogiri::HTML(a.title)
title = doc.text.empty? ? 'no content' : doc.text
{
"department" => author,
"custom_bulletin_links" => links,
"custom_bulletin_files" => files,
"title" => a.title,
"source-site" => "",
"source-site-title" => "",
"source-site-link" => "",
"subtitle" => a.subtitle,
"statuses" => statuses,
"category" => a.category.title,
"postdate" => a.postdate,
"author" => author,
"is_top" => (a.is_top? ? 1 : 0),
"link_to_show" => link_to_show+"\" title=\"#{title}\"",
"target" => target,
"img_src" => a.image.thumb.url || "/assets/custom_announcement-default.jpg",
"img_description" => desc,
"more" => t(:more_plus),
"view_count" => a.view_count
}
else
a
end
end
#If no data , hide title&table
if sorted.count == 0
display = "hide"
end
# custom_anns = custom_anns.concat(feeds_custom_anns)
# total_pages = custom_announcements.total_pages
@data = {
"custom_announcements" => custom_anns,
"extras" => {
"widget-title" =>t('custom_announcement.custom_announcement'),
"title-head" => t('custom_announcement.table.title'),
"date-head" => t('custom_announcement.table.date'),
"status-head" => t('custom_announcement.table.status'),
"author-head" => t('custom_announcement.table.author'),
"subtitle-head" => t('custom_announcement.table.sub_title'),
"category-head" => t('custom_announcement.table.category'),
"link-head" => t('custom_announcement.table.link'),
"file-head" => t('custom_announcement.table.file'),
"view-count-head" => t('custom_announcement.table.view_count'),
"display" => display,
"department-head" => t('custom_announcement.table.department')
},
"total_pages" => total_pages
}
render :layout => false
end
end

View File

@ -0,0 +1,128 @@
# encoding: utf-8
class CustomBulletinsController < ApplicationController
before_filter :set_I18n
def get_custom_bulletins
page = Page.where(:module => "custom_announcement").first rescue nil
# 頁次
page_num = params[:page_num].blank? ? 0 : params[:page_num].to_i
# 每頁顯示的則數
per_page = params[:per_page].blank? ? 10 : params[:per_page].to_i
per_page = per_page > 0 ? per_page : 10
I18n.locale = :zh_tw
if !params[:keyword].blank?
keyword = Regexp.new(".*"+params[:keyword]+".*")
custom_bulletins = CustomBulletin.any_of({:title=>keyword},{:subtitle=>keyword},{:text=>keyword})
else
custom_bulletins = CustomBulletin.all
end
if !params[:category].blank?
module_id = ModuleApp.where(:key=>"custom_announcement").first.id
category = Regexp.new(".*"+params[:category]+".*")
category_id = Category.where(:title => category, :module_app_id => module_id).first.id
custom_bulletins = custom_bulletins.where(:category_id => category_id)
else
custom_bulletins = custom_bulletins
end
custom_bulletins = custom_bulletins.where(:is_preview.in=>[false,nil])
custom_bulletins = custom_bulletins.where(:approved.ne => false , :rejected.ne => true)
custom_bulletins = custom_bulletins.where(:postdate.lt=>Time.now)
custom_bulletins = custom_bulletins.desc( :is_top, :postdate).page(page_num).per(per_page)
custom_bulletins = custom_bulletins.collect do |b|
image = request.protocol + request.host_with_port + b.image.url rescue nil
links = b.custom_bulletin_links.collect do |bl|
{
"title" => bl.title_translations,
"url" => bl.url
}
end rescue nil
files = b.custom_bulletin_files.collect do |bf|
file = request.protocol + request.host_with_port + bf.file.url rescue nil
{
"title" => bf.title_translations,
"description" => bf.description_translations,
"file" => file
}
end rescue nil
ts = b.tags.collect do |t|
{
"name" => t.name_translations
}
end rescue nil
text = {"en" => "", "zh_tw" => ""}
text["en"] = (b.text_translations["en"].nil? ? "" :smart_convertor(b.text_translations["en"]))
text["zh_tw"] = (b.text_translations["zh_tw"].nil? ? "" : smart_convertor(b.text_translations["zh_tw"]))
author = User.find(b.create_user_id).member_profile.name rescue ""
{
"id" => b.id.to_s,
"title" => b.title_translations,
"subtitle" => b.subtitle_translations,
"text" => text,
"postdate" => b.postdate,
"deadline" => b.deadline,
"category" => b.category.title_translations,
"tags" => ts,
"image" => image,
"links" => links,
"files" => files,
"author" => author,
"url" => "/#{I18n.locale.to_s + page.url}/#{b.to_param}"
}
end
# 計算總筆數 Start
if !params[:keyword].blank?
keyword = Regexp.new(".*"+params[:keyword]+".*")
custom_bulletin_count = CustomBulletin.any_of({:title=>keyword},{:subtitle=>keyword},{:text=>keyword})
else
custom_bulletin_count = CustomBulletin.all
end
custom_bulletin_count = custom_bulletin_count.where(:is_preview.in=>[false,nil])
custom_bulletin_count = custom_bulletin_count.where(:approved.ne => false , :rejected.ne => true)
custom_bulletin_count = custom_bulletin_count.where(:postdate.lt=>Time.now)
total_pages = custom_bulletin_count.count
# End
render :json => {
"custom_bulletins" => custom_bulletins,
"custom_bulletins_count" => custom_bulletins.count,
"page_num" => page_num,
"total_pages" => total_pages,
}.to_json
end
def smart_convertor(text)
html_string = text
links = html_string.scan(/img.*?src="(.*?)"/i)
links.each do |link|
l = link.first
new_link = nil
if l.starts_with?("/")
new_link = request.protocol + request.host_with_port + l
elsif l.starts_with?("..")
l1 = l.gsub("../","")
new_link = request.protocol + request.host_with_port + "/" + l1
end
html_string = html_string.sub(l,new_link) if !new_link.nil?
end
return html_string
end
protected
def set_I18n
I18n.locale = params[:lang] if params[:lang].present?
end
end

0
app/helpers/.keep Normal file
View File

View File

@ -0,0 +1,327 @@
require "net/http"
require "uri"
require 'json'
module Admin::CustomAnnouncementsHelper
def back_end_breadcrumb
if params[:controller] == "admin/custom_announcements"
res = ''
divider = "<span class='divider'>/</span>"
res << "<li><a href='#{admin_dashboards_path}'>#{t(:dashboard_)}</a>#{divider}</li>"
if params[:custom_module]
trans_name = I18n.t("module_name.#{params[:custom_module]}")
if trans_name.include?("translation missing")
trans_name = params[:custom_module]
end
res << "<li><a href='/admin/#{params[:custom_module].pluralize}'>#{trans_name}</a>#{divider}</li>"
end
if params[:action] != "index"
if params[:custom_module]
extra_url = "/#{params[:custom_module]}#{params[:bind_uid].present? ? ('-'+params[:bind_uid]) : ''}"
end
res << "<li><a href='/#{params[:controller]}#{extra_url}'>#{t('module_name.'+@module_app.key)}</a>#{divider}</li>"
res << "<li class='active'>#{t(params[:action], scope: 'restful_actions')}</li>"
else
res << "<li>#{t('module_name.'+@module_app.key)}</li>"
end
res.html_safe
else
super
end
end
def page_for_custom_bulletin(custom_bulletin)
ann_page = nil
pages = Page.where(:module=>'custom_announcement')
pages.each do |page|
if page.categories.count ==1
if page.categories.include?(custom_bulletin.category.id.to_s)
ann_page = page
end
end
break if !ann_page.nil?
end
if ann_page.nil?
pages.each do |page|
if (page.categories.include?(custom_bulletin.category.id.to_s) rescue false)
ann_page = page
end
break if !ann_page.nil?
end
end
ann_page = pages.first if ann_page.nil?
(ann_page.get_url+'/'+custom_bulletin.to_param).gsub('//','/') rescue "#"
end
def import_this_custom_announcement(row,categories,tags)
value = {}
custom_anns = CustomBulletin.new
row.cells.each_with_index do |cell,index|
val = cell.value rescue nil
if [8,9,10,11,12,13,14,15].exclude?(index)
next if val.blank?
end
case index
when 0
custom_anns.category = categories[val.to_i]
when 1
new_tags = []
if (val.include?(",") rescue false)
ts = val.split(",")
ts.each do |t|
new_tags << tags[t.to_i]
end
else
new_tags << tags[val.to_i]
end
custom_anns.tags=new_tags
when 2
custom_anns.postdate = val
when 3
custom_anns.deadline = val
when 4
custom_anns.is_top = (val.to_i == 1 ? true : false)
when 5
custom_anns.is_hot = (val.to_i == 1 ? true : false)
when 6
custom_anns.is_hidden = (val.to_i == 1 ? true : false)
when 7
custom_anns.remote_image_url = val
when 8
value["en"] = val
when 9
value["zh_tw"] = val
custom_anns.image_description_translations = value
value = {}
when 10
value["en"] = val
when 11
value["zh_tw"] = val
custom_anns.title_translations = value
value = {}
when 12
value["en"] = val
when 13
value["zh_tw"] = val
custom_anns.subtitle_translations = value
value = {}
when 14
value["en"] = val
when 15
value["zh_tw"] = val
custom_anns.text_translations = value
value = {}
when 16
links = val.split(";") rescue []
desc_en = row.cells[17].value.split(";") rescue []
desc_zh_tw = row.cells[18].value.split(";") rescue []
links.each_with_index do |link,i|
bl = CustomBulletinLink.new
bl.url = link.strip
bl.title_translations = {"en" => desc_en[i], "zh_tw" => desc_zh_tw[i]}
bl.custom_bulletin_id = custom_anns.id
bl.save
end
when 19
files = val.split(";") rescue []
desc_en = row.cells[20].value.split(";") rescue []
desc_zh_tw = row.cells[21].value.split(";") rescue []
alt_en = row.cells[22].value.split(";") rescue []
alt_zh_tw = row.cells[23].value.split(";") rescue []
files.each_with_index do |file, i|
bf = CustomBulletinFile.new
bf.remote_file_url = file.strip rescue nil
bf.title_translations = {"en" => (desc_en[i] rescue ""), "zh_tw" => (desc_zh_tw[i] rescue "")}
bf.description_translations = {"en" => (alt_en[i] rescue ""), "zh_tw" => (alt_zh_tw[i] rescue "")}
bf.custom_bulletin_id = custom_anns.id
bf.save
end
end
end
custom_anns.create_user_id = current_user.id.to_s
custom_anns.update_user_id = current_user.id.to_s
custom_anns.approved = true
custom_anns.save
end
def send_rejection_email(custom_announcement,locale)
user = User.find(custom_announcement.create_user_id) rescue nil
if !user.nil?
email = user.member_profile.email
if !email.nil? && email != ""
url = "http://#{request.host_with_port}/admin/custom_announcements/#{custom_announcement.id}/edit"
datatosend = "<h3>Hello #{user.name},</h3><p>#{current_user.name} #{t("custom_announcement.rejected_annoucement")} : #{custom_announcement.rejection_reason} <a href='#{url}'> #{t("custom_announcement.click_here_to_see")}</a></p>"
mail = Email.new(:mail_to => email, :mail_subject => "CustomAnnouncement rejected公告未通過 : #{custom_announcement.title_translations[locale]}.", :template => "email/custom_announcement_email.html.erb", :template_data => {"html" => datatosend})
mail.save
mail.deliver rescue nil
end
end
end
def send_notification_mail_to_managers(custom_announcement, type, locale)
users = []
if @custom_announcement_setting.email_to.include?("managers")
authorizations = Authorization.where(:module_app_id => @module_app.id)
users = authorizations.collect do |auth|
auth.user
end
end
if @custom_announcement_setting.email_to.include?("admins")
wg = Workgroup.where(:key => "admin").first
admins = User.where(:workgroup_id => wg.id)
users.delete(nil)
users = users.concat(admins.to_a)
end
if @custom_announcement_setting.email_to.include?("approvers")
approvers = User.find(@custom_announcement_setting.approvers).to_a rescue []
auths = Authorization.where(:category_id => custom_announcement.category_id).collect{|a| a.user}
users = users.concat(approvers & auths)
end
users.each do |user|
email = user.member_profile.email
if !email.nil? && email != ""
send_email(user.name, email, custom_announcement, type, locale)
# sleep(1)
end
end
end
def send_email(name, useremail, custom_announcement, type, locale)
url = "http://#{request.host_with_port}/admin/custom_announcements?url=#{page_for_custom_bulletin(custom_announcement).sub("http://" + request.host_with_port, "")}&id=#{custom_announcement.id}"
case type
when "approval"
datatosend = "<h3>#{t("custom_announcement.approval_mail_hi", :name => name)},</h3><p>#{t("custom_announcement.submitted_new_custom_announcement", :poster => current_user.name)}<br /><br />#{t("custom_announcement.approval_custom_announcement_title")} : #{custom_announcement.title_translations[locale]} <br /> #{t("custom_announcement.click_here_to_see")} : <a href='#{url}'> #{url} </a></p>"
when "reapproval"
datatosend = "<h3>#{t("custom_announcement.approval_mail_hi", :name => name)},</h3><p>#{t("custom_announcement.updated_annoucement", :poster => current_user.name)}<br /><br />#{t("custom_announcement.approval_custom_announcement_title")} : #{custom_announcement.title_translations[locale]} <br /> #{t("custom_announcement.click_here_to_see")} : <a href='#{url}'> #{url} </a></p>"
end
email = Email.new(:mail_to => useremail, :mail_subject => " #{t("custom_announcement.custom_announcement_subject")} : #{custom_announcement.title_translations[locale]}.", :template => "email/custom_announcement_email.html.erb", :template_data => {"html" => datatosend})
email.save
email.deliver rescue nil
end
def download_tmp_xml(url)
xml = File.join(Rails.root, "tmp", "ann_cc_ntu.xml")
open(xml, 'wb') do |fo|
fo.print open(url).read
end
end
def import_from_tmp_xml(file)
xml = Nokogiri::XML(file)
return if xml.nil?
custom_announcements = []
xml.xpath("//channel").xpath("//item").each do |custom_anns|
custom_announcements << {
:title => (custom_anns>"title").text,
:category => (custom_anns>"category").text,
:postdate => (custom_anns>"pubDate").text,
:text => (custom_anns>"description").text,
:rss2_sn => (custom_anns>"link").text.split("=").last
}
end
custom_announcements.each do |custom_anns|
ma = ModuleApp.where(:key => "custom_announcement").first
cat = Category.where(:title => custom_anns[:category]).first rescue nil
if cat.nil?
cat = Category.create(:title_translations => {"en" => custom_anns[:category], "zh_tw" => custom_anns[:category]}, :module_app_id => ma.id)
end
ann = CustomBulletin.where(:rss2_sn => custom_anns[:rss2_sn]).first rescue nil
if ann.nil?
ann = CustomBulletin.new(:title_translations => {"en" => "", "zh_tw" => custom_anns[:title]}, :postdate => custom_anns[:postdate], :subtitle_translations => {"en" => "", "zh_tw" => custom_anns[:title]}, :text_translations => {"en" => "", "zh_tw" => custom_anns[:text]}, :rss2_sn => custom_anns[:rss2_sn], :category_id => cat.id, :approved => true, :create_user_id => current_user.id)
else
ann.update_attributes(:title_translations => {"en" => "", "zh_tw" => custom_anns[:title]}, :postdate => custom_anns[:postdate], :subtitle_translations => {"en" => "", "zh_tw" => custom_anns[:title]}, :text_translations => {"en" => "", "zh_tw" => custom_anns[:text]})
end
ann.save
end
File.delete(file)
end
def import_from_wordpress(xmlfile)
xml_file = File.read(xmlfile)
doc = Nokogiri::XML.parse(xml_file)
doc.xpath("//channel").each do|channel_data|
channel_data.xpath('//item').each do|itme|
bu = CustomBulletin.where(:rss2_sn => itme.xpath('wp:post_id').text ).first rescue nil
if bu.nil?
bu = CustomBulletin.new
bu.approved = true
bu.rss2_sn = itme.xpath('wp:post_id').text
bu.title_translations = {"en" => itme.xpath('title').text, "zh_tw" => itme.xpath('title').text}
bu.text_translations = {"en" => itme.xpath('content:encoded').text, "zh_tw" => itme.xpath('content:encoded').text}
bu.postdate = itme.xpath('wp:post_date').text
itme.xpath('category').each do |i_cate|
if i_cate["domain"].to_s == "category"
cat = @module_app.categories.where(:title => i_cate.text.to_s).first rescue nil
if cat.nil?
cat = Category.new
cat.module_app = @module_app
cat.title_translations = {"en" => i_cate.text.to_s, "zh_tw" => i_cate.text.to_s}
cat.save
end
bu.category = cat
elsif i_cate["domain"].to_s == "post_tag"
tag = Tag.where(:name => i_cate.text.to_s ).first rescue nil
if tag.nil?
tag = Tag.new
tag.name_translations = {"en" => i_cate.text.to_s, "zh_tw" => i_cate.text.to_s}
tag.module_app_ids << @module_app.id
tag.save
end
bu.tags = tag
end
end
bu.save
end
end
end
File.delete(xmlfile)
end
def load_access_level
if (current_user.is_admin? rescue false)
@access_level = "admin"
elsif (current_user.is_manager?(@module_app) rescue false)
@access_level = "manager"
else
@access_level = "users"
end
end
def user_can_approve?(custom_anns=nil)
can_approve = false
setting = CustomAnnouncementSetting.first
case @access_level
when "admin"
can_approve = true
when "manager"
can_approve = true
else
can_approve = false
end
if !can_approve
if !custom_anns.nil?
if setting.approvers.include?(current_user.id.to_s)
if (current_user.approved_categories_for_module(@module_app).include?(custom_anns.category) rescue false)
can_approve = true
end
end
else
can_approve = setting.approvers.include?(current_user.id.to_s)
end
end
can_approve
end
end

View File

@ -0,0 +1,488 @@
module CustomAnnouncementsHelper
def self.complementaryColor(my_hex)
if my_hex[0] == '#'
my_hex = my_hex[1..-1]
end
rgb = my_hex.split(//).each_slice(my_hex.length/3).map{|v| v.join}
comp = rgb.map{|a| (255 - a.to_i(16)).to_s(16).rjust(2,'0')}
'#'+comp.join
end
def self.lighten_color(my_hex,percent)
if my_hex[0] == '#'
my_hex = my_hex[1..-1]
end
rgb = my_hex.split(//).each_slice(my_hex.length/3).map{|v| v.join}
comp = rgb.collect do |a|
tmp = a.to_i(16)*(1+percent/100.0)
tmp = 255 if tmp>255
tmp = 0 if tmp < 0
tmp.to_i.to_s(16).rjust(2,'0')
end
'#'+comp.join
end
def set_image_version_for_widget
subpart = OrbitHelper.get_current_widget
@image_version = 'thumb'
if subpart.methods.include? 'select_options'.to_sym
ModuleApp.all.select{|tmp| tmp.key.to_s=='custom_announcement'}.each do |modile_app|
@show_options = modile_app.show_options rescue nil
end
subpart.select_options.each do |select_option|
if !(@show_options.nil?) && select_option.field_name == @show_options.keys.first.to_s
value = YAML.load(select_option.value)
tmp = value[:en]
I18n.with_locale(:en) do
if tmp == t('custom_announcement.small_size')
@image_version = 'thumb'
elsif tmp == t('custom_announcement.medium_size')
@image_version = 'mobile'
elsif tmp == t('custom_announcement.orignal_size')
@image_version = 'orignal'
end
end
end
end
end
end
def data_to_human_type(a,set_tag_ids=nil)
statuses = a.statuses_with_classname.collect do |status|
{
"status" => status["name"],
"status-class" => "status-#{status['classname']}"
}
end
files = a.custom_bulletin_files.map{|file| { "file_url" => file.file.url, "file_title" => (file.title.blank? ? File.basename(file.file.path) : file.title rescue '') } if file.enabled_for?(locale) } rescue []
files.delete(nil)
links = a.custom_bulletin_links.map{|link| { "link_url" => link.url, "link_title" => (link.title.blank? ? link.url : link.title) } } rescue []
author = User.find(a.create_user_id).member_profile.name rescue ""
desc = a.image_description
desc = (desc.nil? || desc == "" ? "custom_announcement image" : desc)
link_to_show = (a.is_external_link? ? a.external_link : OrbitHelper.widget_item_url(a.to_param)) rescue ""
target = a.is_external_link ? "_blank" : "_self"
if @image_version == 'thumb'
image_url = a.image.thumb.url
elsif @image_version == 'mobile'
image_url = a.image.mobile.url
else
image_url = a.image.url
end
{
"custom_bulletin_links" => links,
"custom_bulletin_files" => files,
"title" => a.title,
"source-site" => "",
"source-site-title" => "",
"source-site-link" => "",
"subtitle" => a.subtitle,
"statuses" => statuses,
"category" => (a.category.title rescue ''),
"tag_ids" => (set_tag_ids.nil? ? (a.tag_ids.map{|id| id.to_s}.to_s.gsub('"',"'") rescue '[]') : set_tag_ids),
"postdate" => a.postdate,
"author" => author,
"link_to_show" => link_to_show,
"target" => target,
"img_src" => image_url || "/assets/custom_announcement-default.jpg",
"img_description" => desc
}
end
def get_feed_annc(type,site_source,locale)
ma_key = 'custom_announcement'
if type == "index"
categories = Array(OrbitHelper.page_categories)
elsif type == "widget"
categories = Array(OrbitHelper.widget_categories)
else
categories = []
end
if categories.include?("all")
feeds = SiteFeedCustomAnnc.where(:channel_key => ma_key)
else
feeds = SiteFeedCustomAnnc.where(:channel_key => ma_key, :merge_with_category.in => categories)
end
if feeds.count > 0
temp_ids = []
data = feeds.collect do |feed|
feed.all_contents_for_feed(site_source,locale,type=='widget')
end.flatten.compact
else
data = []
end
data
end
def get_feed_custom_announcements(type,site_source=nil)
locale = OrbitHelper.get_site_locale.to_s
if !(defined? SiteFeedCustomAnnc).nil?
fans = get_feed_annc(type,site_source,locale)
else
feed_custom_anns = OrbitHelper.get_feed_for_module(type)
fans = []
feed_custom_anns.each do |fa|
next if !site_source.nil? && site_source != fa["source-site-title"]
status = {
"status" => "<a href='#{fa["source-site"]}' target='_blank' class='feed-source'>#{fa["source-site-title"]}</a>",
"status-class" => "status-source"
}
files = fa["custom_bulletin_files"].collect{|bf| { "file_url" => bf["url"], "file_title" => (fa["title_translations"][locale].blank? ? File.basename(fa["url"]) : fa["title_translations"][locale] rescue '') }} rescue []
links = fa["custom_bulletin_links"].map{|link| { "link_url" => link["url"], "link_title" => (link["title_translations"][locale].blank? ? link["url"] : link["title_translations"][locale]) } } rescue []
x = {
"custom_bulletin_links" => links,
"custom_bulletin_files" => files,
"custom_bulletin_carousel_images" => fa["custom_bulletin_carousel_images"].to_a,
"title" => fa["title_translations"][locale],
"subtitle" => fa["subtitle_translations"][locale],
"statuses" => [status],
"category" => fa["category"],
"postdate" => fa["postdate"],
"author" => fa["author"],
"source-site" => "<a href='#{fa["source-site"]}' target='_blank' class='feed-source'>#{fa["source-site-title"]}</a>",
"source-site-title" => fa["source-site-title"],
"source-site-link" => fa["source-site"],
"link_to_show" => OrbitHelper.url_to_show(fa["params"]),
"target" => "_self",
"img_src" => fa["image"]["thumb"] || "/assets/custom_announcement-default.jpg",
"img_description" => fa["image_description_translations"][locale],
"more" => t(:more_plus),
"view_count" => ""
}
if (!x["title"].empty? rescue false)
fans << x
end
end
end
fans
end
def filter_by_keywords(sorted,keywords,stime,etime)
kflag = keywords.blank?
sflag = stime.blank?
eflag = etime.blank?
stime = stime.to_s.split('/')
stime = Time.zone.local(*stime) rescue nil
etime = etime.to_s.split('/')
etime = Time.zone.local(*etime) rescue nil
if !kflag || !sflag || !eflag
sorted.select{|custom_anns|
if kflag
flag = true
else
if custom_anns["source-site"].present?
title = Nokogiri::HTML(custom_anns["title"].to_s).text
else
title = Nokogiri::HTML(custom_anns.title.to_s).text
end
flag = title.include?(keywords.to_s)
end
if sflag && !eflag
flag = flag && (custom_anns.postdate<=etime)
elsif !sflag && eflag
flag = flag && (custom_anns.postdate>=stime)
elsif !sflag && !eflag
flag = flag && (custom_anns.postdate>=stime) && (custom_anns.postdate<=etime)
end
flag
}
else
sorted
end
end
def get_sorted_annc(data_count=nil)
params = OrbitHelper.params
locale = OrbitHelper.get_site_locale.to_s
page_number = OrbitHelper.page_number.to_i
page = OrbitHelper.page rescue nil
unless page
page = Page.where(url:params['url']).first
end
page_number = 1 if page_number == 0
page_data_count = data_count || OrbitHelper.page_data_count.to_i
feeds_custom_anns = []
custom_data_field = page.custom_data_field rescue nil
if custom_data_field.nil?
custom_data_field = {}
elsif custom_data_field["bind_module_app"]
custom_data_field["custom_module"] = custom_data_field["bind_module_app"]
custom_data_field.delete('bind_module_app')
end
if @type == "show_widget"
tags = @tags
categories = @categories
else
tags = page.tags
tags = params[:tags] if params[:tags].present?
categories = params['category']=='all' ? (page.categories || []) : (Array(params['category']) rescue (page.categories || []))
if params['category'].present?
tags = ["all"]
end
end
if !params["source"].present?
if @type == "show_widget"
if params[:uids].blank?
custom_announcements = CustomBulletin.where(:title.nin => ["",nil],:is_preview.in=>[false,nil]).where(custom_data_field)
.can_display_and_sorted.is_approved
.filter_by_categories(categories,false).filter_by_tags(tags).to_a
else
member_prfile = MemberProfile.any_in(:uid=>params[:uids])
user_ids = member_prfile.map{|m| m.user.id rescue nil}.select{|id| !id.nil?}
custom_announcements = CustomBulletin.where(:title.nin => ["",nil],:is_preview.in=>[false,nil],:create_user_id.in=>user_ids).where(custom_data_field)
.can_display_and_sorted.is_approved
.filter_by_categories(categories,false).filter_by_tags(tags).to_a
end
else
custom_announcements = CustomBulletin.where(:title.nin => ["",nil],:is_preview.in=>[false,nil]).where(custom_data_field)
.can_display_and_sorted.is_approved
.filter_by_categories(categories,false).filter_by_tags(tags).to_a
end
if !(defined? SiteFeed).nil?
if @type != "show_widget"
feeds_custom_anns = get_feed_custom_announcements("index")
else
feeds_custom_anns = []
end
end
else
custom_announcements = []
if @type != "show_widget"
feeds_custom_anns = get_feed_custom_announcements("index",params["source"])
else
feeds_custom_anns = []
end
end
if !feeds_custom_anns.blank?
if custom_announcements.count != 0
top_custom_anns = custom_announcements.select{|v| v.is_top} + feeds_custom_anns.select{|v| v['is_top']}
rest_all_custom_anns = feeds_custom_anns.select{|v| v['is_top'] != true} + custom_announcements.select{|v| !v.is_top}
rest_custom_anns = rest_all_custom_anns.sort{|v1,v2| v2["postdate"]<=>v1["postdate"]}
all_sorted = top_custom_anns.sort{|v1,v2| v2["postdate"]<=>v1["postdate"]} + rest_custom_anns
else
all_sorted = feeds_custom_anns.select{|v| v['is_top']}.sort{|v1,v2| v2["postdate"]<=>v1["postdate"]} + feeds_custom_anns.select{|v| v['is_top'] != true}.sort{|v1,v2| v2["postdate"]<=>v1["postdate"]}
end
all_filter = filter_by_keywords(all_sorted,params[:keywords],params[:stime],params[:etime])
else
all_filter = filter_by_keywords(custom_announcements,params[:keywords],params[:stime],params[:etime])
end
if page_data_count != 0
sorted = all_filter[(page_number-1)*page_data_count...page_number*page_data_count]
else
sorted = all_filter
end
annc_count = all_filter.count
total_pages = page_data_count == 0 ? 1 : (annc_count.to_f / page_data_count).ceil
[sorted,total_pages]
end
def render_view_for_annc(overridehtml=nil)
@key = Site.first.template
def render_link_to_edit(html, url_to_edit)
if html.scan("{{link_to_edit}}").length == 0
html = url_to_edit.blank? ? html : html + "<p class='admin-edit text-right'><a class='btn btn-primary' href='#{url_to_edit}'><i class='icon-edit'></i> #{t(:edit)}</a></p>"
else
html = url_to_edit.blank? ? html.gsub("{{link_to_edit}}","") : html.gsub("{{link_to_edit}}","<p class='admin-edit text-right'><a class='btn btn-primary' href='#{url_to_edit}'><i class='icon-edit'></i> #{t(:edit)}</a></p>")
end
return html
end
def parsing_repeats_again(elements,d,level)
newhtml = []
oldhtml = []
elements.each do |el|
html_to_render = ""
data_name = el.attr("data-list")
wrap_elements = el.css("*[data-list][data-level='#{level}']")
if d[data_name]
d[data_name].each_with_index do |item,i|
element = el.inner_html
if wrap_elements.count > 0
htmls = parsing_repeats_again(wrap_elements,d[data_name][i], level + 1)
htmls[0].each_with_index do |html,i|
element = element.gsub(html,htmls[1][i])
end
end
item.each do |key,value|
if !value.kind_of?(Array)
value = value.nil? ? "" : value
element = element.gsub("{{#{key}}}",value.to_s.html_safe)
element = element.gsub("%7B%7B#{key}%7D%7D",value.to_s.html_safe)
element = render_link_to_edit(element, value) if key.eql?("url_to_edit")
end
end
html_to_render = html_to_render + element
end
temp = el.to_s
oldhtml << temp
temp = temp.gsub(el.inner_html, html_to_render)
newhtml << temp
end
end
[oldhtml,newhtml]
end
if @target_action == "index"
filename = overridehtml.nil? ? params[:layout_type] : overridehtml
f = File.join(Rails.root, 'app', 'templates', "#{@key}", 'modules', 'custom_announcement', "#{filename}.html.erb")
if !File.exists?f
f = File.join(Rails.root, 'app', 'templates', "#{@key}", 'modules', 'custom_announcement', "index.html.erb")
if !File.exists?f
return "<div class='well'>Maybe the administrator has changed the theme, please select the index page design again from the page settings.</div>".html_safe
end
end
file = File.open(f)
doc = Nokogiri::HTML(file, nil, "UTF-8")
file.close
controller = CustomAnnouncementsController.new
begin
data = @data# rescue nil
rescue Exception => e
write_debug_file(e,'custom_announcements',@target_action) if Site::DEBUG
end
if !data.nil?
wrap_elements = doc.css("*[data-list][data-level='0']")
htmls = parsing_repeats_again(wrap_elements,data,1)
html = doc.to_s
htmls[0].each_with_index do |h,i|
html = html.gsub(h,htmls[1][i])
end
extras = data["extras"] || {}
extras["page-title"] = Page.find_by(:page_id => params[:page_id]).name rescue "" if !extras["page-title"]
extras.each do |key,value|
value = value.nil? ? "" : value
html = html.gsub("{{#{key}}}",value.to_s.html_safe)
html = html.gsub("%7B%7B#{key}%7D%7D",value.to_s.html_safe)
end
total_pages = data['total_pages'].to_i rescue 1
if total_pages > 1
html = html.gsub("{{pagination_goes_here}}",create_pagination(total_pages))
else
html = html.gsub("{{pagination_goes_here}}","");
end
html.html_safe
else
return "<div class='well'>No content to show.</div>".html_safe
end
else
filename = overridehtml.nil? ? @target_action : overridehtml
f = File.join(Rails.root, 'app', 'templates', "#{@key}", 'modules', 'custom_announcement', "#{filename}.html.erb")
if File.exists?f
file = File.open(f)
doc = Nokogiri::HTML(file, nil, "UTF-8")
file.close
controller = CustomAnnouncementsController.new
begin
data = @data# rescue nil
rescue Exception => e
write_debug_file(e,'custom_announcements',@target_action) if Site::DEBUG
end
if data.nil?
return "<div class='well'> No content to show. </div>".html_safe
end
if data.blank? || data.empty?
file = File.open("#{Rails.root}/app/views/errors/404.html")
doc = Nokogiri::HTML(file, nil, "UTF-8")
file.close
doc.to_html.html_safe
else
unless data['impressionist'].blank?
Thread.new do
impression = data['impressionist'].impressions.create
impression.user_id = request.session['user_id']
impression.controller_name = 'custom_announcements'
impression.action_name = @target_action
impression.ip_address = request.remote_ip
impression.session_hash = request.session.id
impression.request_hash = @impressionist_hash
impression.referrer = request.referrer
impression.save
end
data['impressionist'].inc(view_count: 1)
data["data"]["view_count"] = data["impressionist"].view_count if data["data"].present?
end
wrap_elements = doc.css("*[data-list][data-level='0']")
if wrap_elements.count == 0
wrap_element_html = doc.to_s
el = wrap_element_html
data.each do |key,value|
next if key.eql? 'impressionist'
value = value.nil? ? "" : value
el = el.gsub("{{#{key}}}",value.to_s.html_safe)
el = el.gsub("%7B%7B#{key}%7D%7D",value.to_s.html_safe)
end
el.html_safe
else
keys = data.keys
not_array_key = nil
data.keys.each do |key|
not_array_key = key if data["#{key}"].kind_of?(Hash)
end
htmls = parsing_repeats_again(wrap_elements,data,1)
html = doc.to_s
htmls[0].each_with_index do |h,i|
html = html.gsub(h,htmls[1][i])
end
extras = data["#{not_array_key}"] || {}
extras.each do |key,value|
next if key.eql? 'impressionist'
value = value.nil? ? "" : value
html = html.gsub("{{#{key}}}",value.to_s)
html = html.gsub("%7B%7B#{key}%7D%7D",value.to_s)
end
html = render_link_to_edit(html, data["url_to_edit"]) if !data["url_to_edit"].nil?
total_pages = data['total_pages'].to_i rescue 1
if @show_page == "false"
html = html.gsub("{{pagination_goes_here}}","")
else
if total_pages > 1
html = html.gsub("{{pagination_goes_here}}",create_pagination(total_pages))
else
html = html.gsub("{{pagination_goes_here}}","")
end
end
html = Nokogiri::HTML.parse(html)
html.css('.i-annc__page-title').remove
dates = html.css("*[date-format]")
if !dates.blank?
dates.each do |d|
begin
format = d.attributes["date-format"].value
date = DateTime.parse(d.inner_text)
d.inner_html = d.inner_html.gsub(d.inner_text.strip, " " + date.strftime(format))
rescue
next
end
end
end
html.css("body")[0].inner_html = html.css("body")[0].inner_html.gsub("{{page-title}}","")
html.css("body").to_html.html_safe
end
end
else
return "<div class='well'>There is a problem with the design. We will try to fix it as soon as possible. Sorry for the inconvenience!! :(</div>".html_safe
end
end
end
def get_layouts(module_app)
layout_types = []
@key = Site.first.template
f = File.join("#{Rails.root}/app/templates/#{@key}/modules/#{module_app}/info.json")
if File.exists?f
info = File.read(f)
hash = JSON.parse(info) rescue {}
frontends = hash["frontend"] || []
frontends.each do |frontend|
frontend["thumbnail"] = "/assets/#{module_app}/thumbs/#{frontend["thumbnail"]}"
layout_types << frontend
end
end
if layout_types.empty?
Dir.glob("#{Rails.root}/app/templates/#{@key}/modules/#{module_app}/*").each do |w|
next if File.ftype(w).eql?("directory")
w = File.basename(w, ".*")
w = File.basename(w, ".*")
if w[0,1] != "_" && w[0,1] != "s" && w != "info"
layout_types << w
end
end
end
layout_types
end
end

0
app/mailers/.keep Normal file
View File

0
app/models/.keep Normal file
View File

View File

@ -0,0 +1,26 @@
class CustomAnnouncementSetting
include Mongoid::Document
include Mongoid::Timestamps
field :top_limit, type: Integer, :default => 0
field :pro_enabled, type: Boolean, :default => false
field :approvers, type: Array, :default => []
field :email_to, type: Array, :default => ["admins","managers","approvers"]
field :is_display_edit_only, type: Boolean, :default => false
field :only_manager_can_edit_status, type: Boolean, :default => false
field :top_text , type: String , localize: true
field :hot_text , type: String , localize: true
field :hidden_text , type: String , localize: true
has_many :custom_anns_status_settings, :autosave => true, :dependent => :destroy
accepts_nested_attributes_for :custom_anns_status_settings, :allow_destroy => true
def self.check_limit_for_user(user_id, b_id = nil)
limit = self.first.top_limit rescue 0
return true if limit == 0
count = CustomBulletin.where(:is_top => true, :create_user_id => user_id, :id.ne => b_id).count
return count < limit
end
def self.is_pro?
self.first.pro_enabled rescue false
end
end

View File

@ -0,0 +1,6 @@
class CustomAnnsCache
include Mongoid::Document
field :parent_id
field :filter_result
field :locale,type: String,default: 'zh_tw'
end

View File

@ -0,0 +1,7 @@
class CustomAnnsStatusSetting
include Mongoid::Document
field :role_id
field :status
field :top_limit
belongs_to :custom_announcement_setting
end

View File

@ -0,0 +1,246 @@
class CustomBulletin
include Mongoid::Document
include Mongoid::Timestamps
include OrbitModel::Status
include OrbitModel::Impression
# encoding: utf-8
include OrbitTag::Taggable
include OrbitCategory::Categorizable
include Slug
require 'custom_bulletin_model/cache'
include ::CustomBulletinModel::Cache
attr_accessor :org_tag_ids
def tags=(ids)
self.org_tag_ids = self.tag_ids
super(ids)
end
def []=(index,value)
if index.to_s=='tags'
self.org_tag_ids = self.tag_ids
end
super(index,value)
end
SubPart.class_eval { include CustomBulletinModel::Cache }
Page.class_eval { include CustomBulletinModel::Cache }
before_destroy do
CustomAnnsCache.all.destroy
end
field :custom_module
field :bind_uid
field :image_display_class, type: String, default: "full-size-img" #3 choices: full-size-img , pull-left , pull-right
field :add_to_calendar,type: Boolean,default: false
field :calendar_start_date, :type => DateTime
field :calendar_end_date, :type => DateTime
field :calendar_all_day,type: Boolean,default: false
field :calendar_type_id
field :event_id
field :page_id
field :title, type: String, localize: true
field :subtitle, localize: true
field :text, localize: true
field :create_user_id
field :update_user_id
field :public, :type => Boolean, :default => true
field :postdate , :type => DateTime, :default => Time.now
field :deadline , :type => DateTime
field :rss2_sn
field :approved, :type => Boolean, :default => false
field :is_preview, :type => Boolean, :default => false
field :expirable_created_at, type: DateTime
field :rejected, :type => Boolean, :default => false
field :reapproval, :type => Boolean, :default => false
field :rejection_reason
field :is_external_link, :type => Boolean, :default => false
field :external_link
field :display_subtitle, :type => Boolean, :default => false
field :display_img, :type => Boolean, :default => false
field :email_id
field :email_sent, :type => Boolean, :default => false
field :email_sentdate , :type => DateTime
field :email_member_ids
field :other_mailaddress
field :image_description, localize: true
field :top_end_date, :type => DateTime
field :open_comment, :type => Boolean, :default => false
field :comment_end_time, :type => DateTime
field :comment_role, :type => Array, :default => []
mount_uploader :image, ImageUploader
has_many :custom_bulletin_links, :autosave => true, :dependent => :destroy
has_many :custom_bulletin_files, :autosave => true, :dependent => :destroy
has_many :custom_bulletin_comments, :autosave => true, :dependent => :destroy
has_many :custom_bulletin_carousel_images, :autosave => true, :dependent => :destroy
accepts_nested_attributes_for :custom_bulletin_files, :allow_destroy => true
accepts_nested_attributes_for :custom_bulletin_links, :allow_destroy => true
accepts_nested_attributes_for :custom_bulletin_carousel_images, :allow_destroy => true
before_destroy :destroy_email
scope :can_display_and_sorted, ->{where(:is_hidden=>false,:is_preview => false).any_of({:postdate.lte=>Time.now, :deadline.gte=>Time.now},{:postdate.lte=>Time.now, :deadline=>nil},{:postdate=>nil}).order(is_top: :desc,postdate: :desc,id: :desc)}
scope :is_approved, ->{where(:approved => true)}
before_create :set_expire
before_save :check_limit
after_create do
custom_record_callback(1)
end
after_destroy do
custom_record_callback(-1)
end
def custom_record_callback(num)
if self.custom_module && self.bind_uid.present?
custom_bulletin_config = CustomBulletinConfig.where(:module=>self.custom_module).first
if custom_bulletin_config && custom_bulletin_config.custom_record_callback.present? && custom_bulletin_config.bind_model.present?
target_model = custom_bulletin_config.bind_model.constantize rescue nil
if target_model
target_record = target_model.where(custom_bulletin_config.uid_field=>self.bind_uid).first
target_record.send(custom_bulletin_config.custom_record_callback,num)
end
end
end
end
def to_calendar_param
self.to_param
end
def calendar_type
CalendarType.where(:category_id.in => self.calendar_type_id)
end
def event
if !self.event_id.nil?
Event.where(:id => self.event_id).first
else
nil
end
end
def check_limit
check_status_limit(update_user)
end
def check_status_limit(user,check_only=false)
role_ids = user.member_profile.roles.map(&:id) rescue []
status_settings = (role_ids.collect do |role_id|
CustomAnnouncementSetting.first.custom_anns_status_settings.select{|v| v.role_id.to_s == role_id.to_s}
end.flatten rescue [])
reach_limit = []
if status_settings.count != 0
reach_limit = status_settings.collect do |status_setting|
status = status_setting.status
if status_setting.top_limit.to_i <= CustomBulletin.where(:update_user_id.in => Role.find(status_setting.role_id).member_profiles.collect(&:user).flatten.uniq.map{|v| v.id},status => true).count
if !check_only
if self[status] && !CustomBulletin.where(id:self.id).first[status]
self[status] = false
nil
end
else
status
end
else
nil
end
end.compact
reach_limit = reach_limit.group_by{|v| v}.collect do |k,v|
if v.count >= user.member_profile.roles.count
k
else
nil
end
end.compact
end
reach_limit
end
def slug_title
doc = Nokogiri::HTML(self.title)
title = doc.text.gsub('/','-')
end
def set_expire
self.expirable_created_at = Time.now if self.is_preview
return true
end
def update_user
User.find(update_user_id) rescue nil
end
def update_user=(user)
self.update_user_id = user.id
end
def email_members
MemberProfile.find(self.email_member_ids) rescue []
end
def email_addresses
addresses = self.email_members.collect{|member| member.email} rescue []
addresses = addresses +[self.other_mailaddress] if !self.other_mailaddress.blank?
addresses.flatten
end
def email
mail = Email.find(self.email_id) rescue nil
end
def expired?
(self.deadline < Time.now) rescue false
end
def destroy_email
mail = Email.find(self.email_id) rescue nil
mail.destroy if !mail.nil?
end
def self.remove_expired_status
self.where(:is_top => true, :top_end_date.ne => nil, :top_end_date.lt => Time.now).each do |b|
b.is_top = false
b.top_end_date = nil
b.save
end
end
def display_subtitle?
self.display_subtitle rescue false
end
def display_img?
self.display_img rescue false
end
def comments
self.custom_bulletin_comments.select{|v| !v.is_hidden}
end
def open_comment_for_user(user)
role_ids = user.member_profile.roles.collect{|v| v.id.to_s} rescue ['visitor']
self.open_comment && (self.comment_end_time.blank? || self.comment_end_time > Time.now) && (self.comment_role.any?{|v| role_ids.include?(v)} || self.comment_role.include?('visitor') || (self.comment_role.include?('all_member') && role_ids[0] != 'visitor'))
end
def statuses
statuses = []
statuses << top_text if is_top?
statuses << hot_text if is_hot?
statuses << hidden_text if is_hidden?
statuses
end
def statuses_with_classname
statuses = []
statuses << {"name" => top_text, "classname" => "top"} if is_top?
statuses << {"name" => hot_text, "classname" => "hot"} if is_hot?
statuses << {"name" => hidden_text, "classname" => "hidden"} if is_hidden?
statuses
end
def status_for_table
status = ""
status << "<span class='label label-success'>#{top_text}</span> " if self.is_top
status << "<span class='label label-important'>#{hot_text}</span> " if self.is_hot
status << "<span class='label'>#{hidden_text}</span>"if self.is_hidden
status.html_safe
end
def top_text
I18n.t("custom_announcement.status.top")
end
def hot_text
I18n.t("custom_announcement.status.hot")
end
def hidden_text
I18n.t("custom_announcement.status.hidden")
end
end

View File

@ -0,0 +1,15 @@
# encoding: utf-8
class CustomBulletinCarouselImage
include Mongoid::Document
include Mongoid::Timestamps
mount_uploader :file, AssetUploader
field :description, localize: true
belongs_to :custom_bulletin
def description_text
Nokogiri::HTML(self.description.to_s).css("body").text() rescue ""
end
end

View File

@ -0,0 +1,21 @@
# encoding: utf-8
class CustomBulletinComment
include Mongoid::Document
include Mongoid::Timestamps
field :ip
field :comment
field :account_id
field :is_hidden,type: Boolean,default: false
def time
self.created_at.strftime('%Y/%m/%d %H:%M')
end
def account
tmp = MemberProfile.where(:id => self.account_id).collect{|v| v.name}.join
tmp.blank? ? I18n.t('custom_announcement_visitor') : tmp
end
def roles
MemberProfile.where(:id => self.account_id).collect{|v| v.roles}.flatten
end
belongs_to :custom_bulletin
end

View File

@ -0,0 +1,10 @@
class CustomBulletinConfig
include Mongoid::Document
include Mongoid::Timestamps
field :module
field :bind_model , :type => String
field :title_field , :type => String , :default => "slug_title"
field :uid_field , :type => String , :default => "uid"
field :custom_record_callback #if exists, it will call 'custom_record_callback(num)'
#where num is 1 when create bulletin, num is -1 when destroy.
end

View File

@ -0,0 +1,11 @@
class CustomBulletinFeed
include Mongoid::Document
include Mongoid::Timestamps
include Slug
field :title, as: :slug_title, type: String, localize: true
field :tag_ids, type: Array, default: []
before_save do
CustomBulletinFeedCache.where(uid: self.uid).destroy
end
end

View File

@ -0,0 +1,8 @@
class CustomBulletinFeedCache
include Mongoid::Document
include Mongoid::Timestamps
field :content, type: String, default: ''
field :uid
end

View File

@ -0,0 +1,38 @@
# encoding: utf-8
class CustomBulletinFile
include Mongoid::Document
include Mongoid::Timestamps
mount_uploader :file, AssetUploader
field :description, localize: true
field :title, localize: true
field :choose_lang, :type => Array, :default => ["en","zh_tw"]
field :privacy_type, type: String, default: 'public'
belongs_to :custom_bulletin
def file_title
if self.description.present?
return self.description
elsif self.title.present?
return self.title
else
return File.basename(self.file.path)
end
end
def enabled_for?(lang)
if lang.nil?
return true
else
return self.choose_lang.include?(lang)
end
end
def can_access?(user)
if user.nil? && self.privacy_type == 'logged_in'
return false
else
return true
end
end
end

View File

@ -0,0 +1,25 @@
# encoding: utf-8
require 'uri'
class CustomBulletinLink
include Mongoid::Document
include Mongoid::Timestamps
field :url
field :title, localize: true
belongs_to :custom_bulletin
before_validation :add_http
#validates :url, :presence => true, :format => /\A(http|https):\/\/(([a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5})|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(:[0-9]{1,5})?(\/.*)?\Z/i
protected
def add_http
unless self.url[/^http:\/\//] || self.url[/^https:\/\//]
self.url = 'http://' + self.url
end
end
end

0
app/views/.keep Normal file
View File

View File

@ -0,0 +1,122 @@
<style>
#approvalModal {
width: 90%;
height: 600px;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
position: absolute;
}
#approvalModal .preview-iframe {
border: 0;
outline: none;
width: 100%;
height: 100%;
}
#approvalModal .modal-body {
background-color: #fff;
padding: 0;
max-height: none;
height: 100%;
overflow: hidden;
}
#approvalModal .modal-left {
overflow: auto;
float: left;
width: 19.8%;
border-right: 1px solid #DFDFDF;
height: 100%;
padding: 1em;
margin: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
#approvalModal .modal-right {
float: right;
width: 80%;
height: 100%;
}
.approvalModal__form {
padding: 0 10px;
margin: 0;
}
label.approvalModal__radio {
display: inline-block;
}
label.control-label {
display: inline-block;
}
.approvalModal__controls {
display: inline-block;
vertical-align: middle;
}
.approvalModal__group {
display: inline-block;
vertical-align: middle;
}
label.approvalModal__label {
display: inline-block;
margin: 0 4px 0 7px;
position: relative;
top: -1px;
}
.approvalModal__controls .approvalModal__privacy {
margin: 0 5px;
}
.approvalModal__controls .approvalModal__large {
}
#approvalModal .modal-footer {
text-align: left;
padding: 15px 10px 10px;
}
.approvalModal__group.confirm {
float: right;
}
</style>
<div id="approvalModal" class="modal hide fade" role="dialog">
<div class="modal-header">
<a class="close" data-dismiss="modal">×</a>
<h3>預覽</h3>
</div>
<div class="modal-body clearfix">
<div class="modal-left">
<label for="____">寄送對象</label>
</div>
<div class="modal-right">
<iframe class="preview-iframe"></iframe>
</div>
</div>
<div class="modal-footer">
<%= form_tag "/admin/custom_announcement/approve_custom_bulletin", :class=>"approvalModal__form" do %>
<div class="approvalModal__group">
<label class="control-label" for="custom_bulletin_approval_stat">審核狀態</label>
<div class="approvalModal__controls">
<label class="approvalModal__radio">
<input class="approvalModal__privacy" id="custom_bulletin_is_checked_true" name="approved" type="radio" value="true">已認可
</label>
<label class="approvalModal__radio">
<input checked="checked" class="approvalModal__privacy" id="custom_bulletin_approved_false" name="approved" type="radio" value="false">拒絕
</label>
</div>
</div>
<div class="approvalModal__group group--reject">
<label class="approvalModal__label" for="is_checked_false_拒絕原因">拒絕原因</label>
<div class="approvalModal__controls">
<input class="approvalModal__large" id="custom_bulletin_not_checked_reason" name="reason" size="30" type="text">
</div>
</div>
<div class="approvalModal__group confirm">
<input class="approvalModal__btn btn btn-primary" name="commit" type="submit" value="送出">
<input type="hidden" id="object_id" name="id" />
<button class="approvalModal__btn btn" data-dismiss="modal" aria-hidden="true">關閉</button>
</div>
<% end %>
</div>
</div>

View File

@ -0,0 +1,25 @@
<table class="table main-list">
<thead>
<tr class="sort-header">
<% @table_feed_fields.each do |f| %>
<%= thead(f) %>
<% end %>
</tr>
</thead>
<tbody>
<% @comments.each do |comment| %>
<tr>
<td><%= comment.time %></td>
<td><%= comment.comment.html_safe %></td>
<td>
<%= comment.account %>
<% comment.roles.each do |role| %>
<span class="label"><%= role.title rescue '' %></span>
<% end %>
</td>
<td><%= comment.ip %></td>
<td><%= button_tag (comment.is_hidden ? t('show') : t('is_hidden')), type: 'button',"data-href" => "/#{I18n.locale}/admin/annc-comment-hidden/#{comment.id}",:onclick => "update_status(this)" ,class: (comment.is_hidden ? 'btn btn-primary' : 'btn btn-info') %></td>
</tr>
<% end %>
</tbody>
</table>

View File

@ -0,0 +1,38 @@
<%= form_for @custom_announcement_feed, url: admin_custom_announcement_updatefeed_path(:id => @custom_announcement_feed.id), html: {class: "form-horizontal main-forms"} do |f| %>
<fieldset>
<% @site_in_use_locales.each do |locale| %>
<%= f.fields_for :title_translations do |f| %>
<div class="control-group">
<label class="control-label muted" for="custom_bulletin_feed_title_translations_<%= locale.to_s %>"><%= t(:title) + " (#{t(locale.to_s)})" %></label>
<div class="controls">
<%= f.text_field locale, data: {"fv-validation" => "required;","fv-messages" => "Cannot be empty.;"}, value: (@custom_announcement_feed.title_translations[locale.to_s] rescue nil) %>
</div>
</div>
<% end %>
<% end %>
<hr />
<div class="tags">
<div id="tags-list">
<ul class="tags-groups checkbox-card module-tags">
<% @module_app.tags.each do |tag| %>
<li class="filter-item module">
<p class='card pull-left <%= @custom_announcement_feed.tag_ids.include?(tag.id.to_s) ? "active" : "" %>'>
<input type="checkbox" <%= @custom_announcement_feed.tag_ids.include?(tag.id.to_s) ? "checked=checked" : "" %> class="tag-checkbox" value="<%= tag.id.to_s %>" name="custom_bulletin_feed[tag_ids][]">
</p>
<a href="#" onclick="return false;">
<% @site_in_use_locales.each_with_index do |locale,index| %>
<span class="tag"><%= tag.name_translations[locale] %></span>
<% if index < (@site_in_use_locales.count - 1) %>
/
<% end %>
<% end %>
</a>
</li>
<% end %>
</ul>
</div>
</div>
</fieldset>
<% end %>

View File

@ -0,0 +1,51 @@
<tr>
<td>
<%= feed.title %>
<div class="quick-edit">
<ul class="nav nav-pills">
<% if can_edit_or_delete?(feed) %>
<li><a href="#" class="edit-feed" data-feed-id="<%= feed.id.to_s %>"><%= t(:edit) %></a></li>
<li><a href="/admin/custom_announcement/deletefeed?id=<%= feed.id.to_s %>" class="delete-feed text-error" ><%= t(:delete_) %></a></li>
<% end %>
</ul>
</div>
</td>
<td>
<div class="tags">
<div id="tags-list">
<ul class="tags-groups checkbox-card module-tags">
<% tags_to_remove = [] %>
<% feed.tag_ids.each do |t| %>
<% tag = Tag.find(t) rescue nil %>
<% if !tag.nil? %>
<li class="filter-item module">
<a href="#" onclick="return false;">
<% @site_in_use_locales.each_with_index do |locale,index| %>
<span class="tag"><%= tag.name_translations[locale] %></span>
<% if index < (@site_in_use_locales.count - 1) %>
/
<% end %>
<% end %>
</a>
</li>
<% else %>
<% tags_to_remove << t %>
<% end %>
<% end %>
<% if !tags_to_remove.blank?
tags_to_remove.each do |t|
feed.tag_ids.delete(t)
end
feed.save
end %>
</ul>
</div>
</div>
</td>
<td>
<a href="/xhr/custom_announcements/rssfeed/<%= feed.uid %>.rss" target="_blank">RSS Feed</a>
</td>
<td>
<a href="/xhr/custom_announcements/feed/<%= feed.uid %>.json" target="_blank">JSON Feed</a>
</td>
</tr>

View File

@ -0,0 +1,38 @@
<%= form_for @custom_announcement_feed, url: admin_custom_announcement_createfeed_path, html: {class: "form-horizontal main-forms"} do |f| %>
<fieldset>
<% @site_in_use_locales.each do |locale| %>
<%= f.fields_for :title_translations do |f| %>
<div class="control-group">
<label class="control-label muted" for="custom_bulletin_feed_title_translations_<%= locale.to_s %>"><%= t(:title) + " (#{t(locale.to_s)})" %></label>
<div class="controls">
<%= f.text_field locale, data: {"fv-validation" => "required;","fv-messages" => "Cannot be empty.;"}, value: (@custom_announcement_feed.title_translations[locale.to_s] rescue nil) %>
</div>
</div>
<% end %>
<% end %>
<hr />
<div class="tags">
<div id="tags-list">
<ul class="tags-groups checkbox-card module-tags">
<% @module_app.tags.each do |tag| %>
<li class="filter-item module">
<p class="card pull-left">
<input type="checkbox" class="tag-checkbox" value="<%= tag.id.to_s %>" name="custom_bulletin_feed[tag_ids][]">
</p>
<a href="#" onclick="return false;">
<% @site_in_use_locales.each_with_index do |locale,index| %>
<span class="tag"><%= tag.name_translations[locale] %></span>
<% if index < (@site_in_use_locales.count - 1) %>
/
<% end %>
<% end %>
</a>
</li>
<% end %>
</ul>
</div>
</div>
</fieldset>
<% end %>

View File

@ -0,0 +1,705 @@
<% content_for :page_specific_css do %>
<%= stylesheet_link_tag "lib/main-forms" %>
<%= stylesheet_link_tag "lib/fileupload" %>
<%= stylesheet_link_tag "lib/main-list" %>
<% end %>
<style type="text/css">
.reach_limit{
background: #a90c0c;
color: white;
padding: 4px 12px;
font-family: 'Varela Round';
letter-spacing: -.4px;
cursor: default;
display: inline-block;
}
.add-on.btn-group .dropdown-menu{
margin: 0;
}
.main-forms fieldset .input-area .controls .input-prepend a:hover{
color: #fff;
}
</style>
<% content_for :page_specific_javascript do %>
<%= javascript_include_tag "lib/bootstrap-fileupload" %>
<%= javascript_include_tag "lib/bootstrap-datetimepicker" %>
<%= javascript_include_tag "lib/datetimepicker/datetimepicker.js" %>
<%= javascript_include_tag "lib/file-type" %>
<%= javascript_include_tag "lib/module-area" %>
<%= javascript_include_tag "form" %>
<% end %>
<script type="text/javascript">
function trigger_on_add_calendar(ele){
if ($(ele).prop('checked')){
$('.trigger_on_add_calendar').show()
}else{
$('.trigger_on_add_calendar').hide()
}
}
</script>
<!-- Input Area -->
<div class="input-area">
<!-- Module Tabs -->
<div class="nav-name"><strong><%= t(:module) %></strong></div>
<ul class="nav nav-pills module-nav">
<li class="active"><a href="#basic" data-toggle="tab"><%= t(:basic) %></a></li>
<% if defined? Calendar %>
<li><a href="#calendar" data-toggle="tab"><%= t('calendar.calendar') %></a></li>
<% end %>
<% if((!CustomAnnouncementSetting.first.only_manager_can_edit_status) || (CustomAnnouncementSetting.first.only_manager_can_edit_status && (@current_user.is_admin? || @current_user.is_manager?(@module_app))) ) %>
<li><a href="#status" data-toggle="tab"><%= t(:status) %></a></li>
<% end %>
<li><a href="#tag" data-toggle="tab"><%= t(:tags) %></a></li>
<li><a href="#imageupload" data-toggle="tab"><%= t('custom_announcement.image') %></a></li>
<li><a href="#carousel_image_upload" data-toggle="tab" title="<%= t('custom_announcement.carousel_image_title') %>"><%= t('custom_announcement.carousel_image') %></a></li>
<li><a href="#mail-group" data-toggle="tab"><%= t('custom_announcement.email_reminder')%></a></li>
</ul>
<!-- Module -->
<div class="tab-content module-area">
<!-- Basic Module -->
<div class="tab-pane fade in active" id="basic">
<!-- Category -->
<div class="control-group">
<label class="control-label muted"><%= t(:category) %></label>
<div class="controls">
<%= select_category(f, @module_app) %>
</div>
</div>
<!-- Date Time Picker -->
<div class="control-group">
<label class="control-label muted"><%= t(:start_date) %></label>
<div class="controls">
<%= f.datetime_picker :postdate, :no_label => true, :new_record => @custom_bulletin.new_record?, :data=>{"picker-type" => "range", "range" => "start"} %>
</div>
</div>
<div class="control-group">
<label class="control-label muted"><%= t(:end_date) %></label>
<div class="controls">
<%= f.datetime_picker :deadline, :no_label => true, :new_record => @custom_bulletin.new_record?, :data=>{"picker-type" => "range", "range" => "end"} %>
</div>
</div>
<div class="control-group">
<%= f.label :is_external_link, t("custom_announcement.is_external_link"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :is_external_link %>
</div>
</div>
<div class="control-group" style="display: none;" id="external_link_box">
<%= f.label :external_link, t("custom_announcement.external_link"), :class => "control-label muted" %>
<div class="controls">
<%= f.text_field :external_link %>
<div class="hint"><%= t("custom_announcement.external_link_hint") %></div>
</div>
</div>
<!-- display subtitle -->
<div class="control-group">
<%= f.label :display_subtitle, t("custom_announcement.display_subtitle"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :display_subtitle %>
</div>
</div>
<!-- display img src -->
<div class="control-group">
<%= f.label :display_img, t("custom_announcement.display_img"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :display_img %>
</div>
</div>
<!-- Image display setting -->
<% image_display_class_relation = {"full_width"=>"full-size-img","up_left_corner"=>"pull-left","up_right_corner"=>"pull-right"} %>
<div class="control-group <%='hide' if !f.object.display_img %>" id="image_display_setting">
<%= f.label :image_display_class, t("custom_announcement.cover_image_display_setting"), :class => "control-label muted" %>
<div class="controls">
<% image_display_class_relation.each.with_index do |(key,value),i| %>
<label>
<%= radio_button_tag "#{f.object_name}[image_display_class]", value , (f.object.image_display_class == value) %>
<%= t("custom_announcement.#{key}") %>
</label>
<% end %>
</div>
</div>
</div>
<!-- Calendar Module -->
<% if defined? Calendar %>
<div class="tab-pane fade" id="calendar">
<div class="control-group">
<label class="control-label muted"><%= t('custom_announcement.add_to_calendar') %></label>
<div class="controls">
<%= f.check_box :add_to_calendar,onchange: 'trigger_on_add_calendar(this)' %>
</div>
</div>
<div class="trigger_on_add_calendar" <%= "style=display:none;" if !@custom_bulletin.add_to_calendar %>>
<div class="control-group">
<label class="control-label muted"><%= t('calendar.calendar') %></label>
<div class="controls">
<%= f.select :calendar_type_id, @calendar_categories.collect{|t| [ t.title, t.id ]} %>
</div>
</div>
<div class="control-group" style="display: flex;flex-wrap: wrap;">
<div style="display: flex;flex-direction: column;">
<label class="control-label muted"><%= t(:start_date) %></label>
<label class="control-label muted"><%= t('custom_announcement.blank_to_set') %></label>
</div>
<div class="controls" style="margin-left: 1.5em;">
<%= f.datetime_picker :calendar_start_date, :new_record => @custom_bulletin.new_record?, :no_label => true, :data=>{"picker-type" => "range", "range" => "start"} %>
</div>
</div>
<div class="control-group" style="display: flex;flex-wrap: wrap;">
<div style="display: flex;flex-direction: column;">
<label class="control-label muted"><%= t(:end_date) %></label>
<label class="control-label muted"><%= t('custom_announcement.blank_to_set') %></label>
</div>
<div class="controls" style="margin-left: 1.5em;">
<%= f.datetime_picker :calendar_end_date, :new_record => @custom_bulletin.new_record?, :no_label => true, :data=>{"picker-type" => "range", "range" => "end"} %>
</div>
</div>
<div class="control-group">
<label class="control-label muted"><%= t('calendar.all_day') %></label>
<div class="controls">
<%= f.check_box :calendar_all_day %>
</div>
</div>
<div class="control-group">
<label class="control-label muted">Select Read More Page :</label>
<div class="controls">
<%= f.select :page_id,[["----- Select a page -----",nil]]+@module_pages %>
</div>
</div>
</div>
<%= f.hidden_field :event_id %>
</div>
<% end %>
<!-- Status Module -->
<% if((!CustomAnnouncementSetting.first.only_manager_can_edit_status) || (CustomAnnouncementSetting.first.only_manager_can_edit_status && (@current_user.is_admin? || @current_user.is_manager?(@module_app))) ) %>
<div class="tab-pane fade" id="status">
<!-- Status -->
<div class="control-group">
<label class="control-label muted"><%= t(:status) %></label>
<div class="controls" data-toggle="buttons-checkbox">
<% if !(@reach_limit.include?('is_top') && @custom_bulletin.is_top != true) || current_user.is_admin? %>
<label class="checkbox inline btn <%= 'active' if @custom_bulletin.is_top? || (!@custom_bulletin.top_end_date.nil? && @custom_bulletin.top_end_date > Time.now) %>">
<%= f.check_box :is_top %> <%= t(:top) %>
</label>
<% else %>
<label class="reach_limit">
<%= t(:top) %>
</label>
<% end %>
<% if !(@reach_limit.include?('is_hot') && @custom_bulletin.is_hot != true) || current_user.is_admin? %>
<label class="checkbox inline btn <%= 'active' if @custom_bulletin.is_hot? %>">
<%= f.check_box :is_hot %> <%= t(:hot) %>
</label>
<% else %>
<label class="reach_limit">
<%= t(:hot) %>
</label>
<% end %>
<label class="checkbox inline btn <%= 'active' if @custom_bulletin.is_hidden? %>">
<%= f.check_box :is_hidden %> <%= t(:hide) %>
</label>
</div>
<div class="controls">
<% if !@custom_bulletin.is_top? && !CustomAnnouncementSetting.check_limit_for_user((@custom_bulletin.new_record? ? current_user.id : @custom_bulletin.create_user_id)) %>
<span>Top limit has been reached. The custom_bulletin wont be marked as top even if you click on it.</span>
<% end %>
</div>
</div>
<div class="control-group <%= @custom_bulletin.is_top? || (!@custom_bulletin.top_end_date.nil? && @custom_bulletin.top_end_date > Time.now) ? "" : "hide" %>" data-for="is_top">
<label for="" class="control-label muted">Top end time</label>
<div class="controls">
<%= f.datetime_picker :top_end_date, :no_label => true, :new_record => @custom_bulletin.new_record? %>
</div>
</div>
<div class="control-group">
<label class="control-label muted"><%= t('custom_announcement.open_comment')%></label>
<div class="controls">
<%= f.check_box :open_comment %><%= t('custom_announcement.open') %>
</div>
</div>
<div class="control-group <%= @custom_bulletin.open_comment ? "" : "hide" %>" data-for="open_comment">
<label for="" class="control-label muted"><%= t('custom_announcement.comment_end_time')%></label>
<div class="controls">
<%= f.datetime_picker :comment_end_time, :no_label => true, :new_record => @custom_bulletin.new_record? %>
</div>
</div>
<div class="control-group <%= @custom_bulletin.open_comment ? "" : "hide" %>" data-for="open_comment">
<label for="" class="control-label muted"><%= t('custom_announcement.comment_role')%></label>
<div class="controls">
<%= check_box_tag 'custom_bulletin[comment_role][]','visitor',@custom_bulletin.comment_role.include?('visitor') %>
<%= t('custom_announcement.visitor') %>
<br>
<%= check_box_tag 'custom_bulletin[comment_role][]','all_member',@custom_bulletin.comment_role.include?('all_member'),class: 'role_all_member' %>
<%= t('custom_announcement.all_member') %>
<br>
<% Role.all.each do |role| %>
<%= check_box_tag 'custom_bulletin[comment_role][]',role.id.to_s,@custom_bulletin.comment_role.include?(role.id.to_s),class: 'role' %>
<%= role.title %>
<% end %>
</div>
</div>
</div>
<% end %>
<!-- Tag Module -->
<div class="tab-pane fade" id="tag">
<div class="control-group">
<label class="control-label muted"><%= t(:tags) %></label>
<%= select_tags(f, @module_app) %>
</div>
</div>
<!-- Images Module -->
<div class="tab-pane fade" id="imageupload">
<!-- Images Upload -->
<div class="control-group">
<label class="control-label muted"><%= t(:image) %></label>
<div class="controls">
<div class="fileupload fileupload-new clearfix <%= 'fileupload-edit' if @custom_bulletin.image.file %>" data-provides="fileupload">
<div class="fileupload-new thumbnail pull-left">
<% if @custom_bulletin.image.file %>
<%= image_tag @custom_bulletin.image %>
<% else %>
<img src="http://www.placehold.it/50x50/EFEFEF/AAAAAA" />
<% end %>
</div>
<div class="fileupload-preview fileupload-exists thumbnail pull-left"></div>
<span class="btn btn-file">
<span class="fileupload-new"><%= t(:select_image) %></span>
<span class="fileupload-exists"><%= t(:change) %></span>
<%= f.file_field :image %>
</span>
<a href="#" class="btn fileupload-exists" data-dismiss="fileupload"><%= t(:cancel) %></a>
<div class="controls" data-toggle="buttons-checkbox">
<label class="checkbox inline btn btn-danger fileupload-remove">
<%= f.check_box :remove_image %><%= t(:remove) %>
</label>
</div>
</div>
</div>
</div>
<% @site_in_use_locales.each do |locale| %>
<%= f.fields_for :image_description_translations do |f| %>
<div class="control-group">
<label class="control-label muted" for="image_description_<%= locale.to_s %>"><%= t(:description) + " (#{t(locale.to_s)})" %></label>
<div class="controls">
<%= f.text_field locale, value: (@custom_bulletin.image_description_translations[locale.to_s] rescue nil) %>
</div>
</div>
<% end %>
<% end %>
</div>
<!-- Images Module -->
<div class="tab-pane fade" id="carousel_image_upload">
<% if @custom_bulletin && !@custom_bulletin.custom_bulletin_carousel_images.blank? %>
<div class="exist">
<% @custom_bulletin.custom_bulletin_carousel_images.each_with_index do |custom_bulletin_carousel_image, i| %>
<%= f.fields_for :custom_bulletin_carousel_images, custom_bulletin_carousel_image do |f| %>
<%= render :partial => 'form_image', :object => custom_bulletin_carousel_image, :locals => {:f => f, :i => i} %>
<% end %>
<% end %>
<hr>
</div>
<% end %>
<!-- Add -->
<div class="add-target">
</div>
<p class="add-btn controls">
<%= hidden_field_tag 'custom_bulletin_carousel_image_count', @custom_bulletin.custom_bulletin_carousel_images.count %>
<a id="add_carousel_image" class="trigger btn btn-small btn-primary"><i class="icons-plus"></i> <%= t(:add) %></a>
</p>
</div>
</div>
<!-- Mail Group Module -->
<div class="tab-pane fade" id="mail-group">
<!-- Mail Group -->
<div class="control-group">
<label class="control-label muted"><%= t("custom_announcement.email_to") %></label>
<div class="controls">
<label class="checkbox inline">
<%= check_box_tag('custom_bulletin[email_sent]', '1', (!@custom_bulletin.email_sent.blank? ? true : false), :id=>'remind-check') %><%= t('custom_announcement.activate_email_reminder')%>
</label>
<div class="content-box">
<%= render partial: 'admin/member_selects/email_selection_box', locals: {field: 'custom_bulletin[email_member_ids][]', email_members: @custom_bulletin.email_members} %>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label muted"></label>
<div class="controls">
<div class="content-box">
<span class="help-block"><%= "#{t("custom_announcement.other_mailaddress")}(#{t("custom_announcement.other_mailaddress_note")})"%> </span>
<%= f.text_area :other_mailaddress, :class=>"span12", :cols=>"25", :rows=>"10" %>
</div>
</div>
</div>
<div class="content-box">
<div class="control-group">
<label class="control-label muted"><%= t("custom_announcement.email_sentdate") %></label>
<div class="controls">
<%= f.datetime_picker :email_sentdate, :no_label => true %>
</div>
</div>
</div>
<% if (@custom_bulletin.email.is_sent rescue false) %>
<div class="content-box">
<div class="control-group">
<label class="control-label muted"><%= t("custom_announcement.resend_mail") %></label>
<div class="controls">
<input type="checkbox" name="resend_mail" value="true">
</div>
</div>
</div>
<% end %>
</div>
</div>
<!-- Language Tabs -->
<div class="nav-name"><strong><%= t(:language) %></strong></div>
<ul class="nav nav-pills language-nav">
<% @site_in_use_locales.each_with_index do |locale, i| %>
<li class="<%= 'active' if i == 0 %>">
<a data-toggle="tab" href=".<%= locale %>"><%= t(locale) %></a>
</li>
<% end %>
</ul>
<!-- Language -->
<div class="tab-content language-area">
<% @site_in_use_locales.each_with_index do |locale, i| %>
<div class="<%= locale %> tab-pane fade <%= ( i == 0 ) ? "in active" : '' %>">
<!-- Title-->
<div class="control-group input-title">
<label class="control-label muted"><%= t(:title) %></label>
<div class="controls">
<%= f.fields_for :title_translations do |f| %>
<%= f.text_area locale, class: "ckeditor_reduce input-block-level", placeholder: t(:title), value: (@custom_bulletin.title_translations[locale] rescue nil) %>
<% end %>
</div>
</div>
<!-- Sub Title -->
<div class="control-group input-subtitle">
<label class="control-label muted"><%= t(:subtitle) %></label>
<div class="controls">
<div class="textarea">
<%= f.fields_for :subtitle_translations do |f| %>
<%= f.text_area locale, rows: 2, class: "ckeditor input-block-level", value: (@custom_bulletin.subtitle_translations[locale] rescue nil) %>
<% end %>
</div>
</div>
</div>
<!-- Content -->
<div class="control-group input-content">
<label class="control-label muted"><%= t(:content) %></label>
<div class="controls">
<div class="textarea">
<%= f.fields_for :text_translations do |f| %>
<%= f.cktext_area locale, rows: 5, class: "input-block-level", :value => (@custom_bulletin.text_translations[locale] rescue nil) %>
<% end %>
</div>
</div>
</div>
</div>
<% end %>
<!-- Link -->
<div class="control-group">
<label class="control-label muted"><%= t(:link) %></label>
<div class="controls add-input">
<!-- Exist -->
<% if @custom_bulletin && !@custom_bulletin.custom_bulletin_links.blank? %>
<div class="exist">
<% @custom_bulletin.custom_bulletin_links.each_with_index do |custom_bulletin_link, i| %>
<%= f.fields_for :custom_bulletin_links, custom_bulletin_link do |f| %>
<%= render :partial => 'form_link', :object => custom_bulletin_link, :locals => {:f => f, :i => i} %>
<% end %>
<% end %>
<hr>
</div>
<% end %>
<!-- Add -->
<div class="add-target">
</div>
<p class="add-btn">
<%= hidden_field_tag 'custom_bulletin_link_field_count', @custom_bulletin.custom_bulletin_links.count %>
<a id="add_link" class="trigger btn btn-small btn-primary"><i class="icons-plus"></i> <%= t(:add) %></a>
</p>
</div>
</div>
<!-- File -->
<div class="control-group">
<label class="control-label muted"><%= t(:file_) %></label>
<div class="controls">
<div id="file_description_hint"><%= t("custom_announcement.file_description_hint") %></div>
<!-- Exist -->
<% if @custom_bulletin && !@custom_bulletin.custom_bulletin_files.blank? %>
<div class="exist">
<% @custom_bulletin.custom_bulletin_files.each_with_index do |custom_bulletin_file, i| %>
<%= f.fields_for :custom_bulletin_files, custom_bulletin_file do |f| %>
<%= render :partial => 'form_file', :object => custom_bulletin_file, :locals => {:f => f, :i => i} %>
<% end %>
<% end %>
<hr>
</div>
<% end %>
<!-- Add -->
<div class="add-target">
</div>
<p class="add-btn">
<%= hidden_field_tag 'custom_bulletin_file_field_count', @custom_bulletin.custom_bulletin_files.count %>
<a id="add_file" class="trigger btn btn-small btn-primary"><i class="icons-plus"></i> <%= t(:add) %></a>
</p>
</div>
</div>
</div>
</div>
<!-- Form Actions -->
<div class="form-actions">
<%= get_referer_url[:action] rescue "" %>
<%= f.submit t('submit'), class: 'btn btn-primary' %>
<input type="hidden" name="referer_url" value="<%= get_referer_url %>">
<%= button_tag t("preview"), id: "button_for_preview", name: "commit", class: 'btn', type: :button %>
<%= link_to t('cancel'), admin_custom_announcements_path + (params[:custom_module].blank? ? '' : "/#{params[:custom_module]}#{(params[:bind_uid].blank? ? '' : ('-'+params[:bind_uid]))}"), :class=>"btn" %>
<% if params[:custom_module].present? %>
<%= f.hidden_field :custom_module, :value=> params[:custom_module] %>
<% if params[:bind_uid].present? %>
<%= f.hidden_field :bind_uid, :value=> params[:bind_uid] %>
<% end %>
<% end %>
</div>
<span id='show_preview'>
<div class="modal hide fade in banner-preview" id="">
<div class="modal-header">
<a class="close" data-dismiss="modal">×</a>
<h3><%= t(:preview) %></h3>
</div>
<div class="modal-body">
<iframe id="preview-iframe" src=""></iframe>
</div>
<div class="modal-footer">
<a href="#" class="btn" data-dismiss="modal"><%= t(:close) %></a>
</div>
</div>
</span>
<% if !@module_app.tags.empty? %>
<script type="text/javascript">
$("form.previewable").on("submit", function(){
if(!$("input[name='custom_bulletin[tags][]']").is(":checked")){
if(!confirm("You have selected no tag, do you wish to continue?")){
return false;
}
}
})
</script>
<% end %>
<style type="text/css">
[aria-describedby] ul.dropdown-menu {
display: block;
}
[aria-describedby] .checkbox input{
margin-left: 0;
}
</style>
<script>
$("#custom_bulletin_display_img").click(function(){$("#image_display_setting").toggleClass("hide")})
function Appendzero(obj)
{
if(obj<10) return "0" +""+ obj;
else return obj;
}
function add_click_for_privacy()
{
$('.add-on.btn-group').off('show.bs.tooltip').on('show.bs.tooltip',function(){$(this).find('ul').toggleClass('show')});
$(".privacy-changer-btn").off('click')
$(".privacy-changer-btn").click(function(){
var val = $(this).attr('for')
var parent_node = $(this).parents('.add-on.btn-group').eq(0)
parent_node.find('.privacy_type').val(val)
parent_node.find('i').eq(0).attr('class',$(this).find('i').attr('class'))
parent_node.find('.dropdown-menu').hide()
window.setTimeout(function(){
parent_node.find('.dropdown-menu').css('display','')
},1000)
})
}
$(function() {
$('#custom_bulletin_open_comment').change(function(){
$(this).prop('checked') ? $('div[data-for="open_comment"]').removeClass('hide') : $('div[data-for="open_comment"]').addClass('hide')
})
$('.role_all_member').change(function(){
if ($(this).prop('checked')){
$('.role').each(function() {
$(this).prop("checked", true);
})
} else{
$('.role').each(function() {
$(this).prop("checked", false);
})
}
})
$('.role').change(function(){
if (!$(this).prop('checked') && $('.role_all_member').prop('checked')){
$('.role_all_member').prop('checked',false)
}
})
if (location.pathname.substr(-3)=='new'){
var getDate = new Date();
var toDay = getDate.getFullYear()+"/"+ (Appendzero(getDate.getMonth()+1))+"/"+Appendzero(getDate.getDate())+" "+Appendzero(getDate.getHours())+":"+Appendzero(getDate.getMinutes());
$('input[name="custom_bulletin[postdate]"]').val(toDay);
}
$("#main-wrap").after("");
$(document).on('click', '#add_link', function(){
var new_id = $(this).prev().attr('value');
var old_id = new RegExp("new_custom_bulletin_links", "g");
var on = $('.language-nav li.active').index();
var le = $(this).parent('.add-btn').prev('.add-target').children('.start-line').length;
$(this).prev().attr('value', parseInt(new_id) + 1);
$(this).parent().siblings('.add-target').append(("<%= escape_javascript(add_attribute 'form_link', f, :custom_bulletin_links) %>").replace(old_id, new_id));
$(this).parent('.add-btn').prev('.add-target').children('.start-line').eq(le).children('.tab-content').children('.tab-pane').eq(on).addClass('in active').siblings().removeClass('in active');
formTip();
});
$(document).on('click', '#add_file', function(){
var new_id = $(this).prev().attr('value');
var old_id = new RegExp("new_custom_bulletin_files", "g");
var on = $('.language-nav li.active').index();
var le = $(this).parent('.add-btn').prev('.add-target').children('.start-line').length;
$(this).prev().attr('value', parseInt(new_id) + 1);
$(this).parent().siblings('.add-target').append(("<%= escape_javascript(add_attribute 'form_file', f, :custom_bulletin_files) %>").replace(old_id, new_id));
$(this).parent('.add-btn').prev('.add-target').children('.start-line').eq(le).children('.input-append').find('.tab-content').each(function() {
$(this).children('.tab-pane').eq(on).addClass('in active').siblings().removeClass('in active');
});
formTip();
add_click_for_privacy();
});
$(document).on('click', '#add_carousel_image', function(){
var new_id = $(this).prev().attr('value');
var old_id = new RegExp("new_custom_bulletin_carousel_images", "g");
var on = $('.language-nav li.active').index();
var le = $(this).parent('.add-btn').prev('.add-target').children('.start-line').length;
$(this).prev().attr('value', parseInt(new_id) + 1);
$(this).parent().siblings('.add-target').append(("<%= escape_javascript(add_attribute 'form_image', f, :custom_bulletin_carousel_images) %>").replace(old_id, new_id));
$(this).parent('.add-btn').prev('.add-target').children('.start-line').eq(le).children('.input-append').find('.tab-content').each(function() {
$(this).children('.tab-pane').eq(on).addClass('in active').siblings().removeClass('in active');
});
});
$(document).on('click', '.fileupload-remove', function(){
if($(this).find(".delete_image").length != 0){
$(this).parents('.image_group').remove();
}
});
$(document).on('click', '.delete_link', function(){
$(this).parents('.input-prepend').remove();
});
$(document).on('click', '.delete_file', function(){
$(this).parents('.input-prepend').remove();
});
$(document).on('click', '.remove_existing_record', function(){
if(confirm("<%= I18n.t(:sure?)%>")){
$(this).children('.should_destroy').attr('value', 1);
$(this).parents('.start-line').hide();
}
});
$('#remind-check').prop('checked') ? '':$('.content-box').addClass('hide')
$('#remind-check').on('change', function() {
$(this).prop('checked') ? $('.content-box').removeClass('hide'):$('.content-box').addClass('hide')
})
$('#button_for_preview').click(function(){
var method = $('.main-forms input[name="_method"]').val();
$('.main-forms input[name="_method"]').val("post");
for ( instance in CKEDITOR.instances )
CKEDITOR.instances[instance].updateElement();
var formData = new FormData( $('.main-forms')[0] );
formData.append("preview_type", ( (method==undefined) ? "new" : "edit" ));
formData.append("custom_bulletin_id", '<%= @custom_bulletin.id.to_s %>');
$.ajax({
type: "post",
url: '<%= admin_custom_announcement_preview_path %>',
data : formData,
processData: false,
contentType: false
}).done(function(data){
if(window.location.protocol === "https:"){
data = data.replace("http:","https:");
}
$('.modal-body iframe').attr('src',data);
$('#show_preview .modal').modal();
$('#show_preview .modal').height(function() {
return $(window).height() * 0.7;
});
var slug = data.split('/')[(data.split('/').length-1)];
// $('#preview-iframe').on('load', function(){
// $.get('/admin/custom_announcement/destroy_preview/'+slug,function(data){
// });
// });
});
$('.main-forms input[name="_method"]').val(method);
return false;
});
$("#custom_bulletin_is_top").parent().on("click",function(){
setTimeout(function(){
if($("#custom_bulletin_is_top").parent().hasClass("active")){
$("div[data-for=is_top]").removeClass("hide");
}else{
$("div[data-for=is_top]").addClass("hide");
$("div[data-for=is_top]").find("input[type=text]").val("");
}
},100)
})
$("#custom_bulletin_is_external_link").on("click",function(){
if($(this).is(":checked")){
$("#external_link_box").show();
}else{
$("#external_link_box").hide();
}
})
add_click_for_privacy()
});
</script>

View File

@ -0,0 +1,89 @@
<% if form_file.new_record? %>
<div class="fileupload fileupload-new start-line" data-provides="fileupload">
<% else %>
<div class="fileupload fileupload-exists start-line" data-provides="fileupload">
<% if form_file.file.blank? %>
<%= t(:no_file) %>
<% else %>
<%= link_to content_tag(:i) + form_file.file_identifier, form_file.file.url, {:class => 'file-link file-type', :target => '_blank', :title => form_file.file_identifier} %>
<% end %>
<% end %>
<div class="input-prepend input-append">
<label>
<span class="add-on btn btn-file" title='<%= t(:file_) %>'>
<i class="icons-paperclip"></i>
<%= f.file_field :file %>
</span>
<div class="uneditable-input input-medium">
<i class="icon-file fileupload-exists"></i>
<span class="fileupload-preview"><%= (form_file.new_record? || form_file.file.blank?) ? t(:select_file) : t(:change_file) %></span>
</div>
</label>
<span class="add-on icons-pencil" title='<%= t(:alternative) %>'></span>
<span class="tab-content">
<% @site_in_use_locales.each_with_index do |locale, i| %>
<span class="tab-pane fade <%= ( i == 0 ) ? "in active" : '' %> <%= locale %>">
<%= f.fields_for :title_translations do |f| %>
<%= f.text_field locale, :class => "input-medium", placeholder: t(:alternative), :value => (form_file.title_translations[locale] rescue nil) %>
<% end %>
</span>
<% end %>
</span>
<span class="add-on icons-pencil" title='<%= t(:description) %>'></span>
<span class="tab-content">
<% @site_in_use_locales.each_with_index do |locale, i| %>
<span class="tab-pane fade <%= ( i == 0 ) ? "in active" : '' %> <%= locale %>">
<%= f.fields_for :description_translations do |f| %>
<%= f.text_field locale, :class => "input-medium", placeholder: t(:description), :value => (form_file.description_translations[locale] rescue nil) %>
<% end %>
</span>
<% end %>
</span>
</span>
<span class="add-on btn-group btn" title="<%= t('archive.show_lang') %>">
<i class="icons-earth"></i> <span class="caret"></span>
<ul class="dropdown-menu">
<% @site_in_use_locales.each do |locale| %>
<li>
<label class="checkbox">
<%= check_box_tag "custom_bulletin[custom_bulletin_files_attributes][#{( form_file.new_record? ? 'new_custom_bulletin_files' : "#{i}" )}][choose_lang][]", locale, form_file.choose_lang.include?(locale.to_s) %>
<%= t(locale.to_s) %>
</label>
</li>
<% end %>
</ul>
<%= hidden_field_tag 'custom_bulletin[custom_bulletin_files_attributes][0][choose_lang][]', '' %>
</span>
<% if form_file.new_record? %>
<span class="delete_file add-on btn" title="<%= t(:delete_) %>">
<a class="icon-trash"></a>
</span>
<% else %>
<span class="remove_existing_record add-on btn" title="<%= t(:remove) %>">
<%= f.hidden_field :id %>
<a class="icon-remove"></a>
<%= f.hidden_field :_destroy, :value => nil, :class => 'should_destroy' %>
</span>
<% end %>
<span class="add-on btn-group btn" style="background: white;border: 0;margin-left: 1em;" title="<%=t('site.edit_members.privacy_setting')%>">
<% case form_file.privacy_type
when "public"
icon = "icons-earth"
when "logged_in"
icon = "icons-users"
end
%>
<i class="<%= icon %>"></i> <span class="caret"></span>
<ul class="dropdown-menu">
<li>
<a class="privacy-changer-btn" for="public"><i class="icons-earth"></i><%= t('privacy_type.public') %></a>
</li>
<li class="divider"></li>
<li>
<a class="privacy-changer-btn" for="logged_in"><i class="icons-users"></i><%= t('privacy_type.logged_in') %></a>
</li>
</ul>
<%= f.hidden_field :privacy_type, class: 'privacy_type' %>
</span>
</div>
</div>

View File

@ -0,0 +1,49 @@
<!-- Images Upload -->
<div class="image_group">
<div class="control-group">
<label class="control-label muted"><%= t(:image) %></label>
<div class="controls">
<div class="fileupload fileupload-new clearfix <%= 'fileupload-edit' if @custom_bulletin.image.file %>" data-provides="fileupload">
<div class="fileupload-new thumbnail pull-left">
<% if form_image.file.file %>
<%= image_tag form_image.file %>
<% else %>
<img src="http://www.placehold.it/50x50/EFEFEF/AAAAAA" />
<% end %>
</div>
<div class="fileupload-preview fileupload-exists thumbnail pull-left"></div>
<span class="btn btn-file">
<span class="fileupload-new"><%= t(:select_image) %></span>
<span class="fileupload-exists"><%= t(:change) %></span>
<%= f.file_field :file %>
</span>
<a href="#" class="btn fileupload-exists" data-dismiss="fileupload"><%= t(:cancel) %></a>
<div class="controls" data-toggle="buttons-checkbox">
<label class="checkbox inline btn btn-danger fileupload-remove">
<% if form_image.new_record? %>
<span class="delete_file delete_image add-on" title="<%= t(:delete_) %>">
<%= t(:delete_) %>
</span>
<% else %>
<span class="remove_existing_record add-on" title="<%= t(:remove) %>">
<%= f.hidden_field :id %>
<%= f.hidden_field :_destroy, :value => nil, :class => 'should_destroy' %>
<%= t(:remove) %>
</span>
<% end %>
</label>
</div>
</div>
</div>
</div>
<% @site_in_use_locales.each do |locale| %>
<%= f.fields_for :description_translations do |f| %>
<div class="control-group">
<label class="control-label muted" for="image_description_<%= locale.to_s %>"><%= t(:description) + " (#{t(locale.to_s)})" %></label>
<div class="controls">
<%= f.text_field locale, value: (form_image.description_translations[locale.to_s] rescue nil) %>
</div>
</div>
<% end %>
<% end %>
</div>

View File

@ -0,0 +1,26 @@
<div class="input-prepend input-append start-line">
<span class="add-on icons-link" title="<%= t(:url) %>"></span>
<%= f.text_field :url, class: "input-large", placeholder: t(:url) %>
<span class="add-on icons-pencil" title="<%= t(:url_alt) %>"></span>
<span class="tab-content">
<% @site_in_use_locales.each_with_index do |locale, i| %>
<span class="tab-pane fade <%= ( i == 0 ) ? "in active" : '' %> <%= locale %>">
<%= f.fields_for :title_translations do |f| %>
<%= f.text_field locale, :class => "input-large", placeholder: t(:url_alt), :value => (form_link.title_translations[locale] rescue nil) %>
<% end %>
</span>
<% end %>
</span>
<% if form_link.new_record? %>
<span class="delete_link add-on btn" title="<%= t(:delete_) %>">
<a class="icon-trash"></a>
</span>
<% else %>
<span class="remove_existing_record add-on btn" title="<%= t(:remove) %>">
<%= f.hidden_field :id %>
<a class="icon-remove"></a>
<%= f.hidden_field :_destroy, :value => nil, :class => 'should_destroy' %>
</span>
<% end %>
</div>

View File

@ -0,0 +1,98 @@
<script>
if(document.querySelectorAll("#orbit-bar").length==0) location.reload();
</script>
<table class="table main-list">
<thead>
<tr class="sort-header">
<% @table_fields.each do |f| %>
<%= thead(f) %>
<% end %>
</tr>
</thead>
<tbody>
<% @custom_bulletins.each do |b| %>
<tr>
<td>
<%= b.status_for_table %>
</td>
<td>
<%= b.category.title rescue "" %>
<% if (b.category.disable rescue false) %>
<span class='label'><%= t(:disabled) %></span>
<% end %>
</td>
<td>
<% if b.expired? || (b.category.disable rescue false)%>
<%= b.title.to_s.html_safe %>
<% else %>
<a href="<%= page_for_custom_bulletin(b) %>" target="_blank"><%= b.title.to_s.html_safe %></a>
<% end %>
<% if b.expired? %>
<span class='label'><%= t(:expired) %></span>
<% end %>
<% if b.reapproval %>
<span class='label'><%= t("custom_announcement.reapproval") + " " + t(:pending) %></span>
<% end %>
<% if b.rejected %>
<span class='label'><%= t(:rejected) %> : <%= b.rejection_reason rescue "" %></span>
<% end %>
<% if !b.approved? && !b.rejected %>
<span class='label'><%= t(:pending) %></span>
<% end %>
<div class="quick-edit">
<ul class="nav nav-pills">
<li><a href="#" class="detail-row" onclick="$('#<%= "#{b.id.to_s}-detail" %>').slideToggle(300); return false;"><%= t(:detail) %></a></li>
<% if can_edit_or_delete?(b) %>
<li><a href="/admin/custom_announcements<%=params[:custom_module].blank? ? '' : "/#{params[:custom_module]}#{params[:bind_uid].present? ? ('-'+params[:bind_uid]) : ''}"%>/<%=b.id.to_s%>/edit"><%= t(:edit) %></a></li>
<li><a href="#" class="delete text-error" rel="/admin/custom_announcements/<%=b.id.to_s%>"><%= t(:delete_) %></a></li>
<% end %>
<% if ((!b.approved && !b.rejected && !b.reapproval) || (b.rejected && b.reapproval)) && user_can_approve?(b) %>
<li><a href="<%= page_for_custom_bulletin(b) %>" class="approval_button" data-id="<%= b.id.to_s %>" ><%= t("custom_announcement.approval_waiting") %></a></li>
<% end %>
</ul>
</div>
</td>
<td><%= format_value b.postdate %></td>
<td class="<%= b.expired? ? "expired" : "" %>"><%= format_value b.deadline %></td>
<td><%= link_to b.custom_bulletin_comments.count.to_s,"/#{I18n.locale}/admin/custom_announcements/#{params[:custom_module]}#{params[:bind_uid].present? ? ('-'+params[:bind_uid]) : ''}/#{b.id}/comment" %></td>
<td><%= b.update_user.user_name rescue ""%></td>
</tr>
<tr class="footable-row-detail">
<td class="footable-cell-detail" colspan="6">
<div id="<%= "#{b.id.to_s}-detail" %>" class="footable-row-detail-inner" style="display: none;">
<div>
<strong><%= t(:view_count) %></strong> :
<span class="label label-info"><%= b.view_count %></span>
</div>
<div>
<strong><%= t(:tags) %></strong> :
<% b.tags.each do |tag| %>
<span class="label label-warning"><%= tag.name %></span>
<% end %>
</div>
<div>
<strong><%= t("custom_announcement.email_to") %></strong> :
<% b.email_members.each do |member| %>
<span class="label"><%= member.name %></span>
<% end %>
<% unless b.other_mailaddress.nil? %>
<% b.other_mailaddress.split(',').each do |mailaddress| %>
<span class="label"><%= mailaddress %></span>
<% end %>
<% end %>
</div>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
<%=
content_tag :div, class: "bottomnav clearfix" do
content_tag(:div, paginate(@custom_bulletins), class: "pagination pagination-centered") +
content_tag(:div, link_to(t(:new_),(params[:custom_module].blank? ? "#{@module_app.key.pluralize}/new" : "#{params[:custom_module]}#{params[:bind_uid].present? ? ('-'+params[:bind_uid]) : ''}/new"), :class=>"btn btn-primary"), class: "pull-right")
end
%>

View File

@ -0,0 +1,12 @@
<% content_for :page_specific_css do %>
<%= stylesheet_link_tag("admin/tags") %>
<% end %>
<script type="text/javascript">
function update_status(ele) {
$.get($(ele).data('href'),function(data){
$('table').html(data)
})
return false
}
</script>
<%= render 'comment' %>

View File

@ -0,0 +1,74 @@
<% if params[:custom_module].blank? %>
<div class="bind_modules_list">
<ul>
<% @custom_bulletin_configs.each do |c|%>
<% target_model = c.bind_model.constantize rescue nil %>
<% next if target_model.nil? %>
<li>
<a href="<%= admin_custom_announcements_path + "/#{c.module}" %>">
<% icon_class = OrbitApp::Module::SideBarRegistration.all.select{|r| r.get_module_app_key == c.module}.first.get_icon_class rescue '' %>
<i class="<%= icon_class %> icon_big"></i>
<%= t("module_name.#{c.module}") %>
</a>
</li>
<% end %>
</ul>
</div>
<% else %>
<% config = @custom_bulletin_configs.where(:module=>params[:custom_module]).first %>
<% target_model = config.bind_model.constantize %>
<% page_num = params[:page] || 1 %>
<% target_records = target_model.where(config.title_field.to_sym.nin=>[nil,""]).page(page_num).per(10) %>
<% if params[:search_title].present?
target_records = target_records.where(config.title_field.to_sym=>/#{params[:search_title].gsub(/(\[|\]|\(|\)|\.)/){|f| "\\"+f}}/)
end %>
<h3><%= t("module_name.#{config.module}") %></h3>
<form>
<input id="search_title" type="text" name="search_title" placeholder="<%= t(:title) %>" value="<%=params[:search_title]%>"><button><%= t(:search_) %></button>
</form>
<table class="table main-list footable-loaded tablet">
<thead>
<th class="span5"><%= t(:title) %></th>
<th class="span2"><%= t("custom_announcement.total_amount") %></th>
</thead>
<% target_records.each do |record| %>
<tr>
<% uid = record.send(config.uid_field) %>
<td>
<a href="<%= admin_custom_announcements_path + "/#{config.module}-#{uid}" %>" title="<%=record.send(config.title_field)%>"><%= record.send(config.title_field) %></a>
</td>
<td>
<%= CustomBulletin.where(:custom_module=>params[:custom_module],:bind_uid=>uid).count %>
</td>
</tr>
<% end %>
</table>
<%=
content_tag :div, class: "bottomnav clearfix" do
content_tag :div, paginate(target_records), class: "pagination pagination-centered"
end
%>
<% end %>
<style type="text/css">
i.icon_big{
font-size: 3em;
display: block;
}
.bind_modules_list li{
font-size: 1.3em;
list-style: none;
float: left;
margin: 0.8em;
}
.bind_modules_list a{
color: black;
}
.bind_modules_list a:hover {
text-decoration: none;
color: #403f3f;
}
#search_title{
margin-bottom: 0;
margin-right: 1em;
}
</style>

View File

@ -0,0 +1,5 @@
<%= form_for @custom_bulletin, url: admin_custom_announcement_path(@custom_bulletin), html: {class: "form-horizontal main-forms previewable"} do |f| %>
<fieldset>
<%= render :partial => 'form', locals: {f: f} %>
</fieldset>
<% end %>

View File

@ -0,0 +1,125 @@
# encoding: utf-8
wb = xlsx_package.workbook
wb.add_worksheet(name: "CustomAnnoucement") do |sheet|
heading = sheet.styles.add_style(:b => true, :locked => true)
example = sheet.styles.add_style(:i => true)
row = []
row1 = []
row2 = []
row << t("category")
row1 << "select"
t = ""
@module_app.categories.asc(:created_at).each_with_index do |cat,i|
t = t + "#{i}" + " -> " + cat.title + ", "
end
if @module_app.categories.count > 0
t = t + " Example : 0"
else
t = "Leave this field blank"
end
row2 << t
row << t("tags")
row1 << "select"
t = ""
@module_app.tags.asc(:created_at).each_with_index do |tag,i|
t = t + "#{i}" + " -> " + tag.name + ", "
end
if @module_app.tags.count > 0
t = t + " Example : 0,1,2"
else
t = "Leave this field blank"
end
row2 << t
row << t("start_date")
row1 << "date"
row2 << "Format: YYYY/MM/DD, Example: 2015/12/10"
row << t("end_date")
row1 << "date"
row2 << "Format: YYYY/MM/DD, Example: 2015/12/12"
row << t("top")
row1 << "boolean"
row2 << "0 for false, 1 for true"
row << t("hot")
row1 << "boolean"
row2 << "0 for false, 1 for true"
row << t("hide")
row1 << "boolean"
row2 << "0 for false, 1 for true "
row << t("image")
row1 << "url"
row2 << "http://www.example.com/images/example.png"
row << t("image") + " " + t("description") + " - " + t("en")
row1 << "textfield"
row2 << ""
row << t("image") + " " + t("description") + " - " + t("zh_tw")
row1 << "textfield"
row2 << ""
row << t("title") + " - " + t("en")
row1 << "textfield"
row2 << ""
row << t("title") + " - " + t("zh_tw")
row1 << "textfield"
row2 << ""
row << t("subtitle") + " - " + t("en")
row1 << "textarea"
row2 << ""
row << t("subtitle") + " - " + t("zh_tw")
row1 << "textarea"
row2 << ""
row << t("content") + " - " + t("en")
row1 << "editor"
row2 << ""
row << t("content") + " - " + t("zh_tw")
row1 << "editor"
row2 << ""
row << t("link")
row1 << "textfield"
row2 << "Seperate with ';'. Example: http://rulingcom.com; http://google.com"
row << t("link") + " " + t("url_alt") + " - " + t("en")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Rulingcom official site; Google search engine"
row << t("link") + " " + t("url_alt") + " - " + t("zh_tw")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Rulingcom official site; Google search engine"
row << t("file_")
row1 << "textfield"
row2 << "Seperate with ';'. Example: http://www.example.com/images/example.png; http://www.example.com/images/example2.png"
row << t("file_") + " " + t("description") + " - " + t("en")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Great view; Nice potrait"
row << t("file_") + " " + t("description") + " - " + t("zh_tw")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Great view; Nice potrait"
row << t("file_") + " " + t("alternative") + " - " + t("en")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : example1; example2"
row << t("file_") + " " + t("alternative") + " - " + t("zh_tw")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : example1; example2"
sheet.add_row row, :style => heading
sheet.add_row row1
sheet.add_row row2, :style => example
end

View File

@ -0,0 +1,177 @@
# encoding: utf-8
wb = xlsx_package.workbook
wb.add_worksheet(name: "CustomAnnoucement") do |sheet|
heading = sheet.styles.add_style(:b => true, :locked => true)
example = sheet.styles.add_style(:i => true)
row = []
row1 = []
row2 = []
row << t("category")
row1 << "select"
t = ""
categories = @module_app.categories.asc(:created_at)
categories.each_with_index do |cat,i|
t = t + "#{i}" + " -> " + cat.title + ", "
end
if categories.count > 0
t = t + " Example : 0"
else
t = "Leave this field blank"
end
row2 << t
row << t("tags")
row1 << "select"
t = ""
tags = @module_app.tags.asc(:created_at)
tags.each_with_index do |tag,i|
t = t + "#{i}" + " -> " + tag.name + ", "
end
if tags.count > 0
t = t + " Example : 0,1,2"
else
t = "Leave this field blank"
end
row2 << t
row << t("start_date")
row1 << "date"
row2 << "Format: YYYY/MM/DD, Example: 2015/12/10"
row << t("end_date")
row1 << "date"
row2 << "Format: YYYY/MM/DD, Example: 2015/12/12"
row << t("top")
row1 << "boolean"
row2 << "0 for false, 1 for true"
row << t("hot")
row1 << "boolean"
row2 << "0 for false, 1 for true"
row << t("hide")
row1 << "boolean"
row2 << "0 for false, 1 for true "
row << t("image")
row1 << "url"
row2 << "http://www.example.com/images/example.png"
row << t("image") + " " + t("description") + " - " + t("en")
row1 << "textfield"
row2 << ""
row << t("image") + " " + t("description") + " - " + t("zh_tw")
row1 << "textfield"
row2 << ""
row << t("title") + " - " + t("en")
row1 << "textfield"
row2 << ""
row << t("title") + " - " + t("zh_tw")
row1 << "textfield"
row2 << ""
row << t("subtitle") + " - " + t("en")
row1 << "textarea"
row2 << ""
row << t("subtitle") + " - " + t("zh_tw")
row1 << "textarea"
row2 << ""
row << t("content") + " - " + t("en")
row1 << "editor"
row2 << ""
row << t("content") + " - " + t("zh_tw")
row1 << "editor"
row2 << ""
row << t("link")
row1 << "textfield"
row2 << "Seperate with ';'. Example: http://rulingcom.com; http://google.com"
row << t("link") + " " + t("url_alt") + " - " + t("en")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Rulingcom official site; Google search engine"
row << t("link") + " " + t("url_alt") + " - " + t("zh_tw")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Rulingcom official site; Google search engine"
row << t("file_")
row1 << "textfield"
row2 << "Seperate with ';'. Example: http://www.example.com/images/example.png; http://www.example.com/images/example2.png"
row << t("file_") + " " + t("description") + " - " + t("en")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Great view; Nice potrait"
row << t("file_") + " " + t("description") + " - " + t("zh_tw")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Great view; Nice potrait"
row << t("file_") + " " + t("alternative") + " - " + t("en")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : example1; example2"
row << t("file_") + " " + t("alternative") + " - " + t("zh_tw")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : example1; example2"
sheet.add_row row, :style => heading
sheet.add_row row1
sheet.add_row row2, :style => example
@custom_announcements.each do |custom_anns|
row = []
row << categories.to_a.index(custom_anns.category)
t = []
custom_anns.tags.each do |tag|
t << tags.to_a.index(tag)
end
row << t.join(",")
row << (custom_anns.postdate.strftime("%Y/%m/%d") rescue "")
row << (custom_anns.deadline.strftime("%Y/%m/%d") rescue "")
row << (custom_anns.is_top? ? 1 : 0)
row << (custom_anns.is_hot? ? 1 : 0)
row << (custom_anns.is_hidden? ? 1 : 0)
row << ("http://" + request.host_with_port + custom_anns.image.url rescue "")
row << custom_anns.image_description_translations["en"]
row << custom_anns.image_description_translations["zh_tw"]
row << custom_anns.title_translations["en"]
row << custom_anns.title_translations["zh_tw"]
row << custom_anns.subtitle_translations["en"]
row << custom_anns.subtitle_translations["zh_tw"]
row << custom_anns.text_translations["en"]
row << custom_anns.text_translations["zh_tw"]
links = custom_anns.custom_bulletin_links.asc(:created_at)
t = links.collect{|l|l.url}
row << t.join(";")
t = links.collect{|l|l.title_translations["en"]}
row << t.join(";")
t = links.collect{|l|l.title_translations["zh_tw"]}
row << t.join(";")
files = custom_anns.custom_bulletin_files.asc(:created_at)
t = files.collect{|f|("http://" + request.host_with_port + f.file.url rescue nil)}
t.delete(nil)
row << t.join(";")
t = files.collect{|l|l.description_translations["en"]}
row << t.join(";")
t = files.collect{|l|l.description_translations["zh_tw"]}
row << t.join(";")
t = files.collect{|l|l.title_translations["en"]}
row << t.join(";")
t = files.collect{|l|l.title_translations["zh_tw"]}
row << t.join(";")
sheet.add_row row
end
end

View File

@ -0,0 +1,124 @@
<% content_for :page_specific_css do %>
<%= stylesheet_link_tag("admin/tags") %>
<% end %>
<% content_for :page_specific_javascript do %>
<%= javascript_include_tag "validator" %>
<% end %>
<table class="table main-list">
<thead>
<tr class="sort-header">
<% @table_feed_fields.each do |f| %>
<%= thead(f) %>
<% end %>
</tr>
</thead>
<tbody>
<%= render :partial => "feed", :collection => @feeds %>
</tbody>
</table>
<% if current_user.is_admin? or current_user.is_manager?(@module_app) %>
<div class="bottomnav clearfix" style="left: 81px;">
<div class="action pull-right">
<a class="btn btn-primary new-feed" href="#">
<i class="icon-plus"></i> <%= t(:new_) %>
</a>
</div>
<div class="pagination pagination-centered"></div>
</div>
<div id="newFeedModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="newFeedModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="newFeedModalLabel">Create New Feed</h3>
</div>
<div class="modal-body">
<%#= render :partial => "feed_form" %>
</div>
<div class="modal-footer">
<button class="btn btn-primary" id="save_new_feed">Save changes</button>
</div>
</div>
<% end %>
<script type="text/javascript">
$(".new-feed").on("click",function(){
var modal = $("#newFeedModal");
modal.find("#newFeedModalLabel").text("Create New Feed");
modal.modal("show");
openFeedModal("new",null);
})
var bindEditButtons = function(){
$(".edit-feed").on("click",function(){
var modal = $("#newFeedModal");
modal.find("#newFeedModalLabel").text("Edit Feed");
modal.modal("show");
openFeedModal("edit",$(this).data("feed-id"));
return false;
})
$(".delete-feed").on("click",function(){
if(confirm("Are you sure?")){
var el = $(this);
$.ajax({
url : el.attr("href"),
type : "delete",
dataType : "html"
}).done(function(data){
$("table.main-list tbody").html(data);
bindEditButtons();
})
}
return false;
})
}
bindEditButtons();
var openFeedModal = function(type,feed_id){
$.ajax({
url : "/admin/custom_announcements/feedform",
type : "get",
data : {"type" : type, "id" : feed_id},
dataType : "html"
}).done(function(form){
$("#newFeedModal .modal-body").html(form);
bindHandlers();
})
}
var bindHandlers = function(){
$(".tag-checkbox").on("click",function(){
if($(this).is(":checked")){
$(this).parent().addClass("active");
}else{
$(this).parent().removeClass("active");
}
})
var fv = new FormValidator($("#newFeedModal form"));
fv.form.on("submit",function(){
$.ajax({
url : fv.form.attr("action"),
data : fv.form.serializeArray(),
type : "post",
dataType : "html"
}).done(function(data){
$("table.main-list tbody").html(data);
bindEditButtons();
$("#newFeedModal").modal("hide");
fv.form.resetForm();
fv.form.find("ul.tags-groups p.active").removeClass("active");
})
return false;
})
$("#save_new_feed").on("click",function(){
if(fv.isFormValidated()){
fv.form.submit();
}else{
return false;
}
})
}
</script>
</br>

View File

@ -0,0 +1,87 @@
<% content_for :page_specific_javascript do %>
<script type="text/javascript" src="/assets/validator.js"></script>
<% end %>
<form action="<%= admin_custom_announcement_importcustom_anns_path %>" method="post" class="form-horizontal main-forms" id="import-custom_anns-xls" enctype="multipart/form-data">
<h3 style="padding-left: 30px;"><%= t("custom_announcement.export_to_excel") %></h3>
<div class="control-group">
<div class="controls">
<a href="<%= admin_custom_announcement_export_excel_path(:format => "xlsx") %>"><%= t("custom_announcement.export_all_custom_anns") %></a>
</div>
</div>
<h3 style="padding-left: 30px;"><%= t("custom_announcement.import_from_excel") %></h3>
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
<div class="input-area">
<% if @module_app.categories.count > 0 %>
<div class="control-group">
<div class="controls">
<a href="<%= admin_custom_announcement_excel_format_path(:format => "xlsx") %>"><%= t("custom_announcement.download_example_sheet_here") %></a>
</div>
</div>
<div class="control-group">
<label for="import-custom_anns" class="control-label muted"><%= t("upload") %></label>
<div class="controls">
<input type="file" id="import-custom_anns" name="import_file" data-fv-validation="required;mustbexls;" data-fv-messages="Cannot be empty; Must be an excel file.;" />
<span class="help-block"><%= t("custom_announcement.please_create_tags_cats") %></span>
</div>
</div>
<% else %>
<div class="control-group">
<div class="controls">
<h4><%= t("custom_announcement.create_atleast_one_cat") %></h4>
</div>
</div>
<% end %>
</div>
<% if @module_app.categories.count > 0 %>
<div class="form-actions">
<input type="submit" value="<%= t("restful_actions.import") %>" class="btn btn-primary">
</div>
<% end %>
</form>
<!-- import from wp xml -->
<form action="<%= admin_custom_announcement_import_from_wp_path %>" method="post" class="form-horizontal main-forms" id="import-custom_anns-wp-xml" enctype="multipart/form-data">
<h3 style="padding-left: 30px;"><%= t("custom_announcement.import_from_wp_xml") %></h3>
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
<div class="input-area">
<div class="control-group">
<label for="import-custom_anns-wp-xml" class="control-label muted"><%= t("upload") %></label>
<div class="controls">
<input type="file" id="import-custom_anns-wp-xml" name="import_xml" data-fv-validation="required;mustbexml;" data-fv-messages="Cannot be empty; Must be an XML file.;" />
</div>
</div>
</div>
<div class="form-actions">
<input type="submit" value="<%= t("restful_actions.import") %>" class="btn btn-primary">
</div>
</form>
<!-- <form action="<%#= admin_custom_announcement_import_from_xml_path %>" method="post" class="form-horizontal main-forms" id="import-custom_anns-xml" enctype="multipart/form-data">
<h3 style="padding-left: 30px;">Import from XML</h3>
<%#= hidden_field_tag :authenticity_token, form_authenticity_token %>
<div class="input-area">
<div class="control-group">
<label for="import-custom_anns" class="control-label muted">URL :</label>
<div class="controls">
<input type="text" id="import-custom_anns" name="import_xml" data-fv-validation="required;url;" data-fv-messages="Cannot be empty; Must be an URL.;" />
</div>
</div>
</div>
<div class="form-actions">
<input type="submit" value="Import" class="btn btn-primary">
</div>
</form> -->
<script type="text/javascript">
var form = new FormValidator($("#import-custom_anns-xls"));
form.validate_functions.mustbexls = function(val){
var t = val.split("."),
ext = t[t.length - 1];
return (ext == "xls" || ext == "xlsx")
}
var form = new FormValidator($("#import-custom_anns-wp-xml"));
form.validate_functions.mustbexml = function(val){
var t = val.split("."),
ext = t[t.length - 1];
return (ext == "xml")
}
</script>

View File

@ -0,0 +1,37 @@
<%= render_filter @filter_fields, "index_table" %>
<% custom_config = CustomBulletinConfig.where(:module=>params[:custom_module]).first %>
<% target_model = custom_config.bind_model.constantize %>
<h3><%= target_model.where(custom_config.uid_field=>params[:bind_uid]).first.send(custom_config.title_field) %></h3>
<span id="index_table">
<%= render 'index'%>
</span>
<%= render 'layouts/delete_modal', delete_options: @delete_options %>
<% if CustomAnnouncementSetting.is_pro? && user_can_approve? %>
<%= render :partial=> "approval_modal" %>
<script type="text/javascript">
$(function(){
var modal = $("#approvalModal");
$(document).on("click", ".approval_button",function(){
var url = $(this).attr("href");
if(window.location.protocol === "https:"){
url = url.replace("http:","https:");
}
modal.find("iframe").attr("src", url);
modal.find("#object_id").val($(this).data("id"));
modal.modal("show");
return false;
})
var params = getUrlVars();
console.log(params["url"])
if(typeof params["url"] != "undefined"){
modal.find("iframe").attr("src", params["url"]);
modal.find("#object_id").val(params["id"]);
modal.modal("show");
}
})
</script>
<% end %>

View File

@ -0,0 +1,5 @@
<%= form_for @custom_bulletin, url: admin_custom_announcements_path, html: {class: "form-horizontal main-forms previewable"} do |f| %>
<fieldset>
<%= render :partial => 'form', locals: {f: f} %>
</fieldset>
<% end %>

View File

@ -0,0 +1,390 @@
<%= stylesheet_link_tag "select2/select2" %>
<%= javascript_include_tag 'validator' %>
<%= javascript_include_tag "select2/select2.min" %>
<% content_for :page_specific_css do %>
<%= stylesheet_link_tag "lib/main-forms" %>
<% end %>
<style type="text/css">
#notification{
background-color: #ececec;
font-size: 14px;
left: 40%;
padding: 10px;
position: absolute;
text-align: center;
top: 40px;
width: auto;
z-index: 1200;
display: none;
}
.badge-info{
margin-left: 10px;
}
#approver-list{
list-style: none;
margin-left: 5px;
}
#approver-list li {
border-bottom: 1px solid #efefef;
margin-bottom: 10px;
padding-bottom: 10px;
}
#approver-list .approver-avatar{
width: 60px;
height: 60px;
border-radius: 50px;
margin-right: 20px;
}
#approver-list .approver-check{
vertical-align: middle;
margin-top: 25px;
}
#approver-list .approver-check input{
margin-right: 5px;
vertical-align: middle;
}
#approver-list .approver-check label{
display: inline;
vertical-align: middle;
}
#approver-list .approver-title{
font-size: 14px;
}
.table{
display: flex;
flex-direction: column;
}
.table-row,.role_limit_tr,.role_limit_add {
width: 100%;
display: inline-flex;
align-items: center;
margin-bottom: 0.5em;
}
.td{
width: 30%;
display: inline-flex;
justify-content: center;
}
.table{
border: #2d4cd0 0.1em solid;
}
.td-3{
width: 100%;
display: inline-flex;
justify-content: center;
}
.td>*{
max-width: 95%;
}
.td-delete{
width: 10%;
}
</style>
<%
sub_managers = @module_app.sub_managers
sub_managers.delete(nil)
all_statuses = [[t('top'),'is_top'],[t('hot'),'is_hot']]
tp1 = select_tag("custom_announcement_setting[custom_anns_status_settings][-1][status]",options_for_select(all_statuses))
tp2 = select_tag("custom_announcement_setting[custom_anns_status_settings][-1][role_id]",options_for_select(Role.all.map{|r| [r.title,r.id]}))
tp3 = number_field_tag("custom_announcement_setting[custom_anns_status_settings][-1][top_limit]",nil, min: 0,required: true)
tp4 = "<button type='button' onclick='delete_limit_role(this)'' class='btn'>#{t('delete_')}</button>"
all_tp = "<div class='role_limit_tr'><div class='td'>#{tp1}</div><div class='td'>#{tp2}</div><div class='td'>#{tp3}</div><div class='td-delete'>#{tp4}</div></div>"
%>
<script type="text/javascript">
function add_limit_role(){
var role_limit_l = $('.role_limit_tr').length
var role_limit_tp = '<%= all_tp.inspect %>'
role_limit_tp = role_limit_tp.replace(/-1/g,role_limit_l)
$('.role_limit_add').before($('<div/>').html(role_limit_tp).text().slice(1,-2))
}
function delete_limit_role(ele){
var now_index = $(ele).parents('.role_limit_tr').index('.role_limit_tr')
console.log(now_index)
$(ele).parents('.role_limit_tr').remove()
$('.role_limit_tr').each(function(i,v){
if (i >= now_index){
$(v).find('[name^="custom_announcement_setting[custom_anns_status_settings]"]').each(function(i1,v1){
console.log($(v1).attr('name'))
$(v1).attr('name',$(v1).attr('name').replace(/\d+/g,i.toString()))
})
}
})
}
$(document).ready(function(){
var approverList = $(".hidden-approver-list");
$(".approver-check input").on("click",function(){
var el = $(this);
if(el.is(":checked")){
var t = $("<input type='hidden'>");
t.val(el.val());
t.attr("name", "custom_announcement_setting[approvers][]");
t.attr("id", "check_" + el.val());
approverList.append(t);
}else{
approverList.find("#check_" + el.val()).remove();
}
})
})
</script>
<div id="notification"><%= t("custom_announcement.click_on_submit") %></div>
<%= form_for @setting, url: (@setting.new_record? ? admin_custom_announcement_createsettings_path : admin_custom_announcement_updatesettings_path), html: {class: "form-horizontal main-forms"} do |f| %>
<div class="input-area">
<div class="control-group">
<%= f.label :only_manager_can_edit_status, t("custom_announcement.only_manager_can_edit_status"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :only_manager_can_edit_status %>
</div>
</div>
<div class="control-group">
<%= f.label :is_display_edit_only, t("custom_announcement.is_display_edit_only"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :is_display_edit_only %>
</div>
</div>
<div class="control-group">
<%= f.label :top_limit, t("custom_announcement.top_limit"), :class => "control-label muted" %>
<div class="controls">
<%= f.number_field :top_limit, :min => "0" %>
<span class="help-block"><%= t("custom_announcement.for_unlimited") %></span>
</div>
</div>
<div class="control-group">
<div class="table">
<div class="table-row">
<div class="td">
<%= t('status') %>
</div>
<div class="td">
<%= t('role') %>
</div>
<div class="td">
<%= t('custom_announcement.top_limit') %>
</div>
</div>
<% (CustomAnnouncementSetting.first.custom_anns_status_settings rescue []).each_with_index do |v,i| %>
<div class="role_limit_tr">
<%= hidden_field_tag("custom_announcement_setting[custom_anns_status_settings][#{i}][_id]",v.id) %>
<div class="td">
<%= select_tag("custom_announcement_setting[custom_anns_status_settings][#{i}][status]",options_for_select(all_statuses,:selected => v['status'])) %>
</div>
<div class="td">
<%= select_tag("custom_announcement_setting[custom_anns_status_settings][#{i}][role_id]",options_for_select(Role.all.map{|r| [r.title,r.id]},:selected => v['role_id'])) %>
</div>
<div class="td">
<%= number_field_tag("custom_announcement_setting[custom_anns_status_settings][#{i}][top_limit]",v['top_limit'], min: 0,required: true) %>
</div>
<div class="td-delete">
<button type="button" onclick="delete_limit_role(this)" class="btn">
<%= t('delete_') %>
</button>
</div>
</div>
<% end %>
<div class="role_limit_add">
<div class="td-3">
<button type="button" onclick="add_limit_role()" class="btn">
<%= t('add') %>
</button>
</div>
</div>
</div>
</div>
<% if CustomAnnouncementSetting.is_pro? %>
<% if !sub_managers.blank? %>
<div class="control-group">
<%= f.label "Approver Setting", :class => "control-label muted" %>
<div class="controls">
<a href="#approverModal" role="button" class="btn" data-toggle="modal"><%= t("custom_announcement.approvers_list") %></a>
<span class="badge badge-info"><%= @setting.approvers.count %></span>
</div>
</div>
<% else %>
<div class="control-group">
<a href="/admin/authorizations/custom_announcement"><%= t("custom_announcement.click_set_sub_manager") %></a>
</div>
<% end %>
<div class="control-group">
<%= f.label "Send emails to", :class => "control-label muted" %>
<div class="controls">
<input type="checkbox" name="custom_announcement_setting[email_to][]" value="admins" <%= @setting.email_to.include?("admins") ? "checked=checked" : "" %>> <%= t("admin") %>
<input type="checkbox" name="custom_announcement_setting[email_to][]" value="managers" <%= @setting.email_to.include?("managers") ? "checked=checked" : "" %>> <%= t("manager") %>
<input type="checkbox" name="custom_announcement_setting[email_to][]" value="approvers" <%= @setting.email_to.include?("approvers") ? "checked=checked" : "" %>> <%= t("custom_announcement.approver") %>
</div>
</div>
</div>
<div class="hidden-approver-list">
<% sub_managers.each do |sm| %>
<% if @setting.approvers.include?(sm.id.to_s) %>
<input type="hidden" id="check_<%= sm.id.to_s %>" value="<%= sm.id.to_s %>" name="custom_announcement_setting[approvers][]">
<% end %>
<% end %>
</div>
<% end %>
<div class="form-actions">
<%= f.submit t('submit'), class: 'btn btn-primary' %>
</div>
<% end %>
</div>
<% if CustomAnnouncementSetting.is_pro? %>
<div id="approverModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="approverModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="approverModalLabel"><%= t("sub_manager") %></h3>
</div>
<div class="modal-body">
<ul id="approver-list">
<% sub_managers.each do |sm| %>
<li>
<%= image_tag sm.member_profile.avatar.thumb, :class => "approver-avatar" %>
<span class="approver-title"><%= sm.name %></span>
<span class="pull-right approver-check">
<input id="checkbox_<%= sm.id %>" type="checkbox" value="<%= sm.id %>" <%= @setting.approvers.include?(sm.id.to_s) ? "checked=checked" : "" %>>
<label for="checkbox_<%= sm.id %>"><%= t("custom_announcement.approver") %></label>
</span>
</li>
<% end %>
</ul>
</div>
<div class="modal-footer">
<button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">Ok</button>
</div>
</div>
<script type="text/javascript">
$("#approverModal").on("hidden",function(){
$("#notification").slideDown();
$(".badge-info").text($(".hidden-approver-list input").length);
})
</script>
<% end %>
<%= fields_for :iframe do |f| %>
<div class="form-horizontal input-area">
<fieldset id="iframe_settings">
<legend><%=t('custom_announcement.custom_announcement_setting_for_iframe')%></legend>
<div class="control-group">
<%= f.label :layout_type, t("custom_announcement.layout_type"), :class => "control-label muted" %>
<div class="controls">
<% @layout_types = get_layouts(@module_app.key) %>
<% if @layout_types.first.kind_of?(Hash) %>
<select name="iframe[layout_type]" id="page_layout" class="select2">
<% @layout_types.each do |lt| %>
<option value="<%= lt["filename"] %>" data-image="<%= lt["thumbnail"] %>"><%= (lt["name"].kind_of?(Hash) ? (lt["name"][I18n.locale.to_s] || lt["name"]['en']) : lt["name"]) %></option>
<% end %>
</select>
<script type="text/javascript">
$("select.select2").select2({
formatResult: function(el){
var $element = $(el.element),
image = $element.data("image");
return "<img class='thumbnail' src='" + image + "'/><span class='thumbnail-text'>" + el.text + "</span>";
},
minimumResultsForSearch: -1,
width : 250
});
</script>
<% else %>
<%= f.select(:layout, @layout_types) %>
<% end %>
</div>
</div>
<div class="control-group">
<%= f.label :tags, t(:tags), :class => "control-label muted" %>
<div class="controls">
<% @module_app.tags.each_with_index do |t,index| %>
<label class="checkbox inline btn" for="<%="tags_#{index}"%>">
<input id="<%="tags_#{index}"%>" name="iframe[tags][]" type="checkbox" value="<%=t.id%>" style="opacity: 0;">
<%=t.name%>
</label>
<% end %>
</div>
</div>
<div class="control-group">
<label class="control-label muted" ><%=t(:categories)%></label>
<div class="controls">
<% @module_app.categories.each_with_index do |c,index| %>
<label class="checkbox inline btn" for="<%="categories_#{index}"%>">
<input id="<%="categories_#{index}"%>" name="iframe[categories][]" type="checkbox" value="<%=c.id%>" style="opacity: 0;">
<%=c.title%>
</label>
<% end %>
</div>
</div>
<div class="control-group">
<%= f.label :authors, t('custom_announcement.table.author'), :class => "control-label muted" %>
<div class="controls">
<%= render partial: 'admin/members/generate_modal_select' , locals: { :@sorted_members => @sorted_members ,:member_form_id => "card-list-members",:member_field_name=>"iframe[member_ids][]" } %>
</div>
</div>
<div class="control-group">
<%= f.label :show_page, t('custom_announcement.show_page'), :class => "control-label muted" %>
<div class="controls">
<%=f.check_box :show_page ,{:checked=>'checked'},'true','false'%>
</div>
</div>
<div class="control-group">
<%= f.label :data_count, t(:data_count), :class => "control-label muted" %>
<div class="controls">
<%=f.number_field :data_count, {min: 0,:value=> 10} %>
</div>
</div>
<div class="control-group">
<div class="controls">
<a class="btn btn-primary" title="<%= t("custom_announcement.url_generate") %>" id="url_generate"><%= t("custom_announcement.url_generate") %></a>
</div>
</div>
</fieldset>
</div>
<% end %>
<script type="text/javascript">
function getparams(id){
var params_array = $("#"+id).serializeArray();
var params = {};
params_array.forEach(function(dict){
if(params[dict.name] == undefined)
if(dict.name.substr(dict.name.length-2,2) == "[]")
params[dict.name] = [dict.value]
else
params[dict.name] = dict.value
else
if(dict.name.substr(dict.name.length-2,2) == "[]")
params[dict.name].push(dict.value)
else
params[dict.name] = dict.value
})
return params;
}
$(document).ready(function(){
$('label.checkbox input').click(function(){
if($(this).parent().hasClass('active'))
$(this).parent().removeClass('active');
else
$(this).parent().addClass('active');
})
$('#url_generate').off('click').on('click',function(){
var params = getparams('iframe_settings');
$.post("<%=admin_custom_announcement_generate_iframe_url_path%>",params).done(function(url){
var real_url = '/annc_url?url='+window.location.href.split('/')[0]+"//"+window.location.host+url;
if($("#dialog-confirm").length == 0){
$("#url_generate").before("<div id='dialog-confirm' title='<%="iframe "+t('custom_announcement.URL')%>'>"+
"<div style='clear:both;'></div><div id='info_texts'>"+"<label style='float:left;margin-right: 0.2em; line-height: 2em;' for='iframe_url'><%="iframe "+t('custom_announcement.URL') %>:</label><input id= 'iframe_url' style='float:left;cursor:text;' type='text' readyonly value='"+real_url+"'><a class='btn btn-primary copy_text' style='color: white;'><%=t('custom_announcement.copy')%></a>"+"</div>"+
"</div>");
}
$( "#dialog-confirm" ).dialog({
resizable: true,
minHeight: 100,
maxHeight: 400,
width: '80%',
modal: true,
buttons: {
"<%= t(:close) %>": function(){$( this ).dialog( "close" );}
}
});
$('.copy_text').off('click').on('click',function(){
var copyText = document.getElementById("iframe_url");
copyText.select();
copyText.setSelectionRange(0, 99999);
document.execCommand("copy");
})
});
});
})
</script>

View File

@ -0,0 +1,16 @@
xml.instruct! :xml, :version => "1.0"
xml.rss :version => "2.0" do
xml.channel do
xml.title @bf.title
xml.link "/xhr/custom_announcements/rssfeed/73999228.rss"
for custom_announcement in @custom_announcements
xml.item do
xml.title custom_announcement.title
xml.description custom_announcement.subtitle
xml.pubDate custom_announcement.created_at.to_s(:rfc822)
xml.link page_for_custom_bulletin(custom_announcement)
end
end
end
end

View File

@ -0,0 +1,39 @@
<% active_module = @custom_data_field[:bind_module_app] rescue nil %>
<% active_uid = @custom_data_field[:bind_uid] rescue nil %>
<% active_module = @custom_configs.first.module if active_module.nil? %>
<div class="control-group input-content">
<label class="control-label muted" for="custom_bind_module_app"><%=t("custom_announcement.use_module")%> :</label>
<div class="controls">
<%= select_tag("#{@field_name}[custom_data_field][bind_module_app]", options_for_select(@custom_configs.map{|c| [t("module_name.#{c.module}"),c.module]},active_module),{:id=>"custom_bind_module_app"})%>
</div>
</div>
<div class="control-group input-content">
<label class="control-label muted" for="custom_bind_uid"><%=t("custom_announcement.use_content")%> :</label>
<div class="controls">
<% @custom_configs.each do |c| %>
<% title_field = c.title_field
uid_field = c.uid_field
bind_model = c.bind_model.constantize rescue nil
%>
<% if bind_model %>
<div class="<%=(c.module == active_module) ? "show bind_modules" : "hide bind_modules" %>" data-module="<%= c.module %>">
<%= select_tag("#{@field_name}[custom_data_field][bind_uid]", options_for_select(bind_model.where(title_field.to_sym.nin=>[nil,""]).map{|target_model| [target_model.send(title_field),target_model.send(uid_field)]},active_uid),{:id=>"custom_bind_uid"})%>
</div>
<% end %>
<% end %>
</div>
</div>
<script type="text/javascript">
if($(".bind_modules.hide").length != 0){
$(".bind_modules.hide").eq(-1).after($(".bind_modules.show"));
}
$("#custom_bind_module_app").change(function(){
var value = $(this).val();
console.log(value)
$(".bind_modules").removeClass("show").addClass("hide");
$("[data-module=\""+value+"\"]").removeClass("hide").addClass("show");
if($(".bind_modules.hide").length != 0){
$(".bind_modules.hide").eq(-1).after($(".bind_modules.show"));
}
})
</script>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
</head>
<body bgcolor="#FFFFFF">
<div style="text-ident:20px"></div>
<%= t('custom_announcement.mail_hi') %> <br /><br />
<%= t('custom_announcement.mail_url_view') %> <br /><br />
<a href="<%= @data["url"] %>" target="_blank"> <%= @data["title"] %> </a> <br /><br />
<span style="color:#555">--<br />
<%= t('custom_announcement.mail_source') %> <a href="http://<%= @data["host"] %>" target="_blank"> <%= Site.first.title %> </a><br />
<%= t('custom_announcement.mail_time') %> <%= DateTime.now.strftime('%Y/%m/%d %H:%M:%S') %>
</span>
</body>
</html>

View File

@ -0,0 +1,85 @@
<% params = OrbitHelper.params
page = Page.where(url:params['url']).first
enable_search_flag = false
if page.methods.include? 'select_option_items'.to_sym
ModuleApp.all.select{|tmp| tmp.key.to_s=='custom_announcement'}.each do |modile_app|
@show_option_items = modile_app.show_option_items rescue nil
end
page.select_option_items.each do |select_option_item|
if !(@show_option_items.nil?) && select_option_item.field_name == @show_option_items.keys[1].to_s
value = YAML.load(select_option_item.value)
if value[I18n.locale] == t('custom_announcement.yes')
enable_search_flag = true
end
end
end
end
%>
<% if enable_search_flag %>
<style type="text/css">
#category_select_box{
margin: 0;
background: linear-gradient(0deg, #515fff, #ff3e3e);
color: white;
outline: 0;
border-radius: 0.9em;
}
#category_select_box>option{
background: #5640dd;
}
input.search_box{
margin: 0;
background: #a2c3df;
font-weight: bold;
color: #00008b;
border-radius: 0.7em;
outline: 0;
}
input.search_box[type='submit']:hover{
background: #9100ff;
color: white;
}
input.search_box[type='submit']:active{
background: #7201ff;
color: white;
}
input.search_box::-webkit-input-placeholder {
color: #aa58e8;
opacity: 1;
}
input.search_box:-moz-placeholder {
color: #aa58e8;
opacity: 1;
}
input.search_box::-moz-placeholder {
color: #aa58e8;
opacity: 1;
}
</style>
<form>
<% cats = Array(page.categories)
if cats.include? 'all'
cats = ModuleApp.where(key: 'custom_announcement').first.categories
else
cats = cats.map{|v| Category.where(id: v).first}.compact
end
all_cat = [[t('custom_announcement.all'),'all']]
%>
<div class="search_widget" style="display: flex;flex-wrap: wrap;font-size: 1.1em;">
<%= select_tag('category',options_for_select(all_cat.concat(cats.map{|v| [v.title,v.id.to_s]}),:selected => params['category'].to_s),:id=>"category_select_box",:prompt => t('custom_announcement.select_prompt')) %>
<input class="search_box" type="text" name="keywords" value="<%= params['keywords'].to_s.gsub(/\"/,'') %>" placeholder="<%= t('custom_announcement.keywords') %>">
<div style="display: flex;flex-wrap: wrap;">
<div class="default_picker">
<input class="search_box" type="text" name="stime" value="<%= params['stime'].to_s.gsub(/\"/,'') %>" placeholder="<%= t('custom_announcement.stime') %>" data-format="yyyy/mm/dd">
</div>
~
<div class="default_picker">
<input class="search_box" type="text" name="etime" value="<%= params['etime'].to_s.gsub(/\"/,'') %>" placeholder="<%= t('custom_announcement.etime') %>" data-format="yyyy/mm/dd">
</div>
</div>
<input type="hidden" name="authenticity_token" value="<%= (0...46).map { ('a'..'z').to_a[rand(26)] }.join %>">
<input class="search_box" type="submit" value="<%= t('custom_announcement.search') %>">
</div>
</form>
<% end %>
<%= render_view %>

View File

@ -0,0 +1,180 @@
<%
params = OrbitHelper.params
page = Page.where(url:params['url']).first
@show_back_and_next_flag = 0
if page.methods.include? 'select_option_items'.to_sym
ModuleApp.all.select{|tmp| tmp.key.to_s=='custom_announcement'}.each do |modile_app|
@show_option_items = modile_app.show_option_items rescue nil
end
page.select_option_items.each do |select_option_item|
if !(@show_option_items.nil?) && select_option_item.field_name == @show_option_items.keys.first.to_s
value = YAML.load(select_option_item.value)
tmp = value[:en]
I18n.with_locale(:en) do
if tmp == t('custom_announcement.not_show')
@show_back_and_next_flag = 0
elsif tmp == t('custom_announcement.show_top')
@show_back_and_next_flag = 1
elsif tmp == t('custom_announcement.show_bottom')
@show_back_and_next_flag = 2
end
end
end
end
end
if @show_back_and_next_flag != 0
uid = params['uid']
sorted,total_pages = get_sorted_annc(0)
now_index = sorted.to_enum.with_index.select{|v| v[0].uid==uid}[0][1] rescue nil
if !now_index.nil?
if now_index != 0
prev_result = sorted[now_index-1]
prev_url = params['url'] + '/' + prev_result.to_param
prev_content = "<a href='#{prev_url}' title='#{t('custom_announcement.prev')}' class='prev'><b>#{t('custom_announcement.prev')}</b><p>#{prev_result['title'][I18n.locale]}</p></a>"
end
if now_index != sorted.length-1
next_result = sorted[now_index+1]
next_url = params['url'] + '/' + next_result.to_param
next_content = "<a href='#{next_url}' title='#{t('custom_announcement.next')}' class='next'><b>#{t('custom_announcement.next')}</b><p>#{next_result['title'][I18n.locale]}</p></a>"
end
content = "<div class='see_more_boxTitle'>#{prev_content}#{next_content}</div>".html_safe
else
content = ''
end
end
%>
<% if @show_back_and_next_flag!=0 %>
<style type="text/css">
.see_more_boxTitle{
display: flex;
margin: 1em 0em;
padding: 1em;
border: 0.2em solid;
}
a.prev, a.next{
width: 50%;
border: 0.2em solid;
padding: 1em;
flex: 1;
}
a.next{
margin-left: 1em;
}
a.prev{
margin-right: 1em;
}
</style>
<% end %>
<% if @show_back_and_next_flag==1 %>
<%= content %>
<% end %>
<%= render_view %>
<% if @show_back_and_next_flag==2 %>
<%= content %>
<% end %>
<% site = Site.first
hover_color = site.orbit_bar_background_hover_color rescue nil
hover_color = '#0095CF' if hover_color.blank?
bg_color = site.orbit_bar_background_color rescue nil
bg_color = bg_color.blank? ? '#3a3b3c' : CustomAnnouncementsHelper.lighten_color(bg_color,-40)
color1 = CustomAnnouncementsHelper.lighten_color(bg_color,-40)
color2 = CustomAnnouncementsHelper.lighten_color(CustomAnnouncementsHelper.complementaryColor(bg_color),40)
%>
<style type="text/css">
div[contentEditable=true]:empty:before{
content: attr(data-ph);
color: <%= color1 %>;
padding-left: 3%;
font-weight: bold;
font-family: serif;
}
.custom_announcement-comment {
margin-top: 1em;
border: solid 0.2em <%= bg_color %>;
background: <%= color2 %>;
color: <%= bg_color %>;
font-size: 1.15em;
padding: 0.3em 0 0.3em 3%;
border-radius: 0.7em;
display: inline-block;
width: 80%;
outline: 0;
}
.annc-comment-div,.annc-comments{
display: flex;
align-items: center;
flex-wrap: wrap;
}
.btn-comment{
margin-top: 1em;
margin-left: 3%;
color: <%= color2 %>;
font-size: 1em;
background: <%= bg_color %>;
margin-left: 3%;
}
.btn.btn-comment:focus{
color: <%= color2 %>;
}
.btn-comment:hover{
color: <%= color2 %>;
background-color: <%= hover_color %>;
}
.annc-comments-nickname {
margin-top: 1em;
margin-left: 3%;
color: <%= bg_color %>;
}
.comment-time{
padding-left: 1em;
width: 100%;
color: <%= bg_color %>;
}
.annc-comments{
margin: 1.5em 0;
}
@media (max-width: 767px) {
.annc-comment-div,.annc-comments{
justify-content: center;
}
.custom_announcement-comment {
width: 100%;
}
}
</style>
<script type="text/javascript">
$(function(){
$('.annc-comment-div .btn-comment').click(function(){
$.ajax({
url: "<%= "/xhr/custom_announcements/#{params[:slug]}-#{params[:uid]}/comment" %>",
data : {"comment" : $(this).parents('.annc-comment-div').find('.custom_announcement-comment').html()},
dataType : "json",
type : "get",
success : function(data){
window.location.href = window.location.href
}
})
})
})
</script>
<% action_data['comments'].reverse.each do |comment| %>
<div class="annc-comments">
<div class="comment-time">
<%= comment.time %>
</div>
<div class="custom_announcement-comment">
<%= comment.comment.html_safe %>
</div>
<div class="annc-comments-nickname">by <%= comment.account %></div>
<br>
</div>
<% end %>
<% if action_data['show_comment_flag'] %>
<div class="annc-comment-div">
<div data-ph="<%= t('custom_announcement.comment') %>" contenteditable="true" class="custom_announcement-comment"></div>
<button class="btn btn-comment">
<%= t('custom_announcement.send_comment') %>
</button>
</div>
<% end %>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title><%= render_site_title %></title>
<%= stylesheet_link_tag "//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.min.css"%>
<%= stylesheet_link_tag "custom_bulletin/bootstrap/bootstrap.min.css"%>
<%= stylesheet_link_tag "template/template"%>
<%= javascript_include_tag "jquery.min"%>
<%= javascript_include_tag "bootstrap.min"%>
</head>
<body>
<% @target_action = "show_widget" %>
<%=render_view_for_annc((!params[:layout_type].blank? ? params[:layout_type] : 'annc_index1'))%>
</body>
</html>

View File

@ -0,0 +1 @@
<%= @data["html"].html_safe %>

View File

@ -0,0 +1,3 @@
<h3>Hello <%= @data["name"] %>,</h3>
<p><%= @data["submitter"] %> <%= t("custom_announcement.updated_annoucement") %>
<a href="<%= @data['url'] %>" ><%= t("custom_announcement.click_here_to_see") %></a>

View File

@ -0,0 +1,3 @@
<h3>Hello <%= @data["name"] %>,</h3>
<p><%= @data["rejector"] %> <%= t("annoucement.rejected_annoucement") %> : <%= @data["reason"].nil? || @data["reason"] == "" ? "" : "#{@data["reason"]}" %></p>
<a href="<%= @data['url'] %>" ><%= t("custom_announcement.click_here_to_see") %></a>

18
bin/rails Normal file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
ENGINE_ROOT = File.expand_path('../..', __FILE__)
ENGINE_PATH = File.expand_path('../../lib/custom_announcement/engine', __FILE__)
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
# require 'rails/all'
# require 'rails/engine/commands'
require "action_controller/railtie"
require "action_mailer/railtie"
require "sprockets/railtie"
require "rails/test_unit/railtie"
require 'rails/engine/commands'
require "mongoid/railtie"

View File

@ -0,0 +1,9 @@
require 'rufus-scheduler'
scheduler = Rufus::Scheduler.new
#return if defined?(Rails::Console) || Rails.env.test? || File.split($0).last == 'rake'
scheduler.cron '43 2 * * *' do
system('bundle exec rake custom_bulletin:remove_preview_custom_bulletins')
end

169
config/locales/en.yml Normal file
View File

@ -0,0 +1,169 @@
en:
module_name:
custom_announcement: CustomAnnouncement
restful_actions:
feed: Feed
import: Import
custom_announcement:
total_amount: Total amount
use_module: Use Module
use_content: Use Content
cover_image_display_setting: Cover Image display setting
full_width: Full width
up_left_corner: Up-left corner
up_right_corner: Up-right corner
all_tabs_setting: '"All" tab setting'
the_same_as_data_count: The same as data count
display_all_in_other_tabs: Display all contents in other tabs
read_more_position_options: '"read more" button position'
default: Default
upper_left: Upper left
lower_left: Lower left
upper_right: Upper right
lower_right: Lower right
tabs_options: Tabs options
not_enable_tabs: Not enable tabs
enable_tabs_with_categories_include_all: Enable tabs with categories(include all)
enable_tabs_with_categories: Enable tabs with categories
time: Time
send_comment: Send Comment
comment: Comment
account: Account
open_comment: Open for Comment
open: Open
comment_end_time: Comment End Time
comment_role: Comment Role
visitor: Visitor
all_member: All Member
add_to_calendar: Add to calendar
blank_to_set: (blank to use custom_announcement setting)
stime: start time
etime: end time
select_prompt: --select category--
all: All
keywords: Keywords
enable_search: Enable search feature
'yes': 'Yes'
'no': 'No'
image: Cover Image
carousel_image: Carousel Image
carousel_image_title: Carousel Image(display at the bottom of show page)
picture_showing_size: Picture Showing Size
orignal_size: Original Size
small_size: Small Size
medium_size: Medium Size
showing_back_and_next: Show back and next
not_show: Not show
show_top: Show at top
show_bottom: Show at bottom
prev: previous
next: next
table:
title : Title
date : Date
status : Status
sub_title: Sub Title
category: Category
author: Author
link: Link
file: File
view_count: View Count
department: Department
add_new: Add New
export_to_excel: Export to Excel
export_all_custom_anns: Export all CustomAnnouncement
import_from_excel: Import from Excel
download_example_sheet_here: Download example sheet here
please_create_tags_cats: Please create all the tags and categories before hand. Only excel file is allowed
create_atleast_one_cat: Please create atleast one category before importing.
import_from_wp_xml: Import from WordPress XML
click_on_submit: Click on Submit to save the changes
approvers_list: Approvers List
click_set_sub_manager: Click here to set Sub Managers for this module
approver: Approver
top_limit: Top Limit
for_unlimited: Put 0 for unlimited
feed_name: Feed Name
rssfeed: RSS Feed Link
jsonfeed: JSON Feed Link
feed_list: Feed List
approve: Approve
all_articles: All Articles
settings: Settings
import: Import / Export
custom_announcement: CustomAnnouncement
approval_setting: Approval Setting
approve_custom_bulletin_fail: Approval Fail
approve_custom_bulletin_success: Approve Successfully
approval_waiting: Approval
submitted_new_custom_announcement: "%{poster} submitted a new custom_announcement waiting for your approval."
click_here_to_see: Please click the link below to view the custom_announcement.
rejected_annoucement: has rejected your custom_announcement, because
updated_annoucement: "%{poster} updated the rejected custom_announcement."
custom_announcement_subject: New custom_announcement waiting for approval
approval_site: Site
approval_mail_hi: Hello %{name},
approval_custom_announcement_title: CustomAnnouncement Title
custom_bulletins: CustomBulletins
categories: Categories
create_custom_bulletin_success: Create CustomBulletin Successfully
create_custom_bulletin_category_success: Create Category Successfully
date: CustomAnnouncement Date
default_widget:
custom_bulletin_category_with_title: CustomBulletin Category with Title
postdate: Post Date
subtitle: Subtitle
title: Title
editing_custom_announcement: Edit CustomAnnouncement
editing_custom_announcement_category: Edit Category
file: Attachment
file_description: File Description
file_description_hint: 'File Description will display in the title of file link.(When placing mouse on the link,the title will display)'
file_name: File Name
frontend:
custom_bulletins: CustomAnnouncement front-end
search_result: Search result
link_name: Link Name
new_custom_bulletin_category: New CustomBulletin Category
picture: Cover Picture
search: Search
selected_file: Select File
update_custom_bulletin_category_success: Update Category Successfully
url: URL
widget:
custom_bulletins_and_web_links: Differential Nav.
index: Index
search: Search
more: More
more_: 'More '
email_reminder: Email Reminder
activate_email_reminder: Activate Email Reminder
email_sentdate: Email Time
email_to: Email To
mail_subject: this is an custom_announcement reminder from【%{site_title}】
view_count: View Counts
other_mailaddress: Other Email
other_mailaddress_note: Divide different email accounts with ","
mail_hi: Hi
mail_url_view: This email is the reminder of an custom_announcement, please click the link for the details
mail_source: Source
mail_time: Time
image_upload_size_note: The following recommendations %{image_upload_size} upload size
resend_mail: Re-send Email
is_external_link: Enable External Link
external_link: External Link
external_link_hint: "Make sure URL starts with http://"
display_subtitle: Display Subtitle in Content Page
display_img: Display Cover Image in Content Page
is_display_edit_only: Only display editable custom_announcements
only_manager_can_edit_status: Only manager can edit status of custom_announcements
layout_type: Layout type
custom_announcement_setting_for_iframe: CustomAnnouncement settings for iframe
url_generate: Url Generate
show_page: Show pagination
URL: URL
copy: Copy
status:
top: Important
hot: Hot
hidden: Hidden

172
config/locales/zh_tw.yml Normal file
View File

@ -0,0 +1,172 @@
zh_tw:
module_name:
custom_announcement: 客製公告
restful_actions:
feed: 供給
import: 匯入
custom_announcement:
total_amount: 總數
use_module: 使用模組
use_content: 使用內容
cover_image_display_setting: 封面圖片顯示設定
full_width: 滿版呈現
up_left_corner: 左上角
up_right_corner: 右上角
all_tabs_setting: '"全部"頁籤設定'
the_same_as_data_count: 與Data count相同
display_all_in_other_tabs: 顯示在其他頁籤的全部內容
read_more_position_options: '"更多"按鈕的位置'
default: 預設
upper_left: 左上
lower_left: 左下
upper_right: 右上
lower_right: 右下
tabs_options: 頁籤選項
not_enable_tabs: 無頁籤
enable_tabs_with_categories_include_all: 開啟頁籤(依類別,並包含全部所選類別之頁籤)
enable_tabs_with_categories: 開啟頁籤(依類別)
time: 時間
send_comment: 送出留言
comment: 留言內容
account: 帳號
open_comment: 開放評論
open: 開放
comment_end_time: 停止開放時間
comment_role: 留言身分
visitor: 訪客
all_member: 全部會員
add_to_calendar: 加入行事曆
blank_to_set: (留白則使用公告設定)
stime: 開始時間
etime: 結束時間
select_prompt: --選取類別--
all: 全部
keywords: 關鍵字
enable_search: 開啟搜尋功能
'yes':
'no':
image: 封面圖片
carousel_image: 輪播圖片
carousel_image_title: 輪播圖片(在show頁面底部顯示)
picture_showing_size: 圖片顯示大小
orignal_size: 原圖大小
small_size: 小張縮圖
medium_size: 中等縮圖
showing_back_and_next: 顯示上下則
not_show: 不顯示
show_top: 顯示在最上面
show_bottom: 顯示在最下面
prev: 上一則
next: 下一則
table:
title : 標題
date : 張貼日期
status : 標籤
sub_title: 副標題
category: 類別
author: 張貼人
link: 超連結
file: 檔案下載
view_count: 瀏覽人次
department: 單位
add_new: 新建
import: 匯入
export_to_excel: 匯出至Excel檔
export_all_custom_anns: 匯出所有公告
import_from_excel: 從Excel檔匯入
download_example_sheet_here: 在此下載範例
please_create_tags_cats: 甲、 請事先建立所有標籤及分類。 僅限Excel檔。
create_atleast_one_cat: 匯入前, 請先建立至少一個類別
import_from_wp_xml: 從WordPress XML檔匯入
top_limit: 最高設限
for_unlimited: 歸零不設限
click_on_submit: 點"提交"儲存變更
approvers_list: 審核人名單
click_set_sub_manager: 點這邊來設定這個模組的副管理者
approver: 審核人
approve: 通過
feed_name: Feed 標題
settings: 設定
import: 匯入 / 匯出
rssfeed: RSS 供給連結
jsonfeed: JSON 供給連結
feed_list: 訂閱清單
all_articles: 文章列表
custom_announcement: 客製公告
approval_setting: 審核設定
approve_custom_bulletin_fail: 審核失敗
approve_custom_bulletin_success: 審核成功
approval_waiting: 審核
submitted_new_custom_announcement: 貴單位於全球資訊網有一則 %{poster} 張貼的最新消息待您審核發布,
click_here_to_see: 請您點擊以下網址,前往審核
rejected_annoucement: 未通過您的公告審核,原因為
updated_annoucement: 貴單位於全球資訊網有一則 %{poster} 被拒絕的最新消息已重新編輯待您審核發布,
custom_announcement_subject: 系統訊息 - 最新消息內容審核通知
approval_mail_hi: 親愛的 %{name} 主管您好
approval_site: 網址
approval_custom_announcement_title: 消息標題
custom_bulletins: 公告
categories: 類別
create_custom_bulletin_success: 建立公告成功
create_custom_bulletin_category_success: 建立類別成功
date: 起迄日期
default_widget:
custom_bulletin_category_with_title: 公告類別及標題
postdate: 張貼日期
subtitle: 副標題
title: 標題
editing_custom_announcement: 編輯類別
editing_custom_announcement_category: 編輯類別
error:
no_avilb_cate_for_posting: 沒有可以張貼的類別
file: 附加檔案
file_description: 檔案描述
file_description_hint: '檔案描述將會顯示在前台檔案連結的title(把滑鼠放在連結上會出現的文字)'
file_name: 檔案名稱
frontend:
custom_bulletins: 公告前台
search_result: 搜尋結果頁
link_name: 連結名稱
new_custom_bulletin_category: 新增公告類別
picture: 刊頭圖片
search: 搜尋
selected_file: 選擇檔案
update_custom_bulletin_category_success: 更新類別成功
url: 連結位置
widget:
custom_bulletins_and_web_links: 分眾頁籤
index: 索引
search: 搜尋
more: 更多+
more_: 更多
email_reminder: 寄送提醒
activate_email_reminder: 開啟寄送提醒
email_sentdate: 寄送時間
email_to: 寄送對象
view_count: 瀏覽人次
other_mailaddress: 其他Mail
other_mailaddress_note: 輸入多組mail時,請用","逗號隔開
mail_subject: 來自【%{site_title}】的公告事件提醒
mail_hi: 您好
mail_url_view: 此封信件為公告事件提醒,請點選以下連結詳細觀看
mail_source: 來源
mail_time: 時間
image_upload_size_note: 建議檔案小於%{image_upload_size}
resend_mail: 重新寄送提醒
is_external_link: 連結外部網址
external_link: 外部連結
external_link_hint: "確定連結開頭為http://"
display_subtitle: 內容頁顯示副標題
display_img: 內容頁顯示封面圖片
is_display_edit_only: 只顯示可更新的公告
only_manager_can_edit_status: 只有管理者可更新公告狀態
layout_type: 頁面樣式
custom_announcement_setting_for_iframe: 公告iframe設定
url_generate: 網址生成
show_page: 顯示頁碼
URL: 網址
copy: 複製
status:
top: 重要
hot: 熱門
hidden: 隱藏

59
config/routes.rb Normal file
View File

@ -0,0 +1,59 @@
Rails.application.routes.draw do
locales = Site.first.in_use_locales rescue I18n.available_locales
scope "(:locale)", locale: Regexp.new(locales.join("|")) do
namespace :admin do
post 'custom_announcement/preview', to: 'custom_announcements#preview'
post 'custom_announcement/createfeed', to: 'custom_announcements#createfeed'
post 'custom_announcement/importcustom_anns', to: 'custom_announcements#importcustom_anns'
post 'custom_announcement/import_from_xml', to: 'custom_announcements#import_from_xml'
get 'custom_announcement/excel_format', to: 'custom_announcements#excel_format'
get 'custom_announcement/export_excel', to: 'custom_announcements#export_excel'
patch 'custom_announcement/updatefeed', to: 'custom_announcements#updatefeed'
delete 'custom_announcement/deletefeed', to: 'custom_announcements#deletefeed'
get 'custom_announcement/destroy_preview/:slug_title-:uid', to: 'custom_announcements#destroy_preview'
post 'custom_announcement/approve_custom_bulletin', to: 'custom_announcements#approve_custom_bulletin'
get 'custom_announcement/feed', to: 'custom_announcements#feed'
get 'custom_announcements/feedform', to: 'custom_announcements#feedform'
get 'custom_announcement/settings', to: 'custom_announcements#settings'
get 'custom_announcement/import', to: 'custom_announcements#import'
post 'custom_announcement/createsettings', to: 'custom_announcements#createsettings'
patch 'custom_announcement/updatesettings', to: 'custom_announcements#updatesettings'
post 'custom_announcement/import_from_wp', to: 'custom_announcements#import_from_wp'
post 'custom_announcement/generate_iframe_url' => 'custom_announcements#generate_iframe_url'
resources :custom_announcements do
collection do
get "/:custom_module-:bind_uid" => "custom_announcements#index"
get "/:custom_module-:bind_uid/new" => "custom_announcements#new"
get "/:custom_module-:bind_uid/:id/edit" => "custom_announcements#edit"
delete "/:custom_module-:bind_uid/:id/destroy" => "custom_announcements#destroy"
get '/:custom_module-:bind_uid/:id/comment'=> 'custom_announcements#comment'
get "/:custom_module" => "custom_announcements#index"
get "/:custom_module/new" => "custom_announcements#new"
get "/:custom_module/:id/edit" => "custom_announcements#edit"
delete "/:custom_module/:id/destroy" => "custom_announcements#destroy"
get '/:custom_module/:id/comment'=> 'custom_announcements#comment'
end
end
get 'custom_announcements/:id/comment'=> 'custom_announcements#comment'
get 'annc-comment-hidden/:id' => 'custom_announcements#comment_hidden'
end
resources :custom_announcements do
collection do
get ':slug_title-:uid', to: 'custom_announcements#show', as: :display
end
end
get "/xhr/custom_announcements/feed/:uid" => "custom_announcement_feeds#feed"
get "/xhr/custom_announcements/rssfeed/:uid" => "custom_announcement_feeds#rssfeed"
get "/xhr/custom_announcements/feeds" => "custom_announcement_feeds#feeds"
get '/xhr/custom_announcements/custom_announcement.json', to: 'custom_bulletins#get_custom_bulletins'
get '/xhr/panel/custom_announcement/widget/sync_data' => 'custom_announcements#show_widget'
get '/xhr/custom_announcements/:slug_title-:uid/comment', to: 'custom_announcements#comment'
get '/xhr/custom_announcements/file/:id/*f_name' => 'custom_announcements#get_file'
end
end

View File

@ -0,0 +1,37 @@
# encoding: UTF-8
$:.push File.expand_path("../lib", __FILE__)
# Maintain your gem's version:
require "custom_announcement/version"
require 'json'
bundle_update_flag = ARGV[0]=='update' || ARGV[0]=='install'
if bundle_update_flag
env_pwd = ENV['PWD']
app_path = File.expand_path(__dir__)
template_path = env_pwd + '/app/templates'
all_template = Dir.glob(template_path+'/*/')
all_template.each do |folder|
if !folder.include?('mobile')
if Dir.exist?("#{folder}modules/")
Bundler.with_clean_env{system ('cp -r '+ app_path + '/modules/ ' + folder)}
end
end
end
end
# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
s.name = "custom_announcement"
s.version = CustomAnnouncement::VERSION
s.authors = ["RulingDigital"]
s.email = ["bohung@rulingcom.com"]
s.homepage = "http://www.rulingcom.com"
s.summary = "CustomAnnouncements for Orbit"
s.description = "CustomAnnouncements for Orbit"
s.license = "MIT"
s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"]
s.test_files = Dir["test/**/*"]
s.add_dependency "rufus-scheduler", "~> 3.6.0"
s.add_dependency "mimemagic" , "0.3.9"
end

View File

@ -0,0 +1,4 @@
require "custom_announcement/engine"
module CustomAnnouncement
end

View File

@ -0,0 +1,153 @@
require "yaml"
module CustomAnnouncement
class Engine < ::Rails::Engine
initializer "custom_announcement" do
begin
translate_data = Dir["#{CustomAnnouncement::Engine.root}/config/locales/*.yml"] .map{|yaml_file| YAML.load(File.read(yaml_file))}
data = {}
key1 = {}
key2 = {}
key3 = {}
key4 = {}
key1_attr = []
key2_attr = []
key3_attr = []
key4_attr = []
data_item = {}
key_item1 = {}
key_item2 = {}
key_item3 = {}
value_item1 = {}
value_item2 = {}
value_item3 = {}
value2_item1 = {}
value2_item2 = {}
key1_options = ['small_size','medium_size','orignal_size']
key2_options = ['not_enable_tabs','enable_tabs_with_categories_include_all','enable_tabs_with_categories']
key3_options = ['default','upper_left','lower_left','upper_right','lower_right']
key4_options = ['the_same_as_data_count','display_all_in_other_tabs']
key1_options.each_with_index do |k,i|
key1_attr[i] = {}
end
key2_options.each_with_index do |k,i|
key2_attr[i] = {}
end
key3_options.each_with_index do |k,i|
key3_attr[i] = {}
end
key4_options.each_with_index do |k,i|
key4_attr[i] = {}
end
translate_data.each do |t_data|
v = t_data.values
k = t_data.keys[0]
key1[k] = v[0]['custom_announcement']['picture_showing_size']
key2[k] = v[0]['custom_announcement']['tabs_options']
key3[k] = v[0]['custom_announcement']['read_more_position_options']
key4[k] = v[0]['custom_announcement']['all_tabs_setting']
key1_options.each_with_index do |kk,i|
key1_attr[i][k] = v[0]['custom_announcement'][kk]
end
key2_options.each_with_index do |kk,i|
key2_attr[i][k] = v[0]['custom_announcement'][kk]
end
key3_options.each_with_index do |kk,i|
key3_attr[i][k] = v[0]['custom_announcement'][kk]
end
key4_options.each_with_index do |kk,i|
key4_attr[i][k] = v[0]['custom_announcement'][kk]
end
key_item1[k] = v[0]['custom_announcement']['showing_back_and_next']
key_item2[k] = v[0]['custom_announcement']['enable_search']
value_item1[k] = v[0]['custom_announcement']['not_show']
value_item2[k] = v[0]['custom_announcement']['show_bottom']
value_item3[k] = v[0]['custom_announcement']['show_top']
value2_item1[k] = v[0]['custom_announcement']['no']
value2_item2[k] = v[0]['custom_announcement']['yes']
end
data[key1] = key1_attr
data[key2] = key2_attr
data[key3] = key3_attr
data[key4] = key4_attr
data_item[key_item1] = [value_item1,value_item2,value_item3]
data_item[key_item2] = [value2_item1,value2_item2]
require File.expand_path('../../../app/models/custom_anns_cache', __FILE__)
if defined? CustomAnnsCache
CustomAnnsCache.destroy_all
end
rescue => e
puts ['error in custom_announcement',e]
end
OrbitApp.registration "CustomAnnouncement", :type => "ModuleApp" do
module_label "custom_announcement.custom_announcement"
base_url File.expand_path File.dirname(__FILE__)
widget_methods ["widget","random_custom_announcement_widget", "tag_cloud"]
widget_settings [{"data_count"=>30,"enable_custom_widget_data"=>true}]
taggable "CustomBulletin"
categorizable
authorizable
frontend_enabled
feeds_url "/xhr/custom_announcements/feeds"
data_count 1..30
begin
show_options data
show_option_items data_item
rescue => e
puts ['there_was_no_show_option_method',e]
end
side_bar do
head_label_i18n 'custom_announcement.custom_announcement', icon_class: "icons-megaphone"
available_for "users"
active_for_controllers (['admin/custom_announcements'])
head_link_path "admin_custom_announcements_path"
context_link 'custom_announcement.all_articles',
:link_path=>"admin_custom_announcements_path" ,
:priority=>1,
:active_for_action=>{'admin/custom_announcements'=>'index'},
:available_for => 'users'
# context_link 'new_',
# :link_path=>"new_admin_custom_announcement_path" ,
# :priority=>2,
# :active_for_action=>{'admin/custom_announcements'=>'new'},
# :available_for => 'sub_managers'
context_link 'categories',
:link_path=>"admin_module_app_categories_path" ,
:link_arg=>"{:module_app_id=>ModuleApp.find_by(:key=>'custom_announcement').id}",
:priority=>3,
:active_for_action=>{'admin/custom_announcements'=>'categories'},
:active_for_category => 'CustomAnnouncement',
:available_for => 'managers'
context_link 'tags',
:link_path=>"admin_module_app_tags_path" ,
:link_arg=>"{:module_app_id=>ModuleApp.find_by(:key=>'custom_announcement').id}",
:priority=>4,
:active_for_action=>{'admin/custom_announcements'=>'tags'},
:active_for_tag => 'CustomAnnouncement',
:available_for => 'managers'
context_link 'custom_announcement.feed_list',
:link_path=>"admin_custom_announcement_feed_path" ,
:priority=>5,
:active_for_action=>{'admin/custom_announcements'=>'feed'},
:available_for => 'managers'
context_link 'custom_announcement.import',
:link_path=>"admin_custom_announcement_import_path" ,
:priority=>6,
:active_for_action=>{'admin/custom_announcements'=>'import'},
:available_for => 'managers'
context_link 'custom_announcement.settings',
:link_path=>"admin_custom_announcement_settings_path" ,
:priority=>6,
:active_for_action=>{'admin/custom_announcements'=>'settings'},
:available_for => 'managers'
end
end
# temp = YAML.load_file(File.join(Rails.root,"config","mongoid.yml"))
# dbsettings = temp["production"]["sessions"]["default"]
# s = Moped::Session.new(dbsettings["hosts"])
# s.use dbsettings["database"]
# s[:custom_bulletins].indexes.create({expirable_created_at: 1},{ expireAfterSeconds: 180 })
end
end
end

View File

@ -0,0 +1,3 @@
module CustomAnnouncement
VERSION = "0.0.1"
end

View File

@ -0,0 +1,20 @@
module CustomBulletinModel
module Cache
require 'active_support/concern'
extend ActiveSupport::Concern
included do
before_save :do_before_save
end
def do_before_save
if self.class == SubPart
CustomAnnsCache.where(parent_id:self.id).destroy
elsif self.class == CustomBulletin || (self.class == Page && self.module == "custom_announcement")
if self.class == CustomBulletin
tmp_tag_ids = (Array(self.tag_ids) + Array(self.org_tag_ids)).uniq
CustomBulletinFeedCache.where(:uid.in => CustomBulletinFeed.where(:tag_ids.in => tmp_tag_ids.collect{|v| v.to_s}).pluck(:uid)).destroy
end
CustomAnnsCache.all.destroy
end
end
end
end

View File

@ -0,0 +1,8 @@
desc 'Remove duplicated custom_bulletins (custom_announcements) created by preview'
namespace :custom_bulletin do
task :remove_preview_custom_bulletins => [:environment] do
custom_bulletins = CustomBulletin.where(is_preview: true)
custom_bulletins.destroy_all
end
end

View File

@ -0,0 +1,32 @@
<div class="w-annc widget-announcement-1">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<ul class="w-annc__list" data-level="0" data-list="custom_announcements">
<li class="w-annc__item">
<div class="w-annc__img-wrap bullseye">
<img class="w-annc__img" src="{{img_src}}" alt="{{img_description}}" title="{{img_description}}">
</div>
<div class="w-annc__meta">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label status {{status-class}}">{{status}}</span>
</span>
<span class="w-annc__postdate-wrap" date-format="%Y-%m-%d">
<i class="fa fa-calendar-o"></i>
<span class="w-annc__postdate">{{postdate}}</span>
</span>
<span class="w-annc__category-wrap">
<i class="fa fa-tasks"></i>
<span class="w-annc__category">{{category}}</span>
</span>
</div>
<h4 class="w-annc__entry-title">
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
<p class="w-annc__subtitle">{{subtitle}}</p>
</li>
</ul>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,22 @@
<div class="w-annc widget-announcement-10">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<ul class="w-annc__list" data-level="0" data-list="custom_announcements">
<li class="w-annc__item row">
<h4 class="w-annc__entry-title col-sm-9">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label status {{status-class}}">{{status}}</span>
</span>
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
<span class="w-annc__postdate-wrap col-sm-3" date-format="%Y-%m-%d">
<i class="fa fa-calendar-o"></i>
<span class="w-annc__postdate">{{postdate}}</span>
</span>
</li>
</ul>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,21 @@
<div class="w-annc widget-announcement-11">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<ul class="w-annc__list" data-level="0" data-list="custom_announcements">
<li class="w-annc__item row">
<span class="w-annc__postdate-wrap col-sm-3" date-format="%Y-%m-%d">
<span class="w-annc__postdate">{{postdate}}</span>
</span>
<h4 class="w-annc__entry-title col-sm-9">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label status {{status-class}}">{{status}}</span>
</span>
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
</li>
</ul>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,27 @@
<div class="w-annc widget-announcement-12">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<table class="w-annc__table table">
<thead>
<tr>
<th class="w-annc__th w-annc__th--title">{{title-head}}</th>
<th class="w-annc__th w-annc__th--date">{{date-head}}</th>
</tr>
</thead>
<tbody data-level="0" data-list="custom_announcements">
<tr>
<td class="w-annc_content">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label status {{status-class}}">{{status}}</span>
</span>
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</td>
<td class="w-annc__postdate" date-format="%Y-%m-%d">{{postdate}}</td>
</tr>
</tbody>
</table>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,27 @@
<div class="w-annc widget-announcement-13">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<table class="w-annc__table table">
<thead>
<tr>
<th class="w-annc__th w-annc__th--date">{{date-head}}</th>
<th class="w-annc__th w-annc__th--title">{{title-head}}</th>
</tr>
</thead>
<tbody data-level="0" data-list="custom_announcements">
<tr>
<td class="w-annc__postdate" date-format="%Y-%m-%d">{{postdate}}</td>
<td class="w-annc_content">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label status {{status-class}}">{{status}}</span>
</span>
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</td>
</tr>
</tbody>
</table>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,29 @@
<div class="w-annc widget-announcement-14">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<div class="w-annc__inner row">
<div class="w-annc__img-wrap col-xs-4 bullseye">
<img class="w-annc__img" src="{{main_picture}}" alt="{{main_picture_description}}" title="{{main_picture_description}}">
</div>
<ul class="w-annc__list col-xs-8" data-level="0" data-list="custom_announcements">
<li class="w-annc__item">
<div class="w-annc__content row">
<h4 class="w-annc__entry-title col-xs-9">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label {{status-class}}">{{status}}</span>
</span>
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
<span class="w-annc__postdate-wrap col-xs-3" date-format="%Y-%m-%d">
<i class="fa fa-calendar-o"></i>
<span class="w-annc__postdate">{{postdate}}</span>
</span>
</div>
</li>
</ul>
</div>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,162 @@
<div class="w-annc widget-announcement-4 w-annc widget-announcement-15" style="position:relative;">
<div class="w-annc__more-wrap clearfix">
<h2 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h2>
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
<div style="position: absolute;top: 50%;bottom: 50%;width:100%;">
<button class="btn-left" title = "<%= (I18n.locale.to_s =="zh_tw") ? "上一張" : "prev" %>" style="float: left;height: 2.5em; width: 2.5em;background: url(/assets/left-01.png) no-repeat;border: 0;background-size: contain;position: absolute;transition:.3s; left: 0.6%;"></button>
<button class="btn-right" title = "<%= (I18n.locale.to_s =="zh_tw") ? "下一張" : "next" %>" style="float: right;;height: 2.5em; width: 2.5em;background: url(/assets/right-01.png) no-repeat;background-size: contain;border: 0;position: absolute;transition:.3s;right: 0.6%;"></button>
</div>
<ul class="w-annc__list row" data-level="0" data-list="custom_announcements">
<li class="w-annc__item col-md-4">
<div class="w-annc__img-wrap bullseye">
<img class="w-annc__img" src="{{img_src}}" alt="{{img_description}}" title="{{img_description}}">
</div>
<div class="w-annc__content-wrap">
<div class="w-annc__meta">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label {{status-class}}">{{status}}</span>
</span>
<span class="w-annc__postdate-wrap" date-format="%Y-%m-%d">
<i class="fa fa-calendar-o"></i>
<span class="w-annc__postdate">{{postdate}}</span>
</span>
<span class="w-annc__category-wrap">
<i class="fa fa-tasks"></i>
<span class="w-annc__category">{{category}}</span>
</span>
</div>
<h4 class="w-annc__entry-title">
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
<p class="w-annc__subtitle">{{subtitle}}</p>
</div>
</li>
</ul>
</div>
<script src="//code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
function combineul(){
var parents = $('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list').parent();
parents.each(function(i,v){
for(var i=1;i<$(v).find('ul.w-annc__list').length;i++)
$(v).find('ul.w-annc__list').eq(0).find('>li').eq(-1).after($(v).find('ul.w-annc__list').eq(i).html());
var ullength = $(v).find('ul.w-annc__list').length;
for(var i = 1;i < ullength;i++)
$(v).find('ul.w-annc__list').eq(-1).remove();
})
};
var num;
var lilength = $('[data-subpart-id=\"{{subpart-id}}\"] li.w-annc__item').length;
function reorganize(num){
var uls = $('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list').toArray();
var currentul = uls.findIndex(function(v){
return $(v).hasClass("active") && !$(v).hasClass("hidden_item");
})
if(currentul == -1)
currentul = 0;
var li_active_idx = 0;
if(currentul != 0)
li_active_idx = $(uls[currentul]).find("li.w-annc__item").eq(0).index("li.w-annc__item");
combineul();
var parents = $('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list').parent();
parents.each(function(i,v){
var lilength = $(v).find('li.w-annc__item').length;
var ul_length = Math.ceil(lilength/num);
for(var ii=1;ii< ul_length;ii++){
var clone_ul = $(v).find('ul.w-annc__list').eq(-1).clone();
clone_ul.empty();
clone_ul.removeClass("active");
clone_ul.css("display","");
$(v).find('ul.w-annc__list').eq(-1).after(clone_ul.prop("outerHTML"));
var lihtml="";
if(ii != (ul_length-1)){
for(var j=0;j<num;j++){
lihtml += $(v).find('li.w-annc__item').eq(ii*num+j).prop("outerHTML");
};
}else{
for(var j=0;j< lilength - num *(ul_length-1) ;j++){
lihtml += $(v).find('li.w-annc__item').eq(ii*num+j).prop("outerHTML");
};
};
$(v).find('ul.w-annc__list').eq(-1).html(lihtml);
}
if(ul_length != 1 )
for(var i=0;i< lilength -num ; i++)
$(v).find('ul.w-annc__list').eq(0).find("li.w-annc__item").eq(num).remove();
})
$('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list').css("display","none");
$('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list').css('padding','0 1.125em');
$('[data-subpart-id=\"{{subpart-id}}\"] button').css('z-index','10');
$('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list >li').css('width','calc('+100/num+'% - '+20/16+'em)'); //20px=>li的margin
$('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list >li').css('float','left');
var active_ul = $("[data-subpart-id=\"{{subpart-id}}\"] li.w-annc__item").eq(li_active_idx).parents("ul.w-annc__list");
active_ul.addClass("active");
active_ul.removeClass("hidden_item");
active_ul.css("display","");
};
$(window).resize(function(){
if($(window).width()>1024){
reorganize(3);
num=3;
}else if($(window).width()>576){
reorganize(2);
num=2;
}else{
reorganize(1);
num=1;
}
})
$(document).ready(function(){
if($(window).width()>1024){
reorganize(3);
num=3;
}else if($(window).width()>576){
reorganize(2);
num=2;
}else{
reorganize(1);
num=1;
}
var flag=false;
$('.btn-left').click(function(){
if(!flag){
var uls = $('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list:not(.hidden_item)').toArray();
var ul_length = uls.length;
var currentul = uls.findIndex(function(v){
return $(v).hasClass("active");
})
$('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list').css('display','none');
if(currentul - 1 < 0)
currentul += ul_length;
$('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list:not(.hidden_item)').removeClass("active");
var active_item = $(uls[currentul-1]);
active_item.addClass("active");
active_item.find("li").css("display","block");
flag=true;
$('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list.active').eq(0).effect("slide", { direction: "left", mode: 'show', duration: 500},function(){flag=false;});
};
});
$('.btn-right').click(function(){
var lilength = $('[data-subpart-id=\"{{subpart-id}}\"] li.w-annc__item').length;
if(!flag){
var uls = $('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list:not(.hidden_item)').toArray();
var ul_length = uls.length;
var currentul = uls.findIndex(function(v){
return $(v).hasClass("active");
})
$('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list').css('display','none');
if(currentul + 1 > ul_length - 1)
currentul -= ul_length;
$('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list:not(.hidden_item)').removeClass("active");
var active_item = $(uls[currentul+1]);
active_item.addClass("active");
active_item.find("li").css("display","block");
flag=true;
$('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list.active').eq(0).effect("slide", { direction: "left", mode: 'show', duration: 500},function(){flag=false;});
};
});
});
</script>

View File

@ -0,0 +1,47 @@
<div class="w-annc widget-announcement-16">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<div class="slide-button">
<button class="cycle-prev btn btn-warning"> <i class="fa fa-angle-left"></i></button>
<button class="cycle-next btn btn-warning"> <i class="fa fa-angle-right"></i></button>
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多+" : "More NEWS" %></a>
</div>
<div class="w-annc__wrap cycle-slideshow"
data-level="0"
data-list="custom_announcements"
data-cycle-slides=".w-annc__item"
data-cycle-fx="carousel"
data-cycle-carousel-fluid=true
data-cycle-pause-on-hover="true"
data-cycle-speed="200"
data-cycle-carousel-visible="1"
data-cycle-prev=".cycle-prev"
data-cycle-next=".cycle-next"
data-cycle-swipe=true
data-cycle-swipe-fx="carousel"
>
<div class="w-annc__item">
<div class="w-annc__img-wrap">
<img class="w-annc__img" src="{{img_src}}" alt="{{img_description}}" title="{{img_description}}">
</div>
<div class="w-annc__content-wrap">
<div class="w-annc__meta">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label {{status-class}}">{{status}}</span>
</span>
<span class="w-annc__postdate-wrap" date-format="%Y-%m-%d">
<span class="w-annc__postdate">{{postdate}}</span>
</span>
</div>
<h4 class="w-annc__entry-title">
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,31 @@
<div class="w-annc widget-announcement-17">
<div class="search_block">
<p>Search</p>
<form accept-charset="UTF-8" action="{{more_url}}" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓"></div>
<p>
<input id="search_query" name="keywords" placeholder="搜尋" type="text">
<input type="submit" value="搜尋">
</p>
</form>
</div>
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<ul class="w-annc__list" data-level="0" data-list="custom_announcements">
<li class="w-annc__item row">
<span class="w-annc__postdate-wrap col-sm-3" date-format="%Y-%m-%d">
<i class="fa fa-calendar-o"></i>
<span class="w-annc__postdate">{{postdate}}</span>
</span>
<h4 class="w-annc__entry-title col-sm-9">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label status {{status-class}}">{{status}}</span>
</span>
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
</li>
</ul>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,86 @@
<div class="w-annc widget-announcement-18">
<div class="w-annc__more-wrap clearfix">
<h2 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h2>
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
<ul class="w-annc__list row" data-level="0" data-list="custom_announcements">
<li class="w-annc__item col-md-4">
<div class="w-annc__img-wrap">
<a href="{{link_to_show}}" title="{{title}}">
<img class="w-annc__img" src="{{img_src}}" alt="{{img_description}}" title="{{img_description}}">
</a>
</div>
<div class="w-annc__content-wrap">
<h4 class="w-annc__entry-title">
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
<div class="w-annc__subtitle">{{subtitle}}</div>
<div class="w-annc_read_more"><a href="{{link_to_show}}" title="{{title}}">{{read_more_text}}</a></div>
</div>
</li>
</ul>
</div>
<style type="text/css">
.widget-announcement-18 [data-list="custom_announcements"] li > *{
background: #ffffff;
width: 100%;
float: left;
}
.widget-announcement-18 [data-list="custom_announcements"] .w-annc__img{
width: 100%;
}
.widget-announcement-18 [data-list="custom_announcements"] .w-annc__content-wrap{
padding: 0 1em;
}
.widget-announcement-18 .w-annc__title {
line-height: 1.3;
font-size: 1.2rem;
}
.widget-announcement-18 .w-annc__widget-title {
float: left;
}
.widget-announcement-18 .w-annc__more {
margin-top: 1.5em;
}
.widget-announcement-18 .w-annc__list > .w-annc__item:nth-child(3n+1) {
clear: both;
}
.widget-announcement-18 li.w-annc__item{
float: left;
}
.widget-announcement-18 .w-annc__img-wrap {
padding: 0 0 1em 0;
}
.w-annc_read_more{
display: inline-block;
padding: 1em;
}
.w-annc_read_more a{
float: left;
background: #4a97c2;
color: #ffffff;
padding: 0 0.5em;
border-radius: 0.3em;
border: 0.5em solid #4a97c2;
}
.w-annc__subtitle {
padding-bottom: 0.3em;
}
.w-annc_read_more a:hover{
background: #327397;
border: 0.5em solid #327397;
}
</style>
<script type="text/javascript">
$(document).ready(function(){
$("[data-subpart-id=\"{{subpart-id}}\"] .w-annc__subtitle").each(function(i,v){
var subtitle = $(v).text();
if(subtitle.length > 15){
$(v).text(subtitle.slice(0,15) + "...");
}
})
})
</script>

View File

@ -0,0 +1,34 @@
<div class="w-annc widget-announcement-2">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<ul class="w-annc__list" data-level="0" data-list="custom_announcements">
<li class="w-annc__item row">
<div class="w-annc__img-wrap col-sm-4 bullseye">
<img class="w-annc__img" src="{{img_src}}" alt="{{img_description}}" title="{{img_description}}">
</div>
<div class="w-annc__content-wrap col-sm-8">
<div class="w-annc__meta">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label status {{status-class}}">{{status}}</span>
</span>
<span class="w-annc__postdate-wrap" date-format="%Y-%m-%d">
<i class="fa fa-calendar-o"></i>
<span class="w-annc__postdate">{{postdate}}</span>
</span>
<span class="w-annc__category-wrap">
<i class="fa fa-tasks"></i>
<span class="w-annc__category">{{category}}</span>
</span>
</div>
<h4 class="w-annc__entry-title">
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
<p class="w-annc__subtitle">{{subtitle}}</p>
</div>
</li>
</ul>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,34 @@
<div class="w-annc widget-announcement-3">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<ul class="w-annc__list" data-level="0" data-list="custom_announcements">
<li class="w-annc__item row">
<div class="w-annc__content-wrap col-sm-8">
<div class="w-annc__meta">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label status {{status-class}}">{{status}}</span>
</span>
<span class="w-annc__postdate-wrap" date-format="%Y-%m-%d">
<i class="fa fa-calendar-o"></i>
<span class="w-annc__postdate">{{postdate}}</span>
</span>
<span class="w-annc__category-wrap">
<i class="fa fa-tasks"></i>
<span class="w-annc__category">{{category}}</span>
</span>
</div>
<h4 class="w-annc__entry-title">
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
<p class="w-annc__subtitle">{{subtitle}}</p>
</div>
<div class="w-annc__img-wrap col-sm-4 bullseye">
<img class="w-annc__img" src="{{img_src}}" alt="{{img_description}}" title="{{img_description}}">
</div>
</li>
</ul>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,107 @@
<div class="w-annc widget-announcement-4">
<div class="w-annc__more-wrap clearfix">
<h2 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h2>
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
<ul class="w-annc__list row" data-level="0" data-list="custom_announcements">
<li class="w-annc__item col-md-4">
<div class="w-annc__img-wrap bullseye">
<img class="w-annc__img" src="{{img_src}}" alt="{{img_description}}" title="{{img_description}}">
</div>
<div class="w-annc__content-wrap">
<div class="w-annc__meta">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label {{status-class}}">{{status}}</span>
</span>
<span class="w-annc__postdate-wrap" date-format="%Y-%m-%d">
<i class="fa fa-calendar-o"></i>
<span class="w-annc__postdate">{{postdate}}</span>
</span>
<span class="w-annc__category-wrap">
<i class="fa fa-tasks"></i>
<span class="w-annc__category">{{category}}</span>
</span>
</div>
<h4 class="w-annc__entry-title">
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
<p class="w-annc__subtitle">{{subtitle}}</p>
</div>
</li>
</ul>
</div>
<style type="text/css">
[data-subpart-id="{{subpart-id}}"] .bullseye{
overflow: hidden;
}
</style>
<script>
function combineul(){
var parents = $('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list').parent();
parents.each(function(i,v){
for(var i=1;i<$(v).find('ul.w-annc__list').length;i++)
$(v).find('ul.w-annc__list').eq(0).find('>li').eq(-1).after($(v).find('ul.w-annc__list').eq(i).html());
var ullength = $(v).find('ul.w-annc__list').length;
for(var i = 1;i < ullength;i++)
$(v).find('ul.w-annc__list').eq(-1).remove();
})
};
var num;
var lilength = $('[data-subpart-id=\"{{subpart-id}}\"] li.w-annc__item').length;
function reorganize(num){
combineul();
var parents = $('[data-subpart-id=\"{{subpart-id}}\"] ul.w-annc__list').parent();
parents.each(function(i,v){
var lilength = $(v).find('li.w-annc__item').length;
var ul_length = Math.ceil(lilength/num);
for(var ii=1;ii< ul_length;ii++){
var clone_ul = $(v).find('ul.w-annc__list').eq(-1).clone();
clone_ul.empty();
clone_ul.removeClass("active");
clone_ul.css("display","");
$(v).find('ul.w-annc__list').eq(-1).after(clone_ul.prop("outerHTML"));
var lihtml="";
if(ii != (ul_length-1)){
for(var j=0;j<num;j++){
lihtml += $(v).find('li.w-annc__item').eq(ii*num+j).prop("outerHTML");
};
}else{
for(var j=0;j< lilength - num *(ul_length-1) ;j++){
lihtml += $(v).find('li.w-annc__item').eq(ii*num+j).prop("outerHTML");
};
};
$(v).find('ul.w-annc__list').eq(-1).html(lihtml);
}
if(ul_length != 1 )
for(var i=0;i< lilength -num ; i++)
$(v).find('ul.w-annc__list').eq(0).find("li.w-annc__item").eq(num).remove();
})
$('.widget-announcement-4 ul.w-annc__list >li').css('width','calc('+100/num+'% - '+20/16+'em)'); //20px=>li的margin
};
$(window).resize(function(){
if($(window).width()>1024){
reorganize(3);
num=3;
}else if($(window).width()>576){
reorganize(2);
num=2;
}else{
reorganize(1);
num=1;
}
})
$(document).ready(function(){
if($(window).width()>1024){
reorganize(3);
num=3;
}else if($(window).width()>576){
reorganize(2);
num=2;
}else{
reorganize(1);
num=1;
}
})
</script>

View File

@ -0,0 +1,31 @@
<div class="w-annc widget-announcement-5">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<ul class="w-annc__list row" data-level="0" data-list="custom_announcements">
<li class="w-annc__item">
<div class="w-annc__content-wrap">
<div class="w-annc__meta">
<span class="w-annc__postdate-wrap" date-format="%Y-%m-%d">
<i class="fa fa-calendar-o"></i>
<span class="w-annc__postdate">{{postdate}}</span>
</span>
<span class="w-annc__category-wrap">
<i class="fa fa-tasks"></i>
<span class="w-annc__category">{{category}}</span>
</span>
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label status {{status-class}}">{{status}}</span>
</span>
</div>
<h4 class="w-annc__entry-title">
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
<p class="w-annc__subtitle">{{subtitle}}</p>
</div>
</li>
</ul>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,26 @@
<div class="w-annc widget-announcement-6">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<ul class="w-annc__list" data-level="0" data-list="custom_announcements">
<li class="w-annc__item row">
<span class="w-annc__category-wrap col-sm-2">
<i class="fa fa-tasks"></i>
<span class="w-annc__category">{{category}}</span>
</span>
<h4 class="w-annc__entry-title col-sm-8">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label status {{status-class}}">{{status}}</span>
</span>
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
<span class="w-annc__postdate-wrap col-sm-2" date-format="%Y-%m-%d">
<i class="fa fa-calendar-o"></i>
<span class="w-annc__postdate">{{postdate}}</span>
</span>
</li>
</ul>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,26 @@
<div class="w-annc widget-announcement-7">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<ul class="w-annc__list" data-level="0" data-list="custom_announcements">
<li class="w-annc__item row">
<span class="w-annc__postdate-wrap col-sm-2" date-format="%Y-%m-%d">
<i class="fa fa-calendar-o"></i>
<span class="w-annc__postdate">{{postdate}}</span>
</span>
<h4 class="w-annc__entry-title col-sm-8">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label status {{status-class}}">{{status}}</span>
</span>
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</h4>
<span class="w-annc__category-wrap col-sm-2">
<i class="fa fa-tasks"></i>
<span class="w-annc__category">{{category}}</span>
</span>
</li>
</ul>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,29 @@
<div class="w-annc widget-announcement-8">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<table class="w-annc__table table">
<thead>
<tr>
<th class="w-annc__th w-annc__th--category">{{category-head}}</th>
<th class="w-annc__th w-annc__th--title">{{title-head}}</th>
<th class="w-annc__th w-annc__th--date">{{date-head}}</th>
</tr>
</thead>
<tbody data-level="0" data-list="custom_announcements">
<tr>
<td class="w-annc__category">{{category}}</td>
<td class="w-annc_content">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label status {{status-class}}">{{status}}</span>
</span>
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</td>
<td class="w-annc__postdate" date-format="%Y-%m-%d">{{postdate}}</td>
</tr>
</tbody>
</table>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,29 @@
<div class="w-annc widget-announcement-9">
<h3 class="w-annc__widget-title">
<span>{{widget-title}}</span>
</h3>
<table class="w-annc__table table">
<thead>
<tr>
<th class="w-annc__th w-annc__th--date">{{date-head}}</th>
<th class="w-annc__th w-annc__th--title">{{title-head}}</th>
<th class="w-annc__th w-annc__th--category">{{category-head}}</th>
</tr>
</thead>
<tbody data-level="0" data-list="custom_announcements">
<tr>
<td class="w-annc__postdate" date-format="%Y-%m-%d">{{postdate}}</td>
<td class="w-annc_content">
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
<span class="w-annc__status label status {{status-class}}">{{status}}</span>
</span>
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
</td>
<td class="w-annc__category">{{category}}</td>
</tr>
</tbody>
</table>
<div class="w-annc__more-wrap clearfix">
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多最新消息" : "More NEWS" %></a>
</div>
</div>

View File

@ -0,0 +1,25 @@
<div class="i-annc index-announcement-1 {{display}}">
<h1 class="i-annc__page-title">{{page-title}}</h1>
<table class="i-annc__table table table-striped">
<thead>
<tr>
<th class="i-annc__th i-annc__th--category">{{category-head}}</th>
<th class="i-annc__th i-annc__th--title">{{title-head}}</th>
<th class="i-annc__th i-annc__th--date">{{date-head}}</th>
</tr>
</thead>
<tbody data-level="0" data-list="custom_announcements">
<tr>
<td class="i-annc__category">{{category}}</td>
<td class="i-annc__content">
<span class="i-annc__status-wrap" data-list="statuses" data-level="1">
<span class="i-annc__status label status {{status-class}}">{{status}}</span>
</span>
<a class="i-annc__title" href="{{link_to_show}}">{{title}}</a>
</td>
<td class="i-annc__postdate"><span class="i-annc__postdate-content" date-format="%Y-%m-%d">{{postdate}}</span></td>
</tr>
</tbody>
</table>
</div>
{{pagination_goes_here}}

Some files were not shown because too many files have changed in this diff Show More