diff --git a/app/assets/javascripts/back_end.js b/app/assets/javascripts/back_end.js
index affd9a06a..0b2af80ec 100644
--- a/app/assets/javascripts/back_end.js
+++ b/app/assets/javascripts/back_end.js
@@ -2,4 +2,5 @@
//= require lib/footable-0.1.js
//= require lib/all-list
//= require lib/jquery.fastLiveFilter.js
-//= require lib/checkbox.card.js
\ No newline at end of file
+//= require lib/checkbox.card.js
+//= require lib/jquery.form.js
\ No newline at end of file
diff --git a/app/assets/javascripts/lib/bootstrap-datetimepicker.js b/app/assets/javascripts/lib/bootstrap-datetimepicker.js
index 8bd2ae807..4c5e6c9d0 100644
--- a/app/assets/javascripts/lib/bootstrap-datetimepicker.js
+++ b/app/assets/javascripts/lib/bootstrap-datetimepicker.js
@@ -698,6 +698,7 @@
clear: function(e) {
if (this.isInput) this.$element.val(null);
else this.$element.find('input').val(null);
+ this.notifyChange();
},
showMode: function(dir) {
diff --git a/app/assets/javascripts/lib/datetimepicker/datetimepicker.js b/app/assets/javascripts/lib/datetimepicker/datetimepicker.js
new file mode 100644
index 000000000..83408a24d
--- /dev/null
+++ b/app/assets/javascripts/lib/datetimepicker/datetimepicker.js
@@ -0,0 +1,33 @@
+$(document).ready(function(){
+
+ $('.date_picker').datetimepicker({
+ pickTime: false
+ });
+
+ $('.default_picker').datetimepicker();
+
+ $('.time_picker').datetimepicker({
+ pickDate: false
+ });
+
+ $('.separated_picker div').on("changeDate",function(){
+ if ($(this).hasClass('date_picker'))
+ {
+ if ($(this).find('input').val() && $(this).siblings('div').css('pointer-events'))
+ {
+ $(this).siblings('div').css('pointer-events', '');
+ }
+ else
+ {
+ $(this).siblings('div').find('input').val(null);
+ $(this).siblings('div').css('pointer-events', 'none');
+ }
+ }
+ $(this).siblings('input').val($(this).find('input').val() + ' ' + $(this).siblings('div').find('input').val());
+ });
+
+ // $('.date_picker').on("changeDate",function(){
+ // $(this).find('input').val('');
+ // });
+
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/lib/jquery.form.js b/app/assets/javascripts/lib/jquery.form.js
new file mode 100644
index 000000000..7f11d05c8
--- /dev/null
+++ b/app/assets/javascripts/lib/jquery.form.js
@@ -0,0 +1,980 @@
+/*!
+ * jQuery Form Plugin
+ * version: 2.94 (13-DEC-2011)
+ * @requires jQuery v1.3.2 or later
+ *
+ * Examples and documentation at: http://malsup.com/jquery/form/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+;(function($) {
+
+/*
+ Usage Note:
+ -----------
+ Do not use both ajaxSubmit and ajaxForm on the same form. These
+ functions are intended to be exclusive. Use ajaxSubmit if you want
+ to bind your own submit handler to the form. For example,
+
+ $(document).ready(function() {
+ $('#myForm').bind('submit', function(e) {
+ e.preventDefault(); // <-- important
+ $(this).ajaxSubmit({
+ target: '#output'
+ });
+ });
+ });
+
+ Use ajaxForm when you want the plugin to manage all the event binding
+ for you. For example,
+
+ $(document).ready(function() {
+ $('#myForm').ajaxForm({
+ target: '#output'
+ });
+ });
+
+ When using ajaxForm, the ajaxSubmit function will be invoked for you
+ at the appropriate time.
+*/
+
+/**
+ * ajaxSubmit() provides a mechanism for immediately submitting
+ * an HTML form using AJAX.
+ */
+$.fn.ajaxSubmit = function(options) {
+ // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
+ if (!this.length) {
+ log('ajaxSubmit: skipping submit process - no element selected');
+ return this;
+ }
+
+ var method, action, url, $form = this;
+
+ if (typeof options == 'function') {
+ options = { success: options };
+ }
+
+ method = this.attr('method');
+ action = this.attr('action');
+ url = (typeof action === 'string') ? $.trim(action) : '';
+ url = url || window.location.href || '';
+ if (url) {
+ // clean url (don't include hash vaue)
+ url = (url.match(/^([^#]+)/)||[])[1];
+ }
+
+ options = $.extend(true, {
+ url: url,
+ success: $.ajaxSettings.success,
+ type: method || 'GET',
+ iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
+ }, options);
+
+ // hook for manipulating the form data before it is extracted;
+ // convenient for use with rich editors like tinyMCE or FCKEditor
+ var veto = {};
+ this.trigger('form-pre-serialize', [this, options, veto]);
+ if (veto.veto) {
+ log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
+ return this;
+ }
+
+ // provide opportunity to alter form data before it is serialized
+ if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
+ log('ajaxSubmit: submit aborted via beforeSerialize callback');
+ return this;
+ }
+
+ var traditional = options.traditional;
+ if ( traditional === undefined ) {
+ traditional = $.ajaxSettings.traditional;
+ }
+
+ var qx,n,v,a = this.formToArray(options.semantic);
+ if (options.data) {
+ options.extraData = options.data;
+ qx = $.param(options.data, traditional);
+ }
+
+ // give pre-submit callback an opportunity to abort the submit
+ if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
+ log('ajaxSubmit: submit aborted via beforeSubmit callback');
+ return this;
+ }
+
+ // fire vetoable 'validate' event
+ this.trigger('form-submit-validate', [a, this, options, veto]);
+ if (veto.veto) {
+ log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
+ return this;
+ }
+
+ var q = $.param(a, traditional);
+ if (qx) {
+ q = ( q ? (q + '&' + qx) : qx );
+ }
+ if (options.type.toUpperCase() == 'GET') {
+ options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
+ options.data = null; // data is null for 'get'
+ }
+ else {
+ options.data = q; // data is the query string for 'post'
+ }
+
+ var callbacks = [];
+ if (options.resetForm) {
+ callbacks.push(function() { $form.resetForm(); });
+ }
+ if (options.clearForm) {
+ callbacks.push(function() { $form.clearForm(options.includeHidden); });
+ }
+
+ // perform a load on the target only if dataType is not provided
+ if (!options.dataType && options.target) {
+ var oldSuccess = options.success || function(){};
+ callbacks.push(function(data) {
+ var fn = options.replaceTarget ? 'replaceWith' : 'html';
+ $(options.target)[fn](data).each(oldSuccess, arguments);
+ });
+ }
+ else if (options.success) {
+ callbacks.push(options.success);
+ }
+
+ options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
+ var context = options.context || options; // jQuery 1.4+ supports scope context
+ for (var i=0, max=callbacks.length; i < max; i++) {
+ callbacks[i].apply(context, [data, status, xhr || $form, $form]);
+ }
+ };
+
+ // are there files to upload?
+ var fileInputs = $('input:file:enabled[value]', this); // [value] (issue #113)
+ var hasFileInputs = fileInputs.length > 0;
+ var mp = 'multipart/form-data';
+ var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
+
+ var fileAPI = !!(hasFileInputs && fileInputs.get(0).files && window.FormData);
+ log("fileAPI :" + fileAPI);
+ var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
+
+ // options.iframe allows user to force iframe mode
+ // 06-NOV-09: now defaulting to iframe mode if file input is detected
+ if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
+ // hack to fix Safari hang (thanks to Tim Molendijk for this)
+ // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
+ if (options.closeKeepAlive) {
+ $.get(options.closeKeepAlive, function() {
+ fileUploadIframe(a);
+ });
+ }
+ else {
+ fileUploadIframe(a);
+ }
+ }
+ else if ((hasFileInputs || multipart) && fileAPI) {
+ options.progress = options.progress || $.noop;
+ fileUploadXhr(a);
+ }
+ else {
+ $.ajax(options);
+ }
+
+ // fire 'notify' event
+ this.trigger('form-submit-notify', [this, options]);
+ return this;
+
+ // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
+ function fileUploadXhr(a) {
+ var formdata = new FormData();
+
+ for (var i=0; i < a.length; i++) {
+ if (a[i].type == 'file')
+ continue;
+ formdata.append(a[i].name, a[i].value);
+ }
+
+ $form.find('input:file:enabled').each(function(){
+ var name = $(this).attr('name'), files = this.files;
+ if (name) {
+ for (var i=0; i < files.length; i++)
+ formdata.append(name, files[i]);
+ }
+ });
+
+ if (options.extraData) {
+ for (var k in options.extraData)
+ formdata.append(k, options.extraData[k])
+ }
+
+ options.data = null;
+
+ var s = $.extend(true, {}, $.ajaxSettings, options, {
+ contentType: false,
+ processData: false,
+ cache: false,
+ type: 'POST'
+ });
+
+ s.context = s.context || s;
+
+ s.data = null;
+ var beforeSend = s.beforeSend;
+ s.beforeSend = function(xhr, o) {
+ o.data = formdata;
+ if(xhr.upload) { // unfortunately, jQuery doesn't expose this prop (http://bugs.jquery.com/ticket/10190)
+ xhr.upload.onprogress = function(event) {
+ o.progress(event.position, event.total);
+ };
+ }
+ if(beforeSend)
+ beforeSend.call(o, xhr, options);
+ };
+ $.ajax(s);
+ }
+
+ // private function for handling file uploads (hat tip to YAHOO!)
+ function fileUploadIframe(a) {
+ var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
+ var useProp = !!$.fn.prop;
+
+ if (a) {
+ if ( useProp ) {
+ // ensure that every serialized input is still enabled
+ for (i=0; i < a.length; i++) {
+ el = $(form[a[i].name]);
+ el.prop('disabled', false);
+ }
+ } else {
+ for (i=0; i < a.length; i++) {
+ el = $(form[a[i].name]);
+ el.removeAttr('disabled');
+ }
+ };
+ }
+
+ if ($(':input[name=submit],:input[id=submit]', form).length) {
+ // if there is an input with a name or id of 'submit' then we won't be
+ // able to invoke the submit fn on the form (at least not x-browser)
+ alert('Error: Form elements must not have name or id of "submit".');
+ return;
+ }
+
+ s = $.extend(true, {}, $.ajaxSettings, options);
+ s.context = s.context || s;
+ id = 'jqFormIO' + (new Date().getTime());
+ if (s.iframeTarget) {
+ $io = $(s.iframeTarget);
+ n = $io.attr('name');
+ if (n == null)
+ $io.attr('name', id);
+ else
+ id = n;
+ }
+ else {
+ $io = $('');
+ $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
+ }
+ io = $io[0];
+
+
+ xhr = { // mock object
+ aborted: 0,
+ responseText: null,
+ responseXML: null,
+ status: 0,
+ statusText: 'n/a',
+ getAllResponseHeaders: function() {},
+ getResponseHeader: function() {},
+ setRequestHeader: function() {},
+ abort: function(status) {
+ var e = (status === 'timeout' ? 'timeout' : 'aborted');
+ log('aborting upload... ' + e);
+ this.aborted = 1;
+ $io.attr('src', s.iframeSrc); // abort op in progress
+ xhr.error = e;
+ s.error && s.error.call(s.context, xhr, e, status);
+ g && $.event.trigger("ajaxError", [xhr, s, e]);
+ s.complete && s.complete.call(s.context, xhr, e);
+ }
+ };
+
+ g = s.global;
+ // trigger ajax global events so that activity/block indicators work like normal
+ if (g && ! $.active++) {
+ $.event.trigger("ajaxStart");
+ }
+ if (g) {
+ $.event.trigger("ajaxSend", [xhr, s]);
+ }
+
+ if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
+ if (s.global) {
+ $.active--;
+ }
+ return;
+ }
+ if (xhr.aborted) {
+ return;
+ }
+
+ // add submitting element to data if we know it
+ sub = form.clk;
+ if (sub) {
+ n = sub.name;
+ if (n && !sub.disabled) {
+ s.extraData = s.extraData || {};
+ s.extraData[n] = sub.value;
+ if (sub.type == "image") {
+ s.extraData[n+'.x'] = form.clk_x;
+ s.extraData[n+'.y'] = form.clk_y;
+ }
+ }
+ }
+
+ var CLIENT_TIMEOUT_ABORT = 1;
+ var SERVER_ABORT = 2;
+
+ function getDoc(frame) {
+ var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;
+ return doc;
+ }
+
+ // Rails CSRF hack (thanks to Yvan Barthelemy)
+ var csrf_token = $('meta[name=csrf-token]').attr('content');
+ var csrf_param = $('meta[name=csrf-param]').attr('content');
+ if (csrf_param && csrf_token) {
+ s.extraData = s.extraData || {};
+ s.extraData[csrf_param] = csrf_token;
+ }
+
+ // take a breath so that pending repaints get some cpu time before the upload starts
+ function doSubmit() {
+ // make sure form attrs are set
+ var t = $form.attr('target'), a = $form.attr('action');
+
+ // update form attrs in IE friendly way
+ form.setAttribute('target',id);
+ if (!method) {
+ form.setAttribute('method', 'POST');
+ }
+ if (a != s.url) {
+ form.setAttribute('action', s.url);
+ }
+
+ // ie borks in some cases when setting encoding
+ if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
+ $form.attr({
+ encoding: 'multipart/form-data',
+ enctype: 'multipart/form-data'
+ });
+ }
+
+ // support timout
+ if (s.timeout) {
+ timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
+ }
+
+ // look for server aborts
+ function checkState() {
+ try {
+ var state = getDoc(io).readyState;
+ log('state = ' + state);
+ if (state.toLowerCase() == 'uninitialized')
+ setTimeout(checkState,50);
+ }
+ catch(e) {
+ log('Server abort: ' , e, ' (', e.name, ')');
+ cb(SERVER_ABORT);
+ timeoutHandle && clearTimeout(timeoutHandle);
+ timeoutHandle = undefined;
+ }
+ }
+
+ // add "extra" data to form if provided in options
+ var extraInputs = [];
+ try {
+ if (s.extraData) {
+ for (var n in s.extraData) {
+ extraInputs.push(
+ $(' ').attr('value',s.extraData[n])
+ .appendTo(form)[0]);
+ }
+ }
+
+ if (!s.iframeTarget) {
+ // add iframe to doc and submit the form
+ $io.appendTo('body');
+ io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
+ }
+ setTimeout(checkState,15);
+ form.submit();
+ }
+ finally {
+ // reset attrs and remove "extra" input elements
+ form.setAttribute('action',a);
+ if(t) {
+ form.setAttribute('target', t);
+ } else {
+ $form.removeAttr('target');
+ }
+ $(extraInputs).remove();
+ }
+ }
+
+ if (s.forceSync) {
+ doSubmit();
+ }
+ else {
+ setTimeout(doSubmit, 10); // this lets dom updates render
+ }
+
+ var data, doc, domCheckCount = 50, callbackProcessed;
+
+ function cb(e) {
+ if (xhr.aborted || callbackProcessed) {
+ return;
+ }
+ try {
+ doc = getDoc(io);
+ }
+ catch(ex) {
+ log('cannot access response document: ', ex);
+ e = SERVER_ABORT;
+ }
+ if (e === CLIENT_TIMEOUT_ABORT && xhr) {
+ xhr.abort('timeout');
+ return;
+ }
+ else if (e == SERVER_ABORT && xhr) {
+ xhr.abort('server abort');
+ return;
+ }
+
+ if (!doc || doc.location.href == s.iframeSrc) {
+ // response not received yet
+ if (!timedOut)
+ return;
+ }
+ io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
+
+ var status = 'success', errMsg;
+ try {
+ if (timedOut) {
+ throw 'timeout';
+ }
+
+ var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
+ log('isXml='+isXml);
+ if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
+ if (--domCheckCount) {
+ // in some browsers (Opera) the iframe DOM is not always traversable when
+ // the onload callback fires, so we loop a bit to accommodate
+ log('requeing onLoad callback, DOM not available');
+ setTimeout(cb, 250);
+ return;
+ }
+ // let this fall through because server response could be an empty document
+ //log('Could not access iframe DOM after mutiple tries.');
+ //throw 'DOMException: not available';
+ }
+
+ //log('response detected');
+ var docRoot = doc.body ? doc.body : doc.documentElement;
+ xhr.responseText = docRoot ? docRoot.innerHTML : null;
+ xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
+ if (isXml)
+ s.dataType = 'xml';
+ xhr.getResponseHeader = function(header){
+ var headers = {'content-type': s.dataType};
+ return headers[header];
+ };
+ // support for XHR 'status' & 'statusText' emulation :
+ if (docRoot) {
+ xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
+ xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
+ }
+
+ var dt = (s.dataType || '').toLowerCase();
+ var scr = /(json|script|text)/.test(dt);
+ if (scr || s.textarea) {
+ // see if user embedded response in textarea
+ var ta = doc.getElementsByTagName('textarea')[0];
+ if (ta) {
+ xhr.responseText = ta.value;
+ // support for XHR 'status' & 'statusText' emulation :
+ xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
+ xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
+ }
+ else if (scr) {
+ // account for browsers injecting pre around json response
+ var pre = doc.getElementsByTagName('pre')[0];
+ var b = doc.getElementsByTagName('body')[0];
+ if (pre) {
+ xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
+ }
+ else if (b) {
+ xhr.responseText = b.textContent ? b.textContent : b.innerText;
+ }
+ }
+ }
+ else if (dt == 'xml' && !xhr.responseXML && xhr.responseText != null) {
+ xhr.responseXML = toXml(xhr.responseText);
+ }
+
+ try {
+ data = httpData(xhr, dt, s);
+ }
+ catch (e) {
+ status = 'parsererror';
+ xhr.error = errMsg = (e || status);
+ }
+ }
+ catch (e) {
+ log('error caught: ',e);
+ status = 'error';
+ xhr.error = errMsg = (e || status);
+ }
+
+ if (xhr.aborted) {
+ log('upload aborted');
+ status = null;
+ }
+
+ if (xhr.status) { // we've set xhr.status
+ status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
+ }
+
+ // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
+ if (status === 'success') {
+ s.success && s.success.call(s.context, data, 'success', xhr);
+ g && $.event.trigger("ajaxSuccess", [xhr, s]);
+ }
+ else if (status) {
+ if (errMsg == undefined)
+ errMsg = xhr.statusText;
+ s.error && s.error.call(s.context, xhr, status, errMsg);
+ g && $.event.trigger("ajaxError", [xhr, s, errMsg]);
+ }
+
+ g && $.event.trigger("ajaxComplete", [xhr, s]);
+
+ if (g && ! --$.active) {
+ $.event.trigger("ajaxStop");
+ }
+
+ s.complete && s.complete.call(s.context, xhr, status);
+
+ callbackProcessed = true;
+ if (s.timeout)
+ clearTimeout(timeoutHandle);
+
+ // clean up
+ setTimeout(function() {
+ if (!s.iframeTarget)
+ $io.remove();
+ xhr.responseXML = null;
+ }, 100);
+ }
+
+ var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
+ if (window.ActiveXObject) {
+ doc = new ActiveXObject('Microsoft.XMLDOM');
+ doc.async = 'false';
+ doc.loadXML(s);
+ }
+ else {
+ doc = (new DOMParser()).parseFromString(s, 'text/xml');
+ }
+ return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
+ };
+ var parseJSON = $.parseJSON || function(s) {
+ return window['eval']('(' + s + ')');
+ };
+
+ var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
+
+ var ct = xhr.getResponseHeader('content-type') || '',
+ xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
+ data = xml ? xhr.responseXML : xhr.responseText;
+
+ if (xml && data.documentElement.nodeName === 'parsererror') {
+ $.error && $.error('parsererror');
+ }
+ if (s && s.dataFilter) {
+ data = s.dataFilter(data, type);
+ }
+ if (typeof data === 'string') {
+ if (type === 'json' || !type && ct.indexOf('json') >= 0) {
+ data = parseJSON(data);
+ } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
+ $.globalEval(data);
+ }
+ }
+ return data;
+ };
+ }
+};
+
+/**
+ * ajaxForm() provides a mechanism for fully automating form submission.
+ *
+ * The advantages of using this method instead of ajaxSubmit() are:
+ *
+ * 1: This method will include coordinates for elements (if the element
+ * is used to submit the form).
+ * 2. This method will include the submit element's name/value data (for the element that was
+ * used to submit the form).
+ * 3. This method binds the submit() method to the form for you.
+ *
+ * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
+ * passes the options argument along after properly binding events for submit elements and
+ * the form itself.
+ */
+$.fn.ajaxForm = function(options) {
+ // in jQuery 1.3+ we can fix mistakes with the ready state
+ if (this.length === 0) {
+ var o = { s: this.selector, c: this.context };
+ if (!$.isReady && o.s) {
+ log('DOM not ready, queuing ajaxForm');
+ $(function() {
+ $(o.s,o.c).ajaxForm(options);
+ });
+ return this;
+ }
+ // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
+ log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
+ return this;
+ }
+
+ return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
+ if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
+ e.preventDefault();
+ $(this).ajaxSubmit(options);
+ }
+ }).bind('click.form-plugin', function(e) {
+ var target = e.target;
+ var $el = $(target);
+ if (!($el.is(":submit,input:image"))) {
+ // is this a child element of the submit el? (ex: a span within a button)
+ var t = $el.closest(':submit');
+ if (t.length == 0) {
+ return;
+ }
+ target = t[0];
+ }
+ var form = this;
+ form.clk = target;
+ if (target.type == 'image') {
+ if (e.offsetX != undefined) {
+ form.clk_x = e.offsetX;
+ form.clk_y = e.offsetY;
+ } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
+ var offset = $el.offset();
+ form.clk_x = e.pageX - offset.left;
+ form.clk_y = e.pageY - offset.top;
+ } else {
+ form.clk_x = e.pageX - target.offsetLeft;
+ form.clk_y = e.pageY - target.offsetTop;
+ }
+ }
+ // clear form vars
+ setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
+ });
+};
+
+// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
+$.fn.ajaxFormUnbind = function() {
+ return this.unbind('submit.form-plugin click.form-plugin');
+};
+
+/**
+ * formToArray() gathers form element data into an array of objects that can
+ * be passed to any of the following ajax functions: $.get, $.post, or load.
+ * Each object in the array has both a 'name' and 'value' property. An example of
+ * an array for a simple login form might be:
+ *
+ * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
+ *
+ * It is this array that is passed to pre-submit callback functions provided to the
+ * ajaxSubmit() and ajaxForm() methods.
+ */
+$.fn.formToArray = function(semantic) {
+ var a = [];
+ if (this.length === 0) {
+ return a;
+ }
+
+ var form = this[0];
+ var els = semantic ? form.getElementsByTagName('*') : form.elements;
+ if (!els) {
+ return a;
+ }
+
+ var i,j,n,v,el,max,jmax;
+ for(i=0, max=els.length; i < max; i++) {
+ el = els[i];
+ n = el.name;
+ if (!n) {
+ continue;
+ }
+
+ if (semantic && form.clk && el.type == "image") {
+ // handle image inputs on the fly when semantic == true
+ if(!el.disabled && form.clk == el) {
+ a.push({name: n, value: $(el).val(), type: el.type });
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+ }
+ continue;
+ }
+
+ v = $.fieldValue(el, true);
+ if (v && v.constructor == Array) {
+ for(j=0, jmax=v.length; j < jmax; j++) {
+ a.push({name: n, value: v[j]});
+ }
+ }
+ else if (v !== null && typeof v != 'undefined') {
+ a.push({name: n, value: v, type: el.type});
+ }
+ }
+
+ if (!semantic && form.clk) {
+ // input type=='image' are not found in elements array! handle it here
+ var $input = $(form.clk), input = $input[0];
+ n = input.name;
+ if (n && !input.disabled && input.type == 'image') {
+ a.push({name: n, value: $input.val()});
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+ }
+ }
+ return a;
+};
+
+/**
+ * Serializes form data into a 'submittable' string. This method will return a string
+ * in the format: name1=value1&name2=value2
+ */
+$.fn.formSerialize = function(semantic) {
+ //hand off to jQuery.param for proper encoding
+ return $.param(this.formToArray(semantic));
+};
+
+/**
+ * Serializes all field elements in the jQuery object into a query string.
+ * This method will return a string in the format: name1=value1&name2=value2
+ */
+$.fn.fieldSerialize = function(successful) {
+ var a = [];
+ this.each(function() {
+ var n = this.name;
+ if (!n) {
+ return;
+ }
+ var v = $.fieldValue(this, successful);
+ if (v && v.constructor == Array) {
+ for (var i=0,max=v.length; i < max; i++) {
+ a.push({name: n, value: v[i]});
+ }
+ }
+ else if (v !== null && typeof v != 'undefined') {
+ a.push({name: this.name, value: v});
+ }
+ });
+ //hand off to jQuery.param for proper encoding
+ return $.param(a);
+};
+
+/**
+ * Returns the value(s) of the element in the matched set. For example, consider the following form:
+ *
+ *
+ *
+ * var v = $(':text').fieldValue();
+ * // if no values are entered into the text inputs
+ * v == ['','']
+ * // if values entered into the text inputs are 'foo' and 'bar'
+ * v == ['foo','bar']
+ *
+ * var v = $(':checkbox').fieldValue();
+ * // if neither checkbox is checked
+ * v === undefined
+ * // if both checkboxes are checked
+ * v == ['B1', 'B2']
+ *
+ * var v = $(':radio').fieldValue();
+ * // if neither radio is checked
+ * v === undefined
+ * // if first radio is checked
+ * v == ['C1']
+ *
+ * The successful argument controls whether or not the field element must be 'successful'
+ * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
+ * The default value of the successful argument is true. If this value is false the value(s)
+ * for each element is returned.
+ *
+ * Note: This method *always* returns an array. If no valid value can be determined the
+ * array will be empty, otherwise it will contain one or more values.
+ */
+$.fn.fieldValue = function(successful) {
+ for (var val=[], i=0, max=this.length; i < max; i++) {
+ var el = this[i];
+ var v = $.fieldValue(el, successful);
+ if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
+ continue;
+ }
+ v.constructor == Array ? $.merge(val, v) : val.push(v);
+ }
+ return val;
+};
+
+/**
+ * Returns the value of the field element.
+ */
+$.fieldValue = function(el, successful) {
+ var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
+ if (successful === undefined) {
+ successful = true;
+ }
+
+ if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
+ (t == 'checkbox' || t == 'radio') && !el.checked ||
+ (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
+ tag == 'select' && el.selectedIndex == -1)) {
+ return null;
+ }
+
+ if (tag == 'select') {
+ var index = el.selectedIndex;
+ if (index < 0) {
+ return null;
+ }
+ var a = [], ops = el.options;
+ var one = (t == 'select-one');
+ var max = (one ? index+1 : ops.length);
+ for(var i=(one ? index : 0); i < max; i++) {
+ var op = ops[i];
+ if (op.selected) {
+ var v = op.value;
+ if (!v) { // extra pain for IE...
+ v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
+ }
+ if (one) {
+ return v;
+ }
+ a.push(v);
+ }
+ }
+ return a;
+ }
+ return $(el).val();
+};
+
+/**
+ * Clears the form data. Takes the following actions on the form's input fields:
+ * - input text fields will have their 'value' property set to the empty string
+ * - select elements will have their 'selectedIndex' property set to -1
+ * - checkbox and radio inputs will have their 'checked' property set to false
+ * - inputs of type submit, button, reset, and hidden will *not* be effected
+ * - button elements will *not* be effected
+ */
+$.fn.clearForm = function(includeHidden) {
+ return this.each(function() {
+ $('input,select,textarea', this).clearFields(includeHidden);
+ });
+};
+
+/**
+ * Clears the selected form elements.
+ */
+$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
+ var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
+ return this.each(function() {
+ var t = this.type, tag = this.tagName.toLowerCase();
+ if (re.test(t) || tag == 'textarea' || (includeHidden && /hidden/.test(t)) ) {
+ this.value = '';
+ }
+ else if (t == 'checkbox' || t == 'radio') {
+ this.checked = false;
+ }
+ else if (tag == 'select') {
+ this.selectedIndex = -1;
+ }
+ });
+};
+
+/**
+ * Resets the form data. Causes all form elements to be reset to their original value.
+ */
+$.fn.resetForm = function() {
+ return this.each(function() {
+ // guard against an input with the name of 'reset'
+ // note that IE reports the reset function as an 'object'
+ if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
+ this.reset();
+ }
+ });
+};
+
+/**
+ * Enables or disables any matching elements.
+ */
+$.fn.enable = function(b) {
+ if (b === undefined) {
+ b = true;
+ }
+ return this.each(function() {
+ this.disabled = !b;
+ });
+};
+
+/**
+ * Checks/unchecks any matching checkboxes or radio buttons and
+ * selects/deselects and matching option elements.
+ */
+$.fn.selected = function(select) {
+ if (select === undefined) {
+ select = true;
+ }
+ return this.each(function() {
+ var t = this.type;
+ if (t == 'checkbox' || t == 'radio') {
+ this.checked = select;
+ }
+ else if (this.tagName.toLowerCase() == 'option') {
+ var $sel = $(this).parent('select');
+ if (select && $sel[0] && $sel[0].type == 'select-one') {
+ // deselect all other options
+ $sel.find('option').selected(false);
+ }
+ this.selected = select;
+ }
+ });
+};
+
+// expose debug var
+$.fn.ajaxSubmit.debug = false;
+
+// helper fn for console logging
+function log() {
+ if (!$.fn.ajaxSubmit.debug)
+ return;
+ var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
+ if (window.console && window.console.log) {
+ window.console.log(msg);
+ }
+ else if (window.opera && window.opera.postError) {
+ window.opera.postError(msg);
+ }
+};
+
+})(jQuery);
diff --git a/app/assets/javascripts/lib/modal-preview.js b/app/assets/javascripts/lib/modal-preview.js
new file mode 100644
index 000000000..475e56393
--- /dev/null
+++ b/app/assets/javascripts/lib/modal-preview.js
@@ -0,0 +1,72 @@
+//Preview need a link in form as Ex and a corresponding PUT action in controller
+//Ex preview trigger:
+// <%= link_to "NewPreview", realtime_preview_admin_ad_banner_path(ad_banner_tab) , :class=>'preview_trigger'%>
+
+$(document).ready(function() {
+ // $(".post_preview").click(function(e){
+ // $("#main-wrap").after(" ");
+ // e.preventDefault();
+ // var form = $(this).parents("form").first()
+ // //var cont = form["content"].value;
+ // // $.ajax({
+ // // type: 'POST',
+ // // url: $(this).attr("href")+'?preview=true',
+ // // data: form.serialize(),
+ // // dataType: "script",
+ // // success: function (msg) {
+ // // $("#"+start_modal_with_id).modal('show'); },
+ // // error: function(){
+ // // alert("ERROR");
+ // // }
+ // // });
+ // url = "/panel/news/back_end/news_bulletins/preview?preview=true"
+ // // alert(url)
+ // form.attr("action",url);
+ // form.submit();
+ // //return false;
+ // });
+ $("button.post_preview").click(function(){
+ var btn = document.getElementById("button_for_preview");
+ var attrs = btn.attributes;
+ var url = attrs['url'];
+ // url = url.replace("url=","");
+ $("form.previewable").ajaxSubmit({
+ beforeSubmit: function(a,f,o){
+ $("#main-wrap").after(" ");
+ o.dataType = 'script';
+ o.url = url.nodeValue;
+ o.type = 'post';
+ },success: function(msg) { }
+
+ });
+ })
+ // $("form.nccu_ajax_form").ajaxForm({
+ // beforeSubmit: function(a,f,o) {
+ // // if(clicked_what.hasClass("post_preview")){
+ // // $("#main-wrap").after(" ");
+ // // o.dataType = 'script';
+ // // o.url = clicked_what.attr("url");
+ // // }
+ // },
+ // success: function(data) {
+ // // if(!clicked_what.hasClass("post_preview")){
+ // // window.location = data.redirect_url;
+ // // }
+ // }
+ // })
+
+ $("a.preview_trigger").on('click',function(){
+ $("#main-wrap").after(" ");
+ $.ajax({
+ type: 'PUT',
+ url:$(this).attr("href"),
+ data:$(this).parents("form").serialize(),
+ success: function (msg) {
+ $("#"+start_modal_with_id).modal('show'); },
+ error: function(){
+ alert("ERROR");
+ }
+ });
+ return false;
+ });
+});
\ No newline at end of file
diff --git a/app/controllers/admin/tags_controller.rb b/app/controllers/admin/tags_controller.rb
index 817a9726b..c28470c92 100644
--- a/app/controllers/admin/tags_controller.rb
+++ b/app/controllers/admin/tags_controller.rb
@@ -40,7 +40,7 @@ class Admin::TagsController < OrbitBackendController
if @tag.update_attributes(params[:module_tag])
redirect_to action: :index
else
- flash.now[:error] = t('update.error.link')
+ flash.now[:error] = t('update.error.tag')
render :action => "edit"
end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index db7d88a31..2db288d03 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -142,6 +142,8 @@ class ApplicationController < ActionController::Base
end
session[:locale] = condition ? (browser_locale || session[:locale]) : I18n.default_locale.to_s
I18n.locale = session[:locale].to_sym
+ @site_in_use_locales = site_locales_default_head(@site.in_use_locales)
+ @site_valid_locales = site_locales_default_head(@site.valid_locales)
end
# Set the site variables
@@ -149,8 +151,6 @@ class ApplicationController < ActionController::Base
# set site if exist or create site
@site = Site.first || Site.create({:valid_locales => [], :in_use_locales => []})
session[:site] = @site.id
- @site_in_use_locales = site_locales_default_head(@site.in_use_locales)
- @site_valid_locales = site_locales_default_head(@site.valid_locales)
end
def set_current_item
diff --git a/app/controllers/orbit_backend_controller.rb b/app/controllers/orbit_backend_controller.rb
index 699425288..7eeb7eb24 100644
--- a/app/controllers/orbit_backend_controller.rb
+++ b/app/controllers/orbit_backend_controller.rb
@@ -4,6 +4,8 @@ class OrbitBackendController < ApplicationController
include OrbitTag::Tagging
include AdminHelper
include ApplicationHelper
+
+ helper :default_index
layout "back_end"
@@ -163,7 +165,7 @@ class OrbitBackendController < ApplicationController
def get_viewable(object_class, query=nil)
objects = get_objects(object_class,query).order_by(:created_at, :desc)
- Kaminari.paginate_array(objects).page(params[:page]).per(10)
+ Kaminari.paginate_array(objects).page(params[:page]).per(5)
end
def get_objects(object_class, query=nil)
diff --git a/app/helpers/default_index_helper.rb b/app/helpers/default_index_helper.rb
new file mode 100644
index 000000000..c552e91c5
--- /dev/null
+++ b/app/helpers/default_index_helper.rb
@@ -0,0 +1,11 @@
+module DefaultIndexHelper
+
+ def show_title_at_index(object)
+ if object.class.instance_methods.include?(:is_checked?) && object.bulletin.is_checked?
+ link_to bulletin.title, panel_announcement_front_end_bulletin_path(bulletin, :category_id => bulletin.bulletin_category.id) rescue ''
+ else
+ bulletin.title
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/app/helpers/orbit_backend_helper.rb b/app/helpers/orbit_backend_helper.rb
index c1894ac2f..d5f0578eb 100644
--- a/app/helpers/orbit_backend_helper.rb
+++ b/app/helpers/orbit_backend_helper.rb
@@ -1,51 +1,289 @@
module OrbitBackendHelper
- def sortable(column)
- direction = (column == params[:sort] && params[:direction] == "asc") ? "desc" : "asc"
- {:sort => column, :direction => direction}
+#========================================================================================================================
+# from bulletin_helper.rb
+#========================================================================================================================
+
+ def show_reject_reason(object)
+ by_object = object.is_rejected
+ by_user = (((object.create_user_id == current_user.id) rescue nil) or is_manager? or is_admin?)
+ by_object && by_user
end
- def is_sort_active?(name)
- res = ''
- res << ' select' if params[:sort].eql?(name)
- res << ' active' if params[:sort].eql?(name) && params[:direction].eql?('asc')
- res
+ def show_form_status_field(object)
+ #by_object = (!object.is_expired? and object.is_pending?)
+ by_user = ((object.send(@category_field).authed_users('fact_check').include?(current_user) rescue nil) or is_manager? or is_admin?)
+ by_user
end
- def is_sort?(name)
- ' web-symbol' if params[:sort].eql?(name)
+ def show_approval_link(object)
+ by_object = (!object.is_expired? and object.is_pending?)
+ by_user = ((object.send(@category_field).authed_users('fact_check').include?(current_user) rescue nil) or is_manager? or is_admin?)
+ by_object and by_user
end
+ def show_delete_link(object)
+ if !current_user.nil?
+ by_object = (object.create_user_id == current_user.id )
+ by_user = (is_manager? or is_admin?)
+ by_object or by_user
+ else
+ false
+ end
+
+ end
+
+ # def show_bulletin_title_at_index (bulletin)
+ # if bulletin.is_checked?
+ # link_to bulletin.title, panel_announcement_front_end_bulletin_path(bulletin, :category_id => bulletin.bulletin_category.id) rescue ''
+ # else
+ # bulletin.title
+ # end
+ # end
+
+#========================================================================================================================
+#========================================================================================================================
+#========================================================================================================================
+#========================================================================================================================
+#========================================================================================================================
+#========================================================================================================================
+#========================================================================================================================
+
def is_filter_active?(type, id)
' active' if (@filter[type].include?(id.to_s) rescue nil)
end
- def render_sort_bar(delete_all, url, *titles)
- content_tag :table, :class => "table main-list" do
- content_tag :thead do
- content_tag :tr, :class => "sort-header" do
- concat (content_tag :th, :class => "span1 strong" do
- concat check_box_tag :check_all
- concat link_to content_tag(:i, nil, :class => "icon-trash"), '#', :class => "list-remove", :rel => url
- end) if (delete_all && (is_admin? || (is_manager? rescue nil)))
- titles.each do |title|
- concat render_title(title[0], title[1], title[2], title[3])
- end
- end
- end
- end
- end
-
- def render_title(title, fields, span, translation)
- content_tag :th, :class => "sort #{span} #{is_sort_active?(title)}" do
- content_tag :span do
- link_to (t(translation) + content_tag(:b, nil, :class => is_sort?(title))).html_safe, url_for({:filter => @filter}.merge(sortable(title).merge(:sort_options => fields))), :class => 'js_history'
- end
+ def is_sort_active?(field)
+ res = t(field[:translation])
+ if params[:sort].eql?(field[:sort])
+ res << " " + content_tag(:b, nil, class: (params[:direction].eql?('asc') ? "icons-arrow-up-3" : "icons-arrow-down-4 "))
end
+ res.html_safe
end
def show_toggle_archive_btn(object)
- object.disable ? t(:disable) : t(:enable)
+ object.disable ? t(:disable) : t(:enable)
+ end
+
+ def sortable_options(column)
+ direction = (column == params[:sort] && params[:direction] == "asc") ? "desc" : "asc"
+ {:sort => column, :direction => direction}
+ end
+
+
+ # ===============================================================
+ # associated:
+ #
+ # TODO: link for other types
+ # ===============================================================
+ def get_value(object, field)
+ authorization = !@authorization || (@authorization && is_authorized(object))
+ approvable = !@approvable || (@approvable && is_approvable(object))
+ res = ''
+ case field[:type]
+ when 'associated'
+ res << object.send(field[:db_field]).send(field[:associated_value]) rescue ''
+ when 'date'
+ res << (object.send(field[:db_field]) ? display_date_time(object.send(field[:db_field])) : t(:no_date))
+ when 'field'
+ res << with_link?(field, object, object.send(field[:db_field]))
+ if field[:quick_edit]
+ res << (content_tag :div, class: "quick-edit" do
+ content_tag :ul, class: "nav nav-pills" do
+ @quick_edit.each do |quick|
+ concat get_quick_link(quick, object, authorization, approvable)
+ end
+ end
+ end)
+ end
+ when 'status'
+ if object.is_top?
+ res << content_tag(:span, t(:top), class: "label label-success")
+ end
+ if object.is_hot?
+ res << content_tag(:span, t(:hot), class: "label label-important")
+ end
+ if object.is_hidden?
+ res << content_tag(:span, t(:hidden), class: "label")
+ end
+ if object.is_pending?
+ res << content_tag(:span, t(:pending), class: "label")
+ end
+ if object.is_checked?
+ res << content_tag(:span, t(:passed), class: "label")
+ end
+ if object.is_rejected?
+ res << content_tag(:span, t(:rejected), class: "label")
+ end
+ when 'tags'
+ object.sorted_tags.each do |tag|
+ res << content_tag(:span, tag.name, class: "label label-warning")
+ end if object.tags
+ res.html_safe
+ when 'id'
+ res << field[:id_model].constantize.find(object.send(field[:db_field])).name rescue ''
+ end
+ res.html_safe
+ end
+
+ def index_table
+ content_tag :table, class: "table main-list" do
+ concat (content_tag :thead do
+ (content_tag :tr, class: "sort-header" do
+ @fields.each do |field|
+ concat (content_tag :th, "data-hide" => field[:hide], class: ('active' if params[:sort].eql?(field[:sort])) do
+ if @sortable
+ link_to is_sort_active?(field), url_for({:filter => @filter}.merge(sortable_options(field[:sort]).merge(:sort_options => field[:db_field])))
+ else
+ t(field[:translation])
+ end
+ end)
+ end
+ end)
+ end)
+ concat (content_tag :tbody do
+ (@objects.each do |object|
+ concat (content_tag :tr do
+ (@fields.each do |field|
+ concat(content_tag :td, get_value(object, field))
+ end)
+ end)
+ end)
+ end)
+ end
+ end
+
+ def set_default_index(&block)
+ @approvable = false
+ @authorization = false
+ @categories = []
+ @category_field = nil
+ @fields = []
+ @filterable = false
+ @index_footer = nil
+ @quick_edit = []
+ @sortable = false
+ block.call
+ end
+
+ protected
+
+ def approvable
+ @approvable = true
+ end
+
+ def authorization
+ @authorization = true
+ end
+
+ def category_field(name)
+ @category_field = name
+ end
+
+ # ===============================================================
+ # type:
+ # check "get_value"
+ # associated_value:
+ # check "get_value"
+ # db_field:
+ # name of the field(s) in the database
+ # translation:
+ # key in the yml translation files
+ # hide:
+ # - no value: always shown
+ # - all: alway hidden
+ # - phone: hidden for phone
+ # sort:
+ # unique value used for keeping the sorted column
+ # link:
+ # if provided, the values will be shown as link
+ # (only available for type 'field' for now)
+ # ===============================================================
+ def field(args={})
+ @fields << args if !args.blank? && args[:type] && args[:translation] && args[:db_field]
+ end
+
+ def filterable(categories)
+ @filterable = true
+ @categories = categories
+ end
+
+ # ===============================================================
+ # args:
+ # - paginate: default true, there'es no need to specify it
+ # - link: path to the new action
+ # TODO: links to other actions
+ # ===============================================================
+ def footer(args={})
+ paginate = args.has_key?(:paginate) ? args[:paginate] : true
+ link = (is_manager? || is_sub_manager? rescue nil) && args.has_key?(:link) ? true : false
+ if paginate || link
+ @index_footer = content_tag :div, class: "bottomnav clearfix" do
+ concat content_tag :div, link_to(content_tag(:i, nil, :class => 'icon-plus') + ' ' + t(:add), send(args[:link]), :class => 'btn btn-primary' ), class: "action pull-right" if link
+ concat content_tag :div, paginate(@objects, :params => {:direction => params[:direction], :sort => params[:sort], :filter => @filter, :new_filter => nil, :sort_options => params[:sort_options]}), class: "pagination pagination-centered" if paginate
+ end
+ end
+ end
+
+ def get_quick_link(quick, object, authorization, approvable)
+ case quick[:type]
+ when 'approval'
+ if show_approval_link(object)
+ content_tag :li, link_to(t(quick[:translation] || :approval_), eval("#{quick[:link]}('#{object.id}')"), class: "preview_trigger #{quick[:class]}")
+ end
+ when 'edit'
+ if authorization && approvable
+ content_tag :li, link_to(t(quick[:translation] || :edit), eval("#{quick[:link]}('#{object.id}')"), class: quick[:class])
+ end
+ when 'delete'
+ if show_delete_link(object)
+ content_tag :li, link_to(t(quick[:translation] || :delete_), '#', rel: eval("#{quick[:link]}('#{object.id}')"), class: "delete_link #{quick[:class] || 'text-error'}")
+ end
+ when 'detail'
+ content_tag :li, link_to(t(quick[:translation] || :detail), '#', class: (quick[:class] || "detail-row"))
+ when 'reject_reason'
+ if show_reject_reason(object)
+ content_tag :li, link_to(t(quick[:translation] || :rejected_reason) + ' ' + truncate(object.not_checked_reason, :length => 10), '#', rel: "tooltip", 'data-original-title' => (wrap_string_with(object.not_checked_reason, :line_width => 24)), class: "reject_info #{quick[:class]}")
+ end
+ else
+ content_tag :li, link_to(t(quick[:translation]), eval("#{quick[:link]}('#{object.id}')"), class: quick[:class])
+ end
+ end
+
+ def is_approvable(object)
+ current_or_guest_user.admin? || (!object.is_rejected? && !object.is_checked?)
+ end
+
+ def is_authorized(object)
+ # TODO: refactor category code and replace following 'bulletin_category'
+ at_least_module_manager || object.send(@category_field).cur_user_is_sub_manager_of(:submit)
+ end
+
+ def quick_edit_link(args)
+ @quick_edit << args
+ end
+
+ def objects(objects)
+ @objects = objects
+ end
+
+ def sortable
+ @sortable = true
+ end
+
+ def with_link?(field, object, value)
+ if field[:link] && @approvable
+ if object.class.instance_methods.include?(:is_checked?) && object.is_checked?
+ link_to(value, eval("#{field[:link]}('#{object.id}')"))
+ # link_to bulletin.title, panel_announcement_front_end_bulletin_path(bulletin, :category_id => bulletin.bulletin_category.id) rescue ''
+ else
+ value
+ end
+ elsif field[:link]
+ link_to(value, eval("#{field[:link]}('#{object.id}')"))
+ else
+ value
+ end
end
end
\ No newline at end of file
diff --git a/app/views/admin/default_index/_clear_filters.html.erb b/app/views/admin/default_index/_clear_filters.html.erb
new file mode 100644
index 000000000..d8ff1784a
--- /dev/null
+++ b/app/views/admin/default_index/_clear_filters.html.erb
@@ -0,0 +1,3 @@
+
+ <%= link_to content_tag(:i, nil, :class => 'icons-cycle') + t(:clear), url_for(:filter => @filter, :sort => params[:sort], :direction => params[:direction], :clear => true, :type => type), :class => "btn btn-link btn-small" %>
+
\ No newline at end of file
diff --git a/app/views/admin/default_index/_filter_categories.html.erb b/app/views/admin/default_index/_filter_categories.html.erb
new file mode 100644
index 000000000..797f7224c
--- /dev/null
+++ b/app/views/admin/default_index/_filter_categories.html.erb
@@ -0,0 +1,6 @@
+
+<%= render :partial => 'admin/default_index/clear_filters', :locals => {:type => 'categories'} %>
\ No newline at end of file
diff --git a/app/views/admin/default_index/_filter_status.html.erb b/app/views/admin/default_index/_filter_status.html.erb
new file mode 100644
index 000000000..3c5c0b2dd
--- /dev/null
+++ b/app/views/admin/default_index/_filter_status.html.erb
@@ -0,0 +1,9 @@
+
+<%= render :partial => 'admin/default_index/clear_filters', :locals => {:type => 'status'} %>
diff --git a/app/views/admin/default_index/_filter_tags.html.erb b/app/views/admin/default_index/_filter_tags.html.erb
new file mode 100644
index 000000000..a9657e890
--- /dev/null
+++ b/app/views/admin/default_index/_filter_tags.html.erb
@@ -0,0 +1,6 @@
+
+<%= render :partial => 'admin/default_index/clear_filters', :locals => {:type => 'tags'} %>
\ No newline at end of file
diff --git a/app/views/admin/default_index/_index.html.erb b/app/views/admin/default_index/_index.html.erb
new file mode 100644
index 000000000..5fe5e4349
--- /dev/null
+++ b/app/views/admin/default_index/_index.html.erb
@@ -0,0 +1,68 @@
+<% content_for :page_specific_javascript do %>
+ <%= javascript_include_tag "lib/modal-preview" if @approvable %>
+
+<% end %>
+
+<% content_for :right_nav do %>
+
+ <% if @filterable %>
+
+
+
+ <%= render 'admin/default_index/filter_status' %>
+
+
+ <%= render 'admin/default_index/filter_categories' %>
+
+
+ <%= render 'admin/default_index/filter_tags' %>
+
+
+ <% end %>
+<% end %>
+
+<%= index_table %>
+
+<%= @index_footer %>
+
+
+
\ No newline at end of file
diff --git a/app/views/admin/tags/index.html.erb b/app/views/admin/tags/index.html.erb
index c0ac9b508..19682dbdb 100644
--- a/app/views/admin/tags/index.html.erb
+++ b/app/views/admin/tags/index.html.erb
@@ -1,3 +1,9 @@
+<% content_for :right_nav do %>
+
+
+
+<% end %>
+
<%= render 'index' %>
diff --git a/app/views/layouts/back_end.html.erb b/app/views/layouts/back_end.html.erb
index 8db541d8b..dbd89501a 100644
--- a/app/views/layouts/back_end.html.erb
+++ b/app/views/layouts/back_end.html.erb
@@ -6,10 +6,10 @@
<%= render 'layouts/google_font' %>
<%= stylesheet_link_tag "back_end" %>
<%= stylesheet_link_tag params[:controller] %>
+ <%= yield :page_specific_css %>
<%= render 'layouts/ie_html5_fix' %>
<%= javascript_include_tag "back_end" %>
<%= javascript_include_tag params[:controller] %>
- <%= yield :page_specific_css %>
<%= yield :page_specific_javascript %>
<%= csrf_meta_tag %>
@@ -27,10 +27,7 @@
Dashboard /
All
-
-
-
-
+ <%= yield :right_nav %>
<%= yield %>
diff --git a/config/locales/new_ui.en.yml b/config/locales/new_ui.en.yml
index 24c843dc6..61aa9b215 100644
--- a/config/locales/new_ui.en.yml
+++ b/config/locales/new_ui.en.yml
@@ -1,22 +1,37 @@
en:
+ add_category: Add category
add_link: Add link
add_page: Add page
add_to_default: Add to default
+ alternative: Alternative
+ change: Change
create:
error:
- tag: Error when creating tag.
+ category: Error when creating category
+ tag: Error when creating tag
deselect_all: Deselect all
+ detail: Detail
+ edit_category: Edit Categorie
editing:
tag: Editing tag
+ file:
+ name: File name
+ language: Language
login_orbit: Log In to Orbit
merge: Merge
new:
tag: New tag
next: Next
no_app: No module
+ no_date: No date
previous: Previous
+ remove: Remove
remove_default: Remove default
+ search:
+ tags: Search tags
select_all: Select all
+ select_file: Select file
+ select_image: Select image
tag:
add: Add tag
delete: Delete tags
@@ -29,4 +44,6 @@ en:
remove_default: Are you sure you want to remove the default tags?
update:
error:
- tag: Error when updating tag.
\ No newline at end of file
+ tag: Error when updating category
+ tag: Error when updating tag
+ url_alt: Alternative text
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/controllers/panel/announcement/back_end/bulletin_categorys_controller.rb b/vendor/built_in_modules/announcement/app/controllers/panel/announcement/back_end/bulletin_categorys_controller.rb
index 91f458c81..732e85c02 100644
--- a/vendor/built_in_modules/announcement/app/controllers/panel/announcement/back_end/bulletin_categorys_controller.rb
+++ b/vendor/built_in_modules/announcement/app/controllers/panel/announcement/back_end/bulletin_categorys_controller.rb
@@ -17,18 +17,49 @@ class Panel::Announcement::BackEnd::BulletinCategorysController < OrbitBackendCo
before_filter :for_app_sub_manager,:except => [:index,:get_categorys_json,:get_bulletins_json]
def index
- @bulletin_categorys = get_categories_for_index("BulletinCategory")
+ @bulletin_categorys = get_categories_for_index("BulletinCategory").page(params[:page]).per(10)
#TODO 需要做 manager ,admin 才可以 all. 其他 available就好
@bulletin_category = BulletinCategory.new(:display => 'List')
- @url = panel_announcement_back_end_bulletin_categorys_path
+ end
- respond_to do |format|
- format.html # index.html.erb
- # format.xml { render :xml => @bulletins }
- format.js
+ def new
+ @bulletin_category = BulletinCategory.new(:display => 'List')
+ render layout: false
+ end
+
+ def edit
+ @bulletin_category = BulletinCategory.find(params[:id])
+ render layout: false
+ end
+
+ def create
+ @bulletin_category = BulletinCategory.new(params[:bulletin_category])
+ if @bulletin_category.save
+ redirect_to action: :index
+ else
+ @bulletin_category = BulletinCategory.new(params[:module_tag])
+ flash.now[:error] = t('create.error.category')
+ render action: :new
end
end
+ def update
+ @bulletin_category = BulletinCategory.find(params[:id])
+ if @bulletin_category.update_attributes(params[:bulletin_category])
+ redirect_to action: :index
+ else
+ flash.now[:error] = t('update.error.category')
+ render action: :edit
+ end
+ end
+
+ def toggle
+ @bulletin_category = BulletinCategory.find(params[:id])
+ @bulletin_category.disable = @bulletin_category.disable ? false : true
+ @bulletin_category.save!
+ redirect_to action: :index
+ end
+
def get_categorys_json
categorys = BulletinCategory.all
data = Array.new
@@ -78,113 +109,4 @@ class Panel::Announcement::BackEnd::BulletinCategorysController < OrbitBackendCo
render :json => JSON.pretty_generate(data)
end
-
- # GET /bulletins/1
- # GET /bulletins/1.xml
- def show
- @bulletin_category = BulletinCategory.find(params[:id])
-
- respond_to do |format|
- format.html # show.html.erb
- # format.xml { render :xml => @bulletin_category }
- format.js
- end
- end
-
- # GET /bulletins/new
- # GET /bulletins/new.xml
- def new
- @bulletin_category = BulletinCategory.new(:display => 'List')
-
- respond_to do |format|
- format.html # new.html.erb
- # format.xml { render :xml => @bulletin_category }
- format.js
- end
- end
-
- def quick_edit
- # debugger
-
- @bulletin_category = BulletinCategory.find(params[:bulletin_category_id])
-
- @url = panel_announcement_back_end_bulletin_category_path(@bulletin_category)
-
- respond_to do |format|
- format.js
- end
-
- end
-
- # GET /bulletins/1/edit
- def edit
- @bulletin_category = BulletinCategory.find(params[:id])
-
- @url = panel_announcement_back_end_bulletin_category_path(@bulletin_category)
-
- respond_to do |format|
- format.html
- format.js
- end
- end
-
- # POST /bulletins
- # POST /bulletins.xml
- def create
- @bulletin_category = BulletinCategory.new(params[:bulletin_category])
-
- respond_to do |format|
- if @bulletin_category.save
- # format.html { redirect_to @bulletin_category, notice: 'Entry was successfully created.' }
- format.html { redirect_to(panel_announcement_back_end_bulletin_categorys_url, :notice => t('announcement.create_bulletin_category_success')) }
- # format.xml { render :xml => @bulletin_category, :status => :created, :location => @bulletin_category }
- format.js
- else
- format.html { render :action => "new" }
- # format.xml { render :xml => @bulletin_category.errors, :status => :unprocessable_entity }
- format.js { render action: "new" }
- end
- end
- end
-
- # PUT /bulletins/1
- # PUT /bulletins/1.xml
- def update
- @bulletin_category = BulletinCategory.find(params[:id])
-
- @url = panel_announcement_back_end_bulletin_category_path(@bulletin_category)
-
- respond_to do |format|
- if @bulletin_category.update_attributes(params[:bulletin_category])
- # format.html { redirect_to(panel_announcement_back_end_bulletin_category_url(@bulletin_category), :notice => t('announcement.update_bulletin_category_success')) }
- # format.html { redirect_to(panel_announcement_back_end_bulletin_categorys_url, :notice => t('announcement.update_bulletin_category_success')) }
- # format.xml { head :ok }
- format.js
- else
- format.html { render :action => "edit" }
- format.js { render :action => "edit" }
- # format.xml { render :xml => @bulletin_category.errors, :status => :unprocessable_entity }
- end
- end
- end
-
- # DELETE /bulletins/1
- # DELETE /bulletins/1.xml
- def destroy
- @bulletin_category = BulletinCategory.find(params[:id])
- @bulletin_category.disable = @bulletin_category.disable ? false : true
-
- if @bulletin_category.save!
- respond_to do |format|
- flash[:notice] = t("update.success_")
- # flash[:error] += @bulletin_category.disable ? t(:enable) : t(disable)
- format.html { redirect_to(panel_announcement_back_end_bulletin_categorys_url) }
- # format.xml { head :ok }
- format.js
- end
- else
- flash[:error] = t("update.fail")
- format.html { render :action => "index" }
- end
- end
end
diff --git a/vendor/built_in_modules/announcement/app/controllers/panel/announcement/back_end/bulletins_controller.rb b/vendor/built_in_modules/announcement/app/controllers/panel/announcement/back_end/bulletins_controller.rb
index e45ced1d6..e059b8c75 100644
--- a/vendor/built_in_modules/announcement/app/controllers/panel/announcement/back_end/bulletins_controller.rb
+++ b/vendor/built_in_modules/announcement/app/controllers/panel/announcement/back_end/bulletins_controller.rb
@@ -110,59 +110,36 @@ class Panel::Announcement::BackEnd::BulletinsController < OrbitBackendController
# POST /bulletins.xml
def create
@tags = get_tags
- if params[:bulletin_link]
+ @bulletin = Bulletin.new(params[:bulletin])
+ @bulletin.deadline = nil if (@bulletin.deadline < @bulletin.postdate rescue nil)
- @bulletin_link = BulletinLink.new(params[:bulletin_link])
+ @bulletin.create_user_id = current_user.id
+ @bulletin.update_user_id = current_user.id
+ if(is_manager? || is_admin?)
+ @bulletin.is_checked = true
+ @bulletin.is_rejected = false
+ @bulletin.de_pending
+ end
- respond_to do |format|
- if @bulletin_link.save
- format.js { render 'create_bulletin_link' }
- end
- end
+ respond_to do |format|
+ if @bulletin.save
- elsif params[:bulletin_file]
-
- @bulletin_file = BulletinFile.new(params[:bulletin_file])
-
- respond_to do |format|
- if @bulletin_file.save
- format.js { render 'create_bulletin_file' }
- end
- end
-
- else
-
- @bulletin = Bulletin.new(params[:bulletin])
- @bulletin.deadline = nil if (@bulletin.deadline < @bulletin.postdate rescue nil)
-
- @bulletin.create_user_id = current_user.id
- @bulletin.update_user_id = current_user.id
- if(is_manager? || is_admin?)
- @bulletin.is_checked = true
- @bulletin.is_rejected = false
- @bulletin.de_pending
- end
-
- respond_to do |format|
- if @bulletin.save
-
- format.html { redirect_to(panel_announcement_back_end_bulletins_url, :notice => t('announcement.create_bulletin_success')) }
- format.xml { render :xml => @bulletin, :status => :created, :location => @bulletin }
- # format.js
- format.js {
- @info = {"success"=>"true","redirect_url"=>panel_announcement_back_end_bulletins_url}
- flash[:notice] = t('bulletin.create_bulletin_success')
- render "/shared/preview/after_create.js.erb"
- }
- else
- format.html { render :action => "new" }
- format.xml { render :xml => @bulletin.errors, :status => :unprocessable_entity }
- format.js {
- @info = {"success"=>"false","redirect_url"=>new_panel_announcement_back_end_bulletin_url(:bulletin => @bulletin)}
- session[:in_validate_object] = @bulletin
- render "/shared/preview/after_create.js.erb"
- }
- end
+ format.html { redirect_to(panel_announcement_back_end_bulletins_url, :notice => t('announcement.create_bulletin_success')) }
+ format.xml { render :xml => @bulletin, :status => :created, :location => @bulletin }
+ # format.js
+ format.js {
+ @info = {"success"=>"true","redirect_url"=>panel_announcement_back_end_bulletins_url}
+ flash[:notice] = t('bulletin.create_bulletin_success')
+ render "/shared/preview/after_create.js.erb"
+ }
+ else
+ format.html { render :action => "new" }
+ format.xml { render :xml => @bulletin.errors, :status => :unprocessable_entity }
+ format.js {
+ @info = {"success"=>"false","redirect_url"=>new_panel_announcement_back_end_bulletin_url(:bulletin => @bulletin)}
+ session[:in_validate_object] = @bulletin
+ render "/shared/preview/after_create.js.erb"
+ }
end
end
end
diff --git a/vendor/built_in_modules/announcement/app/models/bulletin_category.rb b/vendor/built_in_modules/announcement/app/models/bulletin_category.rb
index 9eb3cfbef..56c335e96 100644
--- a/vendor/built_in_modules/announcement/app/models/bulletin_category.rb
+++ b/vendor/built_in_modules/announcement/app/models/bulletin_category.rb
@@ -19,6 +19,8 @@ class BulletinCategory
field :title, localize: true
has_many :bulletins
+
+ validates :title, :at_least_one => true
def pp_object
title
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_bulletin_category.html.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_bulletin_category.html.erb
index bf4e717c0..281847c55 100644
--- a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_bulletin_category.html.erb
+++ b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_bulletin_category.html.erb
@@ -1,20 +1,20 @@
-
-
+
+ <% @site_valid_locales.each_with_index do |locale, i| %>
- <%= bulletin_category.key %>
-
-
- <% if is_admin?%>
- <%= link_to t(:edit), edit_panel_announcement_back_end_bulletin_category_path(bulletin_category), :remote => true %>
- <%= link_to show_toggle_archive_btn(bulletin_category) , panel_announcement_back_end_bulletin_category_path(bulletin_category), :confirm => t(:sure?), :method => :delete, :remote => true,:class=> "archive_toggle" %>
- <% end %>
- <%if is_manager? || is_admin? %>
- <%= show_anc_cate_permission_link(bulletin_category) %>
- <% end %>
-
-
+ <%= bulletin_category.title_translations[locale] %>
+ <% if i == 0 %>
+
+
+ <% if is_admin?%>
+ <%= link_to t(:edit), edit_panel_announcement_back_end_bulletin_category_path(bulletin_category), class: "open-slide" %>
+ <%= link_to show_toggle_archive_btn(bulletin_category) , toggle_panel_announcement_back_end_bulletin_category_path(bulletin_category), method: :post, remote: true, class: "archive_toggle" %>
+ <% end %>
+ <% if is_manager? || is_admin? %>
+ <%= show_anc_cate_permission_link(bulletin_category) %>
+ <% end %>
+
+
+ <% end %>
- <% @site_valid_locales.each do |locale| %>
- <%= bulletin_category.title_translations[locale] rescue nil %>
- <% end %>
-
+ <% end %>
+
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_edit.html.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_edit.html.erb
new file mode 100644
index 000000000..cfbe07927
--- /dev/null
+++ b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_edit.html.erb
@@ -0,0 +1,10 @@
+<%= form_for @bulletin_category, :url => panel_announcement_back_end_bulletin_category_path(@bulletin_category), remote: true do |f| %>
+
+ <%= t(:edit_category) %>
+ <%= render :partial => 'form', :locals => {:f => f} %>
+
+
+<% end %>
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_form.html.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_form.html.erb
index 9c9880b8e..92f3403e6 100644
--- a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_form.html.erb
+++ b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_form.html.erb
@@ -1,37 +1,9 @@
-<% # encoding: utf-8 %>
+<%= flash_messages %>
+<%= f.error_messages %>
-<%= form_for(@bulletin_category, :remote => true, :url => @url) do |f| %>
-
-
<%= @bulletin_category.new_record? ? t(:add) : t(:edit) %>
-
-
- <%= f.label :key, t(:key) %>
- <%= f.text_field :key %>
-
-
-
-
-
- <%#= f.label :display %>
- <%#= f.radio_button :display, "List" List%>
- <%#= f.radio_button :display, "Picture" Picture%>
- <%# 顯示方式是設定在前台頁面時,資訊所呈現的樣式 %>
-
-
-
-
+<%= f.fields_for :title_translations do |f| %>
+ <% @site_valid_locales.each do |locale| %>
+ <%= label_tag "name-#{locale}", "#{t(:name)} (#{I18nVariable.from_locale(locale)})" %>
+ <%= f.text_field locale, :class => 'input-large', :value => (@bulletin_category.title_translations[locale] rescue ''), placeholder: t(:name) %>
+ <% end %>
<% end %>
-
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_index.html.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_index.html.erb
new file mode 100644
index 000000000..9fd43a1ae
--- /dev/null
+++ b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_index.html.erb
@@ -0,0 +1,21 @@
+
+
+
+
+
+ <%= render :partial => 'bulletin_category', :collection => @bulletin_categorys %>
+
+
+
+
+
+ <%= link_to content_tag(:i, nil, class: "icons-plus") + " " + t(:add), new_panel_announcement_back_end_bulletin_category_path, class: "btn btn-primary open-slide" %>
+
+
+
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_new.html.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_new.html.erb
new file mode 100644
index 000000000..195092cc1
--- /dev/null
+++ b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/_new.html.erb
@@ -0,0 +1,10 @@
+<%= form_for @bulletin_category, :url => panel_announcement_back_end_bulletin_categorys_path, remote: true do |f| %>
+
+ <%= t(:add_category) %>
+ <%= render :partial => 'form', :locals => {:f => f} %>
+
+
+<% end %>
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/create.js.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/create.js.erb
deleted file mode 100644
index e914aacdc..000000000
--- a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/create.js.erb
+++ /dev/null
@@ -1,2 +0,0 @@
-$('<%= j render :partial => 'bulletin_category', :collection => [@bulletin_category] %>').appendTo('#bulletin_categorys').hide().fadeIn();
-$("#new_bulletin_category")[0].reset();
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/destroy.js.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/destroy.js.erb
deleted file mode 100644
index e7f791906..000000000
--- a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/destroy.js.erb
+++ /dev/null
@@ -1 +0,0 @@
-$("#<%= dom_id @bulletin_category %>").find(".archive_toggle").text("<%= show_toggle_archive_btn(@bulletin_category) %> ");
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/edit.html.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/edit.html.erb
index 29e4515ba..9e91e9ef2 100644
--- a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/edit.html.erb
+++ b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/edit.html.erb
@@ -1,7 +1 @@
-
<%= t('announcement.editing_announcement_category') %>
-
-<%= form_for @bulletin_category, :url => panel_announcement_back_end_bulletin_category_path(@bulletin_category) do |f| %>
- <%= render :partial => 'form', :locals => {:f => f} %>
-<% end %>
-
-<%= link_back %>
+<%= render 'edit' %>
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/edit.js.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/edit.js.erb
index eaff01fa3..30d88e18a 100644
--- a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/edit.js.erb
+++ b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/edit.js.erb
@@ -1 +1 @@
-$("#form > form").replaceWith("<%= j render "form" %>");
\ No newline at end of file
+$('#view-page .content').html("<%= j render 'edit' %>");
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/index.html.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/index.html.erb
index cc9dbd9e8..c4c84ca7f 100644
--- a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/index.html.erb
+++ b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/index.html.erb
@@ -1,41 +1,3 @@
-
-<%= flash_messages %>
-
-
-
-
-
-
-
-
- <% @site_valid_locales.each do |locale| %>
-
- <% end %>
-
-
-
-
- <%= render :partial => 'bulletin_category', :collection => @bulletin_categorys %>
-
-
-
-
-
<%= render :partial => "form" if is_manager?%>
-
-
-
+
+ <%= render 'index' %>
+
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/index.js.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/index.js.erb
new file mode 100644
index 000000000..641d1fa74
--- /dev/null
+++ b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/index.js.erb
@@ -0,0 +1,3 @@
+$("#categories_index").html("<%= j render 'index' %>")
+$.pageslide.close();
+openSlide();
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/new.html.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/new.html.erb
index e401b5284..e3355a939 100644
--- a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/new.html.erb
+++ b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/new.html.erb
@@ -1,19 +1 @@
-<% content_for :secondary do %>
-<%= render :partial => '/panel/announcement/back_end/announcement_secondary' %>
-<% end -%>
-
-<%= flash_messages %>
-
-
-
-
-
-
-
-
<%= t('announcement.new_bulletin_category') %>
-<%= form_for @bulletin_category, :url => panel_announcement_back_end_bulletin_categorys_path do |f| %>
- <%= render :partial => 'form', :locals => {:f => f} %>
-<% end %>
-
-<%= link_back %>
-
+<%= render 'new' %>
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/new.js.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/new.js.erb
index 40061b9fc..5ecf8f163 100644
--- a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/new.js.erb
+++ b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/new.js.erb
@@ -1 +1 @@
-$("#form > form").replaceWith("<%= j render "form" %>");
+$('#view-page .content').html("<%= j render 'new' %>");
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/update.js.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/update.js.erb
deleted file mode 100644
index 728757e3c..000000000
--- a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletin_categorys/update.js.erb
+++ /dev/null
@@ -1,4 +0,0 @@
-$("#<%= dom_id @bulletin_category %>").replaceWith("<%= j render :partial => 'bulletin_category', :collection => [@bulletin_category] %>");
-<% @bulletin_category = BulletinCategory.new(:display => 'List') # reset for new form %>
-$(".edit_bulletin_category").replaceWith("<%= j render "form" %>")
-$(".new_bulletin_category")[0].reset();
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletins/_bulletin_file_qe.html.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletins/_bulletin_file_qe.html.erb
deleted file mode 100644
index b9270dbe3..000000000
--- a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletins/_bulletin_file_qe.html.erb
+++ /dev/null
@@ -1,51 +0,0 @@
-<% # encoding: utf-8 %>
-
- <%= form_for @bulletin_file, :url => @file_url, :html => {:id => 'ajaxForm', :multipart => true} do |f| %>
-
-
-
-
-
- <%= f.file_field :file %>
-
-
-
- <%= f.fields_for :title_translations do |f| %>
- <% @site_valid_locales.each do |locale| %>
-
-
<%= t(:name) %> <%= I18nVariable.first(:conditions => {:key => locale})[I18n.locale] %>
-
- <%= f.text_field locale, :id => "file-#{locale}", :class => "input-xlarge", :value => (@bulletin_file.title_translations[locale] rescue nil) %>
-
-
- <% end %>
- <% end %>
-
- <%= f.fields_for :description_translations do |f| %>
- <% @site_valid_locales.each do |locale| %>
-
-
<%= t(:description) %> <%= I18nVariable.first(:conditions => {:key => locale})[I18n.locale] %>
-
- <%= f.text_field locale, :id => "file-#{locale}", :class => "input-xlarge", :value => (@bulletin_file.description_translations[locale] rescue nil) %>
-
-
- <% end %>
- <% end %>
-
-
-
-
-
-
- <% end %>
-
-
-
\ No newline at end of file
diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletins/_bulletin_link_qe.html.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletins/_bulletin_link_qe.html.erb
deleted file mode 100644
index de7567a57..000000000
--- a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletins/_bulletin_link_qe.html.erb
+++ /dev/null
@@ -1,36 +0,0 @@
-<% # encoding: utf-8 %>
-
-<%= form_for(@bulletin_link, :remote => true, :url => @link_url) do |f| %>
-
-
-
-
-
<%= t(:url) %>
-
- <%= f.text_field :url %>
-
-
-
- <%= f.fields_for :title_translations do |f| %>
- <% @site_valid_locales.each do |locale| %>
-
- <%= label_tag "link-#{locale}", "#{t(:name)}-#{I18nVariable.from_locale(locale)}", :class => 'control-label' %>
-
- <%#= f.text_field locale, :class => 'input-xxlarge' %>
- <%= f.text_field locale, :class => 'control-label', :value => (@bulletin_link.title_translations[locale] rescue nil) %>
-
-
- <% end %>
- <% end %>
-
-