Compare commits

...

127 Commits

Author SHA1 Message Date
rulingcom f71fcdcefa updates for property hire 2024-10-23 15:41:55 +08:00
邱博亞 e190f1e23c Fix bug. 2024-10-02 11:17:56 +08:00
rulingcom 420ce3b065 changes made to property hire 2024-09-04 21:03:02 +08:00
rulingcom aa19dd1416 fixed display issue 2024-08-28 22:50:26 +08:00
邱博亞 703c5322ca Add owner_email_rule. 2024-08-24 11:18:42 +08:00
邱博亞 eb8b951253 Fix Error 2024-08-21 21:48:11 +08:00
rulingcom 7080cf7d4d updated lot of features 2024-07-11 15:42:16 +08:00
邱博亞 4d02ff8729 Fix bug. 2024-05-14 21:08:58 +08:00
邱博亞 bd8f88afa3 Add copy feature. 2024-05-14 09:01:56 +08:00
邱博亞 76cd916a26 Fix PropertyHireSetting. 2024-03-14 20:10:33 +08:00
邱博亞 24c8845f28 Remove send_mail to admin. 2023-12-21 21:06:40 +08:00
邱博亞 5d7769270a Fix bug in ruby 2.7. 2023-12-19 22:54:50 +08:00
邱博亞 6dddde451d fix error for non admin user 2023-11-04 09:50:52 +08:00
邱博亞 cde9364f76 修復owners nil錯誤 2023-10-18 22:01:09 +08:00
邱博亞 6ad48313ed 1.設定 不可預約 的資料只有登入的會員才能查看(查詢目前已預約狀況)。
2.設定 不可預約 的資料只有管理者帳號才能預約租借(線上預約)。

3.可以設定未登入的使用者無法查看查詢目前已預約狀況
2023-10-18 21:56:19 +08:00
邱博亞 864358bd69 沒登入也可以看到日曆,沒有開放預約時,管理者仍可以在前臺預約 2023-08-26 11:16:56 +08:00
BoHung Chiu c3eb6f7ac8 Fix bug. 2023-08-15 21:52:43 +08:00
邱博亞 f8e8653c5c add widget 2023-05-01 23:35:38 +08:00
BoHung Chiu 336c940457 Fix bug. 2023-04-22 15:39:05 +08:00
邱博亞 0660a12bff fix error 2023-03-07 21:40:01 +08:00
邱博亞 ab6b79eb29 Fix bug. 2022-12-07 11:39:42 +08:00
BoHung Chiu 16edd24809 Fix bug. 2022-11-24 23:20:09 +08:00
BoHung Chiu 27b4b2aab7 Fix bug. 2022-11-24 19:59:47 +08:00
BoHung Chiu 22ab0909ad Add filter to backend page. 2022-11-24 17:31:30 +08:00
BoHung Chiu 7f14f7db5a Remove vulnerable js. 2022-11-08 09:01:07 +08:00
BoHung Chiu e86b431bbb Fix bug. 2022-10-22 16:05:20 +08:00
BoHung Chiu 14881759b7 Fix data format bug. 2022-08-29 17:51:31 +08:00
BoHung Chiu 56dad2a1b4 Fix bug. 2022-08-04 16:35:33 +08:00
BoHung Chiu f8835c49d0 Fix bug. 2022-08-04 16:00:20 +08:00
BoHung Chiu a6e9c31222 Fix bug. 2022-08-02 21:48:24 +08:00
BoHung Chiu 48c4948946 Fix bug. 2022-07-25 22:37:16 +08:00
BoHung Chiu 82cec4139c Fix bug. 2022-07-22 09:43:01 +08:00
邱博亞 429ef0f11c fix error 2022-07-21 16:43:51 +08:00
BoHung Chiu 53eced22cc Fix js bug. 2022-07-13 12:07:10 +08:00
BoHung Chiu 8892dbb9f8 Fix bug. 2022-07-11 17:02:26 +08:00
BoHung Chiu 02556434b3 Fix bug. 2022-07-11 15:30:37 +08:00
BoHung Chiu 878fc0079d Convert js space to tabs. 2022-07-11 15:26:47 +08:00
BoHung Chiu b3876c00d0 Fix bug. 2022-07-11 15:26:25 +08:00
BoHung Chiu 6e63cf4777 Fix fullcalendar js bug.(stuck at loading and more button out of column) 2022-06-25 19:40:16 +08:00
BoHung Chiu 5ed7a08a1a Update fullcalendar from 5.8.0 to 5.11.0 2022-06-24 17:45:37 +08:00
BoHung Chiu ae43768659 Add fields default value. 2022-06-21 11:44:07 +08:00
BoHung Chiu dba2944273 Fix bug. 2022-06-21 11:39:36 +08:00
BoHung Chiu 92b3b91138 Fix hire bug.
Add required fields check by ruby.
2022-06-20 10:01:36 +08:00
BoHung Chiu d1b61401cb Fix borrow over one day will lead to datetime wrong display. 2022-04-09 20:21:02 +08:00
BoHung Chiu 90dabd7560 Fix hire check bug. 2022-02-23 17:36:59 +08:00
BoHung Chiu 28ef7b0ae0 Fix bug. 2022-02-16 10:10:27 +08:00
邱博亞 e93d34d597 fix error 2022-02-08 15:26:12 +08:00
BoHung Chiu 70388806c6 Fix bug when screen is larger.(it will trigger maximum call statck size exceeded) 2021-12-09 13:30:33 +08:00
BoHung Chiu 388ada1ae3 Fix bug. 2021-12-09 11:48:22 +08:00
BoHung Chiu 33da76f7ae Fix chinese trans. 2021-12-09 10:55:42 +08:00
BoHung Chiu 4b55d3ef39 Fix bug. 2021-11-19 12:56:18 +08:00
BoHung Chiu 2de6ba54ae Fix bug. 2021-10-26 18:58:47 +08:00
BoHung Chiu 12eea8b58e Fix bug.(Add date and time displayed in email when choosing set availability) 2021-10-26 18:45:14 +08:00
BoHung Chiu e98009f659 Fix bug. 2021-10-25 18:36:12 +08:00
BoHung Chiu c0261a90d8 Fix bug. 2021-10-25 18:29:03 +08:00
BoHung Chiu 74881746ab Add default_time_settings feature. 2021-10-23 10:34:18 +08:00
BoHung Chiu a6caffd67f Fix bug. 2021-10-22 22:20:20 +08:00
BoHung Chiu 1dca65f863 Fix bug. 2021-10-22 22:11:06 +08:00
BoHung Chiu 3691a14c64 Add hire success page.
Add display custom fields in calendar event title.
Add need hire before setting.
2021-10-22 22:09:10 +08:00
BoHung Chiu 958bade200 Fix bug. 2021-10-15 21:10:34 +08:00
BoHung Chiu b4aa1d125b Fix display recurring events bug. 2021-10-05 22:26:22 +08:00
BoHung Chiu c4ef2557a3 Fix loading image missing. 2021-10-05 22:15:23 +08:00
BoHung Chiu 9709a8e708 Fix css error in view_calendar page. 2021-10-05 22:03:49 +08:00
BoHung Chiu 5fa2811cbe Fix bug. 2021-10-05 21:58:43 +08:00
BoHung Chiu d78aab6408 Fix recurring event. 2021-10-05 21:56:45 +08:00
BoHung Chiu c902128062 Fix bug. 2021-10-05 10:16:11 +08:00
BoHung Chiu 97d7d0e90f Fix bug. 2021-10-05 10:15:04 +08:00
BoHung Chiu eaa1009dda Edit gotcha width. 2021-09-24 13:02:04 +08:00
BoHung Chiu d8adf49ee0 Fix bug. 2021-09-24 12:37:23 +08:00
BoHung Chiu 456f2b9ece Fix bug. 2021-09-24 12:23:59 +08:00
BoHung Chiu 5c2b124e28 Edit css. 2021-09-24 12:15:33 +08:00
BoHung Chiu 4942cc9573 Fix bug. 2021-09-23 14:42:36 +08:00
BoHung Chiu 912956b65a Fix bug. 2021-09-23 14:40:18 +08:00
BoHung Chiu 2a2121a7c8 Fix bug.
Add fields display sortable.
2021-09-19 15:56:01 +08:00
BoHung Chiu b97a590b5c Update translations. 2021-09-14 16:20:46 +08:00
BoHung Chiu b88915c6e7 Fix bug. 2021-09-09 10:14:57 +08:00
BoHung Chiu ceb60e3afc Fix layout. 2021-09-08 11:29:20 +08:00
BoHung Chiu a5313537ec Fix layout. 2021-09-08 11:06:26 +08:00
BoHung Chiu cae7247750 Fix layout. 2021-09-08 11:03:27 +08:00
BoHung Chiu b0d7599edd Fix layout. 2021-09-08 10:55:20 +08:00
BoHung Chiu e199880f13 Update a lots.(include allow not logins user to hire, let admin set calendar display?,fix bugs) 2021-09-08 10:10:44 +08:00
BoHung Chiu 3366262e62 Fix bugs. 2021-09-07 13:07:09 +08:00
BoHung Chiu 9c85d50c5b Update a lots of things. 2021-09-07 00:45:14 +08:00
BoHung Chiu 24f93f7630 Update fullcalendar from 1.6.1 to 5.8.0.
Add calendar to backedend show page.
Add calendar to frontend hire page.
Add error message description when hiring property.
Add backend edit hire page.
2021-07-05 18:05:49 +08:00
chiu c9f424b30d fix error 2021-01-25 15:01:07 +08:00
BoHung Chiu 69e269cf59 Fix bug. 2020-09-25 21:43:13 +08:00
BoHung Chiu 875c3dc580 Fix recurring hire bug. 2020-09-19 23:11:26 +08:00
BoHung Chiu ce63816765 Fix interval hire bug. 2020-09-19 00:32:56 +08:00
chiu 9e670ae11f Fix bug. 2020-07-26 15:54:19 +08:00
BoHung Chiu 1cfe929348 Fix bug. 2020-07-22 18:53:39 +08:00
BoHung Chiu 5d14e25578 Add notes selector. 2020-07-22 18:13:50 +08:00
BoHung Chiu 262eaa36b9 Fix cannot edit location bug at manage_locations page. 2020-07-22 11:59:08 +08:00
BoHung Chiu 9c8c1bd0c4 Fix bug for last version. 2020-07-20 21:58:29 +08:00
BoHung Chiu 1e18ac077a Fix cannot hire the empty time interval bug caused by the wrong data. 2020-07-20 20:58:24 +08:00
BoHung Chiu 6f3333a857 Fix some important bugs.Add extra fields(can set enabled) to hire page. 2020-07-02 22:56:03 +08:00
BoHung Chiu 9afb891362 Update Chinese translations. 2020-07-02 10:01:04 +08:00
chiu afa62d1d67 fix erorr 2020-06-03 21:05:49 +08:00
chiu a654081664 fix error 2020-06-03 20:42:10 +08:00
chiu eb73011ca4 fix error 2020-05-29 14:44:24 +08:00
chiu 7e3141d4f0 add property title 2020-05-28 17:30:03 +08:00
chiu a8952495f4 fix error 2020-05-26 23:02:37 +08:00
chiu b83b4e5633 fix error 2020-05-26 23:02:09 +08:00
chiu 386cb0c5e0 fix error 2020-05-26 22:15:45 +08:00
chiu d159171993 fix error 2020-05-25 12:09:19 +08:00
chiu 02f46d90e2 fix error 2020-05-23 14:33:03 +08:00
chiu b8c0ff2bd5 fix error 2020-05-21 20:15:10 +08:00
chiu 8342a17aca fix error 2020-05-20 20:20:19 +08:00
chiu a17980e7a7 add editor to email 2020-05-20 20:14:02 +08:00
chiu 1b88e86364 fix error 2020-05-20 17:56:34 +08:00
chiu c73a3ce9a8 fix error 2020-05-20 17:53:06 +08:00
chiu 7c46fbd6ac fix error 2020-05-20 17:42:39 +08:00
chiu b7efc22d1d add content to edit email 2020-05-20 17:34:30 +08:00
chiu 86cf5f9a13 fix error 2020-05-20 16:55:19 +08:00
chiu 73241e7b18 fix error 2020-05-20 00:28:21 +08:00
chiu c43dd3c625 fix error 2020-05-20 00:07:29 +08:00
chiu 79bf7d9694 fix error 2020-05-19 23:24:00 +08:00
chiu 23c6753646 fix error 2020-05-19 23:17:25 +08:00
chiu 6c3cf31b03 fix error 2020-05-19 23:08:52 +08:00
chiu 304dffbe9f fix error 2020-05-19 23:07:06 +08:00
chiu ec3e4463ca fix error 2020-05-19 22:50:45 +08:00
chiu bb3d9ffeb9 fix error 2020-05-19 16:13:07 +08:00
chiu 212574e17a add title of hiring object for email 2020-04-02 23:17:26 +08:00
chiu 9ae24ce5f9 auto send information for hire on hiring 2020-03-24 22:40:22 +08:00
chiu 1a985bad64 add auto send email feature 2020-03-24 01:26:52 +08:00
wmcheng 0bd0a61986 Merge branch 'master' into 'master'
Update property_hire_calendar_frontend.js



See merge request !3
2019-11-09 23:48:17 +08:00
wmcheng b55b5d60e3 Merge branch 'revert-e1e90a83' into 'master'
Revert "Fix show issue if no enough info. provided."

This reverts commit e1e90a83cf

See merge request !1
2019-11-09 23:44:58 +08:00
wmcheng 367a95d7bc Update property_hire_calendar_frontend.js 2019-11-09 23:42:19 +08:00
80 changed files with 41988 additions and 1206 deletions

17
Gemfile.lock Normal file
View File

@ -0,0 +1,17 @@
PATH
remote: .
specs:
property_hire (0.0.1)
GEM
remote: https://rubygems.org/
specs:
PLATFORMS
ruby
DEPENDENCIES
property_hire!
BUNDLED WITH
1.17.3

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,497 @@
// Retrieve the initial data
function temporary() {
attributesArray.length = 0;
$('.attributes').each(function() {
var attributesData = {},
$selectType = $('.dataType').data().type;
// Capture "attributes-body" within the input[type = "text"] val
$(this).find('.attributes-body').find('input[type="text"]').each(function(i) {
var $type = $(this).data().type;
attributesData[$type] = $(this).val();
});
// Capture "attributes-body" within the input[type = "radio"] checked
$(this).find('.attributes-body').find('input[type="radio"]').each(function(i) {
var $type = $(this).data().type;
attributesData[$type] = $(this).prop("checked");
});
// Capture "attributes-body" within the dataType selected
$(this).find('.attributes-body').find('.dataType').children("option:selected").each(function () {
attributesData[$selectType] = {};
attributesData[$selectType].index = $(this).index();
attributesData[$selectType].name = $(this).attr('ref');
if($(this).attr('ref') == 'typeB' || $(this).attr('ref') == 'typeE' || $(this).attr('ref') == 'typeF') {
attributesData[$selectType].option = [];
}
});
// Capture "field-type" within the input[type = "text"] val
$(this).find('.field-type').find('input[type="text"]').each(function(i) {
var $type = $(this).data().type;
if(!$type.match('option_lang')) {
attributesData[$selectType][$type] = $(this).val();
}
});
$(this).find('.field-type .add-target').find('.input-append').each(function() {
var append = []
$(this).children('input[type="text"]').each(function() {
var val = $(this).val();
append.push(val);
});
attributesData[$selectType].option.push(append);
})
// Capture "field-type" within the input[type = "checkbox"] checked
$(this).find('.field-type').find('input[type="checkbox"]').each(function() {
var $type = $(this).data().type;
attributesData[$selectType][$type] = $(this).prop("checked");
});
// Capture "field-type" within the input[type = "radio"] checked
$(this).find('.field-type').find('input[type="radio"]').each(function() {
var $type = $(this).data().type;
attributesData[$selectType][$type] = $(this).prop("checked");
});
// Capture "field-type" within the dataType selected
$(this).find('.field-type').find('select').children("option:selected").each(function () {
attributesData[$selectType].dateFormat = $(this).index();
});
attributesArray.push(attributesData);
});
};
// Determine the Append input length
function inputAppendLength() {
$('.add-target').each(function(i) {
if($(this).children('.input-append:not(:hidden)').length == 1 || $(this).children('.input-append').length == 1) {
$(this).children('.input-append').each(function() {
if($(this).children('div').hasClass('tab-content')) {
var btnLength = $(this).children('.btn').length;
$(this).find('.btn').eq(btnLength-2).addClass('last');
$(this).find('.remove-input').addClass('hide');
} else {
var mediumLength = $(this).children('.input-medium').length;
$(this).children('.input-medium').eq(mediumLength-1).addClass('last');
$(this).children('.remove-input').addClass('hide');
}
});
} else {
$(this).children('.input-append').each(function() {
if($(this).children('div').hasClass('tab-content')) {
$(this).find('.btn').removeClass('last');
$(this).find('.remove-input').removeClass('hide');
} else {
$(this).children('.input-medium').removeClass('last');
$(this).children('.remove-input').removeClass('hide');
}
});
}
});
};
// Role Attribute Template Data
function setData(l, type, ol) {
var fields = $('#info').length ? "info[p_hire_fields]" : $('#sub_property').length ? "sub_property[p_hire_fields]" : "property[p_hire_fields]",
data = {
_add_more: ["add_more_" +l, fields+"["+l+"]["+type+"][add_more]"],
_calendar: ["calendar_" +l, fields+"["+l+"]["+type+"][calendar]"],
_cross_lang: ["cross_lang_" +l, fields+"["+l+"]["+type+"][cross_lang]"],
_disabled: ["disabled_" +l, fields+"["+l+"][disabled]"],
_format: ["format_" +l, fields+"["+l+"]["+type+"][format]"],
_initial: ["initial_" +l, fields+"["+l+"]["+type+"][initial]"],
_is_range: ["is_range_" +l, fields+"["+l+"]["+type+"][is_range]"],
_key: ["key_" +l, fields+"["+l+"][key]"],
_markup: fields+"["+l+"][markup]",
_option_list: ["option_list_"+l+"_"+ol, fields+"["+l+"]["+type+"][option_list]["+ol+"]", "option_list_"+ol],
_placeholder: ["placeholder_" +l, fields+"["+l+"]["+type+"][placeholder]"],
_title_translations: ["title_translations_" +l, fields+"["+l+"][title_translations]"],
_to_delete: ["to_delete_" +l, fields+"["+l+"][to_delete]"],
_to_require: ["to_require_" +l, fields+"["+l+"][to_require]"],
_display_in_reason_for_hire: ["display_in_reason_for_hire_" +l, fields+"["+l+"][display_in_reason_for_hire]"],
};
return data;
}
// Get Default Address Form
function getAddressForm(trigger, element, decide) {
if(decide) {
addressVal.length = addressArray.length = 0;
var addressAllVal = [];
var inputNameArray = [];
trigger.closest('.input-append').find('.tab-pane').each(function() {
var adderssText = $(this).children('input[type="text"]').val(),
addersshidden = '',
addressData = {},
inputName = [];
$(this).children('input:not(:first)').each(function(j) {
var name = $(this).attr('name'),
val = $(this).val();
addersshidden += val;
addressData[name] = val;
inputName.push(name);
});
addressArray.push(addressData);
addressAllVal.push(adderssText);
inputNameArray.push(inputName);
if(adderssText != addersshidden) {
addressVal.push(false);
} else {
addressVal.push(true);
}
});
element.find('.tab-pane').each(function(i) {
$(this).find('textarea, input[type="text"]').each(function(j) {
$(this).attr('name',inputNameArray[i][j]);
});
if(addressVal[i]) {
$(this).find('textarea, input[type="text"]').each(function(j) {
$(this).val(addressArray[i][$(this).attr('name')]);
});
} else {
$(this).find('textarea').val(addressAllVal[i]);
$(this).find('input[type="text"]').each(function(j) {
$(this).val('');
});
}
});
};
element.off('show');
};
// Return Address Form
function returnAddressForm(element, decide) {
if(decide) {
addressArray.length = 0;
element.find('.tab-pane').each(function(i) {
var addressData = {};
$(this).find('textarea, input[type="text"]').each(function(j) {
var name = $(this).attr('name'),
val = $(this).val();
addressData[name] = val;
});
addressArray.push(addressData);
});
$.map(addressInputId, function(n, i) {
var v = '';
$('#'+n).find('input[type="hidden"]').each(function() {
$(this).val(addressArray[i][$(this).attr('name')]);
v += addressArray[i][$(this).attr('name')]
});
$('#'+n).find('input[type="text"]').each(function() {
$(this).val(v);
});
});
};
returnDecide = false;
};
$(function() {
appendIndex = null;
if($('#user-forms').length) {
addressVal = [];
addressArray = [];
addressInputId = [];
propertyType = null;
returnDecide = false;
$('.attributes').each(function() {
if($(this).find('.toggle-check').attr('value') == "true") {
$(this).addClass('disabled').children('.attributes-body').hide();
}
});
$('.returnDecide').on(clickEvent, function() {
returnDecide = true;
})
$('#address-field').on('hidden', function () {
$('.btn[data-toggle="modal"]').removeClass('active').blur();
$(this).find('.nav-tabs > li').removeClass('active').eq(0).addClass('active');
$(this).find('.tab-content > .tab-pane').removeClass('active in').eq(0).addClass('active in');
$(this).on('show', getAddressForm(null, $(this), false));
returnAddressForm($(this), returnDecide)
});
$('.control-group').delegate('.btn[data-toggle="modal"]', 'click', function() {
var $trigger = $(this);
addressInputId.length = 0;
$(this).closest('.input-append').find('.tab-pane').each(function() {
addressInputId.push($(this).attr('id'));
});
$('#address-field').on('show', getAddressForm($trigger, $('#address-field'), true));
});
$('#user-forms').delegate('.togglebox, .delete, .trigger, .remove-input', clickEvent, function(event) {
if($(this).hasClass('togglebox')) {
var property_staus = [];
if($(this).hasClass('disable')) {
$(this).find('.toggle-check')
.attr('value', 'false')
.closest('.attributes')
.removeClass('disabled')
.children('.attributes-body')
.fadeIn(300);
} else {
$(this).find('.toggle-check')
.attr('value', 'true')
.closest('.attributes')
.addClass('disabled')
.children('.attributes-body')
.fadeOut(300)
.find('.check')
.attr("checked",false)
.attr("value",property_staus);
}
$(this).toggleClass('disable');
};
if($(this).hasClass('remove-input')) {
$(this).closest('.input-append').fadeOut(300, function() {
$(this).remove();
inputAppendLength();
});
};
if($(this).hasClass('trigger')) {
appendIndex = $(this).closest('.controls').find('.input-append').length;
nameNumber = $(this).closest('.controls').find('.input-append:eq(0)').find('input').eq(0).attr('name');
nameNumber = nameNumber.match(/[^[\D\]]+(?=])/g)[0];
propertyType = $(this).data('properties')
if($(this).hasClass('textInput')) {
$("#template-text").tmpl().appendTo($(this).closest('.controls').find('.add-target'));
} else if ($(this).hasClass('textLengInput')) {
$("#template-text-language").tmpl().appendTo($(this).closest('.controls').find('.add-target'));
} else if ($(this).hasClass('address')) {
$("#template-address").tmpl().appendTo($(this).closest('.controls').find('.add-target'));
}
inputAppendLength();
};
event.preventDefault();
});
inputAppendLength();
} else {
attributesArray = [];
attributesHeaderLength = null;
templateType = null;
attributeIndex = null;
if($('.add-target').length) {
inputAppendLength();
}
if(!$('.attributes').length) {
$('#attributes-area').addClass('clickHere');
} else {
temporary();
};
$('.add-attributes').on(clickEvent, function() {
if($('#attributes-area').hasClass('clickHere')) {
$('#attributes-area').removeClass('clickHere');
};
attributesHeaderLength = $('.attributes:not(:hidden)').length+1;
attributesLength = $('#attributes-area .attributes').length;
if(templateType == null){
templateType = "typeA";
}
$("#template-attributes").tmpl(setData(attributesLength, templateType, appendIndex)).appendTo( "#attributes-area" );
$('.toggle-check').togglebox();
});
$('.attributes.default').each(function(i) {
$(this).children('.field-type').not('.default').hide();
$(this).find('input[type="text"]').on('keyup', function() {
$(this).trigger("checking");
});
$(this).find('input[type="radio"], input[type="checkbox"], select').change(function() {
$(this).trigger("checking");
});
$(this).delegate('input[type="text"], input[type="radio"], input[type="checkbox"], select', 'checking', function(e) {
var e = e.target.type,
$data = $(this).data().type;
switch(e) {
case 'text':
var val = $(this).val();
if(!$(this).closest('.field-type').length) {
$data = attributesArray[i][$data];
} else if(!$(this).closest('.add-target').length) {
$data = attributesArray[i].select[$data];
} else {
appendIndex = $(this).parent('.input-append').index()
optionIndex = $(this).index()
$data = attributesArray[i].select.option[appendIndex][optionIndex];
}
if(val != $data) {
$(this).closest('.attributes').find('.reply').removeClass('hide');
}
break;
case 'radio':
var checked = $(this).prop("checked");
$data = attributesArray[i][$data];
if(checked != $data) {
$(this).closest('.attributes').find('.reply').removeClass('hide');
}
break;
case 'checkbox':
var checked = $(this).prop("checked");
$data = attributesArray[i].select[$data];
if(checked != $data) {
$(this).closest('.attributes').find('.reply').removeClass('hide');
}
break;
case 'select-one':
var ref,
$data = attributesArray[i].select.name;
$(this).children("option:selected").each(function() {
ref = $(this).attr('ref');
});
if(ref != $data) {
$(this).closest('.attributes').find('.reply').removeClass('hide');
}
break;
};
});
$(this).delegate('.reply', clickEvent, function() {
var $bodyText = $(this).parent('.attributes-header').siblings('.attributes-body').find('input[type="text"]'),
$bodyRadio = $(this).parent('.attributes-header').siblings('.attributes-body').find('input[type="radio"]'),
$bodySelected = $(this).parent('.attributes-header').siblings('.attributes-body').find('.dataType').children("option"),
$fieldTypeO = $(this).parent('.attributes-header').siblings('.field-type.default'),
$fieldTypeN = $(this).parent('.attributes-header').siblings('.field-type').not('.default');
$bodyText.each(function() {
var $type = $(this).data().type;
$(this).val(attributesArray[i][$type]);
});
$bodyRadio.each(function() {
var $type = $(this).data().type;
$(this).prop("checked", attributesArray[i][$type])
});
$fieldTypeO.find('input[type="text"]').each(function() {
var $type = $(this).data().type;
if(!$type.match('option_lang')) {
$(this).val(attributesArray[i].select[$type]);
}
});
$fieldTypeO.find('.add-target').find('.input-append').each(function(k) {
$(this).children('input[type="text"]').each(function(j) {
$(this).val(attributesArray[i].select.option[k][j]);
// var val = $(this).val();
// append.push(val);
});
})
$fieldTypeO.find('input[type="checkbox"], input[type="radio"]').each(function() {
var $type = $(this).data().type;
$(this).prop("checked", attributesArray[i].select[$type]);
});
$fieldTypeO.find('select').children("option").eq(attributesArray[i].select.dateFormat).prop('selected',true);
$bodySelected.eq(attributesArray[i].select.index).prop('selected',true);
$fieldTypeO.show();
$fieldTypeN.empty().hide();
$(this).addClass('hide')
return false
})
});
$('#attributes-area').delegate('.togglebox, .delete, .trigger, .remove-input', clickEvent, function(event) {
if($(this).hasClass('togglebox')) {
if($(this).hasClass('disable')) {
$(this).find('.toggle-check')
.attr('value', 'false')
.closest('.attributes')
.removeClass('disabled')
.find('input, select')
.removeAttr('disabled')
.end('.attributes')
.find('.btn-group .btn')
.removeClass('disabled')
.end().find('.attribute_field_disabled').attr('value', 'false');
if($(this).closest('.attributes').find('.dataType').children("option:selected").attr('ref')) {
$(this).closest('.attributes').find('.field-type').addClass('in').find('.control-group').delay(150).fadeIn(300);
}
} else {
$(this).find('.toggle-check')
.attr('value', 'true')
.closest('.attributes')
.addClass('disabled')
.find('.attributes-body input, .attributes-body select')
.attr({'disabled': 'disabled'})
.end('.attributes')
.find('.btn-group .btn')
.addClass('disabled')
.end().find('.attribute_field_disabled').attr('value', 'true')
.end().find('.field-type .control-group').fadeOut(300, function() {
$(this).parent('.field-type').removeClass('in');
});
}
$(this).toggleClass('disable');
};
if($(this).hasClass('delete')) {
$(this).closest('.attributes').fadeOut(300, function() {
$('.attributes:not(:hidden)').each(function(i) {
$(this).find('.attributes-header h4 span').text(i+1);
});
attributesHeaderLength = $('.attributes:not(:hidden)').length+1;
if(!$('.attributes:not(:hidden)').length) {
$('#attributes-area').addClass('clickHere');
};
}).find('.attribute_field_to_delete').attr('value', 'true');;
};
if($(this).hasClass('trigger')) {
// appendIndex = $(this).closest('.controls').find('.input-append').length;
appendIndex = $(this).closest('.controls').find('.input-append:last-child').children('input:first-child').attr('name');
// appendIndex = appendIndex.split("][");
// appendIndex = parseInt(appendIndex[appendIndex.length-2])+1;
appendIndex = parseInt(appendIndex.match(/[^[\D\]]+(?=])/g)[1])+1;
attributeIndex = $(this).closest('.attributes').index();
templateType = $(this).closest('.attributes').find('.dataType').children("option:selected").attr('ref');
$("#template-input-append").tmpl(setData(attributeIndex, templateType, appendIndex)).appendTo($(this).closest('.controls').find('.add-target'));
inputAppendLength();
};
if($(this).hasClass('remove-input')) {
$(this).parent('.input-append').fadeOut(300, function() {
$(this).remove()
inputAppendLength();
});
}
event.preventDefault();
});
$('#attributes-area').delegate('.dataType', 'change', function() {
$(this).children("option:selected").each(function () {
var target = $(this).closest('.attributes').find('.field-type').not('.default');
attributeIndex = $(this).closest('.attributes').index();
appendIndex = 0
// $(this).closest('.attributes').find('.add-target').find('.input-append').length;
if($(this).closest('.attributes').hasClass('default')){
var i = $(this).closest('.attributes').index()
if($(this).attr('ref') == attributesArray[i].select.name) {
$(this).closest('.attributes').find('.field-type.default').show()
target.empty().hide();
} else {
$(this).closest('.attributes').find('.field-type.default').hide()
if($(this).attr('ref')) {
templateType = $(this).attr('ref');
target.removeAttr('class').addClass('field-type fade in ' + templateType).empty();
$("#template-type").tmpl(setData(attributeIndex, templateType, appendIndex)).appendTo(target);
if(templateType == 'typeB' || templateType == 'typeE' || templateType == 'typeF') {
inputAppendLength();
}
} else {
target.removeAttr('class').addClass('field-type fade')
target.empty();
};
target.show();
}
} else {
if($(this).attr('ref')) {
templateType = $(this).attr('ref');
target.removeAttr('class').addClass('field-type fade in ' + templateType).empty();
$("#template-type").tmpl(setData(attributeIndex, templateType, appendIndex)).appendTo(target);
if(templateType == 'typeB' || templateType == 'typeE' || templateType == 'typeF') {
inputAppendLength();
}
} else {
target.removeAttr('class').addClass('field-type fade')
target.empty();
};
}
});
});
}
});

View File

@ -1,8 +1,115 @@
var Calendar = function(dom,property_id){
window.auto_close_popup = false;
$.fn.fullCalendar = function(args){
var self = this[0]
if(!self.calendar_args)
self.calendar_args = args;
else
args = Object.assign(self.calendar_args, args);
var calendar = new FullCalendar.Calendar(self,args);
calendar.render();
$(window).on("load",function(){
calendar.render();
})
this.calendar = calendar;
self.calendar = calendar;
$.fullCalendar = calendar;
return calendar;
};
function correct_date(date){
var new_date = new Date();
new_date.setTime(date.getTime() + date.getTimezoneOffset() * 60 * 1000);
return new_date;
}
FullCalendar.Calendar.prototype.get_all_events = function(){
this.currentData.all_events = [];
var all_events = this.currentData.all_events;
if(this.currentData.eventStore && this.currentData.eventStore.instances){
var instances = this.currentData.eventStore.instances;
Object.keys(instances).forEach(function(k){
var instance = instances[k];
var range = Object.assign({},instance.range);
range.start = correct_date(range.start);
range.end = correct_date(range.end);
all_events.push(range);
})
}
return this.currentData.all_events;
}
FullCalendar.Calendar.prototype.isAnOverlapEvent = function(eventStartDay, eventEndDay){
eventStartDay = eventStartDay || eventEndDay;
eventEndDay = eventEndDay || eventStartDay;
if((typeof(eventStartDay)).toLowerCase() == "string")
eventStartDay = new Date(eventStartDay);
if((typeof(eventEndDay)).toLowerCase() == "string")
eventEndDay = new Date(eventEndDay);
var events = this.get_all_events();
for (var i = 0; i < events.length; i++) {
var eventA = events[i];
// start-time in between any of the events
if (eventStartDay >= eventA.start && eventStartDay <= eventA.end) {
return true;
}
//end-time in between any of the events
if (eventEndDay >= eventA.start && eventEndDay <= eventA.end) {
return true;
}
//any of the events in between/on the start-time and end-time
if (eventStartDay <= eventA.start && eventEndDay >= eventA.end) {
return true;
}
}
return false;
}
window.is_chinese = ( I18n && I18n.locale.indexOf('zh') != -1 );
window.datetime_format = is_chinese ? 'y M d h:m b' : 'd M, y h:m b';
window.date_format = is_chinese ? 'y M d' : 'd M, y';
window.time_format = "h:m b";
window.date_time_str_format = 'y/MM/d H:m';
window.std_date_format = 'y-MM-d';
window.short_day = (is_chinese ? "d (w)" : "w d");
window.short_date = (is_chinese ? "M d (w)" : "w d, M");
window.short_date_time = (is_chinese ? "M d (w) h:m b" : "w d, M h:m b");
window.getDateString = function(date, format,is_chinese) {
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var week_days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
if(is_chinese){
months = [];
for(var i=0;i<12;i++){
months.push((i+1)+"月");
}
week_days = ["週日","週一","週二","週三","週四","週五","週六"]
}
var getPaddedComp = function(comp) {
return ((parseInt(comp) < 10) ? ('0' + comp) : comp)
},
formattedDate = format,
o = {
"y+": date.getFullYear() + (is_chinese ? "年" : ""), // year
"MM+": getPaddedComp(date.getMonth() + 1), //raw month
"M+": months[date.getMonth()], //month
"d+": (is_chinese ? (date.getDate() + "日") : getPaddedComp(date.getDate())), //day
"w+": week_days[date.getDay()], //weekday
"h+": getPaddedComp((date.getHours() > 12) ? date.getHours() % 12 : date.getHours()), //hour
"H+": getPaddedComp(date.getHours()), //hour
"m+": getPaddedComp(date.getMinutes()), //minute
"s+": getPaddedComp(date.getSeconds()), //second
"S+": getPaddedComp(date.getMilliseconds()), //millisecond,
"b+": (date.getHours() >= 12) ? 'PM' : 'AM'
};
c = this;
for (var k in o) {
if (new RegExp("(" + k + ")").test(format)) {
formattedDate = formattedDate.replace(RegExp.$1, o[k]);
}
}
return formattedDate;
};
var Calendar = function(dom, property_id, valid_range, currentView, display_hire_event, locale = "en"){
var c = this;
display_hire_event = (display_hire_event == undefined ? true : display_hire_event);
this.locale = locale.replace("_","-");
this.title = $("#current_title");
this.calendar = $(dom);
this.calendar_dom = $(dom);
this.nextBtn = $("#next_month_btn");
this.prevBtn = $("#prev_month_btn");
this.todayBtn = $("#today_btn");
@ -11,7 +118,7 @@ var Calendar = function(dom,property_id){
this.dialog = new EventDialog(c);
this.loading = $('#calendar-loading');
this.agenda_space = $("#calendar_agenda");
this.currentView = "month";
this.currentView = currentView || "dayGridMonth";
this.property_id = property_id;
this.navigation = $("#navigation");
this.rangeSelection = $("#range_selection");
@ -22,43 +129,105 @@ var Calendar = function(dom,property_id){
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
var dview = (c.currentView == "agenda" ? "month" : c.currentView);
c.calendar.fullCalendar({
var dview = (c.currentView == "agenda" ? "dayGridMonth" : c.currentView);
c.calendar_dom.css("overflow","visible");
c.calendar_dom.fullCalendar({
themeSystem: 'bootstrap',
editable: false,
selectable: false,
events: "/xhr/property_hires/get_bookings?property_id="+c.property_id,
header: false,
default: dview,
height: $("body").height() - 141,
selectable: true,
width: "100%",
validRange: valid_range,
locale: c.locale,
events: function(args, success_callback, fail_callback) {
var start = args.start;
var end = args.end;
$.ajax({
url: "/xhr/property_hires/get_bookings?property_id="+c.property_id,
dataType: 'json',
type: 'GET',
data: {
start: Math.round(start.getTime() / 1000),
end: Math.round(end.getTime() / 1000),
_: Date.now(),
display_hire_event: display_hire_event
},
success: function(json) {
// json = json.map(function(obj){
// obj.start = new Date(obj.start).toJSON();
// obj.end = new Date(obj.end).toJSON();
// return obj;
// })
success_callback(json);
}
});
},
// events: 'https://fullcalendar.io/demo-events.json',
headerToolbar: false,
fixedWeekCount: false,
initialView: dview,
loading: function(bool) {
if (bool) c.loading.css("left",($(window).width()/2 - 60) + "px").show();
if (bool) c.loading.show();
else c.loading.hide();
if(this.currentData)
$('#current_title').html(this.currentData.viewTitle);
},
windowResize : function(view){
view.setHeight($("body").height() - 141);
c.calendar.fullCalendar("refetchEvents");
c.calendar_dom.calendar.refetchEvents();
},
viewDisplay: function(view) {
c.title.html(view.title);
},
eventClick: function(calEvent, e, view) {
eventTimeFormat: { hour12: true, hour: '2-digit', minute: '2-digit', omitZeroMinute: true, meridiem: 'narrow' },
eventClick: function(eventClickInfo) {
var calEvent = {"event": eventClickInfo.event},
originalEvent = eventClickInfo.jsEvent,
view = eventClickInfo.view,
el = $(eventClickInfo.el);
if(el.hasClass("reserve_btn")){
window.calEvent = calEvent;
var start_time = calEvent.event.start;
var date_str = window.getDateString(start_time,std_date_format);
c.dialog.hide();
var allow_times = calEvent.event._def.extendedProps.allow_times;
window.pick_hire_date(date_str,allow_times);
}else{
c.dialog.dismiss();
c.dialog.inflate(calEvent);
c.dialog.show({"x":e.originalEvent.clientX,"y":e.originalEvent.clientY});
c.dialog.show({"x": originalEvent.clientX,"y": originalEvent.clientY});
}
},
dateClick: function(ev) {
var calendar = this;
var calendar_dom = $(this.el);
if(c.calendar_dom.hasClass("active_picker")){
var date = ev.date,
date_str = getDateString(date,date_time_str_format),
day_element = ev.dayEl,
jsEvent = ev.jsEvent;
var time_str = date_str.split(" ")[1];
var date_str = date_str.split(" ")[0];
calendar_dom.trigger("init_time",[time_str]);
calendar_dom.trigger("select_time",[date_str]);
}
},
views: {
dayGridMonth: {
dayMaxEvents: true
}
}
});
c.nextBtn.click(function(){
c.dialog.dismiss();
c.calendar.fullCalendar('next');
c.calendar_dom.calendar.next();
c.title.text(c.calendar_dom.calendar.currentData.viewTitle);
});
c.prevBtn.click(function(){
c.dialog.dismiss();
c.calendar.fullCalendar('prev');
c.calendar_dom.calendar.prev();
c.title.text(c.calendar_dom.calendar.currentData.viewTitle);
});
c.todayBtn.click(function(){
c.dialog.dismiss();
c.calendar.fullCalendar('today');
c.calendar_dom.calendar.today();
c.title.text(c.calendar_dom.calendar.currentData.viewTitle);
});
c.modeBtns.click(function(){
c.dialog.dismiss();
@ -69,7 +238,7 @@ var Calendar = function(dom,property_id){
if(c.currentView == "agenda")
agendaView.refresh();
else
c.calendar.fullCalendar("refetchEvents");
c.calendar_dom.calendar.refetchEvents();
});
var toggleViews = function(view){
@ -77,7 +246,7 @@ var Calendar = function(dom,property_id){
c.modeBtns.each(function(){
if ($(this).data("mode") == view)
$(this).addClass("active");
})
});
if(view != "agenda"){
if(c.currentView == "agenda"){
// $("#sec1").addClass("span3").removeClass("span7");
@ -85,7 +254,7 @@ var Calendar = function(dom,property_id){
// $("#sec3").addClass("span4").removeClass("span5");
agendaView.hide();
}
c.calendar.fullCalendar('changeView',view);
c.calendar_dom.calendar.changeView(view);
}else{
// $("#sec1").addClass("span7").removeClass("span3");
$("#sec2").hide();
@ -94,84 +263,156 @@ var Calendar = function(dom,property_id){
}
c.currentView = view;
if(loadeventsonviewchange){
c.calendar.fullCalendar("refetchEvents");
c.calendar_dom.calendar.refetchEvents();
loadeventsonviewchange = false;
}
if(c.calendar_dom.calendar.currentData){
var viewTitle = c.calendar_dom.calendar.currentData.viewTitle;
if(view == "timeGridDay" && $('.fc-col-header-cell-cushion ').text() != "")
viewTitle = $('.fc-col-header-cell-cushion ').text() + ', ' + viewTitle;
$('#current_title').html(viewTitle);
}
c.title.text(c.calendar_dom.calendar.currentData.viewTitle);
// c.calendar_dom.calendar.rerenderEvents(); //Rerender to fix layout
};
if(c.currentView == "agenda"){toggleViews("agenda");loadeventsonviewchange = true;}
};
this.destroy = function () {
c.calendar_dom.fullCalendar("destroy");
}
this.renderEvent = function(eventStick){
if(eventStick.recurring == true)
c.calendar.fullCalendar("refetchEvents");
if(eventStick.recurring === true)
c.calendar_dom.calendar.refetchEvents();
else
c.calendar.fullCalendar("renderEvent",eventStick);
}
c.calendar_dom.calendar.addEvent(eventStick);
};
$(document).ready(function() {
c.initialize();
});
}
};
var EventDialog = function(calendar,event){
_t = this;
var event_quick_view = null;
var template = "";
var _this_event = null;
var month_names = ["Jan","Feb","March","April","May","June","July","Aug","Sep","Oct","Nov","Dec"];
this.inflate = function(_event){
if(!_event) throw new UserException("EventStick can't be null!");
_event.allDay = _event.event.allDay;
_event._start = _event.event.start;
_event._end = (_event.event.end ? _event.event.end : _event.event.start);
// var start_date = getDateString(_event._start,date_format);
// var end_date = getDateString(_event._end,date_format);
if(_event._end - _event._start > 86400 * 1000){
_event.allDay = true;
}
_event.title = _event.event.title;
var extendedProps = _event.event.extendedProps;
Object.keys(extendedProps).forEach(function(k){
_event[k] = extendedProps[k];
})
if(!_event.hiring_person_name)
_event.hiring_person_name = "";
_this_event = _event;
var start_time = "",
end_time = "",
time_string = null;
if(_event.allDay) {
start_time = $.fullCalendar.formatDate(_event._start,"MMM dd, yyyy");
start_time = getDateString(_event._start,datetime_format, is_chinese);
if(_event._end)
end_time = $.fullCalendar.formatDate(_event._end,"MMM dd, yyyy");
time_string = (_event._start === _event._end || !_event._end ? "<p class='start-date'><i class='icons-calendar' /> " + start_time + "</p>" : "<i class='icons-calendar' /> " + start_time + " <i class='icons-arrow-right-5' /> " + end_time + "");
end_time = getDateString(_event._end,datetime_format, is_chinese);
time_string = (_event._start === _event._end || !_event._end ? "<p class='start-date'><i class='icons-calendar' /></i>" + start_time + "</p>" : "<i class='icons-calendar' /></i>" + start_time + "<br><i class='icons-arrow-right-5' /></i>" + end_time + "");
} else {
var sh = _event._start.getHours() > 12 ? _event._start.getHours() - 12 : _event._start.getHours(),
eh = _event._end.getHours() > 12 ? _event._end.getHours() - 12 : _event._end.getHours(),
sm = _event._start.getMinutes() < 10 ? '0' + _event._start.getMinutes() : _event._start.getMinutes(),
em = _event._end.getMinutes() < 10 ? '0' + _event._end.getMinutes() : _event._end.getMinutes(),
stime = _event._start.getHours() > 12 ? sh + ':' + sm + " PM" : sh + ':' + sm + " AM",
etime = _event._end.getHours() > 12 ? eh + ':' + em + " PM" : eh + ':' + em + " AM",
same = (_event._start.getDate() == _event._end.getDate() && _event._start.getMonth() == _event._end.getMonth() && _event._start.getFullYear() == _event._end.getFullYear());
start_time = month_names[_event._start.getMonth()] + " " + _event._start.getDate() + ", " + _event._start.getFullYear();
end_time = month_names[_event._end.getMonth()] + " " + _event._end.getDate() + ", " + _event._end.getFullYear();
time_string = (same ? "<p class='date'><i class='icons-calendar' /> " + start_time + "</p><p class='time'><i class='icons-clock' /> " + stime + " <i class='icons-arrow-right-5' /> " + etime : "<p class='start-date'><i class='icons-arrow-right-2' /> " + start_time + "<span class='pull-right'>" + stime + "</span></p><p class='end-date'><i class='icons-arrow-left-2' /> " + end_time + "<span class='pull-right'>" + etime + "</p>");
start_time = getDateString(_event._start,date_format, is_chinese);
end_time = getDateString(_event._end,date_format, is_chinese);
var stime = getDateString(_event._start,time_format, is_chinese),
etime = getDateString(_event._end,time_format, is_chinese),
same = (start_time == end_time);
if( same ){
time_string = "<p class='date'><i class='icons-calendar' /></i> " +
start_time +
"</p><p class='time'><i class='icons-clock' /></i> " + stime +
" <i class='icons-arrow-right-5' /></i> " + etime ;
}else{
time_string = "<i class='icons-calendar' /></i><span class='start-date'>" + start_time + " " + stime +
"</span><br><i class='icons-arrow-right-5' /></i><span class='end-date'>" +
end_time + " " + etime + "</span>"
}
// time_string = (same ? "<p class='date'><i class='icons-calendar' /> " + start_time + "</p><p class='time'><i class='icons-clock' /> " + stime + " <i class='icons-arrow-right-5' /> " + etime : "<p class='start-date'><i class='icons-arrow-right-2' /> " + start_time + "<span class='pull-right'>" + stime + "</span></p><p class='end-date'><i class='icons-arrow-left-2' /> " + end_time + "<span class='pull-right'>" + etime + "</p>");
}
event_quick_view = $('<div class="calendar-modal" style="display:none;"></div>');
template = '<div class="modal-content">' +
'<div class="modal-header">' +
'<div class="property_title">' + _event.property_title + '</div>' +
'<button type="button" class="close event-close-btn" data-dismiss="modal" aria-hidden="true">&times;</button>' +
'<h3>' + _event.title + '</h3>' +
'</div>' +
'<div class="modal-body">' +
'<div class="event_summary">' + time_string + '<br>' + _event.hiring_person_name + '</div>'
_event.note +
'<div class="event_summary">' + time_string + '</br>' + _event.hiring_person_name + '</div>' + _event.note +
(_event.error_message ? ("<br><span style=\"color: #FC4040;\">" + _event.error_message + "</span>") : "") +
'</div>' +
'<div class="modal-footer" />' +
'<div class="modal-footer">' +
(_event.view_button ? '<a href="' + _event.view_path + '" class="btn view-btn">'+ _event.view_path_name +'</a>' : "") +
'</div>'
'</div>';
}
this.show = function(pos){
event_quick_view.css({display: 'inline-block',width: '',height: '', position: "fixed", "z-index": "10000"});
var offset;
var padding = 20;
if(pos){
offset = {"left":pos.x,"top":pos.y};
var pos = getPosition(pos);
event_quick_view.css({"left":pos.x+"px","top":pos.y+"px"});
event_quick_view.offset(offset);
}else{
offset = {"left": padding, "top": padding};
}
event_quick_view.html(template).appendTo("body").show();
event_quick_view.find(".event-close-btn").one("click",function(){_t.dismiss();});
event_quick_view.find("a.delete").one("click",function(){calendar.deleteEvent(_this_event.delete_url,_this_event._id);return false;});
event_quick_view.find("a.edit").one("click",function(){calendar.editEvent(_this_event.edit_url,_this_event.allDay);return false;});
var window_width = $(window).width(),
window_height = $(window).height();
var dialog_width = event_quick_view.width(),
dialog_height = event_quick_view.height();
var new_offset = Object.assign({},offset);
var need_redisplay = false;
var new_width = null, new_height = null;
var padding_top = padding + 40;
if(offset.left + dialog_width > window_width){
new_offset.left = window_width - dialog_width - padding;
need_redisplay = true;
}
if(new_offset.left < padding){
new_width = dialog_width - (padding - new_offset.left);
new_offset.left = padding;
need_redisplay = true;
}
if(offset.top + dialog_height > window_height){
new_offset.top = window_height - dialog_height - padding;
need_redisplay = true;
}
if(new_offset.top < padding_top){
new_height = dialog_height - (padding_top - new_offset.top);
new_offset.top = padding_top;
need_redisplay = true;
}
if(need_redisplay){
event_quick_view.offset(new_offset);
event_quick_view.width(new_width);
event_quick_view.height(new_height);
}
}
this.hide = function(){
calendar.calendar_dom.find('.fc-popover-close').click();
$(event_quick_view).hide();
}
this.dismiss = function(){
if(event_quick_view)
event_quick_view.remove();
@ -239,6 +480,7 @@ var AgendaView = function(calendar){
'<th>Date</th>' +
'<th>Time</th>' +
'<th>Events</th>' +
'<th>Borrower</th>' +
'</tr>' +
'</thead>' +
'<tbody>' +
@ -251,11 +493,9 @@ var AgendaView = function(calendar){
var head_template = '<div>' +
'<label>From</label>' +
'<select name="start_month" class="form-control input-sm" />' +
'<select name="start_year" class="form-control input-sm" />' +
'<input class="input-large" id="agenda_start" placeholder="YYYY/MM" type="text" value="'+start_year+'/'+('0'+(start_month+1)).substr(-2,2)+'" title="YYYY/MM" autocomplete="off">'+
'<label>To</label>' +
'<select name="end_month" class="form-control input-sm" />' +
'<select name="end_year" class="form-control input-sm" />' +
'<input class="input-large" id="agenda_end" placeholder="YYYY/MM" type="text" value="'+end_year+'/'+('0'+(end_month+1)).substr(-2,2)+'" title="YYYY/MM" autocomplete="off">'+
'<button id="show_events" class="btn btn-sm bt-filter btn-primary">Show Events</button>' +
'</div>';
@ -265,6 +505,7 @@ var AgendaView = function(calendar){
'<td>' +
'<div class="event" />' +
'</td>' +
'<td class="Borrower">'+
'</tr>';
// var month_template = '<div class="span4"><h4></h4><div class="tiny_calendar"><table class="table"><tbody><tr><th class="week_title">Sun</th><th class="week_title">Mon</th><th class="week_title">Tue</th><th class="week_title">Wed</th><th class="week_title">Thu</th><th class="week_title">Fri</th><th class="week_title">Sat</th></tr></tbody></table></div></div>';
@ -283,7 +524,7 @@ var AgendaView = function(calendar){
this.inflate = function(forceInflation){
loading(true);
_calendar.calendar.hide();
_calendar.calendar_dom.hide();
_calendar.navigation.hide();
if(!forceInflation){
@ -300,10 +541,12 @@ var AgendaView = function(calendar){
_calendar.rangeSelection.append(renderHead().html()).show();
_calendar.rangeSelection.find("button#show_events").click(function(){
show_event_clicked = true;
start_month = parseInt($("select[name=start_month]").val());
end_month = parseInt($("select[name=end_month]").val());
start_year = parseInt($("select[name=start_year]").val());
end_year = parseInt($("select[name=end_year]").val());
var starts = $("#agenda_start").val().split("/"),
ends = $("#agenda_end").val().split("/");
start_month = parseInt(starts[1]) - 1;
end_month = parseInt(ends[1]) - 1;
start_year = parseInt(starts[0]);
end_year = parseInt(ends[0]);
av.inflate(true);
})
}
@ -337,7 +580,7 @@ var AgendaView = function(calendar){
_calendar.rangeSelection.hide();
agenda_space.hide();
_calendar.navigation.show();
_calendar.calendar.show();
_calendar.calendar_dom.show();
}
this.show = function(){
@ -348,7 +591,7 @@ var AgendaView = function(calendar){
return x.clone();
}
var eventsManager = function(){
var url = "/xhr/calendars/agenda",
var url = "/xhr/property_hires/get_bookings?property_id="+_calendar.property_id,
sd = new Date(start_year,start_month,1),
ed = new Date(end_year,end_month+1,0),
usd = Math.round(sd/1000),
@ -356,9 +599,39 @@ var AgendaView = function(calendar){
$.ajax({
type : "get",
url : url,
data : {"agenda_start":sd.toLocaleString(),"agenda_end":ed.toLocaleString(),"page_id" : _calendar.page_id,"unix_start":usd,"unix_end":ued},
dataType : "json",
data : {"agenda_start":sd.toLocaleString(),"agenda_end":ed.toLocaleString(),"page_id" : _calendar.page_id,"start":usd,"end":ued},
success : function(data){
$.each(data.events,function(i,e){
$("#agenda_start,#agenda_end").datepicker({
dateFormat: "yy/mm",
onChangeMonthYear: function( year, month, inst ){
$(this).val($.datepicker.formatDate('yy/mm', new Date(year, month-1, 1)));
},
gotoCurrent: true
});
$("#agenda_start,#agenda_end").on("focus",function(){
var input = this;
var inst = $(this).data("datepicker");
var year_month = $(input).val().split("/");
if(year_month.length == 2){
inst.selectedYear = parseInt(year_month[0]);
inst.selectedMonth = parseInt(year_month[1]) - 1;
inst.drawYear = inst.selectedYear;
inst.drawMonth = inst.selectedMonth;
inst.currentYear = inst.selectedYear;
inst.currentMonth = inst.selectedMonth;
}
$.datepicker._updateDatepicker(inst);
})
$("#agenda_start,#agenda_end").focus(function () {
$(".ui-datepicker-calendar").hide();
$("#ui-datepicker-div").position({
my: "center top",
at: "center bottom",
of: $(this)
});
});
$.each(data,function(i,e){
var ed = eventDom(e),
s = new Date(e.start),
e = new Date(e.end),
@ -415,14 +688,16 @@ var AgendaView = function(calendar){
var e_t = $(event_template),
s = new Date(event.start),
e = new Date(event.end),
dateFormat = "";
dateFormat = "",
hiring_person_name = event.hiring_person_name;
if(s.getDate() == e.getDate() && s.getMonth() == s.getMonth() && e.getFullYear() == e.getFullYear())
dateFormat = $.fullCalendar.formatDate(s, "ddd dd");
dateFormat = getDateString(s, short_day,is_chinese);
else
dateFormat = $.fullCalendar.formatDates(s, e, "ddd dd, MMM - {ddd dd, MMM}");
dateFormat = getDateString(s,short_date,is_chinese) + ' - ' + getDateString(e,short_date,is_chinese);
e_t.find("td:first").text(dateFormat);
e_t.find("td.event_time").text((event.allDay ? "All Day" : $.fullCalendar.formatDate(s, "hh:mm")));
e_t.find("div.event").text(event.title).css("color",event.color);
e_t.find("td.event_time").text((event.diff_day ? (getDateString(s, short_date_time,is_chinese)+"~"+getDateString(e, short_date_time, is_chinese)) : (getDateString(s, time_format)+"~"+getDateString(e, time_format))));
e_t.find("div.event").html(event.title).css("color",event.color);
e_t.find("td.Borrower").text(hiring_person_name);
return e_t;
}
@ -565,33 +840,3 @@ var AgendaView = function(calendar){
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

15303
app/assets/javascripts/tmp.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,140 @@
.card {
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
background-color: #fff;
background-clip: border-box;
border: 1px solid rgba(0,0,0,.125);
border-radius: .25rem;
}
.card hr {
margin-right: 0;
margin-left: 0;
}
.card-header {
padding: .75rem 1.25rem;
margin-bottom: 0;
background-color: rgba(0,0,0,.03);
border-bottom: 1px solid rgba(0,0,0,.125);
}
.card-header:first-child {
border-radius: calc(.25rem - 1px) calc(.25rem - 1px) 0 0;
}
.card-body {
align-items: normal;
-webkit-box-flex: 1;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
padding: 1.25rem;
}
.card-title {
margin-bottom: .75rem;
}
.card-header + .list-group .list-group-item:first-child {
border-top: 0;
}
.card-text:last-child {
margin-bottom: 0;
}
.card-footer {
padding: .75rem 1.25rem;
background-color: rgba(0,0,0,.03);
border-top: 1px solid rgba(0,0,0,.125);
}
.card-footer:last-child {
border-radius: 0 0 calc(.25rem - 1px) calc(.25rem - 1px);
}
.card-group {
display: flex;
flex-direction: column;
// The child selector allows nested `.card` within `.card-group`
// to display properly.
> .card {
margin-bottom: 0.9375em;
}
@media screen and (min-width: 576px) {
flex-flow: row wrap;
// The child selector allows nested `.card` within `.card-group`
// to display properly.
> .card {
flex: 1 0 0%;
margin-bottom: 0;
+ .card {
margin-left: 0;
border-left: 0;
}
&:first-child {
border-right-radius: 0;
.card-img-top,
.card-header {
border-top-right-radius: 0;
}
.card-img-bottom,
.card-footer {
border-bottom-right-radius: 0;
}
}
&:last-child {
border-left-radius: 0;
.card-img-top,
.card-header {
border-top-left-radius: 0;
}
.card-img-bottom,
.card-footer {
border-bottom-left-radius: 0;
}
}
&:only-child {
border-radius: .25rem;
.card-img-top,
.card-header {
border-top-radius: .25rem;
}
.card-img-bottom,
.card-footer {
border-radius: .25rem;
}
}
&:not(:first-child):not(:last-child):not(:only-child) {
border-radius: 0;
.card-img-top,
.card-img-bottom,
.card-header,
.card-footer {
border-radius: 0;
}
}
}
}
}

View File

@ -0,0 +1,79 @@
/*reset*/
h1, h2, h3, h4, h5, p{
margin: 0;
padding: 0;
}
br{
display: block;
margin: 0 0 5px;
}
ol, ul{
margin: 0;
padding: 0;
}
li{
list-style: none;
}
body > img {
display: none;
}
img{
border: none;
padding: 0;
margin: 0;
}
a {
outline: none;
text-decoration: none !important;
}
table, tr, td{
padding: 0;
border-spacing: 0;
}
/*reset end *//* CSS Document */
#property_order_table{
border-collapse: unset !important;
position: relative;
width: 593px;
margin: 40px auto;
}
#property_order_table th{
background-color: #454545;
color: #fff;
}
.position-text{
position: relative;
width: 85px;
}
#property_order_table .editable-input{
position: relative;
width: 25px;
margin-bottom: 0;
padding: 0px 0px 0px 5px;
}
.position-text-div{
height: 22px;
}
.order-edit-notification{
background-color: #ffffd5;
z-index: 10;
display: none;
height: 25px;
left: 40%;
position: fixed;
text-align: center;
margin-top: 5px;
top: 85px;
width: 400px;
font-size: 13px;
}

View File

@ -1,3 +1,18 @@
#hire_form label.col-sm-4.control-label{
padding-left: 0;
padding-right: 0;
}
#calendar.active_picker .fc-scrollgrid-sync-inner,#calendar.active_picker .fc-timegrid-slot{
cursor: pointer;
}
#calendar.active_picker{
.fc-scrollgrid-sync-inner:hover, .fc-timegrid-slot:hover{
background: var(--fc-highlight-color, rgba(188, 232, 241, 0.3));
}
}
a.reserve_btn{
cursor: pointer;
}
/* orbit calendar */
#orbit_calendar {
transition: all 0.3s ease;
@ -96,7 +111,9 @@
& > * {
margin: 0 5px;
}
& > select {
height: 3em;
}
@media screen and (max-width: 479px) {
margin-right: 0;
@ -253,6 +270,9 @@
.event_list td {
padding: 0;
}
.event_list th {
width: 25%;
}
}
.event_holder {
@ -627,8 +647,9 @@
}
#calendar-loading {
position: absolute;
top: 40%;
position: fixed;
top: 50%;
left: 50%;
z-index: 10;
width: 120px;
height: 120px;
@ -636,11 +657,12 @@
border-radius: 4px;
border: 1px solid #dbdbdb;
background-color: rgba(255, 255, 255, 0.95);
background-image: url("/assets/loading1.gif");
background-image: url("/assets/property_hire/loading1.gif");
background-repeat: no-repeat;
background-position: center 20px;
background-size: 50%;
box-shadow: 0 0 25px 0 rgba(0, 0, 0, 0.2);
transform: translate(-50%, -50%);
&:after {
content: "Loading...";
@ -691,7 +713,7 @@
.calendar-modal {
position: fixed;
z-index: 1050;
z-index: 10000;
width: 300px;
margin: 0;
font-size: 12px;
@ -739,3 +761,369 @@
height: auto;
}
}
/* fullcalendar custom css */
.table-bordered th, .table-bordered td {
border: 1px solid #dee2e6;
}
.fc .fc-event,
.fc .fc-scrollgrid table tr {
-moz-column-break-inside: avoid;
break-inside: avoid;
}
.fc-media-print {
display: block; /* undo flexbox. FF doesn't know how to flow */
max-width: 100% /* width will be hardcoded too */
}
.fc-media-print .fc-timegrid-slots,
.fc-media-print .fc-timegrid-axis-chunk,
.fc-media-print .fc-timeline-slots,
.fc-media-print .fc-non-business,
.fc-media-print .fc-bg-event {
display: none;
}
.fc-media-print .fc-toolbar button,
.fc-media-print .fc-h-event,
.fc-media-print .fc-v-event {
color: #000 !important;
background: #fff !important;
}
.fc-media-print .fc-event,
.fc-media-print .fc-event-main { /* often controls the text-color */
color: #000 !important;
}
.fc-media-print .fc-timegrid-event {
margin: 0.5em 0;
}
.fc .fc-timeline-body {
min-height: 100%;
position: relative;
z-index: 1; /* scope slots, bg, etc */
}
/*
vertical slots in both the header AND the body
*/
.fc .fc-timeline-slots {
position: absolute;
z-index: 1;
top: 0;
bottom: 0
}
.fc .fc-timeline-slots > table {
height: 100%;
}
.fc {
/* border for both header AND body cells */
}
.fc .fc-timeline-slot-minor {
border-style: dotted;
}
.fc {
/* header cells (aka "label") */
}
.fc .fc-timeline-slot-frame {
display: flex;
align-items: center; /* vertical align */
justify-content: center; /* horizontal align */
overflow: hidden; /* important so text doesn't bleed out and cause extra scroll */
}
.fc .fc-timeline-header-row-chrono { /* a row of times */
}
.fc .fc-timeline-header-row-chrono .fc-timeline-slot-frame {
justify-content: flex-start; /* horizontal align left or right */
}
.fc .fc-timeline-slot-cushion {
padding: 4px 5px; /* TODO: unify with fc-col-header? */
white-space: normal;
}
.fc {
/* NOTE: how does the top row of cells get horizontally centered? */
/* for the non-chrono-row, the fc-sticky system looks for text-align center, */
/* and it's a fluke that the default browser stylesheet already does this for <th> */
/* TODO: have StickyScrolling look at natural left coord to detect centeredness. */
}
/* only owns one side, so can do dotted */
.fc-direction-ltr .fc-timeline-slot { border-right: 0 !important }
.fc-direction-rtl .fc-timeline-slot { border-left: 0 !important }
.fc .fc-timeline-now-indicator-container {
position: absolute;
z-index: 4;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 0;
}
.fc .fc-timeline-now-indicator-arrow,
.fc .fc-timeline-now-indicator-line {
position: absolute;
top: 0;
border-style: solid;
border-color: red;
border-color: var(--fc-now-indicator-color, red);
}
.fc .fc-timeline-now-indicator-arrow {
margin: 0 -6px; /* 5, then one more to counteract scroller's negative margins */
/* triangle pointing down. TODO: mixin */
border-width: 6px 5px 0 5px;
border-left-color: transparent;
border-right-color: transparent;
}
.fc .fc-timeline-now-indicator-line {
margin: 0 -1px; /* counteract scroller's negative margins */
bottom: 0;
border-width: 0 0 0 1px;
}
.fc {
/* container */
}
.fc .fc-timeline-events {
position: relative;
z-index: 3;
width: 0; /* for event positioning. will end up on correct side based on dir */
}
.fc {
/* harness */
}
.fc .fc-timeline-event-harness,
.fc .fc-timeline-more-link {
position: absolute;
top: 0; /* for when when top can't be computed yet */
/* JS will set tht left/right */
}
/* z-index, scoped within fc-timeline-events */
.fc-timeline-event { z-index: 1 }
.fc-timeline-event.fc-event-mirror { z-index: 2 }
.fc-timeline-event {
position: relative; /* contains things. TODO: make part of fc-h-event and fc-v-event */
display: flex; /* for v-aligning start/end arrows and making fc-event-main stretch all the way */
align-items: center;
border-radius: 0;
padding: 2px 1px;
margin-bottom: 1px;
font-size: .85em;
font-size: var(--fc-small-font-size, .85em)
/* time and title spacing */
/* ---------------------------------------------------------------------------------------------------- */
}
.fc-timeline-event .fc-event-main {
flex-grow: 1;
flex-shrink: 1;
min-width: 0; /* important for allowing to shrink all the way */
}
.fc-timeline-event .fc-event-time {
font-weight: bold;
}
.fc-timeline-event .fc-event-time,
.fc-timeline-event .fc-event-title {
white-space: normal;
padding: 0 2px;
}
/* move 1px away from slot line */
.fc-direction-ltr .fc-timeline-event.fc-event-end,
.fc-direction-ltr .fc-timeline-more-link {
margin-right: 1px;
}
.fc-direction-rtl .fc-timeline-event.fc-event-end,
.fc-direction-rtl .fc-timeline-more-link {
margin-left: 1px;
}
/* make event beefier when overlap not allowed */
.fc-timeline-overlap-disabled .fc-timeline-event {
padding-top: 5px;
padding-bottom: 5px;
margin-bottom: 0;
}
/* arrows indicating the event continues into past/future */
/* ---------------------------------------------------------------------------------------------------- */
/* part of the flexbox flow */
.fc-timeline-event:not(.fc-event-start):before,
.fc-timeline-event:not(.fc-event-end):after {
content: "";
flex-grow: 0;
flex-shrink: 0;
opacity: .5;
/* triangle. TODO: mixin */
width: 0;
height: 0;
margin: 0 1px;
border: 5px solid #000; /* TODO: var */
border-top-color: transparent;
border-bottom-color: transparent;
}
/* pointing left */
.fc-direction-ltr .fc-timeline-event:not(.fc-event-start):before,
.fc-direction-rtl .fc-timeline-event:not(.fc-event-end):after {
border-left: 0;
}
/* pointing right */
.fc-direction-ltr .fc-timeline-event:not(.fc-event-end):after,
.fc-direction-rtl .fc-timeline-event:not(.fc-event-start):before {
border-right: 0;
}
/* +more events indicator */
/* ---------------------------------------------------------------------------------------------------- */
.fc-timeline-more-link {
font-size: .85em;
font-size: var(--fc-small-font-size, .85em);
color: inherit;
color: var(--fc-more-link-text-color, inherit);
background: #d0d0d0;
background: var(--fc-more-link-bg-color, #d0d0d0);
padding: 1px;
cursor: pointer;
}
.fc-timeline-more-link-inner { /* has fc-sticky */
display: inline-block;
left: 0;
right: 0;
padding: 2px;
}
.fc .fc-timeline-bg { /* a container for bg content */
position: absolute;
z-index: 2;
top: 0;
bottom: 0;
width: 0;
left: 0; /* will take precedence when LTR */
right: 0; /* will take precedence when RTL */ /* TODO: kill */
}
.fc .fc-timeline-bg .fc-non-business { z-index: 1 }
.fc .fc-timeline-bg .fc-bg-event { z-index: 2 }
.fc .fc-timeline-bg .fc-highlight { z-index: 3 }
.fc .fc-timeline-bg-harness {
position: absolute;
top: 0;
bottom: 0;
}
.fc .fc-resource-timeline-divider {
width: 3px; /* important to have width to shrink this cell. no cross-browser problems */
cursor: col-resize;
}
.fc {
/* will match horizontal groups in the datagrid AND group lanes in the timeline area */
}
.fc .fc-resource-timeline .fc-resource-group:not([rowspan]) {
background: rgba(208, 208, 208, 0.3);
background: var(--fc-neutral-bg-color, rgba(208, 208, 208, 0.3));
}
.fc .fc-timeline-lane-frame {
position: relative; /* contains the fc-timeline-bg container, which liquidly expands */
/* the height is explicitly set by row-height-sync */
}
.fc .fc-timeline-overlap-enabled .fc-timeline-lane-frame .fc-timeline-events { /* has height set on it */
box-sizing: content-box; /* padding no longer part of height */
padding-bottom: 10px; /* give extra spacing underneath for selecting */
}
/* hack to make bg expand to lane's full height in resource-timeline with expandRows (#6134) */
.fc-timeline-body-expandrows td.fc-timeline-lane {
position: relative;
}
.fc-timeline-body-expandrows .fc-timeline-lane-frame {
position: static;
}
/* the "frame" */
.fc-datagrid-cell-frame-liquid {
height: 100%; /* needs liquid hack */
}
.fc-liquid-hack .fc-datagrid-cell-frame-liquid {
height: auto;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.fc {
/* the "frame" in a HEADER */
/* needs to position the column resizer */
/* needs to vertically center content */
}
.fc .fc-datagrid-header .fc-datagrid-cell-frame {
position: relative; /* for resizer */
display: flex;
justify-content: flex-start; /* horizontal align (natural left/right) */
align-items: center; /* vertical align */
}
.fc {
/* the column resizer (only in HEADER) */
}
.fc .fc-datagrid-cell-resizer {
position: absolute;
z-index: 1;
top: 0;
bottom: 0;
width: 5px;
cursor: col-resize;
}
.fc {
/* the cushion */
}
.fc .fc-datagrid-cell-cushion {
padding: 8px;
white-space: normal;
overflow: hidden; /* problem for col resizer :( */
}
.fc {
/* expander icons */
}
.fc .fc-datagrid-expander {
cursor: pointer;
opacity: 0.65
}
.fc .fc-datagrid-expander .fc-icon { /* the expander and spacers before the expander */
display: inline-block;
width: 1em; /* ensure constant width, esp for empty icons */
}
.fc .fc-datagrid-expander-placeholder {
cursor: auto;
}
.fc .fc-resource-timeline-flat .fc-datagrid-expander-placeholder {
display: none;
}
.fc-direction-ltr .fc-datagrid-cell-resizer { right: -3px }
.fc-direction-rtl .fc-datagrid-cell-resizer { left: -3px }
.fc-direction-ltr .fc-datagrid-expander { margin-right: 3px }
.fc-direction-rtl .fc-datagrid-expander { margin-left: 3px }

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +1,87 @@
class Admin::PropertyHiresController < OrbitAdminController
include Admin::PropertyHiresHelper
def index
@tags = @module_app.tags
@categories = @module_app.categories.enabled
@filter_fields = filter_fields(@categories, @tags)
@table_fields = ["property_hire.title", :category, "property_hire.location", "property_hire.available_for_hire"]
@properties = Property.where(:title.ne => "")
.order_by(sort)
@properties = Property.order_by(sort)
.with_categories(filters("category"))
.with_tags(filters("tag"))
@properties = search_data(@properties,[:title]).page(params[:page]).per(10)
if request.xhr?
render :partial => "index"
end
end
def fields_display_order
uid = params[:id].split("-").last
@property = Property.find_by(:uid=>uid)
end
def update_fields_display_order
uid = params[:id].split("-").last
@property = Property.find_by(:uid=>uid)
prop = params.require(:property).permit!
@property.update_attributes(prop)
redirect_to params[:referer_url]
end
def order
@properties = Property.all.sort_order
end
def updateorder
ids_with_order = params[:order]
ids_with_order.each_with_index do |id,idx|
property = Property.find(id) rescue nil
if !property.nil?
property.order_position = idx
property.save
end
end
render :json => {"success" => true}.to_json
end
def my_bookings
@table_fields = ["property_hire.hiring_person_name", "property_hire.reason_for_hire", "property_hire.hiring_person_number", "property_hire.period", "property_hire.passed", :actions]
@table_fields = ["property_hire.title","property_hire.hiring_person_name", "property_hire.reason_for_hire", "property_hire.hiring_person_number", "property_hire.period", "property_hire.passed", :actions]
@bookings = PHire.where(:hiring_person_id => current_user.member_profile.id.to_s).desc(:created_at).page(params[:page]).per(10)
end
def new
@property = Property.new
def copy
@property = Property.where(:uid => params[:id].split("-").last).first.clone_new #rescue nil
create_set (false)
@locations = PropertyLocation.all.desc(:created_at).collect{|loc| [loc.title, loc.id.to_s]}
@locations << ["Other", "other_location"]
end
def new
@property = Property.new
create_set (false)
@locations = PropertyLocation.all.desc(:created_at).collect{|loc| [loc.title, loc.id.to_s]}
@locations << ["Other", "other_location"]
end
def edit_hire
@phire = PHire.find(params[:id])
end
def update_hire
@phire = PHire.find(params[:id])
@phire.update_attributes(phire_params)
redirect_to admin_property_hire_path(:id=>@phire.property)
end
def edit
@property = Property.where(:uid => params[:id].split("-").last).first rescue nil
create_set (true)
@locations = PropertyLocation.all.desc(:created_at).collect{|loc| [loc.title, loc.id.to_s]}
@locations << ["Other", "other_location"]
end
def show
@table_fields = ["property_hire.hiring_person_name", "property_hire.reason_for_hire", "property_hire.hiring_person_number", "property_hire.period", "property_hire.passed", :actions]
@table_fields = ["property_hire.hiring_person_name", "property_hire.reason_for_hire", "property_hire.hiring_person_number", "property_hire.period", "property_hire.passed", "property_hire.actions"]
@property = Property.where(:uid => params[:id].split("-").last).first rescue nil
@bookings = @property.p_hires.desc(:created_at).page(params[:page]).per(10)
end
def destroy
property = Property.find(params[:id]) rescue nil
email = property.get_owner_emails
Admin::PropertyHiresHelper::HireMethod.send_mail('delete',email,property.id,nil,nil,current_user.id)
property.destroy if !property.nil?
if params[:page]
redirect_to admin_property_hires_path(:page => params[:page])
@ -50,17 +93,43 @@ class Admin::PropertyHiresController < OrbitAdminController
def update
property = Property.where(:uid => params[:id].split("-").last).first rescue nil
redirect_to admin_property_hires_path and return if property.nil?
property.update_attributes(property_params)
if params[:page]
redirect_to admin_property_hires_path(:page => params[:page])
else
redirect_to admin_property_hires_path
@property_params = property_params
if @property_params[:p_hire_fields]
@property_params[:p_hire_fields].each do |a|
@field_name = 'property'
field_status = a.last[:id].present?
@attribute_field = PHireField.add_p_hire_field(property, a.last, a.last[:id], field_status)
@attribute = property
end
if property.need_change_tmp_reason
Thread.new do
p_hire_field_ids = property.p_hire_fields.where(:display_in_reason_for_hire=>true).pluck(:id)
property.p_hires.each do |p_hire|
p_hire.tmp_reason_for_hire = p_hire.p_hire_field_values.where(:p_hire_field_id.in=>p_hire_field_ids).map{|v| v.get_value_by_locale(I18n.locale.to_s)}.join(" ")
p_hire.save
end
property.update(:need_change_tmp_reason => false)
end
end
flash.now[:notice] = "Updated Fields"
property.p_hire_fields.each{|t| t.destroy if t["to_delete"] == true}
else
if @property_params["special_unavailable_dates"].nil?
@property_params["special_unavailable_dates"] = []
end
property.update_attributes(@property_params)
email = property.get_owner_emails
Admin::PropertyHiresHelper::HireMethod.send_mail('edit',email,property.id,nil,nil,current_user.id)
end
redirect_to params[:referer_url]
end
def create
property = Property.new(property_params)
if property.save
tmp_property_params = property_params
if tmp_property_params["copy_id"] && tmp_property_params["clone_p_hires"].blank?
tmp_property_params["except_clone_relations"] = ["p_hires","p_hire_field_values"]
end
if Property.create(tmp_property_params)
redirect_to admin_property_hires_path
end
end
@ -70,14 +139,29 @@ class Admin::PropertyHiresController < OrbitAdminController
end
def settings
if PropertyHireSetting.count == 0
@settings = PropertyHireSetting.create
else
@settings = PropertyHireSetting.first
end
if request.request_method == "PATCH"
@settings.update_attributes(settings_params)
@settings.update_attributes(settings_params.except("property_day_settings"))
@settings.save
if settings_params["property_day_settings"]
property_day_settings = settings_params["property_day_settings"].values
property_day_settings.each do |setting|
setting["property_id"] = "default_settings"
s = nil
if setting["id"].present?
s = PropertyDaySetting.where(:id=>setting["id"]).first
end
if s
if setting["_destroy"] == "1"
s.destroy
else
s.update_attributes(setting.except("id","_destroy"))
end
else
s = PropertyDaySetting.create(setting.except("id","_destroy"))
end
end
end
@saved = true
else
@saved = false
@ -104,6 +188,8 @@ class Admin::PropertyHiresController < OrbitAdminController
phire.passed = false
end
phire.save
email = [phire.hiring_person_email].select{|e| e.present?}
Admin::PropertyHiresHelper::HireMethod.send_mail('p_hire',email,phire.property.id,nil,phire.id,(current_user.id rescue nil))
if params[:ref] == "index"
if params[:page]
redirect_to admin_property_hire_path(phire.property, :page => params[:page])
@ -162,6 +248,30 @@ class Admin::PropertyHiresController < OrbitAdminController
end
end
end
def custom_fields
@field_name = 'property'
uid = params[:id].split("-").last
@attribute = Property.find_by(:uid=>uid)
@attribute_type = 'property'
@class = 'properties'
end
def checkforthread
running = !File.exists?("public/uploads/reservation_export/#{params[:property_id]}/#{params[:property_title]}.xlsx")
render :json => {"status" => running}.to_json
end
def export_reservation_data
property = Property.find(params[:id])
title = property.title.gsub(/[ "'*@#$%^&()+=;:.,?>|\\\/<~_!:,、。!?;「」〈〉【】/]/,'')
f = "public/uploads/reservation_export/#{property.id}/#{title}.xlsx"
File.delete(f) if File.exists?(f)
url = request.host_with_port
Thread.new do
system("rake property_hire_tasks:prepare_download[#{property.id},#{url}] >> #{Rails.root}/log/rake.log &")
end
render :json => {"success" => true, "title" => title}.to_json
end
private
@ -172,11 +282,62 @@ class Admin::PropertyHiresController < OrbitAdminController
def location_params
params.require(:property_location).permit!
end
def phire_params
p_hire_params = params.require(:p_hire).permit!
property = (@phire ? @phire.property : Property.find(params[:p_hire][:property_id]) rescue nil)
if(property.enable_notes_selector rescue false)
note_texts = ""
property.notes_selector.each do |index,sub_hash|
name = sub_hash["name"][I18n.locale.to_s]
name = sub_hash["name"].values.select{|v| v.present?}.first.to_s if name.blank?
values = sub_hash["value"][I18n.locale.to_s]
values = sub_hash["value"].values.select{|v| v.present?}.first.to_s if values.blank?
value_text = p_hire_params["notes_selector"][index.to_s].to_a.map{|i| values[i.to_i]}.join(",") rescue ""
value_text = I18n.t("property_hire.none") if value_text.blank?
note_texts += (name + ":"+value_text)
note_texts += "<br>".html_safe
end
p_hire_params["note_for_hire"] = note_texts
p_hire_params.delete("notes_selector")
end
return p_hire_params
end
def property_params
prop = params.require(:property).permit!
if prop[:weekdays].nil?
prop[:weekdays] = []
end
if prop[:owners].nil?
prop[:owners] = []
end
prop.delete(:property_location) if prop[:property_location] == "other"
prop
notes_selector = prop["notes_selector"]
notes_selector = {} if notes_selector.nil?
prop["notes_selector"] = (0 ... notes_selector.keys.count).to_a.map{|k| k.to_s}.zip(notes_selector.values).to_h
return prop
end
def create_set (save_flag)
@email_set = []
['p_hire','edit','delete'].each do |field_name|
email_set = @property.hire_email_sets.select{|v| v.field_name==field_name}
if email_set.length==0
title = Hash.new
content = Hash.new
I18n.available_locales.each do |locale|
I18n.with_locale(locale) do
title[locale] = t("property_hire.email_#{field_name}_success")
content[locale] = t("property_hire.email_#{field_name}_content")
end
end
if save_flag
email_set = @property.hire_email_sets.create(field_name:field_name,title:title,content:content)
else
email_set = @property.hire_email_sets.new(field_name:field_name,title:title,content:content)
end
else
email_set = email_set[0]
end
@email_set << email_set
end
end
end

View File

@ -1,36 +1,93 @@
class PropertyHiresController < ApplicationController
include Admin::PropertyHiresHelper
FrontendMethods = ["hire", "view_calendar", "hire_success"]
def index
properties = Property.filter_by_categories.filter_by_tags.desc(:created_at)
data = properties.collect do |property|
actions = []
if property.can_be_hired
actions << {
"text" => t("property_hire.hire"),
"btn-class" => "btn-primary",
"link" => OrbitHelper.url_to_show(property.to_param) + "?method=hire"
}
actions << {
"text" => t("property_hire.view_calendar"),
"btn-class" => "btn-info",
"link" => OrbitHelper.url_to_show(property.to_param) + "?method=view_calendar"
}
end
{
"title" => property.title,
"image" => property.image.url,
"image-thumb" => property.image.thumb.url,
"url_to_show" => OrbitHelper.url_to_show(property.to_param),
"location" => property.get_location_name,
"actions" => actions
}
end
properties = Property.can_display.filter_by_categories.sort_order
url = "/#{I18n.locale}#{OrbitHelper.page.get_url}"
data = index_data(properties, url)
filterprops = data.dup
filterprops.insert(0,{
"title" => t("property_hire.all_properties"),
"id" => "all&page_id=" + OrbitHelper.page.id.to_s
})
headers = [
{
"column" => t("property_hire.title")
},
{
"column" => t("property_hire.image")
"column" => ""
},
{
"column" => t("property_hire.location")
},
{
"column" => t("property_hire.actions")
}
]
{
"properties" => data,
"filterprops" => filterprops,
"headers" => headers,
"extras" => {
"first_property_id" => filterprops.first["id"],
"today" => t("property_hire.today"),
"day" => t("property_hire.day"),
"week" => t("property_hire.week"),
"month" => t("property_hire.month"),
"language" => OrbitHelper.get_site_locale
},
"manage_booking_btn" => (OrbitHelper.current_user.nil? ? false : true),
"manage_booking" => t("property_hire.manage_booking"),
"manage_booking_url" => "/" + OrbitHelper.get_site_locale.to_s + "/admin/property_hires/my_bookings",
"total_pages" => (properties.total_pages rescue 1)
}
end
def index_data(properties, url)
is_user_manager = check_if_user_is_manager?
data = properties.collect do |property|
actions = []
url_to_show = "#{url}/#{property.to_param}?method=hire"
hire_url = nil
if (property.can_be_hired_frontend && property.can_reserve) || is_user_manager
hire_url = url_to_show
actions << {
"text" => t("property_hire.hire"),
"btn-class" => "btn-primary",
"link" => hire_url
}
end
if (!property.disable_view_calendar_page && property.can_be_show_frontend && property.can_reserve) || is_user_manager
actions << {
"text" => t("property_hire.view_calendar"),
"btn-class" => "btn-info",
"link" => url_to_show
}
end
if property.disable_content_page
if hire_url
url_to_show = hire_url
end
end
{
"title" => property.title,
"id" => property.id.to_s,
"image" => (property.image.url.blank? ? '" style="display: none;' : property.image.url),
"image-thumb" => (property.image.thumb.url.blank? ? '" style="display: none;' : property.image.thumb.url),
"url_to_show" => url_to_show,
"location" => property.get_location_name,
"actions" => actions
}
end
end
def widget
properties = Property.filter_by_widget_categories.sort_order.can_display
url = OrbitHelper.get_current_widget.get_read_more_page_url
data = index_data(properties, url)
headers = [
{
"column" => t("property_hire.title")
},
{
"column" => t("property_hire.location")
@ -42,7 +99,7 @@ class PropertyHiresController < ApplicationController
{
"properties" => data,
"headers" => headers,
"total_pages" => properties.total_pages
"total_pages" => (properties.total_pages rescue 1)
}
end
@ -85,7 +142,7 @@ class PropertyHiresController < ApplicationController
"value" => property.purchase_date.strftime("%Y-%m-%d")
}
end
if property.owners.empty?
if property.owners.blank?
owners = property.other_owner
else
owners = property.owner_profiles.collect{|mp| mp.name}.join(",")
@ -121,16 +178,19 @@ class PropertyHiresController < ApplicationController
}
end
actions = []
if property.can_be_hired
url_to_show = OrbitHelper.url_to_show(property.to_param)
if property.can_be_hired_frontend
actions << {
"text" => t("property_hire.hire"),
"btn-class" => "btn-primary",
"link" => OrbitHelper.url_to_show(property.to_param) + "?method=hire"
"link" => url_to_show + "?method=hire"
}
end
if !property.disable_view_calendar_page && property.can_be_show_frontend
actions << {
"text" => t("property_hire.view_calendar"),
"btn-class" => "btn-info",
"link" => OrbitHelper.url_to_show(property.to_param) + "?method=view_calendar"
"link" => url_to_show + "?method=view_calendar"
}
end
{
@ -148,6 +208,9 @@ class PropertyHiresController < ApplicationController
def view_calendar
params = OrbitHelper.params
property = Property.where(:uid => params[:uid]).first rescue nil
if property.disable_view_calendar_page || !property.can_be_show_frontend
return nil
end
page = Page.where(:page_id => params[:page_id]).first
return {} if property.nil?
{
@ -156,22 +219,97 @@ class PropertyHiresController < ApplicationController
"current_user" => OrbitHelper.current_user
}
end
def hire_success
params = OrbitHelper.params
@property = Property.where(:uid => params[:uid]).first rescue nil
page = OrbitHelper.page rescue Page.where(:page_id => params[:page_id]).first
back_button_text = I18n.t("property_hire.go_to_infos_page")
back_url = (page.url + (params[:slug].present? ? "/#{params[:slug]}" : "") rescue "#")
if @property.disable_content_page
back_url += "?method=hire" if params[:slug].present?
back_button_text = I18n.t("property_hire.back_to_hire_page")
end
{"back_url"=>back_url,"back_button_text"=>back_button_text}
end
def make_booking
booking_p = booking_params
data = check_for_availability(booking_p[:start_time],booking_p[:end_time],booking_p[:property_id], booking_p[:recurring_interval], booking_p[:recurring_end_date])
time_setting_id = booking_p[:time]
start_time = booking_p[:start_time]
end_time = booking_p[:end_time]
time_setting = nil
is_admin_page = (params[:url] == "admin")
if time_setting_id.present?
start_time = booking_p[:date]
end_time = start_time
time_setting = PropertyDaySetting.find(time_setting_id)
if booking_p[:recurring_end_date].present?
booking_p[:recurring_end_date] = DateTime.parse(booking_p[:recurring_end_date].split(" ")[0] + ' ' + time_setting.end_time + Time.zone.to_s)
end
booking_p[:start_time] = booking_p[:date] + " " + time_setting.start_time
booking_p[:end_time] = booking_p[:date] + " " + time_setting.end_time
booking_p[:property_day_setting_id] = booking_p[:time]
booking_p.delete(:time)
end
property = Property.find(booking_p[:property_id]) rescue nil
begin
index_page = is_admin_page ? "/#{I18n.locale}/admin/property_hires/#{property.to_param}" : "/#{I18n.locale}#{params[:url]}/#{property.to_param}"
rescue
index_page = is_admin_page ? "/#{I18n.locale}/admin/property_hires" : "/#{I18n.locale}#{params[:url]}"
end
hire_page = is_admin_page ? request.referer : "#{index_page}?method=hire"
need_validate = (PropertyHireSetting.first.allow_no_logins_user rescue false) && current_user.nil?
session.delete(:hire_data)
if need_validate
unless gotcha_valid?
session[:hire_data] = booking_p
session["hire-save-msg"] = I18n.t("property_hire.recaptcha.errors.verification_failed")
if property.nil?
redirect_to index_page and return
else
redirect_to hire_page and return
end
end
end
phire_id = params[:phire_id] || params[:p_hire][:id]
if params[:url] == "admin"
phire_id = booking_p[:id]
end
data = check_for_availability(start_time,end_time,booking_p[:property_id], booking_p[:recurring_interval], booking_p[:recurring_end_date], time_setting_id)
if data["success"] == true
error_messages = property.check_require_fields(booking_p)
if error_messages.present?
data["msg"] = error_messages
data["success"] = false
end
end
if data["success"] == true
hire = nil
if phire_id
hire = PHire.find(phire_id) rescue nil
if hire.nil?
hire = PHire.new(booking_p)
else
hire.update_attributes(booking_p)
end
else
hire = PHire.new(booking_p)
end
hire.passed = true if PropertyHireSetting.auto_approve_enabled?
hire.save
redirect_to params[:url]
if !property.nil? && !is_admin_page
email = property.get_owner_emails
email << hire.hiring_person_email
email = email.select{|e| e.present?}
Admin::PropertyHiresHelper::HireMethod.send_mail('p_hire',email,property.id,nil,hire.id,(current_user.id rescue nil))
end
redirect_to index_page + "?method=hire_success"
else
session[:hire_data] = booking_p
session["hire-save-msg"] = data["msg"]
if property.nil?
redirect_to "/" + I18n.locale.to_s + params[:url]
redirect_to index_page
else
redirect_to "/" + I18n.locale.to_s + params[:url] + "/#{property.to_param}?method=hire"
redirect_to hire_page
end
end
end
@ -179,49 +317,354 @@ class PropertyHiresController < ApplicationController
def hire
params = OrbitHelper.params
property = Property.where(:uid => params[:uid]).first rescue nil
if !property.can_be_hired_frontend
return nil
end
page = Page.where(:page_id => params[:page_id]).first
return {} if property.nil?
hire = PHire.new
hire = nil
session = OrbitHelper.request.session rescue {}
recover = false
if (session[:hire_data] rescue false)
begin
if session[:hire_data][:property_id] != property.id.to_s
session.delete(:hire_data)
hire = PHire.new(:id=>nil)
else
hire = PHire.new({:id=>nil}.merge(session[:hire_data]))
recover = true
end
rescue => e
puts e.to_s
hire = PHire.new(:id=>nil)
end
else
hire = PHire.new(:id=>nil)
end
allow_no_logins_user = PropertyHireSetting.first.allow_no_logins_user
all_day_settings = property.all_day_settings.map{|d,settings| [d,settings.map{|s| [s.id.to_s,s.title]}]}.to_h
is_user_manager = check_if_user_is_manager?
{
"hire" => hire,
"property" => property,
"page" => page.url,
"current_user" => OrbitHelper.current_user
"is_user_manager" => is_user_manager,
"current_user" => OrbitHelper.current_user,
"allow_no_logins_user" => allow_no_logins_user,
"carousel_display_style" => "width: #{property.carousel_image_width};",
"all_day_settings" => all_day_settings,
"recover" => recover,
"language" => OrbitHelper.get_site_locale
}
end
def check_availability
data = check_for_availability params[:stime], params[:etime], params[:property_id], params[:interval], params[:recurring_end_date]
time_setting_id = params[:time_setting_id]
data = check_for_availability params[:stime], params[:etime], params[:property_id], params[:interval], params[:recurring_end_date], time_setting_id
render :json => data.to_json
end
def get_bookings
events =[]
allevents = []
if params[:property_id] == "all"
categories = Page.find(params["page_id"]).categories rescue []
properties = Property.where(:category_id.in => categories)
properties.each do |property|
allevents += get_each_booking(property)
end
else
property = Property.find(params[:property_id]) rescue nil
if !property.nil?
if params[:start].present? && params[:end].present?
sdt = Time.at(params[:start].to_i)
edt = Time.at(params[:end].to_i)
events = PHire.monthly_event(sdt,edt,params[:property_id])
re = PHire.recurring_event(sdt,edt,params[:property_id])
allevents = events.inject(re, :<<)
end
allevents = get_each_booking(property)
end
respond_to do |format|
format.html # index.html.erb
format.html { render json: allevents.to_json }# index.html.erb
format.json { render json: allevents.to_json }
end
end
def special_unavailable_dates_labels(property)
events = []
@special_unavailable_dates.each_with_index do |dt, idx|
events << {:title=>property.special_unavailable_dates_title[idx][OrbitHelper.get_site_locale], :start=>dt.to_s, :end => (dt + 1.day).to_s, :allDay => true, :color => "#d33535", :classNames=>["special_unavailable_btn"], :note => ""}
end
events
end
def reserve_calendar_event(date,title,allow_times)
available = true
if @special_unavailable_dates.include?(date)
available = false
end
if DateTime.now >= (@property.start_date || DateTime.now - 1.day) && DateTime.now <= (@property.end_date || DateTime.now + 1.month)
if @property.hours_restriction > 0 && @is_user_manager === false
check = false
sd = nil
ed = nil
case @property.hours_restriction_duration
when "week"
weeknumber = date.strftime("%U").to_i
if @weeknumber != weeknumber
sd = date - date.wday
ed = date + (6 - date.wday)
@weeknumber = weeknumber
check = true
end
when "month"
if @monthnumber != date.month
sd = Date.new(date.year, date.month, 1)
ed = sd.next_month.prev_day
@monthnumber = date.month
check = true
end
end
if check === true
@user_total_hired_hours = @property.get_user_total_user_hired_hours(OrbitHelper.current_user.id.to_s, sd, ed)
end
if @user_total_hired_hours >= @property.hours_restriction
available = false
end
end
end
if available
if DateTime.now >= (@property.start_date || DateTime.now - 1.day) && DateTime.now <= (@property.end_date || DateTime.now + 1.month)
available = date > (DateTime.now + (@property.need_hire_before).send(@property.need_hire_before_unit))
end
end
if @check_setting && allow_times.select{|a| !a[5]}.count != 0
available = !need_check_unavailable
if available
available = @property.weekdays.include?(date.wday.to_s) ? false : true
end
unless available
allow_times = allow_times.select do |allow_time|
if allow_time[5]
true
elsif (allow_time[0] > @check_end_time || allow_time[1] < @check_start_time)
true
elsif
false
end
end
available = (allow_times.count != 0)
end
end
if available
{:title=>title, :start=>date.to_s, :end => (date + 1.day).to_s, :allDay => true, :color => "#3788d8",:allow_times=>allow_times,:classNames=>["reserve_btn"]}
else
{}
end
end
def generate_all_reserve_buttons(startt,endt,all_day_settings,check_setting=false)
@check_setting = check_setting
@display_title = I18n.t("property_hire.reserve")
@allevents = []
startt = startt.in_time_zone(Time.zone)
endt = endt.in_time_zone(Time.zone)
start_wday = startt.wday
start_date = startt.to_date
@start_date = start_date
end_date = endt.to_date
@end_date = end_date
@first_check_time = startt.strftime("%H:%M")
@all_day_settings = all_day_settings
@startt = startt
@endt = endt
@weeknumber = 0
@monthnumber = 0
@is_user_manager = check_if_user_is_manager?
def generate_events(start_wday,end_wday,type=0,start_validate=false)
if type == 0
(start_wday..end_wday).each_with_index do |wday,i|
wday_str = wday.to_s
is_start_day = (i == 0 && start_validate)
if @all_day_settings.has_key?(wday_str)
check_time = nil
check_time = @first_check_time if is_start_day
i = @need_check_events.index{|e| e[0] > @start_date}
if i.nil?
if @need_check_events.length != 0 && @need_check_events[-1][0] <= @start_date
i = @need_check_events.length - 1
else
i = -1
end
elsif i != -1
i -= 1
end
check_events = []
if i != -1
check_events = @need_check_events[0..i]
end
@need_check_events = @need_check_events[(i+1)..-1]
settings = @all_day_settings[wday_str]
if check_events.count != 0
settings = settings.select do |s|
flag = true
if check_time
if check_time > s[1]
flag = false
end
end
if flag
if s[4] == 0 #reservation_limit == 0 => no limit
true
else
check_events.select{|e| e[1] == s[2] }.count < s[4]
end
else
false
end
end
end
if settings.count != 0
@allevents << reserve_calendar_event(@start_date,@display_title,settings)
end
end
@start_date += 1.day
if @start_date > @end_date
break
end
end
else
@all_day_settings.each do |wday_str,settings|
tmp_date = @start_date + wday_str.to_i.send("day")
i = @need_check_events.index{|e| e[0] > tmp_date}
if i.nil?
if @need_check_events.length != 0 && @need_check_events[-1][0] <= tmp_date
i = @need_check_events.length - 1
else
i = -1
end
elsif i != -1
i -= 1
end
check_events = []
if i != -1
check_events = @need_check_events[0..i]
end
@need_check_events = @need_check_events[(i+1)..-1]
if check_events.count != 0
settings = settings.select do |s|
if s[4] == 0 #reservation_limit == 0 => no limit
true
else
check_events.select{|e| e[1] == s[2] }.count < s[4]
end
end
end
if settings.count != 0
@allevents << reserve_calendar_event(tmp_date,@display_title,settings)
end
end
@start_date += 7.day
end
end
all_days = (end_date-start_date).to_i
end_wday = 6
end_date_wday = end_date.wday
only_first_week = false
if (start_wday + all_days <= 6)
end_wday = end_date_wday
only_first_week = true
end
generate_events(start_wday,end_wday,0,true)
unless only_first_week
all_days = all_days - (end_wday - start_wday)
while all_days > 6 do
generate_events(0,6,1)
all_days -= 7
end
generate_events(0,all_days)
end
@allevents
end
private
def booking_params
params.require(:p_hire).permit!
p_hire_params = params.require(:p_hire).permit!
property = Property.find(params[:p_hire][:property_id]) rescue Property.last
if(property.enable_notes_selector rescue false)
note_texts = ""
property.notes_selector.each do |index,sub_hash|
name = sub_hash["name"][I18n.locale.to_s]
name = sub_hash["name"].values.select{|v| v.present?}.first.to_s if name.blank?
values = sub_hash["value"][I18n.locale.to_s]
values = sub_hash["value"].values.select{|v| v.present?}.first.to_s if values.blank?
value_text = p_hire_params["notes_selector"][index.to_s].to_a.map{|i| values[i.to_i]}.join(",") rescue ""
value_text = I18n.t("property_hire.none") if value_text.blank?
note_texts += (name + ":"+value_text)
note_texts += "<br>".html_safe
end
p_hire_params["note_for_hire"] = note_texts
p_hire_params.delete("notes_selector")
end
return p_hire_params
end
def get_each_booking(property)
events =[]
allevents = []
@property = property
unless property.nil?
if params[:start].present? && params[:end].present?
sdt = Time.at(params[:start].to_i)
edt = Time.at(params[:end].to_i)
events = PHire.monthly_event(sdt,edt,property.id.to_s,property.set_availability)
re = PHire.recurring_event(sdt,edt,property.id.to_s,property.set_availability)
events = events.map{|e| e.as_json}
allevents = events.inject(re, :<<)
allevents = allevents.sort_by{|e| e[:start]}
@need_check_events = allevents.map{|e| [e[:date],e[:s_id]]}
@special_unavailable_dates = property.special_unavailable_dates.map{|dt| Date.parse(dt)}
is_user_manager = check_if_user_is_manager?
if property.set_availability && params[:display_hire_event] == "true"
check_setting = property.set_unavailibility && (property.property_day_settings.where(:enable=>false).count != 0)
@check_start_time = property.start_time.blank? ? "00:00" : property.start_time
@check_end_time = property.end_time.blank? ? "24:00" : property.end_time
@check_start_date = property.start_date.to_date rescue nil
@check_end_date = property.end_date.to_date rescue nil
if check_setting
if (@check_start_date > edt rescue false) || (@check_end_date < sdt rescue false)
check_setting = false
end
end
all_day_settings = property.all_day_settings.map{|d,settings| [d,settings.map{|s| [s.start_time,s.end_time,s.id.to_s,s.title,s.reservation_limit,s.enable]}]}.to_h
if all_day_settings.count != 0
time_now = Time.zone.now
if is_user_manager
get_start_time = property.p_open_start_time
get_end_time = property.p_open_end_time
else
get_start_time = [sdt,time_now].max
get_end_time = edt
end
if property.set_unavailibility
if property.can_hire_before_months != 0
get_end_time = [time_now + (property.can_hire_before_months).send("month"),edt].min
end
end
if property.can_reserve || is_user_manager
allevents += generate_all_reserve_buttons(get_start_time,get_end_time,all_day_settings,check_setting)
end
end
end
if @special_unavailable_dates.count > 0
allevents += special_unavailable_dates_labels(property)
end
end
end
return allevents
end
end

View File

@ -0,0 +1,561 @@
module Admin::PHireFieldHelper
include ActionView::Helpers::FormTagHelper
include ActionView::Helpers::FormOptionsHelper
include ActionView::Helpers::DateHelper
include ActionView::Helpers::TagHelper
include ActionView::Helpers::RenderingHelper
include ActionView::Context
include OrbitBasis::RenderAnywhere
include OrbitFormHelper
def block_helper(member,index,disable = false,attribute_type=nil,p_hire=nil, to_require=true, col=2, value=nil)
unless self.disabled
return "" if self.title.blank?
@col = col
@index = index
@require = to_require
@markup_options = markup_options.merge(:disabled=>disable, :required => to_require)
@member = member
@attribute_value = @member.get_value_from_field_id(id,p_hire)
@attribute_type = attribute_type
@new_attribute = @attribute_value.nil? || @attribute_value.new_record?
@attribute_value = @attribute_value || p_hire.p_hire_field_values.build(p_hire_field_id: id)
@prefiled_value = value || @attribute_value.value rescue nil
return instance_eval("render_#{markup}") rescue ""
end
end
def lang_tab(str,lang)
content_tag(:div,str,:class=>"tab-pane fade",:id=>(get_field_name_base+"tab_#{lang}"))
end
def render_hint_text
place_holder= self.get_placeholder rescue ''
return "" if place_holder.blank?
control_group_wrapper do |key,value|
if !@prefiled_value.nil?
value = can_muti_lang_input? ? @prefiled_value[key] : @prefiled_value
else
value = nil
end
key = can_muti_lang_input? ? "#{key}" : I18n.locale
name1 = ""
text_area_tag(name1, place_holder,@markup_options.merge(:class=>'input-medium form-control',:readonly=>"",:rows=>"4"))
end
end
def render_address
control_group_wrapper do |key,value|
value = (can_muti_lang_input? ? @prefiled_value[key] : @prefiled_value) rescue nil
key_field = can_muti_lang_input? ? "[#{key}]" : ""
place_holder= @panel_setting["placeholder"][key] rescue ''
# result = text_area_tag(get_field_name_base + key_field, value,@markup_options.merge({:placeholder=>place_holder,:for=>key}))
result = text_field_tag(get_field_name_base + key_field, value,@markup_options.merge({:placeholder=>place_holder,:for=>key}))
add_ext= @attribute_value.address_key[key] rescue {}
result << hidden_field_tag(get_basic_field_name_base+"[address_key][#{key}][county]",add_ext["county"],:class=>"county_#{key}", :id=>nil)
result << hidden_field_tag(get_basic_field_name_base+"[address_key][#{key}][street_address]",add_ext["street_address"],:class=>"street_address_#{key}", :id=>nil)
result << hidden_field_tag(get_basic_field_name_base+"[address_key][#{key}][city]",add_ext["city"],:class=>"city_#{key}", :id=>nil)
result << hidden_field_tag(get_basic_field_name_base+"[address_key][#{key}][zip]",add_ext["zip"],:class=>"zip_#{key}", :id=>nil)
result << hidden_field_tag(get_basic_field_name_base+"[address_key][#{key}][country]",add_ext["country"],:class=>"country_#{key}", :id=>nil)
result << hidden_field_tag(get_basic_field_name_base+"[address_key][#{key}][indicator]",add_ext["indicator"],:class=>"indicator_#{key}", :id=>nil)
end
end
def render_checkbox
@prefiled_value ||=[]
control_group_wrapper do
a = self.typeE[:option_list].collect do |key,value|
label_tag("#{get_basic_field_name_org}_#{self.id}_#{key}",check_box_tag(get_field_name_base+"[#{key}]", true , (@prefiled_value.include?(key) ? true : false), { :id=>"#{get_basic_field_name_org}_#{self.id}_#{key}"})+value[I18n.locale.to_s],@markup_options.merge(:class=>"checkbox inline"))
end.join.html_safe rescue ""
end
end
def render_date
d = DateTime.now()
if date_is_range?
# fill_from = @attribute_value.get_date(:from) rescue nil
# fill_to = @attribute_value.get_date(:to) rescue nil
control_group_wrapper do
case self.typeC['format']
when 'format1'
fill_from = (@prefiled_value && @prefiled_value["from"] ) ? @prefiled_value["from"] : d.strftime("%Y/%m/%d %H:%M")
fill_to = (@prefiled_value && @prefiled_value["to"] ) ? @prefiled_value["to"] : d.strftime("%Y/%m/%d %H:%M")
buf = datetime_picker(get_field_name_base+'[from]', fill_from, 'yyyy/MM/dd hh:mm', true)
buf << ' ~ '
buf << datetime_picker(get_field_name_base+'[to]', fill_to, 'yyyy/MM/dd hh:mm', true)
when 'format2'
fill_from = (@prefiled_value && @prefiled_value["from"] ) ? @prefiled_value["from"] : d.strftime("%Y/%m/%d")
fill_to = (@prefiled_value && @prefiled_value["to"] ) ? @prefiled_value["to"] : d.strftime("%Y/%m/%d")
buf = datetime_picker(get_field_name_base+'[from]', fill_from, 'yyyy/MM/dd')
buf << ' ~ '
buf << datetime_picker(get_field_name_base+'[to]', fill_to, 'yyyy/MM/dd')
when 'format3'
fill_from = (@prefiled_value && @prefiled_value["from"] ) ? @prefiled_value["from"] : d.strftime("%Y/%m")
fill_to = (@prefiled_value && @prefiled_value["to"] ) ? @prefiled_value["to"] : d.strftime("%Y/%m/")
buf = datetime_picker(get_field_name_base+'[from]', fill_from, 'yyyy/MM')
buf << ' ~ '
buf << datetime_picker(get_field_name_base+'[to]', fill_to, 'yyyy/MM')
when 'format4'
fill_from = (@prefiled_value && @prefiled_value["from"] ) ? @prefiled_value["from"] : d.strftime("%Y")
fill_to = (@prefiled_value && @prefiled_value["to"] ) ? @prefiled_value["to"] : d.strftime("%Y")
buf = datetime_picker(get_field_name_base+'[from]', fill_from, 'yyyy')
buf << ' ~ '
buf << datetime_picker(get_field_name_base+'[to]', fill_to, 'yyyy')
end
# buf = date_select(get_field_name_base+'[from]',nil,@markup_options.merge(:default=>fill_from),:class=>"input-small")
# buf << ' ~ '
# buf << date_select(get_field_name_base+'[to]',nil,@markup_options.merge(:default=>fill_to),:class=>"input-small")
buf
end
else
# @prefiled_value = @attribute_value.get_date
# @prefiled_value = @attribute_value.get_date
case self.typeC['format']
when 'format1'
tmp = datetime_picker(get_field_name_base, (@prefiled_value ? @prefiled_value : d.strftime("%Y/%m/%d %H:%M")), 'yyyy/MM/dd hh:mm', true)
when 'format2'
tmp = datetime_picker(get_field_name_base, (@prefiled_value ? @prefiled_value : d.strftime("%Y/%m/%d")), 'yyyy/MM/dd')
when 'format3'
tmp = datetime_picker(get_field_name_base, (@prefiled_value ? @prefiled_value : d.strftime("%Y/%m")), 'yyyy/MM')
when 'format4'
tmp = datetime_picker(get_field_name_base, (@prefiled_value ? @prefiled_value : d.strftime("%Y")), 'yyyy')
end
control_group_wrapper{tmp}
# control_group_wrapper{date_select(get_field_name_base,nil,@markup_options.merge(:default=>@prefiled_value),:class=>"input-small")}
end
end
def property_datetime_picker(object_name, value, format, time=false)
content_tag :div, :class => "input-append datetimepick", "data-date-format"=>format, "data-picktime"=>"#{time}" do
concat text_field_tag(object_name, value, :placeholder=>format)
concat (content_tag :span, :class => 'add-on clearDate' do
content_tag :i, nil, :class => 'icons-cross-3'
end)
concat (content_tag :span, :class => 'add-on iconbtn' do
content_tag :i, nil, 'data-time-icon' => 'icons-clock', 'data-date-icon' => 'icons-calendar', :class=>"icons-calendar"
end)
end
end
def render_date_durnation #Need re-write low priority
end
def render_radio_button
@prefiled_value ||=[]
control_group_wrapper do
self.typeE[:option_list].collect do |key,value|
label_tag("#{get_basic_field_name_org}_#{self.id}_#{key}",radio_button_tag(get_field_name_base, key , (@prefiled_value.include?(key) ? true : false), {:required=>@require,:id=>"#{get_basic_field_name_org}_#{self.id}_#{key}"})+value[I18n.locale.to_s],@markup_options.merge(:class=>"radio inline"))
end.join.html_safe
end
end
def render_property_preferred_session
@prefiled_value ||=[]
@prefiled_value = Array(@prefiled_value)
control_group_wrapper do
@member.summary_chioices.map.with_index do |value,key|
key = key.to_s
label_tag("#{get_basic_field_name_org}_#{self.id}_#{key}",radio_button_tag(get_field_name_base, key , ((@prefiled_value.include?(key) || @prefiled_value.include?(key.to_i)) ? true : false), {:required=>@require,:id=>"#{get_basic_field_name_org}_#{self.id}_#{key}"})+value,@markup_options.merge(:class=>"radio inline"))
end.join.html_safe
end if @member.enable_summary_choice
end
def render_select
prompt = @panel_setting["initial"][I18n.locale.to_s] rescue nil
@markup_options.merge!(:prompt => prompt) unless prompt.nil?
control_group_wrapper{select_tag( get_field_name_base,options_for_select(self.typeB["option_list"].collect{|p| [p[1][I18n.locale.to_s],p[0]]},@prefiled_value),@markup_options)} rescue ""
end
def render_text_area
control_group_wrapper do |key,value|
if !@prefiled_value.nil?
value = can_muti_lang_input? ? @prefiled_value[key] : @prefiled_value
else
value = nil
end
key = can_muti_lang_input? ? "#{key}" : I18n.locale
place_holder= typeD["placeholder"][key] rescue ''
name1 = can_muti_lang_input? ? (get_field_name_base + "[#{key}]") : get_field_name_base
text_area_tag(name1, value,@markup_options.merge(:placeholder=>place_holder,:class=>'ckeditor input-medium form-control'))
end
end
def render_text_field
a = control_group_wrapper do |key,value|
add_more_blank = can_add_more ? "[]" : ""
key_field = can_muti_lang_input? ? "#{key}" : I18n.locale
place_holder= typeA["placeholder"][key_field] rescue ''
name1 = can_muti_lang_input? ? ([get_field_name_base,add_more_blank,"[#{key_field}]"].join) : ([get_field_name_base,add_more_blank].join)
text_field_tag(name1, value,@markup_options.merge(:placeholder=>place_holder,:class=>'input-medium form-control'))
end
end
def date_is_range?
is_range = "false"
data = get_data
if !data.nil?
is_range = data['is_range'] if data.has_key? "is_range"
end
is_range == "true"
end
protected
def valid_locales
site = Site.first
[I18n.locale]+(site.valid_locales-[I18n.locale])
end
def lang_panel_tabbable_wrapper(add_more_params,&block)
add_more_counter = ''
if self.markup=='text_area' #or self.markup=='address'
tmp1 = valid_locales.collect do |key|
if !@prefiled_value.nil?
value = @prefiled_value[key] || @prefiled_value[key.to_s] rescue nil
else
value = nil
end
# div_class_ary = ["tab-pane" ,"fade","#{get_pairing_tab_class({})}_#{key}"]
div_class_ary = ["tab-pane" ,"fade"]
if @show_set_field && @markup=='text_area'
div_id = "ckeditor_#{get_pairing_tab_class({})}_#{key}"
else
div_id = "#{get_pairing_tab_class({})}_#{key}"
end
if can_add_more
add_more_value = add_more_params[0][:value]
add_more_counter = add_more_params[0][:counter]
value = add_more_value[key] rescue nil
div_class_ary << "add_more_item_#{add_more_counter}"
end
div_class = div_class_ary.join(" ")
div_class << (key == I18n.locale ? " active in" : '')
content_tag(:div,yield(key,value), :id=>div_id,:class=>div_class)
end# of VALID_LOCALES.collect for tabed input
tmp2 = content_tag(:div,:class => 'btn-group', :data=>{:toggle=>"buttons-radio"}) do
buff2 = valid_locales.each.collect do |key|
# link_entry = self.add_more ? "#{add_more_tab(:tab_btn,loop_counter,key)}" : "#tab"+id.to_s+"_#{key}"
if @show_set_field && @markup=='text_area'
link_entry_ary = ["#ckeditor_#{get_pairing_tab_class({})}","_#{key}"]
else
link_entry_ary = ["##{get_pairing_tab_class({})}","_#{key}"]
end
link_entry_ary << ".add_more_item_#{add_more_counter}" if can_add_more
link_entry = link_entry_ary.join
link_to(I18n.t(key),link_entry,:data=>{:toggle=>"tab"},:class=>"btn #{(key == I18n.locale ? "active" : nil)}",:for=>key)
end # of VALID_LOCALES.collect for tabs
buff2 << link_to((content_tag :i,'',:class=>'icon-edit'),"##{get_pairing_tab_class({})}_m_window", :role=>"button",:class=>'btn',:data=>{:toggle=>"modal"}) if self.markup == 'address'
buff2 << link_to((content_tag :i,'',:class=>'icon-trash'),"#",:class=>"btn remove-input") if self.add_more
buff2.join.html_safe
end # of content ul
tmp = content_tag :div,:class=> "tab-content textarea-lang" do
tmp2 << tmp1.join('').html_safe
end
else
# tmp = content_tag :div,:class=> (add_more || self.markup=='address') ? "input-append" : "tab-content" do
tmp1 =
content_tag :div,:class=> "tab-content" do
buff = valid_locales.collect do |key|
value = @prefiled_value[key] || @prefiled_value[key.to_s] rescue nil
# div_class_ary = ["tab-pane" ,"fade","#{get_pairing_tab_class({})}_#{key}"]
div_class_ary = ["tab-pane" ,"fade"]
div_id = "#{get_pairing_tab_class({})}_#{key}"
if can_add_more
add_more_value = add_more_params[0][:value]
add_more_counter = add_more_params[0][:counter]
value = add_more_value[key] rescue nil
div_class_ary << "add_more_item_#{add_more_counter}"
end
div_class = div_class_ary.join(" ")
div_class << (key == I18n.locale ? " active in" : '')
content_tag(:div,yield(key,value), :id=>div_id,:class=>div_class)
end# of VALID_LOCALES.collect for tabed input
buff.join('').html_safe
end
tmp2 = content_tag(:div,:class => 'btn-group', :data=>{:toggle=>"buttons-radio"}) do
buff2 = valid_locales.each.collect do |key|
# link_entry = self.add_more ? "#{add_more_tab(:tab_btn,loop_counter,key)}" : "#tab"+id.to_s+"_#{key}"
link_entry_ary = ["##{get_pairing_tab_class({})}","_#{key}"]
link_entry_ary << ".add_more_item_#{add_more_counter}" if can_add_more
link_entry = link_entry_ary.join
link_to(I18n.t(key),link_entry,:data=>{:toggle=>"tab"},:class=>"btn #{(key == I18n.locale ? "active" : nil)}",:for=>key)
end # of VALID_LOCALES.collect for tabs
buff2 << link_to((content_tag :i,'',:class=>'icon-edit'),"#address-field", :role=>"button",:class=>'btn',:data=>{:toggle=>"modal"}) if self.markup == 'address'
buff2 << link_to((content_tag :i,'',:class=>'icon-trash'),"#",:class=>"btn remove-input") if self.add_more
buff2.join.html_safe
end # of content ul
tmp = content_tag :div,:class=> "input-append" do
tmp1 << tmp2
end
end
end
def controls_wrapper(*add_more_params,&block)
result = Array.new
add_more_counter = ""
if can_add_more
add_more_counter = add_more_params[0][:counter]
add_more_value = add_more_params[0][:value]
end
if can_muti_lang_input?
result << lang_panel_tabbable_wrapper(add_more_params,&block)
result << gen_modal_dialog if self.markup == "address"
# result << add_more_unt if can_add_more
else #cross lang field
case can_add_more
when true
value = add_more_params[0][:value]
result << content_tag(:div,:class=>"input-append"){yield(nil,value) + link_to((content_tag :i,'',:class=>'icon-trash'),"#",:class=>"btn remove-input") }
# result << add_more_unt
else
value = @prefiled_value
result << yield(nil,value)
end
end
if self.markup == "address"
result
else
result[0]
end
end # of def controls_wrapper(&block)
def control_group_wrapper(&block)
div_class = can_muti_lang_input? ? "col-sm-#{12-@col} controls" : "col-sm-#{12-@col} controls"
# div_class = can_muti_lang_input? ? "control-group language-swich" : "control-group"
result = ""
case self.markup
when "text_field"
if can_add_more
multipleInputs =
content_tag(:div,:class=>"add-target") do
@attribute_value.add_more_counter.times.collect do |t|
controls_wrapper(:value=>(@prefiled_value[t] rescue nil),:counter=>t,&block)
end.join('').html_safe # of add_more fields
end
temp = content_tag(:div, multipleInputs + add_more_unt, :class=>'add-input')
result = form_label + content_tag(:div,temp,:class=>div_class)
# result = label + multipleInputs + add_more_unt
# result = label + 一堆的輸入框(要用 multipleInput editMore 包起來) + add_more btn + hidden_fields
else
result = form_label + content_tag(:div,controls_wrapper(&block),:class=>div_class)
end
when "address"
# address = content_tag :div,:class=>"multipleInput editMore" do
address = content_tag :div,:class=>"col-sm-#{12-@col}" do
form_label + content_tag(:div, controls_wrapper(&block), :class=>'add-input')
end # of div multipleInput editMore
result = address
else
result = form_label + content_tag(:div,controls_wrapper(&block),:class=>div_class)
end
result = result + end_block
result.html_safe
end
def add_more_unt
temp_field_name = get_basic_field_name_base + '[temp]'
add_more = content_tag :p,:class=> 'add-btn' do
content = link_to (content_tag :i,I18n.t(:add),:class=>"icon-plus"),"#","data-roles"=>"role_a",:class=>"trigger #{can_muti_lang_input? ? 'textLengInput' : 'textInput' } btn btn-small btn-primary"
content << hidden_field_tag("#{temp_field_name}[count]",@attribute_value.add_more_counter ,:class=>"list_count", :id=>nil)
content << hidden_field_tag("#{temp_field_name}[count]",get_basic_field_name_base,:class=>"field_name", :id=>nil)
content
end # of div
# add_more = content_tag :div,:class=> 'controls' do
# content_tag :span,:class=> 'help-block' do
# content = link_to (content_tag :i,I18n.t(:add),:class=>"icon-plus-sign"),"#",:class=>'addinput'
# content << hidden_field_tag("#{temp_field_name}[count]",@attribute_value.add_more_counter ,:class=>"list_count")
# content << hidden_field_tag("#{temp_field_name}[count]",get_basic_field_name_base,:class=>"field_name")
# content
# end # of span
# end # of div
end
def end_block
if @new_attribute
hidden_field_tag(get_basic_field_name_base+"[#{get_basic_field_name}_id]",id,:for=>"field_#{@index}", :id=>nil)
else
hidden_field_tag(get_basic_field_name_base+"[id]",@attribute_value.id,:for=>"field_#{@index}", :id=>nil)
end
end
def add_more_tab(mode,counter,key)
case mode
when :input_field
get_pairing_tab_class(:suffix=>['','tab'+counter.to_s,key].join('-'))
when :tab_btn
".#{get_pairing_tab_class(:suffix=>['','tab'+counter.to_s,key].join('-'))}"
end
end
def get_pairing_tab_class(opts)
prefix = opts[:prefix]
suffix = opts[:suffix]
str = get_basic_field_name_base.gsub("[","_").gsub("]",'')
str = prefix.nil? ? str : prefix+ str
suffix.nil? ? str : str + suffix
end
def get_basic_field_name_org
"p_hire[p_hire_field_values_attributes]"
end
def get_basic_field_name
"p_hire_field"
end
def get_basic_field_name_base
"#{get_basic_field_name_org}[#{@index}]"
end
def get_field_name_base
get_basic_field_name_base + "[value]"
end
def form_label
if self.markup == "text_area"
plc = typeD["placeholder"][I18n.locale].to_s.blank? ? nil : "(#{typeD["placeholder"][I18n.locale]})"
label_tag(key, '' , :class=>"col-sm-#{@col} control-label muted") do
concat (!@require.blank? ? '*'+title : title)
if plc
concat tag(:br)
concat plc
end
end
else
label_tag(key,(!@require.blank? ? '*'+title : title),:class=>"col-sm-#{@col} control-label muted")
end
end
def can_muti_lang_input?
if self.markup == "address"
return true
else
$property_list[:markups][markup]["muti_lang_input_supprt"] and !(get_data["cross_lang"] == "true")
end
end
def can_add_more
if self.markup == "address"
return false
else
add_more
end
end
def gen_modal_dialog
render_anywhere("shared/attribute_field/address_modal_dialog",{
:field_name=>title,
:html_id=>"address-field",
:btn_class => "#{get_pairing_tab_class({})}",
:field_name_basic => get_basic_field_name_base
}
)
end
def show_set_field(field_sets,key_field,key_index,field,markup='text_field')
@show_set_field = true
def self.can_muti_lang_input?
true
end
def self.can_add_more
false
end
@markup = markup
def self.markup
@markup
end
def self.add_more
false
end
@new_attribute = false
@key_index = key_index
def self.key
@key_index
end
def self.form_label
''
end
def self.end_block
unless @attribute_value.new_record?
hidden_field_tag("property[#{@key_field}][#{@key_index}]"+"[id]",
@attribute_value.id,:for=>"field_#{@key_index}", :id=>nil)
else
""
end
end
@key_field = key_field
@field = field
def self.get_basic_field_name_base
"property[#{@key_field}][#{@key_index}][#{@field}]"
end
def self.get_field_name_base
"property[#{@key_field}][#{@key_index}][#{@field}]"
end
@attribute_value = field_sets
@prefiled_value = field_sets[field]
a = control_group_wrapper do |key,value|
add_more_blank = ""
if markup=='text_field'
if key_field == 'property_email_sets'
inside = text_field_tag([get_field_name_base,"[#{key}]"].join,value,:class=>'input-medium form-control')
else
inside = text_field_tag([get_field_name_base,"[#{key}]"].join,value)
end
else
inside = cktext_area("property[#{@key_field}][#{@key_index}][#{@field}]","#{key}",value:value)
end
inside
end
@key_field = nil
@key_index = nil
@field = nil
@show_set_field = nil
return a.html_safe
end
end

View File

@ -0,0 +1,113 @@
module Admin::PHireFieldValuesHelper
def show_property_type_panel(attribute_field,type)
markup = attribute_field.markup
$property_list[:markups][markup]["panel"] == type ? type : [type,'hide'].join(" ")
end
def show_west_calender(from_to=nil)
case from_to
when :to
date = get_date(:to)
when :from
date = get_date(:from)
when nil
date = get_date
end
# case self.member_profile_field["typeC"]["format"]
# when 'format1' # Y/M/D h:m
# date.strftime("%Y/%m/%d %H:%M")
# when 'format2' # Y/M/D
# date.strftime("%Y/%m/%d")
# when 'format3' # Y/M
# date.strftime("%Y/%m")
# when 'format4' # Y
# date.strftime("%Y")
# end # of case west cal format
end
def show_minguo_calendar(from_to=nil)
get_minguo
case from_to
when :to
date = get_date(:to)
when :from
date = get_date(:from)
when nil
date = get_date
end
@date = date.split('/')
date_year = @date[0].to_i
year_str = ""
unless date_year == 1912
m_year = (date_year - 1912).abs.to_s + I18n.t("date.minguo_calendar.year")
year_str = minguo_format_year(m_year)
end
get_minguo_year(from_to) + minguo_m_y_d_time(from_to)
end
def get_minguo_year(from_to=nil)
case from_to
when :to
date = get_date(:to)
when :from
date = get_date(:from)
when nil
date = get_date
end
@date = date.split('/')
date_year = @date[0].to_i
m_year = (date_year - 1911).abs
year_end = I18n.t("date.minguo_calendar.year")
case
when date_year <1912
I18n.t("date.minguo_calendar.before") + (m_year+1).to_s + year_end
when date_year ==1912
I18n.t("date.minguo_calendar.first_year")
when date_year >1912
I18n.t("date.minguo_calendar.after")+ (m_year).to_s + year_end
end # of case tw_calendar year
end
def minguo_m_y_d_time(from_to=nil)
case from_to
when :to
date = get_date(:to)
when :from
date = get_date(:from)
when nil
date = get_date
end
@date = date.split('/')
case self.p_hire_field["typeC"]["format"]
when 'format1' # Y/M/D h:m
"/#{@date[1]}/#{@date[2]}"
when 'format2' # Y/M/D
"/#{@date[1]}/#{@date[2]}"
when 'format3' # Y/M
"/#{@date[1]}#{I18n.t("date.minguo_calendar.month")}"\
when 'format4' # Y
''
end # of case
end
def get_date_by_format(from_to = nil)
case I18n.locale
when :zh_tw
case
when self.p_hire_field["typeC"]["calendar"] == "west_calendar"
show_west_calender(from_to)
when self.p_hire_field["typeC"]["calendar"] == "tw_calendar"
show_minguo_calendar(from_to)
end #case self.p_hire_field["typeC"]["calendar"]
when :en
show_west_calender(from_to)
end
end
end

View File

@ -1,23 +1,182 @@
module Admin::PropertyHiresHelper
def check_for_availability(stime, etime, pid, interval=nil, recurring_end_date=nil)
data = File.open(File.join(File.dirname(__FILE__), '../../../config', 'list.yml')).read
$property_list = YAML::load(ERB.new(data).result(binding)).symbolize_keys
include OrbitBackendHelper
def check_for_availability(stime, etime, pid, interval=nil, recurring_end_date=nil, time_setting_id=nil)
property = Property.find(pid)
return {"success" => false, "msg" => "Values are not ok."} if property.nil? || stime.blank? || etime.blank?
stime = DateTime.parse(stime + Time.zone.to_s) rescue nil
etime = DateTime.parse(etime + Time.zone.to_s) rescue nil
recurring_end_date = DateTime.parse(recurring_end_date + Time.zone.to_s) rescue nil
data = {}
return {"success" => false, "msg" => "Starting time cannot be greater than ending time."} if stime > etime
if property.is_available_for_hire?(stime, etime)
if property.is_already_hired?(stime, etime, interval, recurring_end_date)
data = {"success" => true}
else
data = {"success" => false, "msg" => "Property is already hired during this time."}
values_not_ok = {"success" => false, "msg" => I18n.t("property_hire.values_are_not_ok",:default=>"Values are not ok.")}
return values_not_ok if property.nil? || stime.blank? || etime.blank?
timezone = (params[:timezone] rescue nil)
timezone = timezone ? timezone : Time.zone.to_s
stime = DateTime.parse(stime + timezone) rescue nil
etime = DateTime.parse(etime + timezone) rescue nil
return values_not_ok if stime.nil? || etime.nil?
if !recurring_end_date.blank?
recurring_end_date = DateTime.parse(recurring_end_date + timezone) rescue nil
begin
interval_time = 1.send(interval)
tmp_date = recurring_end_date - interval_time
if tmp_date < etime
I18n.with_locale(params[:locale]) do
interval_str= I18n.t("property_hire.1_#{interval}","1 #{interval}")
default_msg = "Recurring end date must exceed hire end time than #{interval_str}!"
msg = I18n.t("property_hire.recurring_end_date_must_exceed_time",{:time=>interval_str,:default=>default_msg})
return {"success" => false, "msg" => msg}
end
end
rescue
end
else
data = {"success" => false, "msg" => "Property is unavailable during this time."}
recurring_end_date = nil
end
data = {}
if stime > etime
I18n.with_locale(params[:locale]) do
return {"success" => false, "msg" => I18n.t("property_hire.starting_time_cannot_be_greater_than_ending_time")}
end
end
mp = OrbitHelper.current_user.member_profile rescue nil
available_flag = property.is_available_for_hire?(stime, etime, interval, recurring_end_date, time_setting_id, mp)
if available_flag == 1
if property.not_yet_hired?(stime, etime, interval, recurring_end_date,params[:phire_id], time_setting_id)
data = {"success" => true}
else
I18n.with_locale(params[:locale]) do
data = {"success" => false, "msg" => I18n.t("property_hire.property_is_already_hired_during_this_time")}
end
end
else
I18n.with_locale(params[:locale]) do
msg = I18n.t("property_hire.property_is_unavailable_during_this_time")
if available_flag == 2 ## need hire after
if recurring_end_date.present?
stime = [stime,recurring_end_date].max
end
can_hire_date = stime - (property.can_hire_before_months).month
msg += ("<br>" + I18n.t("property_hire.please_hire_after_date",{:date=>"{#{can_hire_date.new_offset(0).to_json.gsub('"','')}}"}))
elsif available_flag == 3 ## need hire before
default_msg = "This property must be reserved #{property.need_hire_before} #{property.need_hire_before_unit}s in advance."
msg += I18n.t("property_hire.unavailable_hint3",{:month=>property.need_hire_before,:unit=>I18n.t("property_hire._#{property.need_hire_before_unit}",:default=>property.need_hire_before_unit),:default=>default_msg})
elsif available_flag == 0
msg += ("<br>" + property.render_unavailable_message)
end
data = {"success" => false, "msg" => msg}
end
end
return data
end
def render_custom_text_field(f,field_name,type)
text = "<div>
<div class=\"input-append\">
<div class=\"tab-content\">"
@site_in_use_locales.each_with_index do |locale,i|
text += "<div class=\"tab-pane fade #{'active in' if i == 0}\" id=\"property_#{field_name}_#{type}_#{locale}\">
#{f.text_field_tag("#{f.object_name}[#{field_name}][#{type}][#{locale}]", f.object.custom_text(field_name,type,locale))}
</div>"
end
text += "<div class=\"btn-group\" data-toggle=\"buttons-radio\">"
@site_in_use_locales.each_with_index do |locale,i|
text += "<a class=\"btn #{'active' if i == 0}\" data-toggle=\"tab\" href=\"#property_#{field_name}_#{type}_#{locale}\" aria-expanded=\"true\">#{t(locale)}</a>"
end
text += "</div>
</div>
</div>
</div>"
text.html_safe
end
def check_if_user_is_manager?
ma = ModuleApp.find_by_key("property_hire")
if OrbitHelper.current_user.nil?
is_user_manager = false
else
is_user_manager = (OrbitHelper.current_user.is_admin? || OrbitHelper.current_user.is_manager?(ma) || OrbitHelper.current_user.is_sub_manager?(ma))
end
return is_user_manager
end
module HireMethod
extend ActionView::Helpers::UrlHelper
extend ActionView::Helpers::TagHelper
extend ActionView::Context
extend ActionView::Helpers::FormTagHelper
def self.set_input_name(input_name)
@input_name = input_name
end
def self.get_input_name
@input_name
end
def self.create_lang_panel(field)
tmp2 = content_tag(:div,:class => 'btn-group', :data=>{:toggle=>"buttons-radio"}) do
I18n.available_locales.collect do |key|
link_entry_ary = ["##{field}","_#{key}"]
link_entry = link_entry_ary.join
link_to(I18n.t(key),link_entry,:data=>{:toggle=>"tab"},:class=>"btn #{(key == I18n.locale ? "active" : nil)}",:for=>key)
end.join.html_safe
end
end
def self.multiple_lang_tag(index1,type_of_tag,field,value=nil,custom_options={},combine_element='',exteral_options={},panel_in_first=false)
content_tag(:div,{:class => "tab-panel"}.merge(exteral_options)) do
all_field = (get_input_name + "[#{index1}][#{field}][parant]").gsub(/\[/,'_').gsub(/\]/,'')
tmp = I18n.available_locales.collect do |locale|
active_flag = ((locale == I18n.locale) ? ' active' : '')
content_tag(:div,:class => "tab-content#{active_flag}",:id=>"#{all_field}_#{locale}") do
value_locale = ((value[locale] || value[locale.to_s]) rescue nil)
self.__send__("#{type_of_tag}_tag","#{get_input_name}[#{index1}][#{field}][#{locale}]",value_locale,custom_options)
end
end.join
if panel_in_first
tmp = create_lang_panel(all_field).html_safe + tmp.html_safe + combine_element
else
tmp = tmp.html_safe + create_lang_panel(all_field).html_safe + combine_element
end
tmp
end
end
def self.show_set_field(id,field_sets,key_field,key_index,field,markup='text_field',with_id=true)
end_block = with_id ? hidden_field_tag("property[#{key_field}][#{key_index}]"+"[id]",id) : ''
custom_options = markup == 'text_area' ? {:class => 'ckeditor'} : {}
a = multiple_lang_tag(key_field,markup,"#{key_index}][#{field}",field_sets,custom_options,end_block,{},markup=='text_area')
a.html_safe
end
def self.send_mail(field_name,email,property_id,send_date=nil,hire_id=nil,user_id=nil)
return if email.blank?
property = Property.where(id: property_id).first
if !property.nil?
email_set = property.hire_email_sets.select{|v| v.field_name == field_name}
title = property.title_translations.collect{|k,v| v}.select{|v| v.present?}.uniq.join('/')
note = property.note_translations.collect{|k,v| v}.select{|v| v.present?}.uniq.join('/')
content = "title:#{title}<br>note:#{note}"
mail_subject = I18n.t("property_hire.email_#{field_name}_success")
email_set_content = nil
enable = false
if email_set.length==0
enable = true
elsif !(email_set[0].disabled)
enable = true
mail_subject = email_set[0].title[I18n.locale]
email_set_content = email_set[0].content.to_yaml
end
if field_name == "p_hire" && (property.set_availability rescue false)
hire = PHire.find(hire_id) rescue nil
if hire
mail_subject += " (#{I18n.t("property_hire.hire_time")}: #{hire.date.to_s.gsub("-","/")} #{hire.time})"
end
end
if enable
mail = Email.create(mail_to: Array(email),
module_app_key:"property_hire",
template:"email/#{field_name}_email.html.erb",
mail_sentdate: send_date || Time.current,
mail_subject: mail_subject,
template_data:{'property_id'=>property_id,'email_set_content'=>email_set_content,'content'=>content,'locale'=>I18n.locale.to_s,'hire_id'=>hire_id,'user_id'=>user_id})
else
return false
end
begin
mail.deliver
rescue => e
puts ["email can't deliver",e]
end
end
end
end
end

View File

@ -0,0 +1,10 @@
class HireEmailSet
include Mongoid::Document
include Mongoid::Timestamps
field :field_name, type: String
field :title
field :content
field :disabled, type: Boolean, default: false
belongs_to :property
end

View File

@ -3,7 +3,7 @@ class PHire
include Mongoid::Timestamps
INTERVALS = ["week", "month"]
field :date, type: Date
field :start_time, type: DateTime
field :end_time, type: DateTime
field :hiring_person_email
@ -11,25 +11,78 @@ class PHire
field :hiring_person_id
field :hiring_person_name
field :reason_for_hire
field :tmp_reason_for_hire, type: String, default: "" # store reason text from custom fields
field :note_for_hire
field :property_day_setting_id
field :passed, type: Boolean, default: false
field :recurring, type: Boolean, :default => false
field :recurring_end_date, type: DateTime
field :recurring_interval
field :organization
field :person_in_charge
field :tel_of_person_in_charge
field :department
field :contact_person
field :tel_of_contact_person
field :mobile_phone_of_contact_person
field :contact_person_Email
field :contact_person_department
belongs_to :property
has_many :p_hire_field_values, :autosave => true, :dependent => :destroy
accepts_nested_attributes_for :p_hire_field_values, allow_destroy: true
def property_day_setting
PropertyDaySetting.find(self.property_day_setting_id) rescue nil
end
def time
property_day_setting.title rescue nil
end
def as_json(options = {})
startt = self.start_time
endt = self.end_time
recurring = false
datet = self.date
classNames = []
viewButton = false
if options[:startt]
startt = options[:startt]
end
if options[:endt]
endt = options[:endt]
end
if options[:datet]
datet = options[:datet]
end
if options[:recurring]
recurring = options[:recurring]
end
if !OrbitHelper.current_user.nil?
if OrbitHelper.current_user.member_profile.id.to_s == self.hiring_person_id
classNames = ["mybooking"]
viewButton = true
end
end
title = startt.strftime("%H:%M") + " ~ " + endt.strftime("%H:%M") + " " + self.hiring_person_name
{
:id => self.id.to_s,
:title => self.reason_for_hire,
# :title => (self.reason_for_hire.to_s + " "+ self.tmp_reason_for_hire.to_s).html_safe,
:property_title => self.property.title,
:title => title,
:hiring_person_id => self.hiring_person_id,
:hiring_person_name => self.hiring_person_name,
:note => self.note_for_hire || "",
:start => self.start_time.rfc822,
:end => self.end_time.rfc822,
:start => startt.to_json.gsub('"',''),
:end => endt.to_json.gsub('"',''),
:allDay => false,
:color => "#FC4040"
:diff_day => (self.end_time - self.start_time >= 1),
:color => (self.passed ? "#3788d8" : "#FC4040"),
:error_message => (self.passed ? nil : "Not approved"),
:s_id=>self.property_day_setting_id.to_s,
:date=>datet,
:recurring=>recurring,
:classNames => classNames,
:view_button => viewButton,
:view_path => "/#{OrbitHelper.get_site_locale}/admin/property_hires/#{self.id.to_s}/show_booking_details",
:view_path_name => I18n.t("property_hire.view")
}
end
@ -38,48 +91,98 @@ class PHire
end
def hirer_name
return self.hiring_person_name.nil? ? self.hiring_person_profile.name : self.hiring_person_name
return self.hiring_person_name.nil? ? (self.hiring_person_profile.name rescue "") : self.hiring_person_name
end
def hiring_person_profile
return MemberProfile.find(self.hiring_person_id) rescue nil
end
def self.monthly_event(start_date,end_date,property_id)
self.where(:property_id => property_id, :recurring => false).any_of(:start_time.gte => start_date, :end_time.gte => start_date).and(:start_time.lte => end_date).asc(:start_time)
def self.monthly_event(start_date,end_date,property_id,date_only=false)
events = self.where(:property_id => property_id, :recurring => false).any_of([{:start_time.gte => start_date}, {:end_time.gte => start_date}]).and(:start_time.lte => end_date).asc(:start_time)
if date_only
events = events.where(:date.ne=>nil)
end
def self.recurring_event(start_date,end_date,property_id)
@recurring_events = self.where(:property_id => property_id, :recurring => true, :recurring_end_date.gte => start_date)
events
end
def self.convert_datetime(time)
if time.class == Time
return time.to_datetime
elsif time.class == DateTime
return time
elsif time.class == String
return DateTime.parse(time)
else
return Time.at(time).to_datetime #time is seconds
end
end
def self.recurring_event(start_date,end_date,property_id,date_only=false)
start_date = convert_datetime(start_date)
end_date = convert_datetime(end_date)
@property = Property.find(property_id) rescue nil
@recurring = []
if @property != nil
unavailable = @property.set_unavailibility && !@property.weekdays.empty? && !@property.start_date.nil? && !@property.end_date.nil?
unavailable_start_date = @property.start_date
unavailable_end_date = @property.end_date
unavailable_start_time = @property.start_time.to_s
unavailable_end_time = @property.end_time.to_s
unavailable_start_date = DateTime.parse(unavailable_start_date.strftime("%Y-%m-%d " + unavailable_start_time.to_s + Time.zone.to_s)) rescue nil
unavailable_end_date = DateTime.parse(unavailable_end_date.strftime("%Y-%m-%d " + unavailable_end_time.to_s + Time.zone.to_s)) rescue nil
unavailable_weekdays = @property.weekdays.collect{|w| w.to_i}
@recurring_events = self.where(:property_id => property_id, :recurring_end_date.gte => start_date)
if date_only
@recurring_events = @recurring_events.where(:date.ne=>nil)
end
start_date_utc_mjd = start_date.to_datetime.new_offset(0).mjd
@recurring_events.each do |re|
case re.recurring_interval
when "week"
datet = re.date
interval = 1.send(re.recurring_interval) rescue 0
if interval != 0
@start_date = re.start_time
recurring_end_date = re.recurring_end_date
new_end_date = [recurring_end_date,end_date].min
@end_date = re.end_time
@i = TimeDifference.between(re.start_time,end_date).in_weeks.to_i
(0..@i).each do |i|
if i > 0
@start_date += 7
@end_date += 7
if @start_date < start_date
add_interval = nil
period_str = nil
if re.recurring_interval == "week"
period_str = 'week'
add_interval = (start_date_utc_mjd - @start_date.new_offset(0).mjd)
days = 7
if add_interval < 0
add_interval = 0
else
add_interval = add_interval / days
end
if @start_date < re.recurring_end_date
@recurring << {:id => re.id.to_s, :title=>re.reason_for_hire, :note=>re.reason_for_hire, :start=>@start_date, :end => @end_date, :allDay => false, :recurring => re.recurring, :color => "#FC4040"}
else
period_str = 'month'
add_interval = ((start_date.year * 12 + start_date.month) - (@start_date.year * 12 + @start_date.month))
add_interval = 0 if add_interval < 0
end
add_interval = add_interval.send(period_str)
@start_date += add_interval
@end_date += add_interval
end
while @start_date <= new_end_date do
if unavailable && (unavailable_start_date <= @start_date) && (unavailable_end_date >= @end_date) && !((@start_date.strftime("%w").to_i .. @end_date.strftime("%w").to_i).to_a & unavailable_weekdays).empty?
startt = DateTime.parse(@start_date.strftime("%Y-%m-%d " + unavailable_start_time + Time.zone.to_s))
endt = DateTime.parse(@end_date.strftime("%Y-%m-%d " + unavailable_end_time + Time.zone.to_s))
if !((startt..endt) & (@start_date..@end_date)).blank?
@start_date += interval
@end_date += interval
datet += interval if datet
next
end
end
when "month"
# if !(start_date..end_date).cover?(re.start_time)
sd = re.start_time
ed = re.end_time
@i = TimeDifference.between(re.start_time,end_date).in_months.to_i
@start_date = sd
# debugger
sd = sd >> @i
ed = ed >> @i
if sd < re.recurring_end_date
@recurring << {:id => re.id.to_s, :title=>re.reason_for_hire, :note=>re.reason_for_hire, :start=>sd, :end => ed, :allDay => false, :recurring => re.recurring, :color => "#FC4040"}
if @start_date >= start_date
@recurring << re.as_json({:startt=>@start_date,:endt=>@end_date,:datet=>datet})
end
@start_date += interval
@end_date += interval
datet += interval if datet
end
end
# end
end
end
@recurring

192
app/models/p_hire_field.rb Normal file
View File

@ -0,0 +1,192 @@
class PHireField
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Attributes::Dynamic
include ::AttributeFieldsHelper
include ::Admin::PHireFieldHelper
field :display_in_reason_for_hire, type: Boolean, default: false
field :key, type: String
field :af_count
field :title, type: String, localize: true
field :markup, default: "text_field"
field :option_list, type: Hash,default: {}
field :markup_options, type: Hash
field :built_in, type: Boolean, default: false
field :disabled, type: Boolean, default: false
field :to_delete, type: Boolean, default: false
field :to_require,type: Boolean, default: true
field :typeA, type: Hash, default: {cross_lang: false}
field :typeB, type: Hash, default: {}
field :typeC, type: Hash, default: {calendar: "west_calendar", format: "format3"}
field :typeD, type: Hash, default: {cross_lang: false}
field :typeE, type: Hash, default: {}
field :typeF, type: Hash, default: {}
belongs_to :property
has_many :p_hire_field_values, autosave: true, dependent: :destroy
accepts_nested_attributes_for :p_hire_field_values, :allow_destroy => true
before_save :check_option_list
before_destroy do
@property = self.property
if @property && @property.custom_field_names
@property.custom_field_names.delete("p_hire_fields.#{self.id}")
@property.save
end
end
after_save do
unless self.disabled
@property = self.property
if @property && @property.custom_field_names
if self.new_record? || !(@property.custom_field_names.include?("p_hire_fields.#{self.id}"))
@property.custom_field_names << "p_hire_fields.#{self.id}"
@property.save
end
end
end
if self.display_in_reason_for_hire_changed? && self.property
self.property.update(:need_change_tmp_reason=>true)
end
end
def markup_value
get_data["option_list"]
end
def add_more
(get_data["add_more"] == "true" ? true : false) rescue false
end
def locale
get_data["cross_lang"] == "true" ? false : true
end
def self_defined_markup_options?
(self.property.method(self[:key].pluralize.to_sym) && self.property.method(self[:key].pluralize+"_for_"+markup)) rescue false
end
def option_list
if self_defined_markup_options?
#Class need to have corresponding field and value agent
# Ex: For "status" the class must have field called "statuses" for the relation and "statuses_for_select" for the select function
method = self.property.method(self[:key].pluralize+"_for_"+markup)
return (method.call rescue {})
elsif self[:option_list].nil? || (self[:option_list].empty?)
return {}
else
return self[:option_list]
end
end
def markup_options=(var)
self[:markup_options] = (eval(var) rescue {})
end
def markup_options
if self[:markup_options].nil?
return {}
else
Hash[self[:markup_options].map{|key,val|[key.to_sym,val]}] rescue {}
end
end
def panel
panel = $property_list[:markups][self[:markup]]["panel"]
end
def get_data
self[panel]
end
def get_placeholder(locale=I18n.locale)
placeholder = self.get_data["placeholder"] rescue nil
if placeholder
if placeholder.respond_to?(:keys)
placeholder[locale.to_s]
else
placeholder
end
else
""
end
end
def typeA=(var)
check_add_more_convert(var)
check_cross_lang_convert(var,"typeA")
self["typeA"] = var
end
def typeD=(var)
check_cross_lang_convert(var,"typeD")
self["typeD"] = var
end
def is_built_in?
self.built_in
end
def is_disabled?
self.disabled
end
def self.add_p_hire_field(property,property_param, p_hire_field_id=nil,field_status)
@field_name = 'property'
if field_status.eql?(true)
@p_hire_field_counter = property.p_hire_fields_enabled.count rescue nil
@p_hire_field = self.find(p_hire_field_id) rescue nil
old_key = @p_hire_field.key
@p_hire_field.update(property_param)
@p_hire_field.save
attribute_values = @p_hire_field.p_hire_field_values
if attribute_values.count > 0
attribute_values.each do |av|
av.key = property_param["key"]
av.save
end
end
@p_hire_field[:af_count] = @p_hire_field_counter
else
@p_hire_field_counter = property.p_hire_fields_enabled.count rescue nil
@p_hire_field = property.p_hire_fields.build(property_param) rescue nil
@p_hire_field.save
@p_hire_field[:af_count] = @p_hire_field_counter
end
return @p_hire_field
end
protected
def check_cross_lang_convert(var,field)
if self[field]["cross_lang"] != var["cross_lang"]
case var["cross_lang"]
when "true" #from no-add_more to add_more
cross_lang_convert(:to_cross_lang)
else #from add_more to no-add_more
cross_lang_convert(:to_no_cross_lang)
end # of case
end # of if
end
def check_add_more_convert(var)
if self["typeA"]["add_more"] != var["add_more"]
case var["add_more"]
when "true" #from no-add_more to add_more
add_more_convert(:to_add_more)
else #from add_more to no-add_more
add_more_convert(:to_no_add_more)
end # of case
end # of if
end
def cross_lang_convert(opt)
end
def check_option_list
self[:option_list] = self[panel]["option_list"] rescue nil
end
def add_more_convert(opt)
end
end

View File

@ -0,0 +1,237 @@
class PHireFieldValue
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Attributes::Dynamic
include ::AttributeValuesHelper
include ::Admin::PHireFieldValuesHelper
field :key, type: String
belongs_to :p_hire_field
belongs_to :p_hire
before_save :check_key
before_save :data_proc
def add_more_counter
index_max = self["val"].count rescue 0
index_max == 0 ? 1 : index_max
end
def value(index = nil)
site = Site.first
result = case self.p_hire_field.markup
when 'text_field','text_area'
if self.p_hire_field.add_more and (self.p_hire_field.markup == "text_field")
index.nil? ? self["val"] : self["val"][index]
else
self.p_hire_field.get_data["cross_lang"] =="true" ? self["val"] : Hash[site.valid_locales.collect{|lang| [lang,self[lang.to_sym]]}]
end
when 'select','radio_button','address'
self["val"]
when 'date'
if !self["val"].blank? and !self["val"]['(1i)'].blank?
"#{self["val"]['(1i)']}/#{self["val"]['(2i)']}/#{self["val"]['(3i)']}"
else
self["val"]
end
when 'checkbox'
self["val"]
end #end of case self.p_hire_field.markup
end
def value=(value)
#save everything to temp_data waiting for futher process
self[:temp_data] = value
end
def get_field_value
p_hire_field = self.p_hire_field
if (p_hire_field.markup.eql?("text_field") || p_hire_field.markup.eql?("text_area"))
if self.value.class == String
field_value = self.value
else
field_value = self.value[I18n.locale]
end
elsif (p_hire_field.markup.eql?("select") || p_hire_field.markup.eql?("radio_button"))
field_value = p_hire_field.markup_value["#{self.value}"][I18n.locale] rescue nil
elsif p_hire_field.markup.eql?("address")
field_value = rf[:address_key][I18n.locale].map{|k,v| v}.delete_if(&:blank?).join(', ')
elsif p_hire_field.markup.eql?("date")
case p_hire_field.typeC['format']
when 'format1'
field_value = self.value.to_date.strftime("%Y/%m/%d")
when 'format2'
field_value = self.value.to_date.strftime("%Y/%m/%d")
when 'format3'
field_value = self.value.to_date.strftime("%Y/%m")
when 'format4'
field_value = self.value.to_date.strftime("%Y")
end
elsif p_hire_field.markup.eql?("checkbox")
field_value = self.value.map {|v| p_hire_field.markup_value["#{v}"][I18n.locale]}.join(', ') rescue nil
end
field_value = (field_value =~ /\A#{URI::regexp(['http', 'https'])}\z/) ? "<a href='#{field_value}' target='blank'>#{field_value}</a>" : field_value
field_value = (field_value =~ /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i) ? "<a href='mailto:#{field_value}'>#{field_value}</a>" : field_value
if p_hire_field.markup.eql?("hint_text")
field_value = p_hire_field.get_placeholder rescue ""
{
"key" => p_hire_field.key,
"title" => p_hire_field.title,
"value" => field_value,
"val" => field_value,
"hint" => true
}
elsif !field_value.blank?
{
"key" => p_hire_field.key,
"title" => p_hire_field.title,
"value" => field_value,
"val" => field_value = self.value
}
else
{
"key" => p_hire_field.key,
"title" => p_hire_field.title,
"value" => "",
"val" => field_value = self.value
}
end
end
def get_value_by_locale(locale,add_more_index=nil)
p_hire_field = self.p_hire_field
case p_hire_field.markup
when "text_field"
case p_hire_field.add_more
when true
if p_hire_field.locale
add_more_index.nil? ? self.value.collect{|t| t[locale.to_s]}.join(",") : self.value(add_more_index)[locale]
else
add_more_index.nil? ? self.value.join(",") : self.value(add_more_index)
end
when false
p_hire_field.locale ? self[locale.to_s] : self.value
end
when "select"
markup_values = p_hire_field.self_defined_markup_options? ? p_hire_field.markup_value : self.p_hire_field.markup_value
markup_values[self.value][locale.to_s] rescue 'NoData'
when "text_area"
p_hire_field.locale ? self[locale.to_s] : self.value
when "date"
if p_hire_field.date_is_range?
get_date_by_format(:from) + ' ~ ' + get_date_by_format(:to)
# self.value["from"] + ' ~ ' + self.value["to"]
else
get_date_by_format
# self.value
end
when "address"
self.value[locale.to_s]
when "radio_button"
markup_values = p_hire_field.markup_value
markup_values[self.value][locale.to_s]
when "checkbox"
markup_values = p_hire_field.markup_value
self.value.collect{|key| markup_values["#{key}"][I18n.locale]}.join(",")
when "date_durnation"
self.value
else
p_hire_field.locale ? self[locale.to_s] : self.value
end
end
def get_date(item = nil)
case item
when :from
# data = self[:val]["from"]
data = self.value["from"]
when :to
# data = self[:val]["to"]
data = self.value["to"]
when nil
# data = self[:val]
data = self.value
end
# Date.new(data["(1i)"].to_i,data["(2i)"].to_i,data["(3i)"].to_i) rescue nil
end
def self.put_field_values(p_hire, field_value_param, field_value_id=nil,field_value_status)
if field_value_status.eql?(true)
@p_hire_field_value = p_hire.p_hire_field_values.find(field_value_id) rescue nil
if @p_hire_field_value!=nil
@p_hire_field_value.update(field_value_param) rescue nil
@p_hire_field_value.save rescue nil
end
else
@p_hire_field_value = p_hire.p_hire_field_values.build(field_value_param) rescue nil
@p_hire_field_value.save
end
return @p_hire_field_value
end
protected
def unset_all_lang_values
VALID_LOCALES.each{|t| self.unset t}
end
def data_proc
p_hire_field = self.p_hire_field
unless self[:temp_data].nil?
case p_hire_field.markup
when "address"
self["val"] = self["temp_data"]
when 'text_field','text_area'
if p_hire_field.add_more
self["val"] = self["temp_data"]
else # if not add_more
if p_hire_field.can_muti_lang_input?
self[:temp_data].each do |key,val|
self[key] = val
end if(!p_hire_field.get_data[:cross_lang])
else
self["val"] = self[:temp_data]
end
end # of self.p_hire_field.add_more
when 'select','date','radio_button'
self["val"] = self[:temp_data]
when 'checkbox'
self["val"] = self[:temp_data].keys
end #end of case self.p_hire_field.markup
end # of self[:temp_data].nil?
self.unset('temp_data')
self.unset('temp')
end #of data_proc
def check_key
if self.p_hire_field_id.present? && self.p_hire_field.nil?
begin
self.p_hire_field = PHireField.find(self.p_hire_field_id)
rescue
nil
end
end
self.key = self.p_hire_field.key rescue nil
end
def method_missing(*field)
if field.size < 1
self[field[0]]
else
self[(field[0].to_s.delete "=")] = field[1]
end
end
end

View File

@ -5,6 +5,15 @@ class Property
include OrbitCategory::Categorizable
include Slug
FIELDSNAME=["hiring_person_email","hiring_person_number","hiring_person_name","reason_for_hire","note_for_hire","organization" ,"person_in_charge" ,"tel_of_person_in_charge" ,"department" ,"contact_person" ,"tel_of_contact_person" , "mobile_phone_of_contact_person" ,"contact_person_Email" ,"contact_person_department"]
field :need_change_tmp_reason, type: Boolean, default: false
field :need_hire_before, type: Integer, default: 0 #0代表沒有限制
field :need_hire_before_unit, type: String, default: "day" #month, day, hour, minute
field :custom_calendar_type, type: Integer, default: 0 #0=>預設, 1=> 顯示, 2=> 不顯示
field :custom_carousel_image_width, type: String, default: ""
field :display_img, :type => Boolean, :default => false
field :image_display_class, type: String, default: "full-size-img" #3 choices: full-size-img , pull-left , pull-right
field :order_position, type: Integer, default: -1
field :title, as: :slug_title, :localize => true
field :property_usage, :localize => true
field :note, :localize => true
@ -14,26 +23,74 @@ class Property
field :owners, type: Array, :default => []
field :other_owner
field :owner_email
field :owner_email_rule, type: Integer, default: 0 # 0 => owners, 1 => owner_email, 2 => owners + owner_email
field :owner_phone
field :price
field :other_location
field :p_hire_start_time, type: DateTime
field :p_hire_end_time, type: DateTime
field :p_open_start_time, type: DateTime
field :p_open_end_time, type: DateTime
field :p_display_start_time, type: DateTime
field :p_display_end_time, type: DateTime
field :recurring_enable, type: Boolean, :default => false
mount_uploader :image, ImageUploader
# unavailibility fields
field :can_hire_before_months, type: Integer, default: 0
field :set_availability, type: Boolean, default: false
field :set_unavailibility, type: Boolean, default: false
field :start_time
field :end_time
field :weekdays, type: Array, default: []
field :start_date, type: DateTime
field :end_date, type: DateTime
field :special_unavailable_dates, type: Array, default: []
field :special_unavailable_dates_title, type: Array, default: []
field :start_date, type: DateTime # unavailable start date
field :end_date, type: DateTime # unavailable end date
field :hours_restriction, type: Integer, default: 0
field :hours_restriction_duration, type: String
field :description, :localize => true
field :unavailibility_note, :localize => true
field :hiring_person_email, type: Hash, default: {"enable"=>"1","required"=>"true"}
field :hiring_person_number, type: Hash, default: {"enable"=>"1","required"=>"true"}
field :hiring_person_name, type: Hash, default: {"enable"=>"1","required"=>"true"}
field :reason_for_hire, type: Hash, default: {"enable"=>"1","required"=>"true"}
field :note_for_hire, type: Hash, default: {"enable"=>"1","required"=>"false"}
field :organization, type: Hash, default: {"enable"=>"1","required"=>"false"}
field :person_in_charge, type: Hash, default: {"enable"=>"1","required"=>"false"}
field :tel_of_person_in_charge, type: Hash, default: {"enable"=>"1","required"=>"false"}
field :department, type: Hash, default: {"enable"=>"1","required"=>"false"}
field :contact_person, type: Hash, default: {"enable"=>"1","required"=>"false"}
field :tel_of_contact_person, type: Hash, default: {"enable"=>"1","required"=>"false"}
field :mobile_phone_of_contact_person, type: Hash, default: {"enable"=>"1","required"=>"false"}
field :contact_person_Email, type: Hash, default: {"enable"=>"1","required"=>"false"}
field :contact_person_department, type: Hash, default: {"enable"=>"1","required"=>"false"}
field :enable_notes_selector , type: Boolean, default: false
field :notes_selector ,type: Hash, default: {}
field :enable_fields_sort , type: Boolean, default: false
field :custom_field_names, type: Array
field :default_field_names, type: Array
field :copy_id
field :except_clone_relations, :type=>Array, :default => []
belongs_to :property_location
has_many :p_hires
has_many :hire_email_sets, :autosave => true, :dependent => :destroy, :inverse_of => :property
accepts_nested_attributes_for :hire_email_sets, :allow_destroy => true
has_many :p_hire_fields, :autosave => true, :dependent => :destroy
accepts_nested_attributes_for :p_hire_fields, :allow_destroy => true
has_many :property_field_sets, :autosave => true, :dependent => :destroy
accepts_nested_attributes_for :property_field_sets, :allow_destroy => true
has_many :property_day_settings, :autosave => true, :dependent => :destroy
accepts_nested_attributes_for :property_day_settings, :allow_destroy => true
has_many :property_carousel_images, :autosave => true, :dependent => :destroy
accepts_nested_attributes_for :property_carousel_images, :allow_destroy => true
has_many :property_files, :autosave => true, :dependent => :destroy
accepts_nested_attributes_for :property_files, :allow_destroy => true
has_many :property_links, :autosave => true, :dependent => :destroy
accepts_nested_attributes_for :property_links, :allow_destroy => true
scope :sort_order, ->{order_by([:created_at,:desc],[:order_position,:asc])}
scope :can_display, ->{any_of({:p_display_start_time.lt=>Time.now, :p_display_end_time.gt=>Time.now},{:p_display_start_time.lt=>Time.now, :p_display_end_time=>nil},{:p_display_start_time=>nil, :p_display_end_time=>nil})}
WEEKDAYS = [
"Sunday",
"Monday",
@ -43,7 +100,204 @@ class Property
"Friday",
"Saturday"
]
CAlENDARTYPE = ["default","display","not_display"]
after_initialize do
unless self.new_record?
save_flag = false
@no_validate = true
if self.default_field_names.nil?
self.default_field_names = self.get_all_fields(true)
save_flag = true
end
if self.custom_field_names.nil?
self.custom_field_names = self.get_all_fields(true)
save_flag = true
end
if save_flag
self.save
end
end
end
before_create do
max_position = self.class.max(:order_position)
max_position = -1 if max_position.nil?
self.order_position = max_position + 1
@no_validate = true
if self.copy_id.present?
self.clone_new(true)
self.created_at = DateTime.now
self.updated_at = DateTime.now
else
self.default_field_names = self.get_all_fields(true)
self.custom_field_names = self.get_all_fields(true)
end
end
before_save do
unless @no_validate || self.new_record?
self.custom_field_names = [] if self.custom_field_names.nil?
self.default_field_names = self.get_all_fields(true)
self.class::FIELDSNAME.each do |f|
if((self.send(f)["enable"] == "1" rescue true) && !(self.custom_field_names.include?(f)))
self.custom_field_names << f
end
end
end
end
after_save do
self.change_day_setting_status
end
def can_reserve
start_time = self.p_hire_start_time || Time.now
end_time = self.p_hire_end_time || (Time.now + 1.month)
return Time.now >= start_time && end_time >= Time.now
end
def p_hire_fields_enabled
self.p_hire_fields.where(disabled: false)
end
def all_day_settings
self.property_day_settings.asc(:key).group_by(&:day)
end
def change_day_setting_status
if self.property_day_settings.count != 0
if self.set_unavailibility && self.weekdays.count != 0
self.property_day_settings.where(:day.nin=>self.weekdays).update_all(:enable=>true)
tmp_start_time = self.start_time.blank? ? "00:00" : self.start_time
tmp_end_time = self.end_time.blank? ? "24:00" : self.end_time
self.property_day_settings.where(:day.in=>self.weekdays).each do |setting|
if setting.end_time < tmp_start_time || setting.start_time > tmp_end_time
setting.enable = true
else
setting.enable = false
end
setting.save
end
else
self.property_day_settings.update_all(:enable=>true)
end
end
end
def calendar_type
(self.custom_calendar_type == 0 ? (PropertyHireSetting.first.calendar_type rescue 0) : (self.custom_calendar_type - 1))
end
def self.init_class_variables
setting = PropertyHireSetting.first
if setting
@@disable_content_page = setting.disable_content_page rescue false
@@disable_view_calendar_page = setting.disable_view_calendar_page rescue false
@@disable_no_logins_view_calendar = setting.disable_no_logins_view_calendar rescue false
else
@@disable_content_page = false
@@disable_view_calendar_page = false
@@disable_no_logins_view_calendar = false
end
end
init_class_variables
def disable_content_page
@@disable_content_page
end
def disable_view_calendar_page
@@disable_view_calendar_page
end
def disable_no_logins_view_calendar
@@disable_no_logins_view_calendar
end
def custom_text(field_name,type="name",locale=nil)
locale = locale || I18n.locale
default_text = I18n.with_locale(locale){I18n.t("property_hire.#{field_name}")}
if (self.send(field_name)[type][locale.to_s].present? rescue false)
self.send(field_name)[type][locale.to_s]
else
default_text
end
end
def render_unavailable_message
message = ""
property = self
weekdays_options = self.class::WEEKDAYS
weekdays_options = weekdays_options.map do |weekday|
trans = I18n.t("property_hire.#{weekday}", :default=>'')
if trans != ""
trans
else
weekday
end
end
if property.set_unavailibility
if property.weekdays.length > 0
translation_missing = (I18n.t('property_hire.unavailable_hint1', {:default => ''}) == "")
str1 = (!property.start_date.nil? ? (I18n.t("property_hire.from",:default=>" from ") + property.start_date.strftime("%Y-%m-%d")) : "")
str2 = (!property.end_date.nil? ? (I18n.t("property_hire.to",:default=>" to ") + property.end_date.strftime("%Y-%m-%d")) : "")
if str1 == "" && str2 != ""
str1 = I18n.t("property_hire.from_now_on")
end
if str1 != "" || str2 != ""
str2 += I18n.t("property_hire.of",:default=>"")
else
str2 += I18n.t("property_hire.at",:default=>"")
end
week_str = ""
if translation_missing
week_str += "every "
else
week_str += I18n.t("property_hire.every")
end
dot_trans = I18n.t("property_hire.dot",:default=>", ")
property.weekdays.each_with_index do |d,i|
if i < (property.weekdays.count - 1)
week_str += (weekdays_options[d.to_i] + dot_trans)
else
week_str += weekdays_options[d.to_i]
end
end
str3 = ""
if property.end_time.blank?
if property.start_time.blank?
str3 = "." if translation_missing
else
str3 = I18n.t("property_hire.from_time",{:time=>property.start_time,:default=>" from #{property.start_time}."})
end
else
if I18n.locale.to_s != "zh_tw"
str3 = " between #{property.start_time} &amp; #{property.end_time}."
else
str3 = I18n.t("property_hire.time1_to_time2",{:time1=>property.start_time,:time2=>property.end_time})
end
end
if str3 != ""
str3 = I18n.t("property_hire.of",:default=>"") + str3
end
hint1 = I18n.t('property_hire.unavailable_hint1', {:str1=>str1,:str2=>str2,:week_str=>week_str,:str3=>str3, :default => ''})
if hint1 == ""
message += "This property is unavaliable#{str1}#{str2} #{week_str}#{str3}"
else
message += hint1
end
end
if property.special_unavailable_dates.count > 1
message += " And on " + property.special_unavailable_dates.join(", ")
end
if property.need_hire_before != 0
if message != ""
message += "<br>"
end
default_msg = "This property must be reserved #{property.need_hire_before} #{property.need_hire_before_unit}s in advance."
message += I18n.t("property_hire.unavailable_hint3",{:month=>property.need_hire_before,:unit=>I18n.t("property_hire._#{property.need_hire_before_unit}",:default=>property.need_hire_before_unit),:default=>default_msg})
end
if property.can_hire_before_months != 0
if message != ""
message += "<br>"
end
default_msg = "This property is unavaliable to reserved before #{property.can_hire_before_months} month ago."
message += I18n.t("property_hire.unavailable_hint2",{:month=>property.can_hire_before_months,:default=>default_msg})
end
if property.hours_restriction > 0
message += "<br />" + I18n.t("property_hire.hours_restriction_message", {:no_of_hours => property.hours_restriction, :duration => I18n.t("property_hire._#{property.hours_restriction_duration}") })
end
end
return message.html_safe
end
def get_location_name
return self.property_location.nil? ? self.other_location : self.property_location.title
end
@ -52,92 +306,586 @@ class Property
MemberProfile.find(self.owners) rescue []
end
def is_available_for_hire?(stime, etime)
return true if self.set_unavailibility == false
return true if self.weekdays.empty?
return true if !self.start_date.nil? && (self.start_date > stime && self.start_date > etime)
return true if !self.end_date.nil? && self.end_date < stime
startt = self.start_date.nil? ? self.created_at : self.start_date
endt = self.end_date.nil? && !startt.nil? ? (startt + 5.years) : self.end_date
def get_user_total_user_hired_hours(start_time, end_time)
member_profile_id = OrbitHelper.current_user.member_profile.id.to_s rescue nil
return 0 if member_profile_id.nil?
hires = self.p_hires.where(:hiring_person_id => member_profile_id, :start_time.gte => start_time, :end_time.lte => end_time)
total_hours = 0.0
hires.each do |hire|
diff = hire.end_time - hire.start_time
total_hours += diff * 24.0
end
return total_hours
end
def is_available_for_hire?(stime, etime, interval = nil, recurring_end_date = nil, time_setting_id = nil, member_profile)
available = 0
is_user_manager = Admin::PropertyHiresController.helpers.check_if_user_is_manager?
return 1 if is_user_manager == true
return 1 if self.set_unavailibility == false
return 1 if self.weekdays.empty? && self.can_hire_before_months == 0
time_now = Time.now.to_datetime
if self.can_hire_before_months != 0
return 2 if ((stime - (self.can_hire_before_months).month) > time_now)
end
if self.need_hire_before != 0
return 3 if (time_now + (self.need_hire_before).send(self.need_hire_before_unit) > stime)
end
self.special_unavailable_dates.each do |dt|
unavailable_date = Date.parse(dt)
cd = (stime..etime) & (unavailable_date..unavailable_date)
if !cd.nil?
return 0
end
end
if DateTime.now >= (self.start_date || DateTime.now - 1.day) && DateTime.now <= (self.end_date || DateTime.now + 1.month)
if self.hours_restriction > 0 && !user.nil?
sd = nil
edd = nil
case self.hours_restriction_duration
when "week"
sd = stime - stime.wday
edd = sd + 6
when "month"
sd = Date.new(stime.year, stime.month, 1)
edd = sd.next_month.prev_day
end
if self.get_user_total_user_hired_hours(sd, edd) >= self.hours_restriction
return 0
end
end
end
available = 1 if startt > etime
available = 1 if endt < stime
weekdays = self.weekdays.collect{|w| w.to_i}
if !startt.nil?
if available == 0
common_dates = (startt..endt) & (stime..etime)
return true if common_dates.nil?
available = 1 if common_dates.nil?
if available == 0
time_weekdays = []
Property.time_iterate(common_dates.min, common_dates.max, 1.day) do |t|
time_weekdays << t.wday
end
time_weekdays.uniq!
weekdays = weekdays & time_weekdays
return true if weekdays.blank?
startt = DateTime.parse(stime.strftime("%Y-%m-%d " + self.start_time + Time.zone.to_s))
endt = DateTime.parse(etime.strftime("%Y-%m-%d " + self.end_time + Time.zone.to_s))
common_dates = (startt..endt) & (stime..etime)
if common_dates.nil?
return true
if weekdays.blank?
available = 1
else
return false
startt = DateTime.parse(stime.strftime("%Y-%m-%d " + (self.start_time.blank? ? "00:00" : self.start_time) + Time.zone.to_s))
endt = DateTime.parse(etime.strftime("%Y-%m-%d " + (self.end_time.blank? ? "23:59" : self.end_time) + Time.zone.to_s))
common_dates = (startt..endt) & (stime..etime)
available = common_dates.nil? ? 1 : 0
end
end
end
if available == 1
if !recurring_end_date.blank?
case interval
when 'week'
d_step = 1.week
when 'month'
d_step = 1.month
else
d_step = 0
end
if d_step != 0
if etime >= stime
Property.time_iterate(etime,recurring_end_date,d_step).each do |date_time|
new_etime = date_time
new_stime = stime + (new_etime - etime)
available = self.is_available_for_hire?(new_stime, new_etime, nil, nil)
break if available != 1
end
else
available = 0
end
end
end
return available
else
return available
end
end
end
def is_already_hired?(stime, etime, interval, recurring_end_date)
bookings = self.p_hires.where(:end_time.gte => stime, :recurring => false)
def not_yet_hired?(stime, etime, interval, recurring_end_date,phire_id=nil,time_setting_id=nil)
phires = self.p_hires
stime = stime.utc
etime = etime.utc
bookings_count = 0
reservation_limit = 0
if time_setting_id
time_setting = PropertyDaySetting.find(time_setting_id)
etime = stime + 1.day
etime = etime.utc
reservation_limit = time_setting.reservation_limit
if reservation_limit == 0
return true
end
bookings_count = phires.where(:start_time.lte => stime,:end_time.gte => stime,:recurring => false,:id.ne=>phire_id,:property_day_setting_id=>time_setting_id).count
+ phires.where(:start_time.gte => stime,:end_time.lte => etime,:recurring => false,:id.ne=>phire_id,:property_day_setting_id=>time_setting_id).count
+phires.where(:start_time.lte => etime,:end_time.gte => etime,:recurring => false,:id.ne=>phire_id,:property_day_setting_id=>time_setting_id).count
if bookings_count < reservation_limit
bookings_count = 0
end
else
bookings_count = phires.where(:start_time.lte => stime,:end_time.gte => stime,:recurring => false,:id.ne=>phire_id).count
+ phires.where(:start_time.gte => stime,:end_time.lte => etime,:recurring => false,:id.ne=>phire_id).count
+phires.where(:start_time.lte => etime,:end_time.gte => etime,:recurring => false,:id.ne=>phire_id).count
end
available = true
bookings.each do |booking|
common_time = (booking.start_time..booking.end_time) & (stime..etime)
if !common_time.nil?
if bookings_count != 0
available = false
end
if available
recurring_bookings = phires.where(:recurring_end_date.gte => stime, :recurring => true,:id.ne=>phire_id)
bookings = phires.where(:recurring => false,:recurring_end_date => nil,:id.ne=>phire_id)
case interval
when 'week'
d_step = 1.week
when 'month'
d_step = 1.month
else
d_step = 0
end
not_in_ids = bookings.any_of([{:end_time.lt=>stime},{:start_time.gt=>etime}]).pluck(:id)
bookings = bookings.where(:id.nin=>not_in_ids)
if time_setting_id
recurring_bookings = recurring_bookings.where(:property_day_setting_id=>time_setting_id)
bookings = recurring_bookings.where(:property_day_setting_id=>time_setting_id)
end
if true#d_step != 0
bookings += recurring_bookings
end
if time_setting_id
tmp = {}
stime_date = stime.strftime("%Y-%m-%d")
bookings = bookings.each_with_index do |booking,i|
if booking.date.wday != stime.wday
next
end
b_interval = booking.recurring_interval
b_recurring_end_date = booking.recurring_end_date ? booking.recurring_end_date.utc : nil
booking_date = booking.start_time.utc.strftime("%Y-%m-%d")
if (b_interval == 'month' || b_interval == 'week') && (booking.recurring_end_date.nil? || !booking.recurring)
b_interval = nil
end
if stime_date == booking_date
if tmp[booking_date].nil?
tmp[booking_date] = 0
end
tmp[booking_date] += 1
available = false if tmp[booking_date] > reservation_limit
end
break if available == false
if b_interval.present?
b_interval = (1).send(b_interval)
b_sdata = booking.start_time.utc
b_datas = Property.time_iterate(b_sdata,b_recurring_end_date,b_interval)
all_stime_datas = Property.time_iterate(stime,b_recurring_end_date,b_interval).map{|t| t.utc.strftime("%Y-%m-%d")}
b_datas.each do |b_data|
booking_date = b_data.utc.strftime("%Y-%m-%d")
if all_stime_datas.include?(booking_date)
if tmp[booking_date].nil?
tmp[booking_date] = 0
end
tmp[booking_date] += 1
available = false if tmp[booking_date] > reservation_limit
end
break if available == false
end
end
break if available == false
end
else
bookings.each_with_index do |booking,i|
stime_tp = stime.clone
etime_tp = etime.clone
b_interval = booking.recurring_interval
b_recurring_end_date = booking.recurring_end_date ? booking.recurring_end_date.utc : nil
b_sdata = booking.start_time.utc
b_edata = booking.end_time.utc
b_delta = b_edata - b_sdata
if (b_interval == 'month' || b_interval == 'week') && (booking.recurring_end_date.nil? || !booking.recurring)
b_interval = nil
end
b_datas = []
if b_interval.present?
b_interval = (1).send(b_interval)
b_datas = Property.time_iterate(b_edata,b_recurring_end_date,b_interval)
b_datas = b_datas.map{|b_end| [b_end-b_delta,b_end]}
start_index = b_datas.count
b_datas.each_with_index do |(b_start,b_end),i|
if b_start >= stime_tp || b_end <= etime_tp
start_index = i
break
end
end
if available
case interval
when "week"
stepu = 1.week
when "month"
stepu = 1.month
b_datas = b_datas[start_index..-1].to_a.map{|b_start,b_end| (b_start..b_end)}
else
stepu = 0
b_datas = [b_sdata..b_edata]
end
bookings = self.p_hires.where(:recurring_end_date.gte => stime, :recurring => true)
bookings.each do |booking|
booking.time_iterate do |st,et|
tst = stime
tet = etime
if stepu != 0
begin
common_time = (tst..tet) & (st..et)
available = false if !common_time.nil?
tet += stepu
break if !available
break if tst > st
end while (tst += stepu) <= recurring_end_date
while b_datas.present?
available = b_datas.find{|b_range| b_range & (stime_tp..etime_tp)}.nil?
stime_tp = stime_tp + d_step
etime_tp = etime_tp + d_step
break if !available || recurring_end_date.blank? || d_step==0
start_index = b_datas.find_index{|b_range| b_range.first >= stime_tp}
if start_index
b_datas = b_datas[start_index..-1]
else
common_time = (tst..tet) & (st..et)
available = false if !common_time.nil?
break if !available
b_datas = []
end
break if !available
end
break if !available
break if available == false
end
end
end
return available
end
def check_require_fields(booking_p)
fields_name = self.get_all_fields
has_p_hire_fields = self.p_hire_fields_enabled.count != 0
p_hire_fields = {}
if has_p_hire_fields
p_hire_fields = self.p_hire_fields_enabled.map{|rf| [rf.id.to_s,rf]}.to_h
end
error_messages = ""
form_index = 0
cross_lang_types = ['select','date','radio_button','checkbox']
unfilled_text = I18n.t('property_hire.unfilled')
available_locales = I18n.available_locales
available_locales_trans = available_locales.map{|l| [l, I18n.t(l)]}.to_h
fields_name.each do |field_name|
if has_p_hire_fields && field_name.include?("p_hire_fields")
rf = p_hire_fields[field_name.sub("p_hire_fields.",'')]
if rf && rf.markup != 'hint_text' && rf.to_require
v = booking_p["p_hire_field_values_attributes"][form_index.to_s]['value']
if cross_lang_types.include?(rf.markup) || rf.get_data["cross_lang"] == "true"
if v.blank?
error_messages += "#{rf.title}: #{unfilled_text}\n"
end
else
available_locales.each do |l|
if (v[l].blank? rescue true)
error_messages += "#{rf.title}(#{available_locales_trans[l]}): #{unfilled_text}\n"
end
end
end
end
form_index = form_index +1
else
field_setting = self.send(field_name)
if field_setting && field_setting["required"] == "true" && booking_p[field_name].blank?
error_messages += "#{self.custom_text(field_name,"name")}: #{unfilled_text}\n"
end
end
end
error_messages
end
def self.time_iterate(start_time, end_time, step, &block)
times = []
if block_given?
begin
times << start_time
yield(start_time, end_time)
end while (start_time += step) <= end_time
else
start_time = start_time.clone
begin
times << start_time
end while (start_time += step) <= end_time
end
times
end
def carousel_image_width
(self.custom_carousel_image_width.blank? ? PropertyHireSetting.first.carousel_image_width : self.custom_carousel_image_width) rescue "75%"
end
def get_attribute_value(attribute_field, p_hire_id)
PHireFieldValue.find_by(p_hire_field_id: attribute_field.id, p_hire_id: p_hire_id)
end
def get_attribute_values(attribute_type=nil)
@attribute_values = attribute_type.p_hire_field_values rescue nil
end
def get_value_from_field_id(field_id,attribute_type=nil)
values = get_attribute_values(attribute_type)
value = values.detect {|value| value.p_hire_field_id == field_id} rescue nil
value ? value : nil
end
def get_basic_fields
basic_fields = self.class::FIELDSNAME
basic_fields = basic_fields.select{|f| (self.send(f)["enable"] == "1" rescue true)}
end
def get_all_fields(get_default=false)
@default_field_names = nil if @default_field_names.nil?
if get_default
if @default_field_names.nil?
basic_fields = self.get_basic_fields
custom_fields = []
self.p_hire_fields_enabled.each do |p_hire_field|
unless p_hire_field.disabled
custom_fields << "p_hire_fields.#{p_hire_field.id}"
end
end
@default_field_names = basic_fields + custom_fields
end
return @default_field_names
else
self.enable_fields_sort ? self.custom_field_names : self.default_field_names
end
end
def can_be_hired_frontend
if PropertyHireSetting.first.allow_no_logins_user
return true
else
user = OrbitHelper.current_user
return self.can_be_hired || (user && (user.is_admin? || (self.owners && self.owners.include?(user.member_profile_id))))
end
end
def can_be_show_frontend
user = OrbitHelper.current_user
(!disable_no_logins_view_calendar && self.can_be_hired) || user
end
def clone_new(clone_mode=false)
@records_all = {}
if clone_mode
clone_target = self.class.find(object.copy_id) rescue nil
else
clone_target = self
end
property,clone_target = clone_new_for_object(self,clone_target,clone_mode)
property
end
def fix_uploader(clone_relation, r, f)
return r.send(f).blank?
if !@clone_mode || (clone_relation[f].blank? && clone_relation.send(f).blank?)
clone_relation[f] = r[f]
if @clone_mode
clone_relation.send(f).retrieve_from_store!(r[f])
else
org_id = clone_relation.id
clone_relation.id = r.id
clone_relation.send(f).retrieve_from_store!(r[f])
clone_relation.id = org_id
end
source_filepath = r.send(f).file.file
if @clone_mode
dest_filepath = clone_relation.send(f).file.file
FileUtils.mkdir_p(File.dirname(dest_filepath))
FileUtils.cp(source_filepath,dest_filepath)
end
elsif (clone_relation.send(f).file rescue nil)
clone_relation[f] = File.basename(clone_relation.send(f).file.file.to_s)
end
end
def clone_new_for_object(object,clone_target=nil,clone_mode=false,fix_only=false)
@except_clone_relations ||= self.except_clone_relations
if clone_mode || fix_only
new_object = object
clone_target = object.class.find(object.copy_id) rescue nil if clone_target.nil?
else
clone_target = object if clone_target.nil?
new_object = object.dup
end
return if @except_clone_relations.include?(new_object.class.to_s.underscore)
@records_all["#{new_object.class.to_s.underscore}_ids"] = {} if @records_all["#{new_object.class.to_s.underscore}_ids"].nil?
begin
@records_all["#{new_object.class.to_s.underscore}_ids"][clone_target.id] = new_object
rescue
nil
end
if !clone_target.nil? && !new_object.nil?
unless fix_only
if clone_mode
initialize_fields = []
if new_object.fields.keys.include?("uid")
new_object.generate_uid
end
else
initialize_fields = ["uid","created_at","updated_at"]
end
initialize_fields.each do |f|
new_object.send("#{f}=",nil) if new_object.fields.keys.include?(f)
end
end
relations_fields = clone_target.relations.except("impressions").keys
all_fields = clone_target.fields.keys - relations_fields
all_fields = all_fields - relations_fields.map{|k| "#{k}_id"}
all_fields = all_fields - relations_fields.map{|k| "#{k.singularize}_ids"}
new_object_class_name = new_object.class.to_s.underscore
unless @parent_level
unsort_relation_keys = clone_target.relations.keys - ['taggings']
fields_to_delete = [new_object_class_name]
tmp_relations_fields = [new_object_class_name]
while relations_fields.count > 0
tmp_singularize_relations_fields = tmp_relations_fields.map{|f| f.singularize}
approve_append = nil
relations_fields.each do |k|
belongs_to_class = clone_target.relations[k].class_name.constantize.relations.select{|k,v| v.macro == :belongs_to}.keys
has_many_class = clone_target.relations[k].class_name.constantize.relations.select{|k,v| v.macro.to_s.start_with?('has') }.keys
if (belongs_to_class - tmp_singularize_relations_fields).count == 0
other_has_many_class = (has_many_class - unsort_relation_keys)
if other_has_many_class.count == 0
tmp_relations_fields << k
else
org_k = k.to_s
result = other_has_many_class.map do |k|
belongs_to_class = k.classify.constantize.relations.select{|kk,v| v.macro == :belongs_to}.keys
has_many_class = k.classify.constantize.relations.select{|kk,v| v.macro.to_s.start_with?('has') }.keys
if (belongs_to_class - tmp_singularize_relations_fields - [org_k]).count == 0
true
else
fields_to_delete = fields_to_delete.concat(belongs_to_class)
tmp_relations_fields.concat(belongs_to_class)
false
end
end
if result.select{|t| !t}.count == 0
if (fields_to_delete.map{|f| f.pluralize} - tmp_relations_fields).count == 0
tmp_relations_fields << k
elsif clone_target.relations[k].class_name.constantize.fields.keys.include?("key")
tmp_relations_fields << k
elsif (clone_target.relations[k].class_name.constantize.relations.keys.map{|f| f.singularize} & fields_to_delete).count != 0
approve_append = k
end
end
end
elsif !unsort_relation_keys.include?(clone_target.relations[k].class_name.underscore) && !unsort_relation_keys.include?(clone_target.relations[k].class_name.underscore.pluralize)
tmp_relations_fields << k
end
end
tmp_relations_fields << approve_append if approve_append.present?
approve_append = nil
relations_fields = relations_fields - tmp_relations_fields
relations_fields -= @relations_fields if @relations_fields
end
relations_fields = tmp_relations_fields
fields_to_delete.each{|f| relations_fields.delete(f)}
end
if @parent_level
relations_fields -= @relations_fields
else
@clone_mode = clone_mode
@relations_fields = relations_fields
end
@parent_level = true
if clone_mode
all_fields.each do |f|
next if f == "uid"
unless new_object.send("#{f}_changed?") && new_object.send("#{f}_changed_from_default?")
unless fix_only
new_object.send("#{f}=",clone_target.send(f))
end
if new_object.class.uploaders.include?(f.to_sym)
fix_uploader(new_object, clone_target, f)
end
end
end
else
all_fields.each do |f|
if new_object.class.uploaders.include?(f.to_sym)
fix_uploader(new_object, clone_target, f)
end
end
end
relations_fields.each do |f|
no_dup_flag = false
if clone_target.relations[f].macro == :belongs_to || clone_target.relations[f].macro == :has_one
no_dup_flag = new_object.send(f).present?
elsif clone_target.relations[f].macro == :has_many || clone_target.relations[f].macro == :has_and_belongs_to_many
no_dup_flag = new_object.send(f).to_a.count != 0
elsif clone_target.relations[f].macro == :embeds_many #Fix localize fields
if new_object.send(f).to_a.count != 0
need_fix_fields = new_object.send(f).to_a[0].fields.select{|k,v| (v.options[:localize] rescue false)}.keys
locale = I18n.locale.to_s
embeded_records = new_object.send(f).map do |embeded_record|
need_fix_fields.each do |f|
if (embeded_record[f][locale].class != String rescue false)
embeded_record.send("#{f}_translations=",embeded_record[f][locale])
else
embeded_record.send("#{f}_translations=",embeded_record[f])
end
end
embeded_record
end
new_object.send("#{f}=",embeded_records)
end
end
if clone_target.relations[f].macro == :belongs_to || clone_target.relations[f].class_name == "MemberProfile"
if f == 'taggable'
map_f = @taggable_name
else
map_f = f
end
if @records_all["#{map_f}_ids"].nil?
new_object.send("#{f}_id=",clone_target.send("#{f}_id"))
else
obj = @records_all["#{map_f}_ids"][clone_target.send("#{f}_id")]
if obj
new_object.send("#{f}_id=", obj.id)
new_object.send("#{f}=", obj)
end
end
elsif clone_target.relations[f].macro == :has_one
next if @except_clone_relations.include?(f)
need_clone_relation = clone_target.send(f)
next if need_clone_relation.nil?
clone_relation = new_object.send(f)
if clone_relation.nil?
clone_relation, need_clone_relation = clone_new_for_object(need_clone_relation.dup, need_clone_relation, clone_mode, fix_only)
else
clone_relation, r = clone_new_for_object(clone_relation, r, clone_mode, true)
end
new_object.send("#{f}=",clone_relation)
elsif clone_target.relations[f].macro == :has_many || clone_target.relations[f].macro == :has_and_belongs_to_many
next if @except_clone_relations.include?(f)
clone_relations = []
need_clone_relations = clone_target.send(f).asc(:_id).to_a
file_flag = false
if f == 'taggings'
@taggable_name = new_object.class.to_s.underscore
end
need_clone_relations.each_with_index do |r,i|
clone_relation = new_object.send(f)[i]
if clone_relation.nil?
clone_relation, r = clone_new_for_object(r.dup, r, clone_mode, fix_only)
else
clone_relation, r = clone_new_for_object(clone_relation, r, clone_mode, true)
end
clone_relations << clone_relation
end
if !no_dup_flag || (no_dup_flag && file_flag)
new_object_relations = new_object.send(f).to_a
new_object_relations_count = new_object_relations.count
if new_object_relations_count != 0
if clone_relations.count > new_object_relations_count
clone_relations = clone_relations[0...new_object_relations_count]
else
clone_relations = clone_relations.concat(new_object.send(f)[clone_relations.count...new_object_relations_count])
end
new_object.send("#{f}=",clone_relations)
else
new_object.send("#{f}=",clone_relations)
end
end
end
end
new_object.copy_id = clone_target.id if new_object.fields.keys.include?("copy_id")
return new_object, clone_target
end
end
def get_owner_emails
emails = []
case self.owner_email_rule
when 0
emails = MemberProfile.where(:id.in=> self.owners.to_a).pluck(:email)
when 1
emails = [self.owner_email]
when 2
emails = MemberProfile.where(:id.in=> self.owners.to_a).pluck(:email) + [self.owner_email]
end
emails.select{|email| email.present?}
end
end

View File

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

View File

@ -0,0 +1,12 @@
class PropertyDaySetting
include Mongoid::Document
include Mongoid::Timestamps
field :enable, type: Boolean, default: true
field :key
field :day
field :title
field :start_time
field :end_time
field :reservation_limit, type: Integer, default: 1
belongs_to :property
end

View File

@ -0,0 +1,11 @@
class PropertyFieldSet
include Mongoid::Document
include Mongoid::Timestamps
field :field_name, type: String
field :placeholder
field :name
field :disabled, type: Boolean, default: false
field :hidden, type: Boolean, default: false
belongs_to :property
end

View File

@ -0,0 +1,12 @@
# encoding: utf-8
class PropertyFile
include Mongoid::Document
include Mongoid::Timestamps
mount_uploader :file, AssetUploader
field :description, :type => String, :default=> ""
field :title, :type => String, :default=> ""
belongs_to :property
end

View File

@ -3,8 +3,19 @@ class PropertyHireSetting
include Mongoid::Timestamps
field :auto_approve, type: Boolean, :default => false
field :carousel_image_width, type: String, :default => "75%"
field :disable_content_page, type: Boolean, :default => false
field :disable_view_calendar_page, type: Boolean, :default => false
field :disable_no_logins_view_calendar, type: Boolean, :default => false
field :allow_no_logins_user, type: Boolean, :default => false
field :calendar_type, type: Integer, default: 0 # 0=> 顯示, 1=> 不顯示
def self.auto_approve_enabled?
self.first.auto_approve
self.first.auto_approve rescue false
end
after_save do
Property.init_class_variables
end
def default_time_settings
PropertyDaySetting.where(:property_id=>"default_settings").asc(:key)
end
end

View File

@ -0,0 +1,25 @@
# encoding: utf-8
require 'uri'
class PropertyLink
include Mongoid::Document
include Mongoid::Timestamps
field :url, :type => String, :default=> ""
field :title, :type => String, :default=> ""
before_validation :add_http
belongs_to :property
def display_title
self.title.blank? ? self.url : self.title
end
protected
def add_http
unless self.url[/^http:\/\//] || self.url[/^https:\/\//]
self.url = 'http://' + self.url
end
end
end

View File

@ -0,0 +1,146 @@
<div class="attributes default <%= attribute_field.disabled ? 'disabled' : ''%>">
<%
attribute_field.af_count ? @af_counter = attribute_field_counter + attribute_field.af_count : @af_counter = attribute_field_counter
%>
<div class="attributes-header clearfix">
<div class="toggle-control" style="float: right;">
<div class="togglebox <%= attribute_field.disabled ? 'disabled' : ''%>">
<%= hidden_field "#{@field_name}[p_hire_fields][#{@af_counter}]","disabled",:value=>attribute_field.disabled,:class=>"toggle-check", :data=>{:deploy=>"right"} %>
<label><b></b></label>
</div>
</div>
<a class="btn btn-mini pull-right btn-danger delete" href="#"><i class="icon-trash"></i> <%= t(:delete_)%></a>
<%= hidden_field "#{@field_name}[p_hire_fields][#{@af_counter}]","to_delete",:value=>false,:class=>"attribute_field_to_delete"%>
<a class="btn btn-mini pull-right btn-inverse reply hide" href="#"><i class="icons-reply"></i> Reset</a>
<h4>Field <span><%= @af_counter + 1 %></span></h4>
</div>
<div class="attributes-body">
<div class="control-group">
<label class="control-label muted" for="key_<%= @af_counter %>"><%= t(:key) %></label>
<div class="controls">
<%= text_field "#{@field_name}[p_hire_fields][#{@af_counter}]","key",:value=>attribute_field.key, :data=>{:type=>"key"} %>
</div>
</div>
<%= render :partial=>"shared/attribute_field/placeholder_block",:locals=>{:values=>attribute_field.title_translations,:class_ext=>"pull-left",:label_ext=>t(:name),:field_name=>"#{@field_name}[p_hire_fields][#{@af_counter}][title_translations]"}%>
<div class="control-group">
<label class="control-label muted" for=""><%= t('property_hire.to_require') %></label>
<div class="controls">
<label class="radio inline">
<%= radio_button("#{@field_name}[p_hire_fields][#{@af_counter}]", "to_require", "true",:checked => (attribute_field.to_require == true ? true : false), :data=>{:type=>"search_true"}) %><%= t(:yes_)%>
</label>
<label class="radio inline">
<%= radio_button("#{@field_name}[p_hire_fields][#{@af_counter}]", "to_require", "false",:checked => (attribute_field.to_require == false ? true : false), :data=>{:type=>"search_false"}) %><%= t(:no_)%>
</label>
</div>
</div>
<div class="control-group">
<label class="control-label muted" for=""><%= t('property_hire.display_in_reason_for_hire') %></label>
<div class="controls">
<label class="radio inline">
<%= radio_button("#{@field_name}[p_hire_fields][#{@af_counter}]", "display_in_reason_for_hire", "true",:checked => (attribute_field.display_in_reason_for_hire == true ? true : false), :data=>{:type=>"search_true"}) %><%= t(:yes_)%>
</label>
<label class="radio inline">
<%= radio_button("#{@field_name}[p_hire_fields][#{@af_counter}]", "display_in_reason_for_hire", "false",:checked => (attribute_field.display_in_reason_for_hire == false ? true : false), :data=>{:type=>"search_false"}) %><%= t(:no_)%>
</label>
</div>
</div>
<div class="control-group">
<label class="control-label muted" for=""><%= t(:type)%></label>
<div class="controls">
<select class="dataType" data-type="select" name=<%= "#{@field_name}[p_hire_fields][#{@af_counter}][markup]"%>>
<%$property_list[:markups].each do |key,val|%>
<% next if val["display_only"] && val["display_only"] != "p_hire_field" %>
<% if key != 'address' %>
<option value="<%= key %>" <%= attribute_field.markup == key ? 'selected="selected"' : '' %> ref="<%=val["panel"]%>"><%=t("lists.markups."+key)%></option >
<% end %>
<% end %>
</select>
</div>
</div>
</div>
<div class="field-type fade"></div>
<%= content_tag :div,:class=>"field-type default fade in #{show_property_type_panel(attribute_field,"typeA")}" do%>
<div class="control-group">
<label class="control-label muted"><%= t(:enabled_for)%></label>
<div class="controls">
<label class="checkbox inline">
<%= check_box_tag("#{@field_name}[p_hire_fields][#{@af_counter}][typeA][cross_lang]","true",attribute_field["typeA"]["cross_lang"],:data=>{:type=>"cross_lang"}) %>
<%= t(:cross_lang) %>
</label>
<label class="checkbox inline">
<%= check_box_tag("#{@field_name}[p_hire_fields][#{@af_counter}][typeA][add_more]","true",attribute_field["typeA"]["add_more"],:data=>{:type=>"add_more"}) %>
<%= t(:add_more)%>
</label>
</div>
</div>
<%= render :partial=>"shared/attribute_field/placeholder_block",:locals=>{:values=>attribute_field["typeA"]["placeholder"],:field_name=>"#{@field_name}[p_hire_fields][#{@af_counter}][typeA][placeholder]"}%>
<% end if show_property_type_panel(attribute_field,"typeA") != 'typeA hide' %>
<%= content_tag :div,:class=>"field-type default fade in #{show_property_type_panel(attribute_field,"typeB")}" do %>
<%= render :partial=>"shared/attribute_field/placeholder_block",:locals=>{:label_ext=>t(:initial),:values=>attribute_field["typeB"]["initial"],:field_name=>"#{@field_name}[p_hire_fields][#{@af_counter}][typeB][initial]"}%>
<% if attribute_field.self_defined_markup_options?%>
<%= render :partial=>"shared/attribute_field/list_block",:locals=>{:values=>attribute_field["option_list"],:field_name=> "#{@field_name}[p_hire_fields][#{@af_counter}][attribute][property][statuses]"} %>
<%else #normal list%>
<%= render :partial=>"shared/attribute_field/list_block",:locals=>{:values=>attribute_field["option_list"],:field_name=> "#{@field_name}[p_hire_fields][#{@af_counter}][typeB][option_list]"} %>
<% end #of self_defined_markup_options?%>
<% end if show_property_type_panel(attribute_field,"typeB") != 'typeB hide' %>
<%= content_tag :div,:class=>"field-type default fade in #{show_property_type_panel(attribute_field,"typeC")}" do %>
<div class="control-group">
<label class="control-label"><%= t("date.format")%></label>
<div class="controls">
<%= select "#{@field_name}[p_hire_fields][#{@af_counter}][typeC]","format",Admin::AttributeValuesViewHelper::OPT,:class=>"dataType",:selected=>attribute_field["typeC"]["format"] %>
</div>
</div>
<div class="control-group">
<label class="control-label"><%= t("date.range")%></label>
<div class="controls">
<label class="radio inline">
<%= radio_button("#{@field_name}[p_hire_fields][#{@af_counter}][typeC]", "is_range", "false",:checked => (!attribute_field.date_is_range? ? true : false)) %><%= t(:yes_)%>
</label>
<label class="radio inline">
<%= radio_button("#{@field_name}[p_hire_fields][#{@af_counter}][typeC]", "is_range", "true",:checked => (attribute_field.date_is_range? ? true : false)) %><%= t(:no_)%>
</label>
</div>
</div>
<div class="control-group">
<label class="control-label"><%= t("date.calendar")%></label>
<div class="controls">
<label class="radio inline">
<%= radio_button("#{@field_name}[p_hire_fields][#{@af_counter}][typeC]", "calendar", "west_calendar",:checked =>(attribute_field["typeC"]["calendar"]== "west_calendar" ? true : false)) %><%= t("date.west_calendar")%>
</label>
<label class="radio inline">
<%= radio_button("#{@field_name}[p_hire_fields][#{@af_counter}][typeC]", "calendar", "tw_calendar",:checked =>(attribute_field["typeC"]["calendar"]== "tw_calendar" ? true : false)) %><%= t("date.tw_calendar")%>
</label>
</div>
</div>
<% end if show_property_type_panel(attribute_field,"typeC") != 'typeC hide' %>
<%= content_tag :div,:class=>"field-type default fade in #{show_property_type_panel(attribute_field,"typeD")}" do%>
<div class="control-group">
<label class="control-label"><%= t(:enabled_for)%></label>
<div class="controls">
<label class="checkbox inline">
<%= check_box_tag("#{@field_name}[p_hire_fields][#{@af_counter}][typeD][cross_lang]","true",attribute_field["typeD"]["cross_lang"]) %>
<%= t(:cross_lang)%>
</label>
</div>
</div>
<%= render :partial=>"shared/attribute_field/placeholder_block",:locals=>{:field_name=>"#{@field_name}[p_hire_fields][#{@af_counter}][typeD][placeholder]",:values=>attribute_field["typeD"]["placeholder"]} %>
<% end if show_property_type_panel(attribute_field,"typeD") != 'typeD hide' %>
<%= content_tag :div,:class=>"field-type default fade in #{show_property_type_panel(attribute_field,"typeE")}" do%>
<%= render :partial=>"shared/attribute_field/list_block",:locals=>{:field_name=>"#{@field_name}[p_hire_fields][#{@af_counter}][typeE][option_list]",:values=>attribute_field["typeE"]["option_list"]}%>
<% end if show_property_type_panel(attribute_field,"typeE") != 'typeE hide' %>
<%= content_tag :div,:class=>"field-type default fade in #{show_property_type_panel(attribute_field,"typeF")}" do%>
<%= render :partial=>"shared/attribute_field/hint_block",:locals=>{:values=>attribute_field["typeF"]["placeholder"],:field_name=>"#{@field_name}[p_hire_fields][#{@af_counter}][typeF][placeholder]"}%>
<% end if show_property_type_panel(attribute_field,"typeF") != 'typeF hide' %>
<%= hidden_field "#{@field_name}[p_hire_fields][#{@af_counter}]","id",:value=>attribute_field.id%>
</div>

View File

@ -1,7 +1,75 @@
<%
hire_method = Admin::PropertyHiresHelper::HireMethod
hire_method.set_input_name('property')
with_id = !(@property.new_record?)
%>
<style type="text/css">
.tab-panel > .tab-content{
display: none;
}
.tab-panel > .tab-content.active{
display: block;
}
.tab-panel{
display: flex;
flex-wrap: wrap;
}
.label_left{
float: left;
margin-right: 0.5em;
}
.select_field_block{
border: 0.2em solid #666;
padding: 1em;
}
.remove_btn:hover{
font-size: 1.3em;
}
.remove_btn{
cursor: pointer;
}
.card-header a{
text-align: center;
display: block;
}
.card-header:hover{
background: aquamarine;
}
.card-header:hover a{
text-decoration: none;
}
.add_weekday_setting{
text-align: center;
align-self: center;
}
.time_setting_form, .image_group{
border: 0.2em solid #333;
padding-top: 0;
}
.add-on.iconbtn{
display: none;
}
.time_setting_form:last-child, .image_group:last-child {
margin-bottom: 1em;
}
.card-header {
padding: 0;
}
.card-header a {
padding: .75rem 1.25rem;
}
.card-header h4 {
margin: 0;
}
.apply_default_time_settings{
margin-bottom: 1em;
}
</style>
<% content_for :page_specific_css do %>
<%= stylesheet_link_tag "lib/main-forms" %>
<%= stylesheet_link_tag "lib/fileupload" %>
<%= stylesheet_link_tag "lib/main-list" %>
<%= stylesheet_link_tag "admin/card" %>
<% end %>
<% content_for :page_specific_javascript do %>
<%= javascript_include_tag "lib/bootstrap-fileupload" %>
@ -18,9 +86,15 @@
<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>
<li><a href="#page_setting" data-toggle="tab"><%= t("property_hire.page_setting") %></a></li>
<li><a href="#files_links" data-toggle="tab"><%= t("property_hire.files_links") %></a></li>
<li><a href="#tag" data-toggle="tab"><%= t(:tags) %></a></li>
<li><a href="#imageupload" data-toggle="tab"><%= t(:image) %></a></li>
<li><a href="#unavailability" data-toggle="tab"><%= t('property_hire.unavailability')%></a></li>
<li><a href="#carousel_image_upload" data-toggle="tab" title="<%= t('property_hire.carousel_image_title') %>"><%= t('property_hire.carousel_image') %></a></li>
<li><a href="#unavailability" data-toggle="tab"><%= t('property_hire.unavailable_time')%></a></li>
<li><a href="#available_time" data-toggle="tab"><%= t('property_hire.available_time')%></a></li>
<li><a href="#auto_send_email_set" data-toggle="tab"><%= t('property_hire.auto_send_email_set') %></a></li>
<li><a href="#settings" data-toggle="tab"><%= t('property_hire.reservation_fields') %></a></li>
</ul>
<!-- Module -->
<div class="tab-content module-area">
@ -51,24 +125,73 @@
<%= f.text_field :other_location %>
</div>
</div>
<%
=begin%>
<div class="control-group">
<%= f.label :property_number, t("property_hire.property_number"), :class => "control-label muted" %>
<div class="controls">
<%= f.text_field :property_number %>
</div>
</div>
<%
=end%>
<div class="control-group">
<%= f.label :can_be_hired, t("property_hire.can_be_hired"), :class => "control-label muted" %>
<%= f.label :p_display_start_time, t("property_hire.p_display_start_time"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :can_be_hired %>
<%= f.datetime_picker :p_display_start_time, :picker_type => "date", :no_label => true, :new_record => @property.new_record?, :data=>{"picker-type" => "range", "range" => "start"}, :format => "yyyy/MM/dd hh:mm" %>
</div>
</div>
<div class="control-group">
<%= f.label :p_display_end_time, t("property_hire.p_display_end_time"), :class => "control-label muted" %>
<div class="controls">
<%= f.datetime_picker :p_display_end_time, :picker_type => "date", :no_label => true, :new_record => @property.new_record?, :data=>{"picker-type" => "range", "range" => "end"}, :format => "yyyy/MM/dd hh:mm" %>
</div>
</div>
<div class="control-group">
<%= f.label :p_hire_start_time, t("property_hire.p_hire_start_time"), :class => "control-label muted" %>
<div class="controls">
<div class="muted"><%= t("property_hire.time_period_note") %></div>
<%= f.datetime_picker :p_hire_start_time, :picker_type => "date", :no_label => true, :new_record => @property.new_record?, :data=>{"picker-type" => "range", "range" => "start"}, :format => "yyyy/MM/dd hh:mm" %>
</div>
</div>
<div class="control-group">
<%= f.label :p_hire_end_time, t("property_hire.p_hire_end_time"), :class => "control-label muted" %>
<div class="controls">
<%= f.datetime_picker :p_hire_end_time, :picker_type => "date", :no_label => true, :new_record => @property.new_record?, :data=>{"picker-type" => "range", "range" => "end"}, :format => "yyyy/MM/dd hh:mm" %>
</div>
</div>
<div class="control-group">
<%= f.label :recurring_enable, t("property_hire.recurring_enable"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :recurring_enable %>
</div>
</div>
<div id="open-time" >
<div class="control-group">
<%= f.label :p_open_start_time, t("property_hire.p_open_start_time"), :class => "control-label muted" %>
<div class="controls">
<div class="muted"><%= t("property_hire.available_time_note") %></div>
<%= f.datetime_picker :p_open_start_time, :picker_type => "date", :no_label => true, :new_record => @property.new_record?, :data=>{"picker-type" => "range", "range" => "start"}, :format => "yyyy/MM/dd" %>
</div>
</div>
<div class="control-group">
<%= f.label :p_open_end_time, t("property_hire.p_open_end_time"), :class => "control-label muted" %>
<div class="controls">
<%= f.datetime_picker :p_open_end_time, :picker_type => "date", :no_label => true, :new_record => @property.new_record?, :data=>{"picker-type" => "range", "range" => "end"}, :format => "yyyy/MM/dd" %>
</div>
</div>
</div>
<%
=begin%>
<div class="control-group">
<%= f.label :purchase_date, t("property_hire.purchase_date"), :class => "control-label muted" %>
<div class="controls">
<%= f.datetime_picker :purchase_date, :no_label => true, :new_record => @property.new_record?, :picker_type => "date", :format => "yyyy/MM/dd" %>
</div>
</div>
<%
=end%>
<div class="control-group">
<%= f.label :owners, t("property_hire.owners"), :class => "control-label muted" %>
<div class="controls">
@ -87,18 +210,41 @@
<%= f.text_field :owner_email %>
</div>
</div>
<div class="control-group">
<%= f.label :owner_email_rule, t("property_hire.owner_email_rule"), :class => "control-label muted" %>
<div class="controls">
<%= f.select :owner_email_rule, options_for_select([0,1,2].map{|i| [t("property_hire.owner_email_rules.#{i}"), i]}, f.object.owner_email_rule) %>
</div>
</div>
<div class="control-group">
<%= f.label :owner_phone, t("property_hire.owner_phone"), :class => "control-label muted" %>
<div class="controls">
<%= f.text_field :owner_phone %>
</div>
</div>
<%
=begin%>
<div class="control-group">
<%= f.label :price, t("property_hire.price"), :class => "control-label muted" %>
<div class="controls">
<%= f.text_field :price %>
</div>
</div>
<%
=end%>
</div>
<!-- page_setting -->
<div class="tab-pane fade" id="page_setting">
<div class="control-group">
<%= f.label :custom_calendar_type, t("property_hire.display_calendar"), :class => "control-label muted" %>
<div class="controls">
<%= f.select :custom_calendar_type, options_for_select(Property::CAlENDARTYPE.map.with_index{|type,i| [t("property_hire.custom_calendar_type.#{type}"), i]}, f.object.custom_calendar_type) %>
</div>
</div>
</div>
<!-- files_links -->
<div class="tab-pane fade" id="files_links">
<%= render :partial => "form_file_link", :locals=>{:f=>f} %>
</div>
<!-- tags -->
<div class="tab-pane fade" id="tag">
@ -118,7 +264,7 @@
<% if @property.image.file %>
<%= image_tag @property.image %>
<% else %>
<img src="http://www.placehold.it/50x50/EFEFEF/AAAAAA" />
<img src="/assets/property_hire/AAAAAA.png" />
<% end %>
</div>
<div class="fileupload-preview fileupload-exists thumbnail pull-left"></div>
@ -136,8 +282,116 @@
</div>
</div>
</div>
<!-- display img src -->
<div class="control-group">
<%= f.label :display_img, t("property_hire.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("property_hire.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("property_hire.#{key}") %>
</label>
<% end %>
</div>
</div>
</div>
<!-- Images Module -->
<div class="tab-pane fade" id="carousel_image_upload">
<div class="control-group">
<label class="control-label muted" for="carousel_image_width"><%= t("property_hire.carousel_image_width") %></label>
<div class="controls">
<%= f.text_field :custom_carousel_image_width, :placeholder => t("property_hire.custom_carousel_image_width_hint") %>
</div>
</div>
<% if f.object && !f.object.property_carousel_images.blank? %>
<div class="exist">
<% f.object.property_carousel_images.each_with_index do |property_carousel_image, i| %>
<%= f.fields_for :property_carousel_images, property_carousel_image do |f| %>
<%= render :partial => 'form_image', :object => property_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 'property_carousel_image_count', f.object.property_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>
<!-- Email Set Module -->
<div class="tab-pane fade" id="auto_send_email_set" style="padding: 1.2em;">
<ul class="nav nav-pills module-nav">
<li class="active">
<a href="#email_set0" data-toggle="tab">
<%= t('property_hire.hire') %>
</a>
</li>
<li class="">
<a href="#email_set1" data-toggle="tab">
<%= t('property_hire.edit') %>
</a>
</li>
<li class="">
<a href="#email_set2" data-toggle="tab">
<%= t('property_hire.delete') %>
</a>
</li>
</ul>
<div class="tab-content">
<% (0..2).each do |index1| %>
<% active_email_set = index1==0 ? ' active' : '' %>
<div class="tab-pane<%= active_email_set %>" id="email_set<%= index1 %>" style="padding: 1.2em;">
<table style="width:100%;">
<tbody>
<tr>
<td>
<%= t('disable') %>
</td>
<td>
<input type="hidden" class="field_set" name='<%= "property[hire_email_sets][#{index1}][disabled]" %>' value="false">
<%= check_box_tag("property[hire_email_sets][#{index1}][disabled]", true ,@email_set[index1].disabled) %>
</td>
</tr>
<tr>
<td>
<%= t('property_hire.email_title') %>
</td>
<td>
<%= hire_method.show_set_field(@email_set[index1].id,@email_set[index1]['title'],'hire_email_sets',index1,'title','text_field',with_id) %>
</td>
</tr>
<tr>
<td>
<%= t('property_hire.email_content') %>
</td>
<td>
<div class="form-group">
<%= hire_method.show_set_field(@email_set[index1].id,@email_set[index1]['content'],'hire_email_sets',index1,'content','text_area',with_id) %>
</div>
<%= hidden_field_tag("property[hire_email_sets][#{index1}][field_name]",@email_set[index1]['field_name']) %>
<% unless @property.new_record? %>
<%= hidden_field_tag("property[hire_email_sets][#{index1}][property_id]",@property.id) %>
<% end %>
</td>
</tr>
</tbody>
</table>
</div>
<% end %>
</div>
</div>
<!-- unavailability -->
<div class="tab-pane fade" id="unavailability">
<div class="control-group">
@ -146,50 +400,72 @@
<%= f.check_box :set_unavailibility %>
</div>
</div>
<% if @property.new_record? %>
<div id="set_unavailibility_div" style="display: none;">
<% elsif @property.set_unavailibility %>
<% if @property.set_unavailibility %>
<div id="set_unavailibility_div">
<% else %>
<div id="set_unavailibility_div" style="display: none;">
<% end %>
<div class="control-group">
<%= f.label :start_time, t("property_hire.start_time"), :class => "control-label muted" %>
<%= f.label :can_hire_before_months, t("property_hire.how_many_months_ago_can_be_hired"), :class => "control-label muted" %>
<div class="controls">
<%= f.datetime_picker :start_time, :picker_type => "time", :no_label => true, :new_record => @property.new_record?, :value => (Time.parse(@property.start_time) rescue "") %>
<%= f.select :can_hire_before_months, options_for_select([[t("property_hire.no_limit"),0]] + (1..12).to_a.map{|month| [t("property_hire.month", month: month), month]},f.object.can_hire_before_months) %>
</div>
</div>
<div class="control-group">
<%= f.label :end_time, t("property_hire.end_time"), :class => "control-label muted" %>
<div class="controls">
<%= f.datetime_picker :end_time, :picker_type => "time", :no_label => true, :new_record => @property.new_record?, :value => (Time.parse(@property.end_time) rescue "") %>
</div>
</div>
<div class="control-group">
<label class="control-label muted">Weekdays</label>
<label class="control-label muted"><%=t("property_hire.weekdays").html_safe%></label>
<div class="controls">
<% weekdays = @property.weekdays rescue [] %>
<label for="sunday">
<input id="sunday" type="checkbox" name="property[weekdays][]" value="0" <%= weekdays.include?("0") ? "checked=checked" : "" %> /> Sunday
</label>
<label for="monday">
<input id="monday" type="checkbox" name="property[weekdays][]" value="1" <%= weekdays.include?("1") ? "checked=checked" : "" %> /> Monday
</label>
<label for="tuesday">
<input id="tuesday" type="checkbox" name="property[weekdays][]" value="2" <%= weekdays.include?("2") ? "checked=checked" : "" %> /> Tuesday
</label>
<label for="wednesday">
<input id="wednesday" type="checkbox" name="property[weekdays][]" value="3" <%= weekdays.include?("3") ? "checked=checked" : "" %> /> Wednesday
</label>
<label for="thursday">
<input id="thursday" type="checkbox" name="property[weekdays][]" value="4" <%= weekdays.include?("4") ? "checked=checked" : "" %> /> Thursday
</label>
<label for="friday">
<input id="friday" type="checkbox" name="property[weekdays][]" value="5" <%= weekdays.include?("5") ? "checked=checked" : "" %> /> Friday
</label>
<label for="saturday">
<input id="saturday" type="checkbox" name="property[weekdays][]" value="6" <%= weekdays.include?("6") ? "checked=checked" : "" %> /> Saturday
<% Property::WEEKDAYS.each_with_index do |weekday,i| %>
<label for="<%=weekday%>">
<input id="<%=weekday%>" type="checkbox" name="property[weekdays][]" value="<%=i%>" <%= weekdays.include?(i.to_s) ? "checked=checked" : "" %> /> <% trans = t("property_hire.#{weekday}") %><%= (trans.class == ActiveSupport::SafeBuffer ? weekday : trans) %>
</label>
<% end %>
</div>
</div>
<div class="control-group">
<label class="control-label muted"><%=t("property_hire.special_unavailable_date")%></label>
<div class="controls" id="special_unavailable_date_holder">
<% @property.special_unavailable_dates.each_with_index do |dt, idx| %>
<div class="temp_date_holder" style="margin-bottom:5px;">
<div class="date_picker input-append" style="margin-bottom:3px;">
<input placeholder="yyyy/MM/dd" class="input-large" data-format="yyyy/MM/dd" type="text" name="property[special_unavailable_dates][]" title="yyyy/MM/dd" autocomplete="off" value="<%= dt %>">
<span class="add-on clearDate"><i class="icons-cross-3"></i></span>
<span class="add-on deleteDate"><i class="icon-trash"></i></span>
</div>
<div class="tab-panel">
<div class="tab-content active" id="special_unavailable_title_<%= idx %>_en">
<input type="text" name="property[special_unavailable_dates_title][][en]" value="<%= @property.special_unavailable_dates_title[idx]["en"] %>">
</div>
<div class="tab-content" id="special_unavailable_title_<%= idx %>_zh_tw">
<input type="text" name="property[special_unavailable_dates_title][][zh_tw]" value="<%= @property.special_unavailable_dates_title[idx]["zh_tw"] %>">
</div>
<div class="btn-group" data-toggle="buttons-radio">
<a data-toggle="tab" class="btn active" for="en" href="#special_unavailable_title_<%= idx %>_en" aria-expanded="true" aria-pressed="true"><%= t("en") %></a>
<a data-toggle="tab" class="btn" for="zh_tw" href="#special_unavailable_title_<%= idx %>_zh_tw" aria-expanded="true" aria-pressed="true"><%= t("zh_tw") %></a>
</div>
</div>
</div>
<% end %>
</div>
<div class="controls">
<button class="primary" id="add_special_unavailable_date">Add</button>
</div>
</div>
<div class="control-group">
<%= f.label :need_hire_before, t("property_hire.need_hire_before"), :class => "control-label muted" %>
<div class="controls">
<% units = ['month', 'day', 'hour', 'minute'] %>
<%= f.number_field :need_hire_before, :min=>0 %>
<%= f.select :need_hire_before_unit, options_for_select(units.map{|unit| [t("property_hire._#{unit}"), unit]},f.object.need_hire_before_unit) %>
</div>
</div>
<div class="control-group">
<label class="control-label muted"><%=t("property_hire.hours_restriction") %></label>
<div class="controls">
<% units = ['week', 'month'] %>
<%= f.number_field :hours_restriction, :min=>0, :max=>24 %>
<%= f.select :hours_restriction_duration, options_for_select(units.map{|unit| [t("property_hire._#{unit}"), unit]},f.object.need_hire_before_unit) %>
</div>
</div>
<div class="control-group">
@ -204,6 +480,18 @@
<%= f.datetime_picker :end_date, :picker_type => "date", :no_label => true, :new_record => @property.new_record?, :data=>{"picker-type" => "range", "range" => "end"}, :format => "yyyy/MM/dd" %>
</div>
</div>
<div class="control-group">
<%= f.label :start_time, t("property_hire.limit_start_time"), :class => "control-label muted" %>
<div class="controls">
<%= f.datetime_picker :start_time, :picker_type => "time", :no_label => true, :new_record => @property.new_record?, :value => (Time.parse(@property.start_time) rescue "") %>
</div>
</div>
<div class="control-group">
<%= f.label :end_time, t("property_hire.limit_end_time"), :class => "control-label muted" %>
<div class="controls">
<%= f.datetime_picker :end_time, :picker_type => "time", :no_label => true, :new_record => @property.new_record?, :value => (Time.parse(@property.end_time) rescue "") %>
</div>
</div>
<% @site_in_use_locales.each do |locale| %>
<%= f.fields_for :description_translations do |f| %>
<div class="control-group">
@ -215,7 +503,7 @@
<% end %>
<% end %>
<% @site_in_use_locales.each do |locale| %>
<%= f.fields_for :unavailibility_note do |f| %>
<%= f.fields_for :unavailibility_note_translations do |f| %>
<div class="control-group">
<label class="control-label muted" for="note_<%= locale.to_s %>"><%= t(:note) + " (#{t(locale.to_s)})" %></label>
<div class="controls">
@ -226,6 +514,164 @@
<% end %>
</div>
</div>
<!-- available_time -->
<div class="tab-pane fade" id="available_time">
<div class="control-group">
<%= f.label :set_availability, t("property_hire.set_availability"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :set_availability %>
</div>
</div>
<% if @property.set_availability %>
<div id="set_availability_div">
<% else %>
<div id="set_availability_div" style="display: none;">
<% end %>
<ul>
<% all_day_settings = f.object.all_day_settings %>
<% setting_count = 0 %>
<% Property::WEEKDAYS.each_with_index do |weekday,i| %>
<li class="card">
<div class="card-header">
<h4>
<a data-toggle="collapse" href="#<%=weekday%>_setting" role="button" aria-expanded="false" aria-controls="<%=weekday%>_setting"><% trans = t("property_hire.#{weekday}") %><%= (trans.class == ActiveSupport::SafeBuffer ? weekday : trans) %></a>
</h4>
</div>
<div class="collapse" id="<%=weekday%>_setting">
<div class="card card-body">
<div>
<button type="button" class="btn btn-primary apply_default_time_settings pull-right" data-target="#add_target_weekday_<%=i%>" data-count="0" data-day="<%=i%>"><%=t("property_hire.apply_default_time_settings")%></button>
</div>
<div id="add_target_weekday_<%=i%>">
<% if all_day_settings[i.to_s] %>
<% all_day_settings[i.to_s].each_with_index do |setting,j| %>
<%= f.fields_for :property_day_settings, setting,:child_index => setting_count do |f| %>
<%= render :partial => "time_form", :locals=>{:key=>j,:day=>i,:f=>f} %>
<% setting_count += 1 %>
<% end %>
<% end %>
<% end %>
</div>
<a class="btn btn-primary add_weekday_setting" data-target="#add_target_weekday_<%=i%>" data-count="<%= all_day_settings[i] ? all_day_settings[i].count : 0 %>" data-day="<%=i%>"><%=t(:add)%></a>
</div>
</div>
</li>
<% end %>
</ul>
</div>
</div>
<div class="tab-pane fade" id="settings">
<% fields_name = f.object.class::FIELDSNAME %>
<div style="padding: 1.2em;">
<table style="margin: 0;">
<thead>
<th><%= t('property_hire.field_name') %></th>
<th><%= t('property_hire.name') %></th>
<th><%= t('property_hire.placeholder') %></th>
<th><%= t('property_hire.disable') %></th>
<th><%= t('property_hire.required') %></th>
</thead>
<tbody>
<% fields_name.each do |field_name| %>
<tr>
<td>
<%= t("property_hire.#{field_name}") %>
</td>
<td>
<%= render_custom_text_field(f,field_name,"name") %>
</td>
<td>
<%= render_custom_text_field(f,field_name,"placeholder") %>
</td>
<td>
<input type="hidden" name='<%= "#{f.object_name}[#{field_name}][enable]" %>' value="1">
<%= check_box_tag("#{f.object_name}[#{field_name}][enable]", "0" , (f.object.send(field_name)["enable"] == "0" rescue false)) %>
</td>
<td>
<input type="hidden" name='<%= "#{f.object_name}[#{field_name}][required]" %>' value="false">
<%= check_box_tag("#{f.object_name}[#{field_name}][required]", "true" , (f.object.send(field_name)["required"] == "true" rescue false)) %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<hr style="border-color: black; ">
<div class="control-group">
<% field_name = "enable_notes_selector" %>
<label class="control-label muted"><%= t("property_hire.#{field_name}") %></label>
<div class="controls">
<label for="act_enabled_name" class="checkbox inline">
<%= hidden_field_tag "property[#{field_name}]", "0" %>
<%= f.check_box_tag "property[#{field_name}]", "1" , (@property[field_name] rescue false) %>
Enable
</label>
</div>
</div>
<div class="control-group" id="selector_block">
<% field_name = "notes_selector" %>
<label class="control-label muted"><%= t("property_hire.#{field_name}") %></label>
<div class="controls">
<div id="select_choice_block">
<% @property[field_name].each do |index,sub_hash| %>
<div id="select_choice<%=index.to_s%>" class="select_field_block">
<span class="remove_btn">❌</span>
<div class="field_name_block">
<div>
<label for="select_choice_type_index<%=index.to_s%>" class="label_left"><%=t("property_hire.field_type")%>:</label>
<select name="<%="property[#{field_name}][#{index}][type]"%>">
<option value="radio" <%=(@property["#{field_name}"]["#{index}"]["type"] == "radio") ? 'selected="selected"' : ''%>><%=t("property_hire.radio")%></option>
<option value="checkbox" <%=(@property["#{field_name}"]["#{index}"]["type"] == "checkbox") ? 'selected="selected"' : ''%>><%=t("property_hire.checkbox")%></option>
</select>
</div>
<div><label for="select_choice_name_index<%=index.to_s%>" class="label_left"><%=t("property_hire.field_name")%>:</label>
<div class="input-append">
<div class="tab-content">
<% @site_in_use_locales.each_with_index do |locale, i| %>
<div class="tab-pane fade <%= ( i == 0 ) ? "active in" : '' %>" id="select_choice_name_index<%=index%>_<%=locale.to_s%>">
<input type="text" value="<%=sub_hash['name'][locale.to_s] rescue ''%>" name="<%="property[#{field_name}][#{index}][name][#{locale}]"%>">
</div>
<% end %>
</div>
<div class="btn-group" data-toggle="buttons-radio">
<% @site_in_use_locales.each_with_index do |locale, i| %>
<a class="btn <%= ( i == 0 ) ? "active" : '' %>" href="#select_choice_name_index<%=index%>_<%=locale.to_s%>" data-toggle="tab"><%= t(locale.to_s) %></a>
<% end %>
</div>
</div>
</div>
</div>
<div class="field_value_block">
<label><%=t("property_hire.field_value")%></label>
<% @property["#{field_name}"]["#{index}"]["value"].values.first.each_with_index do |v,val_index|%>
<div class="value_choice">
<span class="remove_btn">❌</span>
<div class="input-append">
<div class="tab-content">
<% @site_in_use_locales.each_with_index do |locale, i| %>
<div class="tab-pane fade <%= ( i == 0 ) ? "active in" : '' %>" id="select_choice_value_index<%=index.to_s%>_<%=locale.to_s%>_<%=val_index%>">
<input type="text" name="property[notes_selector][<%=index.to_s%>][value][<%=locale.to_s%>][]" value="<%=@property["#{field_name}"][index.to_s]["value"][locale.to_s][val_index]%>">
</div>
<% end %>
</div>
<div class="btn-group" data-toggle="buttons-radio">
<% @site_in_use_locales.each_with_index do |locale, i| %>
<a class="btn <%= ( i == 0 ) ? "active" : '' %>" href="#select_choice_value_index<%=index.to_s%>_<%=locale.to_s%>_<%=val_index%>" data-toggle="tab"><%= t(locale.to_s) %></a>
<% end %>
</div>
</div>
</div>
<% end %>
<div style="clear: both;"></div>
<a class="btn btn-primary add_choice" data-index="<%=index.to_s%>"><%=t("property_hire.add_choice")%></a>
</div>
</div>
<% end %>
</div>
<a id="add_note_select_field" class="btn btn-primary"><%=t(:add)%></a>
</div>
</div>
</div>
</div>
<!-- Language Tabs -->
<div class="nav-name"><strong><%= t(:language) %></strong></div>
@ -253,7 +699,7 @@
<label class="control-label muted"><%= t("property_hire.property_usage") %></label>
<div class="controls">
<%= f.fields_for :property_usage_translations do |f| %>
<%= f.text_area locale, class: "input-block-level", placeholder: t("property_hire.property_usage"), value: (@property.property_usage_translations[locale] rescue nil) %>
<%= f.text_area locale, class: "ckeditor input-block-level", placeholder: t("property_hire.property_usage"), value: (@property.property_usage_translations[locale] rescue nil) %>
<% end %>
</div>
</div>
@ -261,23 +707,33 @@
<label class="control-label muted"><%= t("property_hire.note") %></label>
<div class="controls">
<%= f.fields_for :note_translations do |f| %>
<%= f.text_area locale, class: "input-block-level", placeholder: t("property_hire.note"), value: (@property.note_translations[locale] rescue nil) %>
<%= f.text_area locale, class: "ckeditor input-block-level", placeholder: t("property_hire.note"), value: (@property.note_translations[locale] rescue nil) %>
<% end %>
</div>
</div>
</div>
<% end %>
</div>
</div>
<!-- Form Actions -->
<div class="form-actions">
<% if params[:page] %>
<input type="hidden" name="page" value="<%= params[:page] %>" />
<% referer = request.referer rescue nil %>
<% referer = get_referer_url if referer.blank? || request.host != URI.parse(URI.encode(referer)).host %>
<input type="hidden" name="referer_url" value="<%= referer %>">
<% unless @property.new_record? %>
<%= hidden_field_tag("property[id]", @property.id) %>
<% end %>
<%= f.submit t('submit'), class: 'btn btn-primary' %>
<%= link_to t('cancel'), admin_property_hires_path, :class=>"btn" %>
<%= link_to t('cancel'), referer, :class=>"btn" %>
</div>
<script type="text/javascript">
$("#bulletin_display_img").click(function(){$("#image_display_setting").toggleClass("hide")})
$(document).ready(function(){
if($("[type=checkbox][name='property[enable_notes_selector]']:checked").length == 0){
$("#selector_block").css("display","none");
}else{
$("#selector_block").css("display","");
}
})
$("#property_set_unavailibility").on("click",function(){
if($(this).is(":checked")){
$("#set_unavailibility_div").show();
@ -285,7 +741,13 @@
$("#set_unavailibility_div").hide();
}
})
$("#property_set_availability").on("click",function(){
if($(this).is(":checked")){
$("#set_availability_div").show();
}else{
$("#set_availability_div").hide();
}
})
$("#property_property_location").on("change",function(){
if($(this).val() == "other_location"){
$("#other-location-div").show();
@ -293,6 +755,300 @@
$("#other-location-div").hide();
}
})
$("#add_note_select_field").on("click",function(){
var index = ($("#select_choice_block").find(">div").length == 0) ? 0 : (Number($("#select_choice_block").find(">div").eq(-1).attr("id").split("select_choice").last()) + 1);
$("#select_choice_block").append('<div id="select_choice'+String(index)+'" class="select_field_block"><span class="remove_btn">❌</span>'+
'<div class="field_name_block">'+
'<div>'+
'<label for="select_choice_type_index'+String(index)+'" class="label_left"><%=t("property_hire.field_type")%>:</label>'+
'<select name="property[notes_selector]['+String(index)+'][type]">'+
'<option value="radio"><%=t("property_hire.radio")%></option>'+
'<option value="checkbox"><%=t("property_hire.checkbox")%></option>'+
'</select>'+
'</div>'+
'<div><label for="select_choice_name_index'+String(index)+'" class="label_left"><%=t("property_hire.field_name")%>:</label>'+
'<div class="input-append" id="select_choice_name_index'+String(index)+'">'+
'<div class="tab-content">'+
<% @site_in_use_locales.each_with_index do |locale, i| %>
'<div class="tab-pane fade <%= ( i == 0 ) ? "active in" : '' %>" id="select_choice_name_index'+String(index)+'_<%=locale.to_s%>">'+
'<input type="text" name="property[notes_selector]['+String(index)+'][name][<%=locale.to_s%>]">'+
'</div>'+
<% end %>
'</div>'+
'<div class="btn-group" data-toggle="buttons-radio">'+
<% @site_in_use_locales.each_with_index do |locale, i| %>
'<a class="btn <%= ( i == 0 ) ? "active" : '' %>" href="#select_choice_name_index'+String(index)+'_<%=locale.to_s%>" data-toggle="tab"><%= t(locale.to_s) %></a>'+
<% end %>
'</div>'+
'</div>'+
'</div>'+
'</div>'+
'<div class="field_value_block">'+
'<label><%=t("property_hire.field_value")%></label>'+
'<div class="value_choice">'+
'<span class="remove_btn">❌</span>'+
'<div class="input-append">'+
'<div class="tab-content">'+
<% @site_in_use_locales.each_with_index do |locale, i| %>
'<div class="tab-pane fade <%= ( i == 0 ) ? "active in" : '' %>" id="select_choice_value_index'+String(index)+'_<%=locale.to_s%>_0">'+
'<input type="text" name="property[notes_selector]['+String(index)+'][value][<%=locale.to_s%>][]">'+
'</div>'+
<% end %>
'</div>'+
'<div class="btn-group" data-toggle="buttons-radio">'+
<% @site_in_use_locales.each_with_index do |locale, i| %>
'<a class="btn <%= ( i == 0 ) ? "active" : '' %>" href="#select_choice_value_index'+String(index)+'_<%=locale.to_s%>_0" data-toggle="tab"><%= t(locale.to_s) %></a>'+
<% end %>
'</div>'+
'</div>'+
'</div>'+
'<div style="clear: both;"></div>'+
'<a class="btn btn-primary add_choice" data-index="'+String(index)+'"><%=t("property_hire.add_choice")%></a>'+
'</div>'+
'</div>');
$(".add_choice").off("click").on("click",function(){
var index = $(this).attr("data-index");
var val_index = $(this).siblings(".value_choice").length;
var $last_item = $(this).siblings(".value_choice").eq(-1);
if(val_index == 0){
$last_item = $(this).siblings("label").eq(-1);
}
$last_item.after('<div class="value_choice"><span class="remove_btn">❌</span><div class="input-append">'+
'<div class="tab-content">'+
<% @site_in_use_locales.each_with_index do |locale, i| %>
'<div class="tab-pane fade <%= ( i == 0 ) ? "active in" : '' %>" id="select_choice_value_index'+String(index)+'_<%=locale.to_s%>_'+String(val_index)+'">'+
'<input type="text" name="property[notes_selector]['+String(index)+'][value][<%=locale.to_s%>][]">'+
'</div>'+
<% end %>
'</div>'+
'<div class="btn-group" data-toggle="buttons-radio">'+
<% @site_in_use_locales.each_with_index do |locale, i| %>
'<a class="btn <%= ( i == 0 ) ? "active" : '' %>" href="#select_choice_value_index'+String(index)+'_<%=locale.to_s%>_'+String(val_index)+'" data-toggle="tab"><%= t(locale.to_s) %></a>'+
<% end %>
'</div>'+
'</div></div>');
$(".remove_btn").off("click").on("click",function(){
$(this).parent().remove();
})
})
$(".remove_btn").off("click").on("click",function(){
$(this).parent().remove();
})
})
$(".add_choice").off("click").on("click",function(){
var index = $(this).attr("data-index");
var val_index = $(this).siblings(".value_choice").length;
var $last_item = $(this).siblings(".value_choice").eq(-1);
if(val_index == 0){
$last_item = $(this).siblings("label").eq(-1);
}
$last_item.after('<div class="value_choice"><span class="remove_btn">❌</span><div class="input-append">'+
'<div class="tab-content">'+
<% @site_in_use_locales.each_with_index do |locale, i| %>
'<div class="tab-pane fade <%= ( i == 0 ) ? "active in" : '' %>" id="select_choice_value_index'+String(index)+'_<%=locale.to_s%>_'+String(val_index)+'">'+
'<input type="text" name="property[notes_selector]['+String(index)+'][value][<%=locale.to_s%>][]">'+
'</div>'+
<% end %>
'</div>'+
'<div class="btn-group" data-toggle="buttons-radio">'+
<% @site_in_use_locales.each_with_index do |locale, i| %>
'<a class="btn <%= ( i == 0 ) ? "active" : '' %>" href="#select_choice_value_index'+String(index)+'_<%=locale.to_s%>_'+String(val_index)+'" data-toggle="tab"><%= t(locale.to_s) %></a>'+
<% end %>
'</div>'+
'</div></div>');
$(".remove_btn").off("click").on("click",function(){
$(this).parent().remove();
})
});
$(".remove_btn").off("click").on("click",function(){
$(this).parent().remove();
})
$("[type=checkbox][name='property[enable_notes_selector]']").click(function(){
if(!$(this).prop("checked")){
$("#selector_block").css("display","none");
}else{
$("#selector_block").css("display","");
}
})
var setting_count = <%=setting_count%>;
var default_time_settings = <%= PropertyHireSetting.first.default_time_settings.map{|s| s.attributes.except("_id","created_at","updated_at")}.to_s.gsub("=>",": ").html_safe rescue "[]" %>
<% property_day_setting = f.object.property_day_settings.new(:id=>nil) %>
<%= f.fields_for :property_day_settings,property_day_setting,:child_index => "new_index" do |f| %>
var template_html = "<%= escape_javascript(render(:partial=>"time_form",:locals=>{:f=>f})) %>";
console.log(template_html);
<%end%>
$(".apply_default_time_settings").click(function(){
var target = $($(this).data("target"));
var key = $(this).data("count");
var day = $(this).data("day");
var new_key = $(this).prev().attr('value');
var old_key = new RegExp("new_key", "g");
var new_day = day;
var old_day = new RegExp("new_day", "g");
target.empty();
default_time_settings.forEach(function(setting){
var old_index = new RegExp("new_index", "g");
var new_index = setting_count;
var new_key = key;
setting_count += 1;
var tmp = $(template_html.replace(old_index,new_index).replace(old_key,new_key).replace(old_day,new_day));
Object.keys(setting).forEach(function(k){
if(k != "day" && k != "key"){
if(tmp.find("[name*='["+k+"]'").length != 0){
tmp.find("[name*='["+k+"]']").val(setting[k]);
console.log([k,setting[k]])
}
}
});
target.append(tmp);
key += 1;
})
$(this).data("count",key);
target.find("input[data-format]").each(function(i,input){
var $input = $(input);
var format = $input.data("format"),
timeOnly = !(format.match(/Y|M|d/)), timeFormat, dateFormat = "";
if(timeOnly){
timeFormat = format;
}else{
dateFormat = format.match(/yy(\/|-|)(mm|)(\/|-|)(dd|)/i)[0];
timeFormat = $.trim(format.replace(dateFormat,""));
}
var options = {dateFormat: dateFormat,timeFormat: timeFormat,timeOnly: timeOnly};
var additionalOptions = $input.data();
$.extend(options, additionalOptions);
$input.ui_datetimepicker(options);
$input.siblings('.clearDate').click(function(){
$input.val('');
$input.trigger('change');
});
})
})
$(".add_weekday_setting").click(function(){
var target = $($(this).data("target"));
var key = $(this).data("count");
var day = $(this).data("day");
var new_key = $(this).prev().attr('value');
var old_key = new RegExp("new_key", "g");
var new_day = day;
var old_day = new RegExp("new_day", "g");
var new_key = key;
key += 1;
$(this).data("count",key);
var old_index = new RegExp("new_index", "g");
var new_index = setting_count;
setting_count += 1;
<% property_day_setting = f.object.property_day_settings.new(:id=>nil) %>
<%= f.fields_for :property_day_settings,property_day_setting,:child_index => "new_index" do |f| %>
var template_html = "<%= escape_javascript(render(:partial=>"time_form",:locals=>{:f=>f})) %>";
<%end%>
var tmp = $(template_html.replace(old_index,new_index).replace(old_key,new_key).replace(old_day,new_day));
target.append(tmp);
tmp.find("input[data-format]").each(function(i,input){
var $input = $(input);
var format = $input.data("format"),
timeOnly = !(format.match(/Y|M|d/)), timeFormat, dateFormat = "";
if(timeOnly){
timeFormat = format;
}else{
dateFormat = format.match(/yy(\/|-|)(mm|)(\/|-|)(dd|)/i)[0];
timeFormat = $.trim(format.replace(dateFormat,""));
}
var options = {dateFormat: dateFormat,timeFormat: timeFormat,timeOnly: timeOnly};
var additionalOptions = $input.data();
$.extend(options, additionalOptions);
$input.ui_datetimepicker(options);
$input.siblings('.clearDate').click(function(){
$input.val('');
$input.trigger('change');
});
})
})
$(document).on('click', '.setting-form-remove', function(){
if($(this).find(".remove_existing_record").length != 0){
if(confirm("<%= I18n.t(:sure?)%>")){
$(this).find('.should_destroy').attr('value', 1);
$(this).parents('.time_setting_form').hide();
}
}else{
$(this).parents('.time_setting_form').remove();
}
});
$(document).on('click', '.image-form-remove', function(){
if($(this).find(".remove_existing_record").length != 0){
if(confirm("<%= I18n.t(:sure?)%>")){
$(this).find('.should_destroy').attr('value', 1);
$(this).parents('.image_group').hide();
}
}else{
$(this).parents('.image_group').remove();
}
});
$(document).on('click', '#add_carousel_image', function(){
var new_id = $(this).prev().attr('value');
var old_id = new RegExp("new_property_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, :property_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", "#property_can_be_hired", function () {
// if($(this).is(":checked")){
// $("#open-time").attr("class","show");
// }else{
// $("#open-time").attr("class","hide");
// $("#open-time").find("input").val("");
// }
// })
var special_unavailable_title_counter = <%= @property.special_unavailable_dates.count %>;
$(document).on("click","#add_special_unavailable_date", function(){
var datepicker = $('<div class="date_picker input-append" style="margin-bottom:3px;"> \
<input placeholder="yyyy/MM/dd" class="input-large" data-format="yyyy/MM/dd" type="text" name="property[special_unavailable_dates][]" title="yyyy/MM/dd" autocomplete="off"> \
<span class="add-on clearDate"><i class="icons-cross-3"></i></span> \
<span class="add-on deleteDate"><i class="icon-trash"></i></span> \
</div>');
var id = "special_unavailable_title_" + special_unavailable_title_counter;
var title = $('<div class="tab-panel"> \
<div class="tab-content active" id="' + id + '_en"> \
<input type="text" name="property[special_unavailable_dates_title][][en]" value=""> \
</div> \
<div class="tab-content" id="' + id + '_zh_tw"> \
<input type="text" name="property[special_unavailable_dates_title][][zh_tw]" value=""> \
</div> \
<div class="btn-group" data-toggle="buttons-radio"> \
<a data-toggle="tab" class="btn active" for="en" href="#' + id + '_en" aria-expanded="true" aria-pressed="true"><%= t("en") %></a> \
<a data-toggle="tab" class="btn" for="zh_tw" href="#' + id + '_zh_tw" aria-expanded="true" aria-pressed="true"><%= t("zh_tw") %></a> \
</div> \
</div>');
datepicker.find('input').datepicker({
dateFormat : "yy/mm/dd"
});
var html = $('<div class="temp_date_holder" style="margin-bottom:5px;"></div>');
html.append(datepicker);
html.append(title);
$("#special_unavailable_date_holder").append(html);
special_unavailable_title_counter++;
return false;
})
$(document).on("click","#special_unavailable_date_holder .clearDate", function (params) {
$(this).parents('.default_picker,.time_picker,.date_picker').eq(-1).find('input').val('')
$(this).parents('.default_picker,.time_picker,.date_picker').eq(-1).find('input').trigger('change')
})
$(document).on("click","#special_unavailable_date_holder .deleteDate", function (params) {
$(this).parents('#special_unavailable_date_holder .temp_date_holder').eq(-1).remove();
})
</script>

View File

@ -0,0 +1,63 @@
<% if form_file.nil? || form_file.file.blank? %>
<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.nil? || 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">
<% if form_file.fields["title"].options[:localize] %>
<% @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 %>
<% else %>
<%= f.text_field :title, :class => "input-medium", placeholder: t(:alternative) %>
<% end %>
</span>
<span class="add-on icons-pencil" title='<%= t(:description) %>'></span>
<span class="tab-content">
<% if form_file.fields["description"].options[:localize] %>
<% @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 %>
<% else %>
<%= f.text_field :description, :class => "input-medium", placeholder: t(:description) %>
<% end %>
</span>
</span>
<% if form_file.nil? || 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 %>
</div>
</div>

View File

@ -0,0 +1,93 @@
<!-- Link -->
<div class="control-group">
<label class="control-label muted"><%= t(:link) %></label>
<div class="controls add-input">
<!-- Exist -->
<% if !f.object.nil? && !f.object.property_links.blank? %>
<div class="exist">
<% f.object.property_links.each_with_index do |property_link, i| %>
<%= f.fields_for :property_links, property_link do |f| %>
<%= render :partial => 'form_link', :object=> property_link, :locals => {:f => f, :i => i } %>
<% end %>
<% end %>
<hr>
</div>
<% end %>
<!-- Add -->
<div class="add-target">
</div>
<p class="add-btn">
<%= hidden_field_tag 'property_link_field_count', f.object.property_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">
<!-- Exist -->
<% if !f.object.nil? && !f.object.property_files.blank? %>
<div class="exist">
<% f.object.property_files.each_with_index do |property_file, i| %>
<%= f.fields_for :property_files, property_file do |f| %>
<%= render :partial => 'form_file',:object => property_file, :locals => {:f => f, :i => i} %>
<% end %>
<% end %>
<hr>
</div>
<% end %>
<!-- Add -->
<div class="add-target">
</div>
<p class="add-btn">
<%= hidden_field_tag 'property_file_field_count', f.object.property_files.count %>
<a id="add_file" class="trigger btn btn-small btn-primary"><i class="icons-plus"></i> <%= t(:add) %></a>
</p>
</div>
</div>
<script type="text/javascript">
$(function() {
$(document).on('click', '#add_link', function(){
var new_id = $(this).prev().attr('value');
var old_id = new RegExp("new_property_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, :property_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_property_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, :property_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();
});
$(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();
}
});
});
</script>

View File

@ -0,0 +1,47 @@
<!-- Images Upload -->
<div class="image_group">
<label class="checkbox inline btn btn-danger image-form-remove">
<% if f.object.new_record? %>
<span class="delete_form" title="<%= t(:delete_) %>">
X
</span>
<% else %>
<span class="remove_existing_record" title="<%= t(:remove) %>">
<%= f.hidden_field :id %>
<%= f.hidden_field :_destroy, :value => nil, :class => 'should_destroy' %>
X
</span>
<% end %>
</label>
<div class="control-group">
<label class="control-label muted"><%= t(:image) %></label>
<div class="controls">
<div class="fileupload fileupload-new clearfix <%= 'fileupload-edit' if form_image.file.present? %>" data-provides="fileupload">
<div class="fileupload-new thumbnail pull-left">
<% if form_image.file.file %>
<%= image_tag form_image.file %>
<% else %>
<img src="/assets/property_hire/AAAAAA.png" />
<% 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>
</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,30 @@
<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">
<% if form_link.fields["title"].options[:localize] %>
<% @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 %>
<% else %>
<%= f.text_field :title, :class => "input-large", placeholder: t(:url_alt) %>
<% end %>
</span>
<% if form_link.nil? || 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,48 @@
<table class="table main-list">
<thead>
<tr class="sort-header">
<% @table_fields.each do |f| %>
<%= thead(f) %>
<% end %>
</tr>
</thead>
<tbody>
<% @properties.each do |property| %>
<tr>
<td>
<% if can_edit_or_delete?(property) %>
<a href="<%= admin_property_hire_path(property) %>"><%= property.title %></a>
<div class="quick-edit">
<ul class="nav nav-pills">
<li><a href="<%= edit_admin_property_hire_path(property, :page => params[:page]) %>"><%= t(:edit) %></a></li>
<li><a href="<%= copy_admin_property_hire_path(property, :page => params[:page]) %>"><%= t("property_hire.copy") %></a></li>
<li><a href="<%= custom_fields_admin_property_hire_path(property) %>"><%= t("property_hire.custom_fields") %></a></li>
<li><a href="<%= fields_display_order_admin_property_hire_path(property) %>"><%= t("property_hire.fields_display_order") %></a></li>
<li><a href="<%= export_reservation_data_admin_property_hire_path(property.id) %>" class="export-xls" data-property-id="<%= property.id.to_s %>"><%= t("property_hire.export_reservation_data") %></a></li>
<li><a href="<%= admin_property_hire_path(property.id, :page => params[:page]) %>" data-method="delete" data-confirm="Are you sure?"><%= t(:delete_) %></a></li>
</ul>
</div>
<% else %>
<%= property.title %>
<% end %>
</td>
<td>
<%= property.category.title rescue nil %>
</td>
<td>
<%= property.get_location_name %>
</td>
<td>
<% if property.can_reserve %>
<span class="badge badge-success">Yes</span>
<% else %>
<span class="badge badge-important">No</span>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<div class="bottomnav clearfix">
<%= content_tag(:div, paginate(@properties), class: "pagination pagination-centered") %>
</div>

View File

@ -0,0 +1,309 @@
<%#= encoding: utf-8 %>
<script id="template-attributes" type="text/x-tmpl">
<div class="attributes">
<div class="attributes-header clearfix">
<input class="toggle-check" data-deploy="right" id="${_disabled[0]}" name="${_disabled[1]}" type="hidden" value="false">
<a class="btn btn-mini pull-right btn-danger delete" href="#"><i class="icon-trash"></i> Delete</a>
<a class="btn btn-mini pull-right btn-inverse reply hide" href="#"><i class="icons-reply"></i> Reply</a>
<input class="attribute_field_to_delete" id="${_to_delete[0]}" name="${_to_delete[1]}" type="hidden" value="false">
<h4>Field <span>${attributesHeaderLength}</span></h4>
</div>
<div class="attributes-body">
<div class="control-group">
<label class="control-label muted" for="${_key[0]}"><%= t(:key) %></label>
<div class="controls">
<input type="text" data-type="key" id="${_key[0]}" name="${_key[1]}" placeholder="<%= t(:key) %>">
</div>
</div>
<div class="control-group">
<label class="control-label muted" for=""><%= t(:name) %></label>
<div class="controls">
<div class="input-append">
<div class="tab-content">
<% @site_in_use_locales.each do |locale| %>
<% active = (locale == @site_in_use_locales.first ? "active" : "") %>
<div class="tab-pane <%= active %> fade in" id="${_title_translations[0]+'_<%= locale%>'}">
<input type="text" data-type="lang_<%= locale%>" name="${_title_translations[1]+'[<%= locale%>]'}" placeholder="<%= t(locale).to_s %>">
</div>
<% end %>
</div>
<div class="btn-group" data-toggle="buttons-radio">
<% @site_in_use_locales.each do |locale| %>
<% active = (locale == @site_in_use_locales.first ? "active" : "") %>
<a class="btn <%= active %>" href="${'#'+_title_translations[0]+'_<%= locale%>'}" data-toggle="tab"><%= t(locale).to_s %></a>
<% end %>
</div>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label muted" for=""><%= t('property_hire.to_require') %></label>
<div class="controls">
<label class="radio inline">
<input type="radio" data-type="search_true" id="${_to_require[0]+'_true'}" name="${_to_require[1]}" value="true" checked=""> <%= t(:yes_)%>
</label>
<label class="radio inline">
<input type="radio" data-type="search_false" id="${_to_require[0]+'_false'}" name="${_to_require[1]}" value="false"> <%= t(:no_)%>
</label>
</div>
</div>
<div class="control-group">
<label class="control-label muted" for=""><%= t('property_hire.display_in_reason_for_hire') %></label>
<div class="controls">
<label class="radio inline">
<input type="radio" data-type="search_true" id="${_display_in_reason_for_hire[0]+'_true'}" name="${_display_in_reason_for_hire[1]}" value="true"> <%= t(:yes_)%>
</label>
<label class="radio inline">
<input type="radio" data-type="search_false" id="${_display_in_reason_for_hire[0]+'_false'}" name="${_display_in_reason_for_hire[1]}" value="false" checked=""> <%= t(:no_)%>
</label>
</div>
</div>
<div class="control-group">
<label class="control-label muted" for=""><%= t(:type)%></label>
<div class="controls">
<select class="dataType" data-type="select" name="${_markup}">
<%$property_list[:markups].each do |key,val|%>
<% next if val["display_only"] && val["display_only"] != params["action"] %>
<% if key != 'address' %>
<option value="<%= key %>" ref="<%=val["panel"]%>"><%=t("lists.markups."+key)%></option >
<% end %>
<% end %>
</select>
</div>
</div>
</div>
<div class="field-type fade in typeA">
<div class="control-group">
<label class="control-label muted"><%= t(:enabled_for)%></label>
<div class="controls">
<label class="checkbox inline">
<input type="checkbox" data-type="enable_monolingual" id="${_cross_lang[0]}" name="${_cross_lang[1]}" value="true">
<%= t(:cross_lang) %>
</label>
<label class="checkbox inline">
<input type="checkbox" data-type="extendable_field" id="${_add_more[0]}" name="${_add_more[1]}" value="true">
<%= t(:add_more)%>
</label>
</div>
</div>
<div class="control-group">
<label class="control-label muted"><%= t(:placeholder) %></label>
<div class="controls">
<div class="input-append">
<div class="tab-content">
<% @site_in_use_locales.each do |locale| %>
<% active = (locale == @site_in_use_locales.first ? "active" : "") %>
<div class="tab-pane <%= active %> fade in" id="${_placeholder[0]+'_<%= locale %>'}">
<input type="text" data-type="lang_<%= locale %>" placeholder="<%= t(locale).to_s %>" name="${_placeholder[1]+'[<%= locale %>]'}">
</div>
<% end %>
</div>
<div class="btn-group" data-toggle="buttons-radio">
<% @site_in_use_locales.each do |locale| %>
<% active = (locale == @site_in_use_locales.first ? "active" : "") %>
<a class="btn <%= active %>" href="${'#'+_placeholder[0]+'_<%= locale %>'}" data-toggle="tab"><%= t(locale).to_s %></a>
<% end %>
</div>
</div>
</div>
</div>
</div>
</div>
</script>
<script id="template-type" type="text/x-tmpl">
{{if templateType == 'typeA' || templateType == 'typeD' || templateType == 'typeG'}}
<div class="control-group">
<label class="control-label muted"><%= t(:enabled_for)%></label>
<div class="controls">
{{if templateType == 'typeA' || templateType == 'typeD'}}
<label class="checkbox inline">
<input type="checkbox" data-type="enable_monolingual" id="${_cross_lang[0]}" name="${_cross_lang[1]}" value="true">
<%= t(:cross_lang) %>
</label>
{{/if}}
{{if templateType == 'typeA' || templateType == 'typeG'}}
<label class="checkbox inline">
<input type="checkbox" data-type="extendable_field" id="${_add_more[0]}" name="${_add_more[1]}" value="true">
<%= t(:add_more)%>
</label>
{{/if}}
</div>
</div>
{{/if}}
{{if templateType == 'typeA' || templateType == 'typeB' || templateType == 'typeD'}}
<div class="control-group">
<label class="control-label muted">
{{if templateType == 'typeB'}}
<%= t(:initial) %>
{{else}}
<%= t(:placeholder) %>
{{/if}}
</label>
<div class="controls">
<div class="input-append">
<div class="tab-content">
<% @site_in_use_locales.each do |locale| %>
<% active = (locale == @site_in_use_locales.first ? "active" : "") %>
<div class="tab-pane <%= active %> fade in" id=
{{if templateType == 'typeB'}}
"${_initial[0]+'_<%= locale %>'}"
{{else}}
"${_placeholder[0]+'_<%= locale %>'}"
{{/if}}
>
<input type="text" data-type="lang_<%= locale %>" placeholder="<%= t(locale).to_s %>" name=
{{if templateType == 'typeB'}}
"${_initial[1]+'[<%= locale %>]' }"
{{else}}
"${_placeholder[1]+'[<%= locale %>]'}"
{{/if}}
>
</div>
<% end %>
</div>
<div class="btn-group" data-toggle="buttons-radio">
<% @site_in_use_locales.each do |locale| %>
<% active = (locale == @site_in_use_locales.first ? "active" : "") %>
<a class="btn <%= active %>" href=
{{if templateType == 'typeB'}}
"${'#'+_initial[0]+'_<%= locale %>'}"
{{else}}
"${'#'+_placeholder[0]+'_<%= locale %>'}"
{{/if}}
data-toggle="tab"><%= t(locale).to_s %></a>
<% end %>
</div>
</div>
</div>
</div>
{{/if}}
{{if templateType == 'typeB' || templateType == 'typeE'}}
<div class="control-group">
<label class="control-label muted" for=""><%= t(:options)%></label>
<div class="controls add-input">
<div class="add-target single">
<%= content_tag :div,:class=>"input-append" do%>
<% @site_in_use_locales.each do |locale| %>
<% last = (locale == @site_in_use_locales.last ? true : false) %>
<input type="text" data-type="${_option_list[2]+'_<%= locale %>' }" id="${_option_list[0]+'_<%= locale %>'}" name="${_option_list[1]+'[<%= locale %>]'}" class="input-medium" placeholder="<%= t(locale).to_s %>">
<% if last %>
<a href="#" class="btn remove-input"> <i class="icon-trash"></i> </a>
<% end %>
<% end %>
<% end %>
</div>
<p class="add-btn">
<a href="#" class="${templateType+' trigger btn btn-mini btn-primary'}"><i class="icons-plus"></i> Add</a>
</p>
</div>
</div>
{{/if}}
{{if templateType == 'typeC'}}
<div class="control-group">
<label class="control-label muted" for=""><%= t("date.format")%></label>
<div class="controls">
<select data-type="date" id="${_format[0]}" name="${_format[1]}">
<option value="format1">YYYY / MM / DD hh : mm</option>
<option value="format2">YYYY / MM / DD</option>
<option value="format3">YYYY / MM</option>
<option value="format4">YYYY</option>
</select>
</div>
</div>
<div class="control-group">
<label class="control-label muted" for=""><%= t("date.range")%></label>
<div class="controls">
<label class="radio inline">
<input type="radio" data-type="time_period_flase" id="${_is_range[0]+'_false'}" name="${_is_range[1]}" value="false" checked="checked"> <%= t(:yes_)%>
</label>
<label class="radio inline">
<input type="radio" data-type="time_period_true" id="${_is_range[0]+'_true'}" name="${_is_range[1]}" value="true"> <%= t(:no_)%>
</label>
</div>
</div>
<div class="control-group">
<label class="control-label muted" for=""><%= t("date.calendar")%></label>
<div class="controls">
<label class="radio inline">
<input type="radio" data-type="calendar_ac" id="${_calendar[0]+'_west_calendar'}" name="${_calendar[1]}" value="west_calendar" checked="checked"> <%= t("date.west_calendar")%>
</label>
<label class="radio inline">
<input type="radio" data-type="calendar_roc" id="${_calendar[0]+'_tw_calendar'}" name="${_calendar[1]}" value="tw_calendar"> <%= t("date.tw_calendar")%>
</label>
</div>
</div>
{{/if}}
{{if templateType == 'typeF'}}
<div class="control-group">
<label class="control-label muted">
<%= t("lists.markups.hint_text") %>
</label>
<div class="controls">
<div class="input-append">
<div class="tab-content">
<% @site_in_use_locales.each do |locale| %>
<% active = (locale == @site_in_use_locales.first ? "active" : "") %>
<div class="tab-pane <%= active %> fade in" id=
"${_placeholder[0]+'_<%= locale %>'}">
<textarea data-type="lang_<%= locale %>" placeholder="<%= t(locale).to_s %>" name="${_placeholder[1]+'[<%= locale %>]'}"></textarea>
</div>
<% end %>
</div>
<div class="btn-group" data-toggle="buttons-radio">
<% @site_in_use_locales.each do |locale| %>
<% active = (locale == @site_in_use_locales.first ? "active" : "") %>
<a class="btn <%= active %>" href="${'#'+_placeholder[0]+'_<%= locale %>'}"data-toggle="tab">
<%= t(locale).to_s %>
</a>
<% end %>
</div>
</div>
</div>
</div>
{{/if}}
</script>
<script id="template-input-append" type="text/x-tmpl">
<%= content_tag :div,:class=>"input-append" do%>
<% @site_in_use_locales.each do |locale| %>
<% last = (locale == @site_in_use_locales.last ? true : false) %>
<input type="text" data-type="${_option_list[2]+'_<%= locale %>' }" id="${_option_list[0]+'_<%= locale %>'}" name="${_option_list[1]+'[<%= locale %>]'}" class="input-medium" placeholder="<%= t(locale).to_s %>">
<% if last %>
<a href="#" class="btn remove-input"> <i class="icon-trash"></i> </a>
<% end %>
<% end %>
<% end %>
</script>
<script id="template-text" type="text/x-tmpl">
<div class="input-append">
<input type="text" id="${'text'+_text[0]}" name="${_text[1]+'[text]'}" class="input-medium" placeholder="Text">
<a href="#" class="btn remove-input">
<i class="icon-trash"></i>
</a>
</div>
</script>

View File

@ -0,0 +1,44 @@
<div class="time_setting_form">
<% key = (defined?(key) && key) ? key : "new_key"
day = (defined?(day) && day) ? day : "new_day"
%>
<label class="checkbox inline btn btn-danger setting-form-remove">
<% if f.object.new_record? %>
<span class="delete_form" title="<%= t(:delete_) %>">
X
</span>
<% else %>
<span class="remove_existing_record" title="<%= t(:remove) %>">
<%= f.hidden_field :id %>
<%= f.hidden_field :_destroy, :value => nil, :class => 'should_destroy' %>
X
</span>
<% end %>
</label>
<div class="control-group">
<%= f.label "time_title_#{key}_#{day}", t("property_hire.time_title"), :class => "control-label muted" %>
<div class="controls">
<%= f.text_field :title, :id=>"time_title_#{key}_#{day}" %>
</div>
</div>
<div class="control-group">
<%= f.label :start_time, t("property_hire.limit_start_time"), :class => "control-label muted" %>
<div class="controls">
<%= f.datetime_picker :start_time, :picker_type => "time", :no_label => true, :new_record => (@property.new_record? rescue true) %>
</div>
</div>
<div class="control-group">
<%= f.label :end_time, t("property_hire.limit_end_time"), :class => "control-label muted" %>
<div class="controls">
<%= f.datetime_picker :end_time, :picker_type => "time", :no_label => true, :new_record => (@property.new_record? rescue true) %>
</div>
</div>
<%= f.hidden_field :key, :value => key, :data => {"type" => "key"} %>
<%= f.hidden_field :day, :value => day, :data => {"type" => "day"} %>
<div class="control-group">
<%= f.label "reservation_limit_#{key}_#{day}", t("property_hire.reservation_limit"), :class => "control-label muted" %>
<div class="controls">
<%= f.number_field :reservation_limit, :id=>"reservation_limit_#{key}_#{day}" %>
</div>
</div>
</div>

View File

@ -0,0 +1,6 @@
<%= form_for @property , :url => {:action => "create"}, html: {class: "form-horizontal main-forms"} do |f| %>
<fieldset>
<%= f.hidden_field :copy_id %>
<%= render :partial => "form", locals: {:f => f} %>
</fieldset>
<% end %>

View File

@ -0,0 +1,44 @@
<% content_for :page_specific_css do -%>
<%= stylesheet_link_tag "lib/wrap-nav.css" %>
<%= stylesheet_link_tag "lib/pageslide.css" %>
<%= stylesheet_link_tag "lib/main-forms.css" %>
<%= stylesheet_link_tag "lib/togglebox.css" %>
<% end -%>
<% content_for :page_specific_javascript do -%>
<%= javascript_include_tag "lib/jquery.tmpl.min.js" %>
<%= javascript_include_tag "property_hire/property-field-forms.js" %>
<% end -%>
<style type="text/css">
.input-append, .input-prepend{
font-size: 1em;
}
</style>
<%= form_for @attribute,:url => admin_property_hire_path(@attribute) , :html => { :class=> "form-horizontal main-forms" } do |f| %>
<% if flash.now[:notice].present? %>
<%= flash.now[:notice]%>
<% end %>
<h3><%= @attribute.title %></h3>
<fieldset>
<div id="attributes-area" class="input-area">
<%= render partial: "attribute_field",collection: @attribute.p_hire_fields_enabled.asc(:_id)%>
</div>
<div class="form-actions">
<button type="button" class="btn btn-success add-attributes"><%= t(:add_attribute_field) %></button>
<% referer = request.referer rescue nil %>
<% referer = get_referer_url if referer.blank? || request.host != URI.parse(URI.encode(referer)).host %>
<input type="hidden" name="referer_url" value="<%= referer %>">
<%= hidden_field_tag 'id', params[:id] if !params[:id].blank? %>
<%= f.submit t(:submit),:class=>"btn btn-primary"%>
<%= link_to t('cancel'), get_go_back, :class=>"btn" %>
</div>
</fieldset>
<% end %>
<% content_for :page_specific_javascript do -%>
<%= render 'support_member_form_js' %>
<% end -%>

View File

@ -0,0 +1,940 @@
<style type="text/css">
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.row{
margin-left: 0;
}
.form-group {
margin-bottom: 0.9375em;
clear: both;
}
@media (min-width:768px){
.modal-content {
-webkit-box-shadow: 0 0.3125em 0.9375em rgb(0 0 0 / 50%);
box-shadow: 0 0.3125em 0.9375em rgb(0 0 0 / 50%);
}
.col-sm-offset-2 {
margin-left: 16.66666667%;
}
.form-horizontal .control-label {
padding-top: 0.4375em;
margin-bottom: 0;
width: auto;
text-align: right;
}
[class*="col-sm"],[class*="col-md"]{
float: left;
position: relative;
min-height: 0.0625em;
padding-right: 0.9375em;
padding-left: 0.9375em;
}
.form-horizontal .col-sm-2 {
width: 16.66666667%;
}
.form-horizontal .col-sm-5 {
width: 41.66666667%;
}
.form-horizontal .col-sm-10 {
width: 83.33333333%;
}
.form-horizontal .col-md-4 > * {
padding: 0 0.5em;
}
.form-horizontal .col-md-8 > * {
padding: 0 1em;
}
.form-horizontal .col-md-4{
width: 33.3%;
}
.form-horizontal .col-md-8{
width: 66.6%;
}
}
.modal-content {
position: relative;
background-color: #fff;
-webkit-background-clip: padding-box;
background-clip: padding-box;
border: 0.0625em solid #999;
border: 0.0625em solid rgba(0,0,0,.2);
border-radius: 0.375em;
outline: 0;
-webkit-box-shadow: 0 0.1875em 0.5625em rgb(0 0 0 / 50%);
box-shadow: 0 0.1875em 0.5625em rgb(0 0 0 / 50%);
}
.modal-header {
padding: 0.9375em;
border-bottom: 0.0625em solid #e5e5e5;
}
.modal-body {
position: relative;
padding: 0.9375em;
max-height: 400px;
overflow: initial;
}
.input-append{
font-size: 1em;
display: block;
}
</style>
<%= content_for :page_specific_css do %>
<% ["basic/bootstrap-datetimepicker.css","property_hire_fullcalendar.css","property_hire_calendar"].each do |css| %>
<%= stylesheet_link_tag css %>
<% end %>
<% end %>
<script src="/assets/validator.js"></script>
<script src="https://polyfill.io/v3/polyfill.min.js?features=Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.en,Intl.NumberFormat.~locale.en"></script>
<script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script>
<script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script>
<%
hire = @phire
property = @phire.property
%>
<% data = {"carousel_display_style"=>"width: #{property.carousel_image_width};"}
recover = true
allow_no_logins_user = false
calendar_type = property.calendar_type.to_i rescue 0
right_col = 12
label_col = 2
input_col = 10
if calendar_type == 0
right_col -= 7
label_col += 2
input_col -= 2
end
url = "admin"
all_day_settings = property.all_day_settings
%>
<style type="text/css">
.w-ba-banner{
position: relative;
}
ul.list-unstyled li {
list-style: none;
}
.s-annc__related-link-list, .s-annc__related-file-list{
display: inline-block;
}
#sec1{
float: left;
}
.btn-toolbar {
margin-top: 0;
}
.form-group .controls{
margin-left: 0;
}
@media (min-width: 1200px){
.col-lg-7{
width: 58.3%;
float: left;
}
.col-lg-5{
width: 41.7%;
float: left;
}
}
@media (min-width: 768px){
.form-horizontal .col-sm-4 {
width: 33.33333333%;
}
.form-horizontal .col-sm-8 {
width: 66.66666667%;
}
.form-horizontal .col-sm-2 {
width: 16.66666667%;
}
.form-horizontal .col-sm-10 {
width: 83.33333333%;
}
.form-horizontal .col-sm-offset-4 {
margin-left: 33.33%;
}
}
</style>
<style type="text/css">
.full-size-img img {
width: 100%;
}
.full-size-img {
width: 100%;
}
.s-annc__sub-img.pull-right {
margin-left: 2em;
}
.s-annc__sub-img.pull-left {
margin-right: 2em;
}
strong.carousel__description {
color: white;
}
.carousel_images{
<%=data["carousel_display_style"]%>
}
@media (max-width: 767px){
.carousel_images{
width: 100%;
}
}
.carousel_img_item{
display: none;
float: left;
}
.controlplay {
position: absolute;
right: 1em;
top: 3%;
z-index: 200;
}
.controlplay a {
display: inline-block;
margin-right: 0.25em;
cursor: pointer;
padding: 5px 10px;
border: 1px solid rgba(255,255,255,0.5);
background: rgba(0,0,0,0.2);
}
.controlplay a i {
font-family: FontAwesome;
position: relative;
font-size: 1rem;
line-height: 1;
color: #FFF;
vertical-align: middle;
font-style: unset;
}
.controlplay .resume-slide i::before {
content: "\f04b";
}
.controlplay .pause-slide i::before {
content: "\f04c";
}
ul.button-mid .prev-button {
transition: 0.4s;
position: relative;
float: left;
left: 0.5rem;
width: 2.5rem;
height: 2.5rem;
font-size: 2.2rem;
color: #ffffff;
background: rgba(0,0,0,0.2);
text-align: center;
line-height: 2.5rem;
top: 50%;
position: absolute;
transform: translateY(-50%);
z-index: 999;
}
ul.button-mid .next-button {
float: right;
transition: 0.4s;
position: relative;
right: 0.5rem;
width: 2.5rem;
height: 2.5rem;
font-size: 2.2rem;
color: #fff;
background: rgba(0,0,0,0.2);
text-align: center;
line-height: 2.5rem;
top: 50%;
position: absolute;
transform: translateY(-50%);
z-index: 999;
}
.carousel_images_slide{
padding: 3em;
}
.carousel_img_item img{
cursor: pointer;
}
@media (max-width: 479px){
.carousel_img_item:nth-child(-n+1){
display: block;
width: 100%;
float: left;
}
.carousel_img_item{
width: 100%;
}
}
@media (min-width: 480px){
.carousel_img_item:nth-child(-n+2){
display: block;
width: 50%;
float: left;
}
.carousel_img_item{
width: 50%;
}
}
@media (min-width: 768px){
.carousel_img_item:nth-child(-n+3){
display: block;
width: 33%;
float: left;
}
.carousel_img_item{
width: 33%;
}
}
@media (min-width: 1280px){
.carousel_img_item:nth-child(-n+4){
display: block;
width: 25%;
float: left;
}
.carousel_img_item{
width: 25%;
}
}
form#hire_form .form-group input,form#hire_form .form-group select, form#hire_form .form-group textarea{
min-width: 100%;
max-width: 300px;
}
form#hire_form .form-group input[name="_rucaptcha"], form#hire_form .form-group input[type="submit"], form#hire_form .form-group input[type="radio"], form#hire_form .form-group input[type="checkbox"]{
width: auto;
min-width: auto;
position: relative;
margin-left: 0;
}
form#hire_form .form-control {
display: block;
width: 100%;
height: auto;
padding: 0.375em 1.125em;
font-size: 0.875em;
line-height: 1.42857143;
color: #555;
background-color: #fff;
background-image: none;
border: 0.0625em solid #ccc;
border-radius: 0.25em;
-webkit-box-shadow: inset 0 0.0625em 0.0625em rgb(0 0 0 / 8%);
box-shadow: inset 0 0.0625em 0.0625em rgb(0 0 0 / 8%);
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
}
.form-horizontal .form-group {
margin-bottom: 0.9375em;
display: inline-block;
width: 100%;
}
</style>
<% if !property.can_be_hired_frontend %>
<script type="text/javascript">
alert("This property is unavailable for hire.");
window.location.href = "<%= "/" + I18n.locale.to_s + url %>";
</script>
<% end %>
<% if !allow_no_logins_user && current_user.nil? %>
<script type="text/javascript">
alert("Please login before you hire.");
window.location.href = "<%= "/" + I18n.locale.to_s + url %>";
</script>
<% else %>
<script type="text/javascript">
var pick_date_mode = <%=property.set_availability%>;
</script>
<h3 class="property_title"><%= property.title.html_safe %></h3>
<article class="s-annc s-property">
<section class="s-annc__post-wrap">
<% if property.display_img %>
<div class="s-annc__sub-img full-size-img">
<img src="<%=property.image.url%>" alt="<%=property.title%>">
<span class="s-annc__img_description"><%=property.title.html_safe%></span>
</div>
<% end %>
<h4 class="property_subtitle"><%= property.property_usage.html_safe %></h4>
<% property_carousel_images = property.property_carousel_images %>
<% if property_carousel_images.count != 0 %>
<div class="carousel_images">
<div class="w-ba-banner ba-banner-widget-1">
<div class="w-ba-banner__wrap cycle-slideshow"
data-list="property_carousel_images"
data-level="0"
data-cycle-slides=".property_carousel_slide"
data-cycle-log="false"
data-cycle-auto-height="0"
data-cycle-speed="300"
data-cycle-timeout="5000"
data-cycle-fx="fade"
data-pager-active-class="active-slide"
data-cycle-swipe=true
data-cycle-swipe-fx="scrollHorz"
>
<% property_carousel_images.each do |carousel_image| %>
<div class="w-ba-banner__slide property_carousel_slide"
data-cycle-title="{{description_text}}"
>
<img class="w-ba-banner__image banner-responsive" src="<%=carousel_image.file.url %>" alt="<%=carousel_image.description_text %>">
<div class="ad-overlay w-ad-banner__overlay property_carousel__overlay">
<p><strong class="carousel__description"><%=carousel_image.description %></strong></p>
</div>
<div class="transitionfade"></div>
</div>
<% end %>
</div>
<ul class="controlplay"><a class="resume-slide" title="<%=data["resume_btn_title"]%>"><i></i></a><a class="pause-slide" title="<%=data["pause_btn_title"]%>"><i></i></a></ul>
<ul class="button-mid">
<i class="fa fa-angle-left prev-button" aria-hidden="true" title="<%=data["prev_btn_title"]%>"></i>
<i class="fa fa-angle-right next-button" aria-hidden="true" title="<%=data["next_btn_title"]%>"></i>
</ul>
</div>
</div>
<% end %>
<div class="property_note"><%= property.note.html_safe %></div>
</section>
<ul class="s-property__related-wrap list-unstyled no-print">
<% if property.property_files.count != 0%>
<li class="s-annc__related-file s-property__related-file">
<i class="fa fa-fw fa-paperclip"></i>
<div class="s-annc__related-file-list s-property__related-file-list" data-list="property_files" data-level="0">
<% property.property_files.each do |property_file| %>
<a class="s-annc__flie-title s-property__flie-title btn btn-default btn-sm" href="<%=property_file.file.url %>" title="<%=property_file.title %>"><%=property_file.title %></a>
<% end %>
</div>
</li>
<% end %>
<% if property.property_links.count != 0%>
<li class="s-annc__related-link s-property__related-link">
<i class="fa fa-fw fa-link"></i>
<div class="s-annc__related-link-list s-property__related-link-list" data-list="bulletin_links" data-level="0">
<% property.property_links.each do |property_link| %>
<a class="s-annc__link-title s-property__link-title btn btn-default btn-sm" href="<%=property_link.url %>" target="_blank"><%=property_link.display_title %></a>
<% end %>
</div>
</li>
<% end %>
</ul>
<% if session["hire-save-msg"].present? %>
<div id="property-unavaialable-alert" class="alert alert-danger" role="alert"><b>Sorry! </b><span> <%= session["hire-save-msg"] %></span></div>
<script type="text/javascript">alert("<%= session["hire-save-msg"] %>")</script>
<% session.delete("hire-save-msg") %>
<% end %>
</article>
<% if property.calendar_type == 0 %>
<div id="orbit_calendar" class="col-lg-<%=12-right_col%>">
<div id="sec1">
<div class="btn-toolbar" id="navigation">
<div id="calendar-nav">
<div class="btn-group">
<button class="btn btn-default btn-sm" id="today_btn">Today</button>
</div>
</div>
</div>
<div class="form-inline" id="range_selection"></div>
</div>
<div id='sec3' class="btn-toolbar">
<div class="btn-group calendar_mode">
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridDay" >day</button>
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridWeek" >week</button>
<button class="btn btn-default active mode_switch btn-sm" data-mode="dayGridMonth" >month</button>
</div>
<button id="refresh_btn" class="btn btn-default btn-sm">
<i class="icons-cycle"></i>
</button>
</div>
<div class="pull-right">
<button class="btn btn-default btn-sm" id="prev_month_btn">
<i class="icon-chevron-left"></i>
</button>
<button class="btn btn-default btn-sm" id="next_month_btn">
<i class="icon-chevron-right"></i>
</button>
</div>
<div class="clearfix"></div>
<div id="view_holder">
<h3 id="current_title" class="current_day_title"></h3>
<div id="calendar"></div>
<div id="calendar_agenda"></div>
</div>
<div id="calendar-loading"></div>
<div id="hidden_timepicker" class="hide">
<span id="hidden_title" class="pull-left" style="margin-right: 1em;font-weight: bold;"></span>
<div style="display: grid;">
<span id="hidden_date" class="pull-left" style="margin-right: 1em;"></span>
<%= fields_for :timepicker do |f|%>
<%= f.time_picker :timepicker, :no_label => true, :new_record => hire.new_record? && !recover,:format=>"HH:mm", :class => "pull-left", :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<% end %>
<div class="pull-left btn-group" style="margin-top: 0.5em;">
<button id="confirm_date" class="btn btn-primary btn-sm" style="margin-right: 0.5em;" onclick="set_datetimepicker()"><%=t("property_hire.confirm")%></button>
<button id="cancel_date" class="btn btn-primary btn-sm" onclick="goto_calendar()"><%=t("property_hire.cancel")%></button>
</div>
</div>
<div style="clear: both;"></div>
<hr>
</div>
</div>
<div id="event_quick_view" class="modal" style="width: 300px; display:none; margin:0 0 0 0;"></div>
<script type="text/javascript">
var property_id = "<%= property.id.to_s %>";
var calendar = new Calendar("#calendar",property_id);
function pick_hire_date(date,allow_times){
if(window.processing_hire)
return;
window.processing_hire = true;
try{
var date_target = $("#date_target_block").find("input");
var offset = date_target.offset();
if(date_target.val() == date){
scrollTo(0,offset.top - 40);
return;
}
$("#date_target_block").find("input").val(date);
var select_target;
if($("#hire_time_range_block").find("select").length == 0){
select_target = $("<select name=\""+$("#hire_time_range_block").find("input").attr("name")+"\"></select>");
$("#hire_time_range_block").find("input").remove();
}
else{
select_target = $("#hire_time_range_block").find("select").eq(0);
}
select_target = select_target.empty();
select_target.append("<option value=\"\"><%=t("property_hire.please_select")%></option>");
allow_times.forEach(function(allow_time){
select_target.append("<option value=\""+allow_time[2]+"\">"+allow_time[3]+"</option>");
});
select_target.appendTo($("#hire_time_range_block"));
scrollTo(0,offset.top - 40);
}catch(e){};
window.processing_hire = false;
}
function change_pick(target){
if( $(target).attr("id") == "pick_recurring_end_date"){
if($('#p_hire_recurring_interval').val() == ""){
alert("<%=t("property_hire.please_select_recurring_interval")%>");
$('#p_hire_recurring_interval').focus();
return;
}
$("#calendar").data("recurring_interval", $('#p_hire_recurring_interval').val());
}
$("#hidden_timepicker").addClass("hide");
$("#calendar").data("target","#"+$(target).attr("id"));
$("#calendar").data("title", $(target).parents(".col-sm-10").prev("label").text().replace("*",""));
$("#calendar").addClass("active_picker");
goto_calendar();
}
$("#calendar").on("select_time",function(ev,date_str){
$("#hidden_date").text(date_str);
$("#hidden_title").text($("#calendar").data("title"));
$('#hidden_timepicker .time_picker').addClass("pull-left");
$("#hidden_timepicker").removeClass("hide");
var target = $('#timepicker');
var window_width = $(window).width();
var window_height = $(window).height();
var target_offset = target.offset();
scrollTo(target_offset.left - window_width / 2, target_offset.top - window_height / 2);
$('#timepicker').trigger('focus');
})
$("#calendar").on("init_time",function(ev,time_str){
$('#timepicker').val(time_str);
})
function set_datetimepicker(){
var date_time = $("#hidden_date").text() + " " + $('#timepicker').val();
var start_date, end_date, interval = null, recurring_end_date = null;
var target = $("#calendar").data("target");
if(target == "#pick_start_date"){
start_date = date_time;
end_date = $("#p_hire_end_time").val();
}else if(target == "#pick_end_date"){
end_date = date_time;
start_date = $("#p_hire_start_time").val();
}else if(target == "#pick_recurring_end_date"){
if(pick_date_mode){
start_date = $("#p_hire_date").val();
end_date = start_date;
}else{
start_date = $("#p_hire_start_time").val();
end_date = $("#p_hire_end_time").val();
}
interval = $("#p_hire_recurring_interval").val();
recurring_end_date = date_time;
}
end_date = (end_date == "" ? null : end_date);
start_date = (start_date == "" ? null : start_date);
if(start_date != null && end_date != null && $("#p_hire_start_time").val() != "" && $("#p_hire_end_time").val() != ""){
if(start_date > end_date){
if(target == "#pick_start_date"){
end_date = start_date.split(" ")[0] + " " + end_date.split(" ")[1];
$("#p_hire_end_time").val(end_date);
}else{
start_date = end_date.split(" ")[0] + " " + start_date.split(" ")[1];
$("#p_hire_start_time").val(start_date);
}
}
}
var check_only = (start_date == null || end_date == null);
if(check_available(start_date,end_date,interval,recurring_end_date,check_only)){
var target = $($("#calendar").data("target"));
target.prev().find("input").val(date_time);
$("#hidden_timepicker").addClass("hide");
$("#calendar").removeClass("active_picker");
var window_width = $(window).width();
var window_height = $(window).height();
var target_offset = target.offset();
scrollTo(target_offset.left - window_width / 2, target_offset.top - window_height / 2);
}else{
if(window.check_message !== ""){
alert(window.check_message.replace(/<br>/g,"\n"));
}else{
alert('<%=t("property_hire.unavailability")%>');
}
}
}
function goto_calendar(){
$("#hidden_timepicker").addClass("hide");
var offset = $('#orbit_calendar').offset();
scrollTo(0,offset.top-40);
window.setTimeout(function(){
scrollTo(0,offset.top-40);
},500);
}
</script>
<% end %>
<div class="col-lg-<%=right_col%>">
<%= form_for hire, :url => "/xhr/property_hires/make_booking", html: { class: "form-horizontal", id: "hire_form" } do |f| %>
<% if property.set_availability %>
<div class="form-group">
<%= f.label :date, "*"+t("property_hire.date"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-<%=input_col%>" id="date_target_block">
<% if calendar_type == 0 %>
<%= f.text_field :date, :value=>(recover ? f.object.date.to_s : t("property_hire.please_choose_date")),:readonly=>"",:onclick=>"goto_calendar()" %>
<% else %>
<%= f.datetime_picker :date, :no_label => true, :new_record => hire.new_record? && !recover ,:class => "pull-left", :picker_type => "date", :format=>"yyyy/MM/dd", :data=>{ "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<% end %>
</div>
</div>
<div class="form-group">
<%= f.label :time, "*"+t("property_hire.time"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-<%=input_col%>" id="hire_time_range_block">
<% property_day_setting = recover ? hire.property_day_setting : nil %>
<% if property_day_setting %>
<%= select_tag "#{f.object_name}[time]", options_for_select([[t("property_hire.please_select"),""],[property_day_setting.title,property_day_setting.id.to_s]],hire.property_day_setting_id), :required=>"required" %>
<% else %>
<% if property.calendar_type == 0 %>
<%= f.text_field :time, :value=>t("property_hire.please_choose_date"),:readonly=>"",:onclick=>"goto_calendar()" %>
<% else %>
<%= select_tag "#{f.object_name}[time]", options_for_select([[t("property_hire.please_choose_date"),""]]), :required=>"required" %>
<% end %>
<% end %>
</div>
</div>
<% else %>
<div class="form-group">
<%= f.label :start_time, "*"+t("property_hire.start_time"), :class => "col-sm-#{label_col} control-label" %>
<% if property.calendar_type == 0 %>
<div class="col-sm-<%=input_col%>">
<%= f.datetime_picker :start_time, :no_label => true, :new_record => hire.new_record? && !recover,:class => "pull-left", :data=>{"picker-type" => "range", "range" => "start", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<button type="button" id="pick_start_date" onclick="change_pick(this)" class="btn btn-primary btn-sm pull-left" style="margin-left: 1em;"><%=t("property_hire.pick_from_calendar")%></button>
</div>
<% end %>
</div>
<div class="form-group">
<%= f.label :end_time, "*"+t("property_hire.end_time"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-<%=input_col%>">
<%= f.datetime_picker :end_time, :no_label => true, :new_record => hire.new_record? && !recover,:class => "pull-left", :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<button type="button" id="pick_end_date" onclick="change_pick(this)" class="btn btn-primary btn-sm pull-left" style="margin-left: 1em;"><%=t("property_hire.pick_from_calendar")%></button>
</div>
</div>
<% end %>
<!-- ############# recurring ############# -->
<div class="form-group">
<%= f.label :recurring, t("property_hire.recurring"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-1">
<%= f.check_box :recurring %>
</div>
</div>
<div id="recurring-block" <%= hire.recurring ? "" : "style=display:none;" %>>
<div class="form-group">
<%= f.label :recurring_interval, t("property_hire.recurring_interval"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-1">
<%= f.select :recurring_interval, PHire::INTERVALS.collect{|int| [t("property_hire.recurring_interval_types.#{int}"), int] }, {:prompt => t('property_hire.select_interval')}, {:data => {"fv-validation" => "requiredifrecurring;" , "fv-messages" => "Cannot be empty;"}} %>
</div>
</div>
<div class="form-group">
<%= f.label :recurring_end_date, "*"+t("property_hire.recurring_end_date"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-<%=input_col%>">
<%= f.datetime_picker :recurring_end_date, :no_label => true, :new_record => hire.new_record? && !recover, :class=>"pull-left", :data=>{"fv-validation" => "requiredifrecurring;", "fv-messages" => "Cannot be empty;"} %>
<% if calendar_type == 0 %>
<button type="button" id="pick_recurring_end_date" onclick="change_pick(this)" class="btn btn-primary btn-sm pull-left" style="margin-left: 1em;"><%=t("property_hire.pick_from_calendar")%></button>
<% end %>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-<%=label_col%> col-sm-<%=input_col%>">
<div id="property-avaialable-alert" style="margin-bottom: 5px; padding: 10px;<%= 'display: none;' unless recover %>" class="alert alert-success" role="alert"><%=t("property_hire.this_property_is_available",:default=>"<b>Hooray! </b>This property is available.").html_safe%></div>
<div id="property-unavaialable-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-danger" role="alert"><b>Sorry! </b><span> This property is available.</span></div>
<div id="values-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-warning" role="alert">
<% hint1 = t("property_hire.please_select_recurring_interval_and_recurring_end_time",:default=>"") %>
<% if hint1 == ""%>
<b>Please! </b><span> Select an interval time and recurring event end date.</span>
<% else %>
<span><b><%=hint1%></b></span>
<% end %>
</div>
</div>
<% if property.set_unavailibility %>
<div class="col-sm-offset-<%=label_col%> col-sm-<%=input_col%>">
<b><%= t("property_hire.Unavailibility_Schedule") %></b>
<div>
<%= property.render_unavailable_message%>
</div>
</div>
<% end %>
</div>
<div class="form-group">
<label for="" class="col-sm-<%=label_col%> control-label"></label>
<div class="col-sm-<%=input_col%>">
<a href="/xhr/property_hires/check_availability" id="check-avail-btn" class="btn btn-primary"><%= t('property_hire.check_availibility') %></a>
<img style="display: none;" width="40" src="/assets/spin.gif" id="spinner" />
</div>
</div>
<% default_values = {"hiring_person_email" => ( current_user.member_profile.email rescue ""),
"hiring_person_number" => ( current_user.member_profile.mobile_no rescue ""),
"hiring_person_name" => ( current_user.name rescue "")
} %>
<% if recover
default_values = default_values.merge(Property::FIELDSNAME.map{|f| [f,hire.send(f)]}.to_h)
end %>
<%= f.hidden_field :hiring_person_id, :value => (current_user.member_profile.id.to_s rescue "") %>
<% custom_field_inputs = {} %>
<% custom_field_type = {"note_for_hire"=>"text_area"} %>
<% if(property.enable_notes_selector rescue false) %>
<% custom_field_inputs["note_for_hire"] = render(:partial=>"property_hires/notes_selector",:locals=>{:f=>f,:property=>property,:label_col=>label_col,:input_col=>input_col,:hire=>hire}) %>
<% end %>
<% fields_name = property.get_all_fields %>
<% has_p_hire_fields = property.p_hire_fields_enabled.count != 0
p_hire_fields = {}
if has_p_hire_fields
p_hire_fields = property.p_hire_fields_enabled.map{|rf| [rf.id.to_s,rf]}.to_h
end
%>
<% @form_index = 0 %>
<% fields_name.each do |field_name| %>
<% if has_p_hire_fields && field_name.include?("p_hire_fields") %>
<div class="form-group">
<% rf = p_hire_fields[field_name.sub("p_hire_fields.",'')] %>
<% next if rf.nil? %>
<%= rf.block_helper(property,@form_index,false,"p_hire",hire, rf.to_require,label_col) %>
</div>
<% @form_index = @form_index +1 %>
<% else %>
<% if(property[field_name]["enable"] == "1" rescue true) %>
<% required = (property[field_name]["required"] == "true" rescue false) %>
<% if custom_field_inputs[field_name] %>
<%= custom_field_inputs[field_name] %>
<% else %>
<div class="form-group">
<%= f.label field_name, (required ? "*" : "") + property.custom_text(field_name,"name"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-<%=input_col%>">
<% placeholder = property.custom_text(field_name,"placeholder") %>
<% if custom_field_type[field_name] %>
<%= f.send(custom_field_type[field_name], field_name , {:class => "form-control", :placeholder => placeholder, :value => default_values[field_name], :data => (required ? {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} : nil)}) %>
<% else %>
<%= f.text_field field_name, :class => "form-control", :placeholder => placeholder, :value => default_values[field_name], :data => (required ? {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} : nil) %>
<% end %>
</div>
</div>
<% end %>
<% end %>
<% end %>
<% end %>
<% if allow_no_logins_user && current_user.nil? %>
<!-- 驗證碼 -->
<div class="form-group">
<label for="note" class="col-sm-<%=label_col%> control-label"><%= t('property_hire.recaptcha.recaptcha') %></label>
<div class="col-sm-<%=input_col%>">
<%= gotcha_error %>
<%= gotcha %>
</div>
</div>
<% end %>
<div class="form-group">
<div class="col-sm-offset-<%=label_col%> col-sm-<%=input_col%>">
<% if f.object.id.present? %>
<%= f.hidden_field :id %>
<% end %>
<%= f.submit t("property_hire.save"), :class => "btn btn-primary" %>
<%= f.hidden_field :property_id, :value => property.id %>
<input type="hidden" name="url" value="<%= url %>" />
<input type="hidden" id="dates_validated" name="dates_validated" value="<%=recover ? 1 : 0 %>" data-fv-validation="checkForDates;" data-fv-messages="Please make sure first if dates are available.;">
</div>
</div>
<% end %>
</div>
<div class="clearfix"></div>
<div style="height: 50px;"></div>
<script type="text/javascript">
var property_id = "<%= property.id.to_s %>";
var timezone = (new Date().getTimezoneOffset() / -60).toString();
var all_day_settings = <%= all_day_settings.to_json.html_safe %>;
if(timezone[0] != "-"){
timezone = "+" + timezone;
}
$("#p_hire_date").on("change",function(){
var _this = $(this);
var date = new Date(_this.val());
if(date.getTime()){
var wday = date.getDay();
var select_target = $("#p_hire_time");
if(select_target.data("wday") == wday){
return;
}
select_target.empty();
select_target.data("wday",wday);
if(all_day_settings[wday]){
select_target.append("<option value=\"\"><%=t("property_hire.please_select")%></option>");
all_day_settings[wday].forEach(function(allow_time){
select_target.append("<option value=\""+allow_time[0]+"\">"+allow_time[1]+"</option>");
});
}else{
select_target.append("<option value=\"\"><%=t("property_hire.no_time_can_select",:default=>"No time can be selected!")%></option>");
}
}
})
var check_available = function(stime,etime,interval,recurring_end_date,check_only,property_id){
var el = $("#check-avail-btn"),
url = $("#check-avail-btn").attr("href"),
spinner = $("#spinner"),
time_setting_id = $("#hire_time_range_block select").val();
if(Number.isNaN(new Date(stime).getDate())){
window.check_message = "<%=t("property_hire.please_choose_date")%>";
if(!check_only){
$("#property-unavaialable-alert").find("span").html(window.check_message);
$("#property-unavaialable-alert").show();
}
spinner.hide();
el.show();
return false;
}
if(time_setting_id == ""){
window.check_message = "<%=t("property_hire.please_select_time")%>";
if(!check_only){
$("#property-unavaialable-alert").find("span").html(window.check_message);
$("#property-unavaialable-alert").show();
}
$("#hire_time_range_block select").focus();
$("#hire_time_range_block select").css("border","2px solid red");
spinner.hide();
el.show();
return false;
}
stime = stime || etime;
etime = etime || stime;
property_id = property_id || window.property_id;
data = {
"stime": stime,
"etime": etime,
"property_id": property_id,
"locale": "<%=I18n.locale%>",
"timezone": timezone,
"time_setting_id": time_setting_id,
"phire_id": "<%=hire.id.to_s%>"
}
data["interval"] = interval;
data["recurring_end_date"] = recurring_end_date;
var flag = false;
window.check_message = "";
$.ajax({
"url" : url,
"type" : "get",
"data" : data,
"dataType" : "json",
"async": false
}).done(function(data){
if(data.success){
$("#dates_validated").val("1");
$("#property-unavaialable-alert").hide();
flag = true;
if(!check_only){
$("#property-avaialable-alert").show();
}
}else{
$("#dates_validated").val("0");
$("#property-avaialable-alert").hide();
window.check_message = data.msg;
window.check_message = window.check_message.replace(/{(.*)}/,function(v){
return getDateString(new Date(RegExp.$1),datetime_format,is_chinese);
})
if(!check_only){
$("#property-unavaialable-alert").find("span").html(window.check_message);
$("#property-unavaialable-alert").show();
}
}
spinner.hide();
el.show();
})
return flag;
}
$(document).on("change","#hire_time_range_block select",function(){
$(this).css("border","");
})
$("#check-avail-btn").on("click",function(){
var el = $(this),
url = $(this).attr("href"),
spinner = $("#spinner");
$(".alert").hide();
var stime, etime;
if(pick_date_mode){
stime = $("#p_hire_date").val();
etime = stime;
}else{
stime = $("#p_hire_start_time").val();
etime = $("#p_hire_end_time").val();
}
var interval = null, recurring_end_date = null, is_recurring = false;;
if($("#p_hire_recurring").is(":checked")){
is_recurring = true;
interval = $("#p_hire_recurring_interval").val(),
recurring_end_date = $("#p_hire_recurring_end_date").val();
if(interval == "" || recurring_end_date == ""){
$("#values-alert").show();
return false;
}
}
spinner.show();
el.hide();
check_available(stime,etime,interval,recurring_end_date);
return false;
})
$("#unavailable-schedule").on("click",function(){
})
var hireForm = new FormValidator($("#hire_form"));
hireForm.validate_functions.checkForDates = function(value,element){
return value == "1";
}
hireForm.validate_functions.requiredifrecurring = function(value, element){
if($("#p_hire_recurring").is(":checked")){
return value != "";
}else{
return true;
}
}
$("#p_hire_recurring").on("click",function(){
$("#dates_validated").val("0");
$("#property-avaialable-alert").hide();
$("#property-unavaialable-alert").hide();
if($(this).is(":checked")){
$("#recurring-block").slideDown();
}else{
$("#recurring-block").slideUp();
}
})
</script>
<% end %>

View File

@ -0,0 +1,207 @@
<style>
.icons-list-2 {
cursor: all-scroll;
}
legend{
width: auto;
text-align: center;
padding: 0 1em;
}
.position-text-div {
cursor: text;
margin: -8px;
padding: 8px;
}
.position-text-div:hover {
background: aqua;
}
</style>
<%= form_for @property , :url => {:action => "update_fields_display_order"}, html: {class: "form-horizontal main-forms"} do |f| %>
<% p_hire_fields = @property.p_hire_fields_enabled.map{|rf| [rf.id.to_s,rf]}.to_h %>
<fieldset>
<legend><%= @property.title %></legend>
<div class="control-group">
<label class="control-label" for="enable_fields_sort"><%=t("property_hire.enable_fields_sort")%></label>
<div class="controls">
<%= f.check_box :enable_fields_sort, :id=>"enable_fields_sort" %>
</div>
</div>
<div id="fields_sort_block" class="<%= 'hide' unless f.object.enable_fields_sort %>">
<table width="100%" id="property_order_table" class="table table-striped">
<thead>
<tr>
<th></th>
<th><%= t("property_hire.sort_number") %></th>
<th><%= t("property_hire.field_name") %></th>
</thead>
<tbody>
<% @property.custom_field_names.each_with_index do |field_name,i| %>
<% p_hire_field = nil
if field_name.include?("p_hire_fields")
p_hire_field = p_hire_fields[field_name.sub("p_hire_fields.",'')]
next if p_hire_field.nil?
end %>
<tr data-index="<%=i%>">
<td><span class="brand"><i class="icons-list-2"></i></span></td>
<td class="position-text">
<div class="position-text-div" data-value="<%= (i + 1).to_s %>"><%= (i + 1).to_s %></div>
</td>
<td>
<% if p_hire_field %>
<%= p_hire_field.title %>
<% else %>
<%= @property.custom_text(field_name) %>
<% end %>
<%= hidden_field_tag "#{f.object_name}[custom_field_names][]", field_name %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div class="form-actions">
<% referer = request.referer rescue nil %>
<% referer = get_referer_url if referer.blank? || request.host != URI.parse(URI.encode(referer)).host %>
<%= f.submit t('submit'), class: 'btn btn-primary' %>
<input type="hidden" name="referer_url" value="<%= referer %>">
<%= link_to t('cancel'), referer, :class=>"btn" %>
</div>
</fieldset>
<% end %>
<script>
$("#enable_fields_sort").click(function(){
$("#fields_sort_block").toggleClass("hide");
update_table_cache_width();
})
</script>
<script type="text/javascript">
var makeEditable = function(){
var input_box = $("<input type='text'/>"),
el = $(this);
input_box.addClass("editable-input");
input_box.val(el.data("value"));
input_box.attr("data-old-id",el.data("value"));
input_box.on("blur",function(){
putBackdiv($(this));
});
input_box.on("keypress",function(e){
if(e.keyCode == 13 || e.keyCode == 27){
putBackdiv($(this),e.keyCode);
}
})
el.parent().html(input_box);
input_box.focus();
}
var putBackdiv = function(el,keyCode){
current_value = parseInt((el.val() == "" ? el.data("old-id") : el.val())),
old_value = parseInt(el.data("old-id"));
if(isNaN(current_value) || keyCode == 27){
current_value = old_value;
}
if(old_value != current_value){
var new_index_value = (current_value > old_value ? current_value + 1 : current_value - 1),
div = $("<div class='position-text-div' data-value='" + current_value + "'>" + new_index_value + "</div>");
div.on("click",makeEditable);
el.parent().html(div);
sortTable(el.data("old-id"),current_value);
}else{
var div = $("<div class='position-text-div' data-value='" + current_value + "'>" + current_value + "</div>");
div.on("click",makeEditable);
el.parent().html(div);
}
}
var sortTable = function(changed_index,changed_to){
var table_element = document.getElementById("property_order_table"),
data = [],
allRows = table_element.rows;
for(i = 1; i < allRows.length; i++){
var thisRow = allRows[i],
text = thisRow.cells[1].textContent.trim(),
hash = {};
hash.index = parseInt(text);
text = thisRow.cells[2].innerHTML.trim();
if(text != "&nbsp;"){
hash.property = text;
}
data.push(hash);
}
data = data.sort(function(a,b){return a.index - b.index});
renderSortedTable(data,table_element);
}
var renderSortedTable = function(data,table_element){
var allRows = table_element.rows;
for(i = 0;i < data.length; i++){
var thisRow = allRows[i + 1],
current_value = i + 1;
thisRow.cells[1].innerHTML = "<div class='position-text-div' data-value='" + current_value + "'>" + current_value + "</div>";
thisRow.cells[2].innerHTML = data[i].property;
}
$("#property_order_table div.position-text-div").on("click",makeEditable);
}
$("#property_order_table div.position-text-div").on("click",makeEditable);
</script>
<script>
window.update_table_cache_width = function(){
$( ".table tbody" ).each(function(i,tbody){
var table = $(tbody).parents("table").eq(0);
table.data("index",i);
th_width[i] = [];
table.find("thead th").each(function(j,th){
th_width[i].push($(th).outerWidth(true));
})
})
}
var th_width = {};
$(document).ready(function(){
update_table_cache_width();
$( ".table tbody" ).sortable({
revert: true,
axis: "y",
handle: ".brand",
start: function(event, ui){
var item = ui.item;
var target = $(event.target);
var index = target.parents(".table").eq(0).data("index");
item.css("width",target.width());
item.find("td").each(function(i,td){
$(td).width(th_width[index][i]);
})
},
stop: function(event, ui) {
var item = ui.item;
item.css("width","");
item.find("td").css("width","");
},
update: function(event, ui) {
var item = ui.item;
var org_index = item.data("index");
console.log(org_index);
var new_index = item.index();
var indices = [org_index,new_index].sort();
var table = item.parents(".table").eq(0);
table.find("tbody tr").each(function(i,tr){
if(i >= indices[0] && i <= indices[1]){
var position_text_div = $(tr).find(".position-text-div");
position_text_div.text(i+1).data("value",i+1);
$(tr).data("index",i);
}
if(i > indices[1]){
return;
}
})
}
});
})
$(window).resize(function(){
th_width = {};
$( ".table tbody" ).each(function(i,tbody){
var table = $(tbody).parents("table").eq(0);
th_width[i] = [];
table.find("thead th").each(function(j,th){
th_width[i].push($(th).outerWidth(true));
})
})
})
</script>

View File

@ -1,44 +1,74 @@
<table class="table main-list">
<thead>
<tr class="sort-header">
<% @table_fields.each do |f| %>
<%= thead(f) %>
<% end %>
</tr>
</thead>
<tbody>
<% @properties.each do |property| %>
<tr>
<td>
<% if can_edit_or_delete?(property) %>
<a href="<%= admin_property_hire_path(property) %>"><%= property.title %></a>
<div class="quick-edit">
<ul class="nav nav-pills">
<li><a href="<%= edit_admin_property_hire_path(property, :page => params[:page]) %>"><%= t(:edit) %></a></li>
<li><a href="<%= admin_property_hire_path(property.id, :page => params[:page]) %>" data-method="delete" data-confirm="Are you sure?"><%= t(:delete_) %></a></li>
</ul>
<%= render_filter @filter_fields, "index_table" %>
<span id="index_table">
<%= render 'index'%>
</span>
<div id="downloadModal" data-backdrop="static" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="downloadModalLabel" aria-hidden="true">
<div class="modal-header">
<h3 id="downloadModalLabel">Download</h3>
</div>
<% else %>
<%= property.title %>
<% end %>
</td>
<td>
<%= property.category.title %>
</td>
<td>
<%= property.get_location_name %>
</td>
<td>
<% if property.can_be_hired %>
<span class="badge badge-success">Yes</span>
<% else %>
<span class="badge badge-important">No</span>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<div class="bottomnav clearfix">
<%= content_tag(:div, paginate(@properties), class: "pagination pagination-centered") %>
<div class="modal-body">
<p id="wait-zone" style="text-align: center;">
Please wait while we prepare your download. This may take a while.
<br />
<img src="/assets/spin.gif" />
</p>
<p id="link-zone" style="display: none; text-align: center;">
Please click the link below to download.
<br />
<a href="" id="download-link" target="_blank">Download</a>
</p>
</div>
<div class="modal-footer">
<button class="btn" id="modal-close-btn" style="display:none;" data-dismiss="modal" aria-hidden="true">Close</button>
</div>
</div>
<script type="text/javascript" src="/assets/lib/process.manager.js"></script>
<script type="text/javascript">
var downloadModal = $("#downloadModal"),
checkForThread = null,
waitZone = $("#wait-zone"),
linkZone = $("#link-zone"),
downloadLink = $("a#download-link"),
modalBtn = $("#modal-close-btn"),
processManager = new ProcessManager();
$(document).on("click", ".export-xls", function(){
var link = $(this).attr("href"),
title = null,
id = $(this).data("property-id");
linkZone.hide();
waitZone.show();
modalBtn.hide();
$.ajax({
url : link,
type : "get",
dataType : "json"
}).done(function(data){
title = data.title;
checkForThread = new Process(function(){
$.ajax({
url : "/admin/property_hires/checkforthread",
type : "get",
data : {"property_id" : id, "property_title" : title},
dataType : "json"
}).done(function(data){
if(!data.status){
downloadLink.attr("href", "/uploads/reservation_export/" + id + "/" + title + ".xlsx");
waitZone.hide();
linkZone.show();
modalBtn.show();
checkForThread.kill();
}
})
})
checkForThread.setTimeInterval(1000);
checkForThread.setRepeat(Process.CONSTANTS.REPEAT_INFINITE);
processManager.queue(checkForThread);
})
downloadModal.modal("show");
return false;
})
</script>

View File

@ -61,7 +61,7 @@
<div class="bottomnav clearfix">
<%= content_tag(:div, paginate(@locations), class: "pagination pagination-centered") %>
<div class="pull-right">
<%= link_to t(:add), add_location_admin_property_hires_path, :class => "btn btn-primary", :data => {"toggle" => "modal", "target" => "#location-modal"} %>
<%= link_to t(:add), add_location_admin_property_hires_path, :id=>'create_new_location', :class => "btn btn-primary", :data => {"toggle" => "modal", "target" => "#location-modal"} %>
</div>
</div>
@ -72,4 +72,16 @@
$("#edit-location-btn").on("click",function(){
$("#edit-location-modal form").submit();
})
$("#create_new_location").on("click",function(){
var url = $(this).attr("href");
$.get(url).done(function(data){
$("#location-modal .modal-body").html(data);
})
})
$('[data-target="#edit-location-modal"]').on("click",function(){
var url = $(this).attr("href");
$.get(url).done(function(data){
$("#edit-location-modal .modal-body").html(data);
})
})
</script>

View File

@ -10,6 +10,9 @@
<tbody>
<% @bookings.each do |p_hire| %>
<tr>
<td>
<%= p_hire.property.title rescue nil %>
</td>
<td>
<%= p_hire.hirer_name %>
</td>
@ -30,7 +33,11 @@
<% end %>
</td>
<td>
<a href="<%= show_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-info">View</a>
<a href="<%= delete_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">Delete</a>
</td>
</tr>

View File

@ -0,0 +1,199 @@
<% content_for :page_specific_css do %>
<%= stylesheet_link_tag "admin/properties" %>
<% end %>
<style>
.icons-list-2 {
cursor: all-scroll;
}
.position-text-div {
cursor: text;
margin: -8px;
padding: 8px;
}
.position-text-div:hover {
background: aqua;
}
</style>
<div class="order-edit-notification"><%= t("property_hire.please_save") %></div>
<table width="100%" id="property_order_table" class="table table-striped" class="web_soursce_table">
<thead>
<tr>
<th></th>
<th><%= t("property_hire.position") %></th>
<th><%= t("property_hire.title") %></th>
</thead>
<tbody>
<% @properties.each_with_index do |property,i| %>
<tr data-index="<%=i%>">
<td><span class="brand"><i class="icons-list-2"></i></span></td>
<td class="position-text">
<div class="position-text-div" data-value="<%= (i + 1).to_s %>"><%= (i + 1).to_s %></div>
</td>
<td>
<div class="property-text-id" data-property-id="<%= property.id.to_s %>"><%= property.title %></div>
</td>
</tr>
<% end %>
</tbody>
</table>
<div class="bottomnav clearfix" style="left: 81px;">
<div class="action pull-right">
<a class="btn btn-info disabled" id="save-order-button" href="#"><%= t("property.save_order") %></a>
</div>
<div class="pagination pagination-centered"></div>
</div>
<script type="text/javascript">
var makeEditable = function(){
var input_box = $("<input type='text'/>"),
el = $(this);
input_box.addClass("editable-input");
input_box.val(el.data("value"));
input_box.attr("data-old-id",el.data("value"));
input_box.on("blur",function(){
putBackdiv($(this));
});
input_box.on("keypress",function(e){
if(e.keyCode == 13 || e.keyCode == 27){
putBackdiv($(this),e.keyCode);
}
})
el.parent().html(input_box);
input_box.focus();
}
var putBackdiv = function(el,keyCode){
current_value = parseInt((el.val() == "" ? el.data("old-id") : el.val())),
old_value = parseInt(el.data("old-id"));
if(isNaN(current_value) || keyCode == 27){
current_value = old_value;
}
if(old_value != current_value){
var new_index_value = (current_value > old_value ? current_value + 1 : current_value - 1),
div = $("<div class='position-text-div' data-value='" + current_value + "'>" + new_index_value + "</div>");
div.on("click",makeEditable);
el.parent().html(div);
$("#save-order-button").removeClass("disabled");
$(".order-edit-notification").slideDown();
sortTable(el.data("old-id"),current_value);
}else{
var div = $("<div class='position-text-div' data-value='" + current_value + "'>" + current_value + "</div>");
div.on("click",makeEditable);
el.parent().html(div);
}
}
var sortTable = function(changed_index,changed_to){
var table_element = document.getElementById("property_order_table"),
data = [],
allRows = table_element.rows;
for(i = 1; i < allRows.length; i++){
var thisRow = allRows[i],
text = thisRow.cells[1].textContent.trim(),
hash = {};
hash.index = parseInt(text);
text = thisRow.cells[2].innerHTML.trim();
if(text != "&nbsp;"){
hash.property = text;
}
data.push(hash);
}
data = data.sort(function(a,b){return a.index - b.index});
renderSortedTable(data,table_element);
}
var renderSortedTable = function(data,table_element){
var allRows = table_element.rows;
for(i = 0;i < data.length; i++){
var thisRow = allRows[i + 1],
current_value = i + 1;
thisRow.cells[1].innerHTML = "<div class='position-text-div' data-value='" + current_value + "'>" + current_value + "</div>";
thisRow.cells[2].innerHTML = data[i].property;
}
$("#property_order_table div.position-text-div").on("click",makeEditable);
}
$("#save-order-button").on("click",function(){
var el = $(this);
if(!el.hasClass("disabled")){
var data = [];
$("#property_order_table .property-text-id").each(function(){
data.push($(this).data("property-id"));
})
$.ajax({
url : "<%=updateorder_admin_property_hires_path%>",
data : {"order" : data},
dataType : "json",
type : "post"
}).done(function(){
el.addClass("disabled");
$(".order-edit-notification").slideUp();
})
}
})
$("#property_order_table div.position-text-div").on("click",makeEditable);
</script>
<script>
var th_width = {};
$(document).ready(function(){
$( ".table tbody" ).each(function(i,tbody){
var table = $(tbody).parents("table").eq(0);
table.data("index",i);
th_width[i] = [];
table.find("thead th").each(function(j,th){
th_width[i].push($(th).outerWidth(true));
})
})
$( ".table tbody" ).sortable({
revert: true,
axis: "y",
handle: ".brand",
start: function(event, ui){
var item = ui.item;
var target = $(event.target);
var index = target.parents(".table").eq(0).data("index");
item.css("width",target.width());
item.find("td").each(function(i,td){
$(td).width(th_width[index][i]);
})
},
stop: function(event, ui) {
var item = ui.item;
item.css("width","");
item.find("td").css("width","");
},
update: function(event, ui) {
var item = ui.item;
var org_index = item.data("index");
console.log(org_index);
var new_index = item.index();
var indices = [org_index,new_index].sort();
var table = item.parents(".table").eq(0);
table.find("tbody tr").each(function(i,tr){
if(i >= indices[0] && i <= indices[1]){
var position_text_div = $(tr).find(".position-text-div");
position_text_div.text(i+1).data("value",i+1);
$(tr).data("index",i);
}
if(i > indices[1]){
return;
}
})
$("#save-order-button").removeClass("disabled");
$(".order-edit-notification").slideDown();
}
});
})
$(window).resize(function(){
th_width = {};
$( ".table tbody" ).each(function(i,tbody){
var table = $(tbody).parents("table").eq(0);
th_width[i] = [];
table.find("thead th").each(function(j,th){
th_width[i].push($(th).outerWidth(true));
})
})
})
</script>

View File

@ -6,6 +6,18 @@
<% content_for :page_specific_javascript do %>
<%= javascript_include_tag "lib/module-area" %>
<% end %>
<style>
.time_setting_form, .image_group{
border: 0.2em solid #333;
padding-top: 0;
}
.add-on.iconbtn{
display: none;
}
.time_setting_form:last-child, .image_group:last-child {
margin-bottom: 1em;
}
</style>
<%= form_for @settings , :url => settings_admin_property_hires_path, html: {class: "form-horizontal main-forms"} do |f| %>
<fieldset>
<% if @saved %>
@ -23,12 +35,68 @@
<div class="tab-content module-area">
<!-- Basic Module -->
<div class="tab-pane fade in active" id="basic">
<div class="control-group">
<%= f.label :allow_no_logins_user, t("property_hire.allow_no_logins_user"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :allow_no_logins_user %>
</div>
</div>
<div class="control-group">
<%= f.label :calendar_type, t("property_hire.display_calendar_default"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :calendar_type, {}, "0", "1" %>
</div>
</div>
<div class="control-group">
<%= f.label :auto_approve, t("property_hire.auto_approve"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :auto_approve %>
</div>
</div>
<div class="control-group">
<%= f.label :disable_content_page, t("property_hire.disable_content_page"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :disable_content_page %>
</div>
</div>
<div class="control-group">
<%= f.label :disable_view_calendar_page, t("property_hire.disable_view_calendar_page"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :disable_view_calendar_page %>
</div>
</div>
<div class="control-group">
<%= f.label :disable_no_logins_view_calendar, t("property_hire.disable_no_logins_view_calendar"), :class => "control-label muted" %>
<div class="controls">
<%= f.check_box :disable_no_logins_view_calendar %>
</div>
</div>
<div class="control-group">
<%= f.label :carousel_image_width, t("property_hire.default_carousel_image_width"), :class => "control-label muted" %>
<div class="controls">
<%= f.text_field :carousel_image_width %>
</div>
</div>
<div class="control-group">
<%= f.label :default_time_settings, t("property_hire.default_time_settings"), :class => "control-label muted" %>
<% default_time_settings = f.object.default_time_settings %>
<% setting_count = 0 %>
<div class="controls">
<div id="default_time_settings">
<% if default_time_settings %>
<% default_time_settings.each_with_index do |setting,j| %>
<%= f.fields_for :property_day_settings do |f| %>
<%= f.fields_for setting_count.to_s, setting do |f| %>
<%= render :partial => "time_form", :locals=>{:key=>j,:day=>0,:f=>f} %>
<% setting_count += 1 %>
<% end %>
<% end %>
<% end %>
<% end %>
</div>
<a class="btn btn-primary add_weekday_setting" data-target="#default_time_settings" data-count="<%= default_time_settings.count %>" data-day="0"><%=t(:add)%></a>
</div>
</div>
</div>
</div>
</div>
@ -37,4 +105,59 @@
<%= f.submit t('submit'), class: 'btn btn-primary' %>
</div>
</fieldset>
<script>
var setting_count = <%=setting_count%>;
$(".add_weekday_setting").click(function(){
var target = $($(this).data("target"));
var key = $(this).data("count");
var day = $(this).data("day");
var new_key = $(this).prev().attr('value');
var old_key = new RegExp("new_key", "g");
var new_day = day;
var old_day = new RegExp("new_day", "g");
var new_key = key;
key += 1;
$(this).data("count",key);
var old_index = new RegExp("new_index", "g");
var new_index = setting_count;
setting_count += 1;
<% property_day_setting = PropertyDaySetting.new(:id=>nil,:property_id=>"default_settings") %>
<%= f.fields_for :property_day_settings do |f| %>
<%= f.fields_for "new_index",property_day_setting do |f| %>
var template_html = "<%= escape_javascript(render(:partial=>"time_form",:locals=>{:f=>f})) %>";
<%end%>
<%end%>
var tmp = $(template_html.replace(old_index,new_index).replace(old_key,new_key).replace(old_day,new_day));
target.append(tmp);
tmp.find("input[data-format]").each(function(i,input){
var $input = $(input);
var format = $input.data("format"),
timeOnly = !(format.match(/Y|M|d/)), timeFormat, dateFormat = "";
if(timeOnly){
timeFormat = format;
}else{
dateFormat = format.match(/yy(\/|-|)(mm|)(\/|-|)(dd|)/i)[0];
timeFormat = $.trim(format.replace(dateFormat,""));
}
var options = {dateFormat: dateFormat,timeFormat: timeFormat,timeOnly: timeOnly};
var additionalOptions = $input.data();
$.extend(options, additionalOptions);
$input.ui_datetimepicker(options);
$input.siblings('.clearDate').click(function(){
$input.val('');
$input.trigger('change');
});
})
})
$(document).on('click', '.setting-form-remove', function(){
if($(this).find(".remove_existing_record").length != 0){
if(confirm("<%= I18n.t(:sure?)%>")){
$(this).find('.should_destroy').attr('value', 1);
$(this).parents('.time_setting_form').hide();
}
}else{
$(this).parents('.time_setting_form').remove();
}
});
</script>
<% end %>

View File

@ -1,4 +1,96 @@
<%= csrf_meta_tag %>
<div class="pull-right">
<a href="?type=" class="btn <%= 'active' if params[:type] != 'Calendar' %>"><%= t("property_hire.table") %></a>
<a href="?type=Calendar" class="btn <%= 'active' if params[:type] == 'Calendar' %>"><%= t("property_hire.calendar") %></a>
</div>
<hr>
<% if params[:type] == "Calendar" %>
<style type="text/css">
.row{
margin-left: 0;
}
.modal-content {
position: relative;
background-color: #fff;
-webkit-background-clip: padding-box;
background-clip: padding-box;
border: 1px solid #999;
border: 1px solid rgba(0,0,0,0.2);
border-radius: 6px;
outline: 0;
-webkit-box-shadow: 0 3px 9px rgb(0 0 0 / 50%);
box-shadow: 0 3px 9px rgb(0 0 0 / 50%);
}
@media (min-width:768px){
.modal-content {
-webkit-box-shadow: 0 5px 15px rgb(0 0 0 / 50%);
box-shadow: 0 5px 15px rgb(0 0 0 / 50%);
}
.col-md-4 > * {
padding: 0 0.5em;
}
.col-md-8 > * {
padding: 0 1em;
}
.col-md-4{
float: left;
width: 33.3%;
}
.col-md-8{
float: left;
width: 66.6%;
}
}
</style>
<%= content_for :page_specific_css do %>
<% ["basic/bootstrap-datetimepicker.css","property_hire_fullcalendar.css","property_hire_calendar"].each do |css| %>
<%= stylesheet_link_tag css %>
<% end %>
<% end %>
<script src="https://polyfill.io/v3/polyfill.min.js?features=Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.en,Intl.NumberFormat.~locale.en"></script>
<script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script>
<script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script>
<div id="orbit_calendar">
<div id="sec1">
<div class="btn-toolbar" id="navigation">
<div id="calendar-nav">
<div class="btn-group">
<button class="btn btn-default btn-sm" id="prev_month_btn">
<i class="icon-chevron-left"></i>
</button>
<button class="btn btn-default btn-sm" id="next_month_btn">
<i class="icon-chevron-right"></i>
</button>
<button class="btn btn-default btn-sm" id="today_btn">Today</button>
</div>
</div>
</div>
<div class="form-inline" id="range_selection"></div>
</div>
<div id='sec3' class="btn-toolbar">
<div class="btn-group calendar_mode">
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridDay" >day</button>
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridWeek" >week</button>
<button class="btn btn-default mode_switch btn-sm" data-mode="dayGridMonth" >month</button>
<button class="btn btn-default active mode_switch btn-sm" data-mode="agenda" >agenda</button>
</div>
<button id="refresh_btn" class="btn btn-default btn-sm">
<i class="icons-cycle"></i>
</button>
</div>
<div id="view_holder">
<h3 id="current_title" class="current_day_title"></h3>
<div id="calendar"></div>
<div id="calendar_agenda"></div>
</div>
</div>
<div id="event_quick_view" class="modal" style="width: 300px; display:none; margin:0 0 0 0;"></div>
<div id="calendar-loading"></div>
<script type="text/javascript">
var property_id = "<%= @property.id.to_s %>";
var calendar = new Calendar("#calendar",property_id,"agenda",false);
</script>
<% else %>
<table class="table main-list">
<thead>
<tr class="sort-header">
@ -14,7 +106,7 @@
<%= p_hire.hirer_name %>
</td>
<td>
<%= p_hire.reason_for_hire %>
<%= p_hire.reason_for_hire.to_s + p_hire.tmp_reason_for_hire %>
</td>
<td>
<%= p_hire.hiring_person_number %>
@ -31,13 +123,14 @@
</td>
<td>
<% if can_edit_or_delete?(p_hire.property) %>
<a href="<%= show_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-info">View</a>
<a href="<%= edit_hire_admin_property_hire_path(p_hire) %>" class="btn btn-info"><%= t("property_hire.edit") %></a>
<a href="<%= show_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-info"><%= t("property_hire.view") %></a>
<% if p_hire.passed %>
<a href="<%= pass_booking_admin_property_hire_path(p_hire, :page => params[:page], :status => "reject", :ref => "index") %>" class="btn btn-warning">Reject</a>
<a href="<%= pass_booking_admin_property_hire_path(p_hire, :page => params[:page], :status => "reject", :ref => "index") %>" class="btn btn-warning"><%= t("property_hire.reject") %></a>
<% else %>
<a href="<%= pass_booking_admin_property_hire_path(p_hire, :page => params[:page], :status => "accept", :ref => "index") %>" class="btn btn-success">Accept</a>
<a href="<%= pass_booking_admin_property_hire_path(p_hire, :page => params[:page], :status => "accept", :ref => "index") %>" class="btn btn-success"><%= t("property_hire.accept") %></a>
<% end %>
<a href="<%= delete_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">Delete</a>
<a href="<%= delete_booking_details_admin_property_hire_path(p_hire, :page => params[:page]) %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?"><%= t("property_hire.delete") %></a>
<% end %>
</td>
</tr>
@ -48,3 +141,4 @@
<a href="<%= admin_property_hires_path %>" class="btn btn-warning">Back</a>
<%= content_tag(:div, paginate(@bookings), class: "pagination pagination-centered") %>
</div>
<% end %>

View File

@ -1,5 +1,6 @@
<%= csrf_meta_tag %>
<h3><%= @booking.property.title %></h3>
<% property = @booking.property %>
<h3><%= property.title %></h3>
<table class="table main-list">
<tbody>
<tr>
@ -34,8 +35,26 @@
</tr>
<tr>
<td><%= t("property_hire.note_for_hire") %></td>
<td><%= @booking.note_for_hire %></td>
<td><%= @booking.note_for_hire.html_safe %></td>
</tr>
<% fields_name = ["organization" ,"person_in_charge" , "tel_of_person_in_charge" , "department" , "contact_person" , "tel_of_contact_person" , "mobile_phone_of_contact_person" , "contact_person_Email" , "contact_person_department"] %>
<% fields_name.each do |field_name| %>
<% if(property[field_name]["enable"] == "1" rescue false) %>
<tr>
<td><%= property.custom_text(field_name,"name") %></td>
<td><%= @booking[field_name].to_s %></td>
</tr>
<% end %>
<% end %>
<% @booking.p_hire_field_values.each do |v| %>
<% field_info = v.get_field_value rescue {} %>
<% if field_info["title"].present? && !field_info["value"].nil? && !field_info["hint"] %>
<tr>
<td><%=field_info["title"]%>:&nbsp;</td>
<td><%=field_info["value"]%></td>
</tr>
<% end%>
<% end%>
<tr>
<td><%= t("property_hire.passed") %></td>
<td>
@ -50,12 +69,13 @@
</table>
<a href="" onclick="window.history.back();return false;" class="btn btn-warning">Back</a>
<% if can_edit_or_delete?(@booking.property) %>
<a href="<%= edit_hire_admin_property_hire_path(@booking) %>" class="btn btn-info"><%= t("property_hire.edit") %></a>
<% if @booking.passed %>
<a href="<%= pass_booking_admin_property_hire_path(@booking, :status => "reject") %>" class="btn btn-warning">Reject</a>
<a href="<%= pass_booking_admin_property_hire_path(@booking, :status => "reject") %>" class="btn btn-warning"><%= t("property_hire.reject") %></a>
<% else %>
<a href="<%= pass_booking_admin_property_hire_path(@booking, :status => "accept") %>" class="btn btn-success">Accept</a>
<a href="<%= pass_booking_admin_property_hire_path(@booking, :status => "accept") %>" class="btn btn-success"><%= t("property_hire.accept") %></a>
<% end %>
<a href="<%= delete_booking_details_admin_property_hire_path(@booking, :page => params[:page]) %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">Delete</a>
<a href="<%= delete_booking_details_admin_property_hire_path(@booking, :page => params[:page]) %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?"><%= t("property_hire.delete") %></a>
<% end %>

View File

@ -0,0 +1,49 @@
<% if !@data['email_set_content'].nil? %>
<% email_set_content = YAML.load(@data['email_set_content'])
now_locale = @data['locale'] %>
<%= email_set_content[now_locale].html_safe rescue nil %>
<% end %>
<br>
<%= @data['content'].html_safe %>
<% property = Property.where(id: @data['property_id']).first %>
<% if !property.nil? %>
<h3><%= property.title_translations.collect{|k,v| v}.select{|v| v.present?}.uniq.join('/') rescue nil %></h3>
<% I18n.with_locale(@data['locale']) do %>
<table>
<thead>
<tr>
<td></td>
<td></td>
</tr>
</thead>
<tbody>
<% ['editor','property_usage','note','category','property_location','property_number','can_be_hired','purchase_date','owners','other_owner','owner_email','owner_phone','price'].each do |k| %>
<% v = property.send(k) rescue nil %>
<tr>
<td>
<%= k=='category' ? t('category') : t("property_hire.#{k}") %>:&nbsp;
</td>
<td>
<% if k == 'editor' %>
<%= User.find(user_id).name rescue nil %>
<% elsif ['purchase_date'].include?(k) %>
<%= v.strftime('%Y/%m/%d %H:%M') rescue nil %>
<% elsif ['property_usage','note'].include?(k) %>
<%= property.send("#{k}_translations").collect{|k,v| v}.select{|v| v.present?}.uniq.join('/') rescue nil %>
<% elsif k=='owners' %>
<%= property.owner_profiles.collect{|v| v.name}.join(', ') %>
<% elsif ['category','property_location'].include?(k) %>
<%= v.title %>
<% elsif k == 'can_be_hired' %>
<%= v ? t('yes_') : t('no_') %>
<% else %>
<%= v %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% end %>
<% end %>

View File

@ -0,0 +1,47 @@
<% property = Property.where(id: @data['property_id']).first %>
<% email_set = property.hire_email_sets.select{|v| v.field_name == 'edit'} %>
<% if email_set.length != 0 %>
<% if !(email_set[0].content.nil?) %>
<%= email_set[0].content[@data['locale']].html_safe %>
<% end %>
<% else %>
<%= t('property_hire.email_edit_success') %>
<% end %>
<h3><%= property.title_translations.collect{|k,v| v}.select{|v| v.present?}.uniq.join('/') rescue nil %></h3>
<% I18n.with_locale(@data['locale']) do %>
<table>
<thead>
<tr>
<td></td>
<td></td>
</tr>
</thead>
<tbody>
<% ['editor','property_usage','note','category','property_location','property_number','can_be_hired','purchase_date','owners','other_owner','owner_email','owner_phone','price'].each do |k| %>
<% v = property.send(k) rescue nil %>
<tr>
<td>
<%= k=='category' ? t('category') : t("property_hire.#{k}") %>:&nbsp;
</td>
<td>
<% if k == 'editor' %>
<%= User.find(user_id).name rescue nil %>
<% elsif ['purchase_date'].include?(k) %>
<%= v.strftime('%Y/%m/%d %H:%M') rescue nil %>
<% elsif ['property_usage','note'].include?(k) %>
<%= property.send("#{k}_translations").collect{|k,v| v}.select{|v| v.present?}.uniq.join('/') rescue nil %>
<% elsif k=='owners' %>
<%= property.owner_profiles.collect{|v| v.name}.join(', ') rescue nil %>
<% elsif ['category','property_location'].include?(k) %>
<%= v.title rescue nil %>
<% elsif k == 'can_be_hired' %>
<%= v ? t('yes_') : t('no_') %>
<% else %>
<%= v %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% end %>

View File

@ -0,0 +1,95 @@
<% property = Property.where(id: @data['property_id']).first%>
<% email_set = property.hire_email_sets.select{|v| v.field_name == 'p_hire'} %>
<% if email_set.length != 0 %>
<% if !(email_set[0].content.nil?) %>
<%= email_set[0].content[@data['locale']].html_safe %>
<% end %>
<% else %>
<%= t('property_hire.email_p_hire_content') %>
<% end %>
<br>
<style>
.hire_infos td:first-child {
white-space: nowrap;
}
</style>
<% I18n.with_locale(@data['locale']) do %>
<h3><%= property.title rescue nil %></h3>
<% if !@data['hire_id'].nil? %>
<% hire = PHire.where(id: @data['hire_id']).first %>
<table id="hire_infos">
<thead>
<tr>
<td></td>
<td></td>
</tr>
</thead>
<tbody>
<%
p_hire_fields = property.p_hire_fields_enabled.map{|rf| [rf.id.to_s,rf]}.to_h
fields_name = property.get_all_fields
basic_keys = []
if (property.set_availability rescue false)
basic_keys = ['date','time','hiring_person_name','hiring_person_email','recurring','recurring_interval','recurring_end_date','passed']
else
basic_keys = ['hiring_person_name','hiring_person_email','start_time','end_time','recurring','recurring_interval','recurring_end_date','passed']
end
fields_name = fields_name - basic_keys
keys = basic_keys + fields_name
keys = keys.select do |field_name|
return true if field_name.include?('p_hire_fields.')
tmp = property[field_name]
tmp.is_a?(Hash) ? (tmp["enable"] == "1") : true
end
p_hire_fields = property.p_hire_fields_enabled.map{|rf| [rf.id.to_s,rf]}.to_h
has_p_hire_fields = p_hire_fields.count != 0
tmp_keys = []
all_trans = keys.map do |k|
if has_p_hire_fields && k.include?("p_hire_fields")
tmp_keys << k.sub("p_hire_fields.",'')
nil
else
tmp_keys << k
property.custom_text(k,"name")
end
end
%>
<% p_hire_field_values = hire.p_hire_field_values.to_a %>
<% keys.each_with_index do |k,i| %>
<% if has_p_hire_fields && k.include?("p_hire_fields")
p_hire_field_id = tmp_keys[i]
v = p_hire_field_values.select{|v| v.p_hire_field_id.to_s == p_hire_field_id}.first
field_info = v.get_field_value rescue {}
if field_info["title"].present? && !field_info["value"].nil?
all_trans[i] = field_info["title"]
v = field_info["value"]
end
else
v = hire.send(k)
end
%>
<% if !v.nil? && !(k.include?('recurring') && hire.recurring != true)%>
<tr>
<td>
<%= all_trans[i] %>:&nbsp;
</td>
<td>
<% if ['start_time','end_time','recurring','recurring_interval','recurring_end_date','passed'].exclude?(k) %>
<%= v.to_s.html_safe %>
<% elsif ['start_time','end_time','recurring_end_date'].include?(k) %>
<%= v.strftime('%Y/%m/%d %H:%M') rescue nil %>
<% elsif k == 'recurring_interval' %>
<%= t("property_hire.recurring_interval_types.#{v}") %>
<% elsif 'recurring' == k %>
<%= v ? t('property_hire.yes') : t('property_hire.no') %>
<% else %>
<%= v ? t('property_hire.yes') : t('property_hire.wait_for_permit') %>
<% end %>
</td>
</tr>
<% end %>
<% end %>
</tbody>
</table>
<% end %>
<% end %>

View File

@ -0,0 +1,51 @@
# encoding: utf-8
wb = xlsx_package.workbook
wb.add_worksheet(name: "Reservations") do |sheet|
heading = sheet.styles.add_style(:b => true, :locked => true)
type = sheet.styles.add_style(:i => true)
wrap = sheet.styles.add_style alignment: {wrap_text: true}
row = [
t("property_hire.hiring_person_name"),
t("property_hire.hiring_person_number"),
t("property_hire.hiring_person_email"),
t("property_hire.period"),
t("property_hire.recurring_interval"),
t("property_hire.recurring_end_date"),
t("property_hire.reason_for_hire"),
t("property_hire.note_for_hire")
]
fields_name = ["organization" ,"person_in_charge" , "tel_of_person_in_charge" , "department" , "contact_person" , "tel_of_contact_person" , "mobile_phone_of_contact_person" , "contact_person_Email" , "contact_person_department"]
fields_name.each do |field_name|
if(property[field_name]["enable"] == "1" rescue false)
row << property.custom_text(field_name,"name")
end
end
sheet.add_row row, :style => heading
property.p_hires.asc(:created_at).each do |entry|
row = [
entry.hirer_name,
entry.hiring_person_number,
entry.hiring_person_email,
entry.period,
entry.recurring_interval,
entry.recurring_end_date,
entry.reason_for_hire,
entry.note_for_hire.html_safe
]
entry.p_hire_field_values.each do |v|
field_info = v.get_field_value rescue {}
if field_info["title"].present? && !field_info["value"].nil? && !field_info["hint"]
row << field_info["title"] + ":&nbsp;" + field_info["value"]
end
end
sheet.add_row row, style: wrap
end
end

View File

@ -0,0 +1,50 @@
<%
hire = (defined?(hire) ? hire : nil)
if hire
notes_selector_value = hire.note_for_hire.split('<br>').map{|s| s.split(':', 2)}.to_h
use_default = false
else
use_default = true
end
%>
<% property.notes_selector.each do |index,sub_hash| %>
<% name = sub_hash["name"][I18n.locale.to_s] %>
<% name = sub_hash["name"].values.select{|v| v.present?}.first.to_s if name.blank? %>
<% values = sub_hash["value"][I18n.locale.to_s] %>
<% values = sub_hash["value"].values.select{|v| v.present?}.first.to_s if values.blank? %>
<% type = sub_hash["type"] %>
<div class="form-group">
<%= f.label "notes_selector[#{index}]", name, :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-<%=input_col%>">
<%
if use_default
if type == "radio"
selected_indices = [0]
else
selected_indices = []
end
else
selected_indices = []
sub_hash["name"].each do |l, k|
if notes_selector_value.has_key?(k)
sub_hash["value"][l].each_with_index do |v, i|
if notes_selector_value[k].match(/(^|,)#{::Regexp.escape(v)}(,|$)/)
selected_indices << i
end
end
end
end
end
%>
<% values.each_with_index do |v,i| %>
<label class="checkbox-inline">
<input type="<%=type%>" name="p_hire[notes_selector][<%=index.to_s%>][]" value="<%=i%>" <%= (selected_indices.include?(i)) ? "checked=\"checked\"" : "" %>>
<%=v%>
</label>
<% end %>
<% if type == "checkbox" && (values.count > 1) %>
<small class="help-block"><%= t("property_hire.checkbox_hint") %></small>
<% end %>
</div>
</div>
<% end %>

View File

@ -1,188 +1,782 @@
<% OrbitHelper.render_css_in_head(["basic/bootstrap-datetimepicker.css"]) %>
<%= javascript_include_tag "lib/bootstrap-datetimepicker" %>
<%= javascript_include_tag "lib/datetimepicker/datetimepicker.js" %>
<% OrbitHelper.render_css_in_head(["basic/bootstrap-datetimepicker.css","property_hire_fullcalendar.css","property_hire_calendar"]) %>
<%= javascript_include_tag "validator.js" %>
<script src="https://polyfill.io/v3/polyfill.min.js?features=Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.en,Intl.NumberFormat.~locale.en"></script>
<script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script>
<script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script>
<script type="text/javascript" src="/assets/locale-all.min.js"></script>
<%= javascript_include_tag "basic/jquery.nanoscroller.js" %>
<%
data = action_data
hire = data["hire"]
property = data["property"]
is_user_manager = data["is_user_manager"]
url = data["page"]
current_user = data["current_user"]
allow_no_logins_user = data["allow_no_logins_user"]
all_day_settings = data["all_day_settings"]
recover = data["recover"]
locale = data["language"]
calendar_type = property.calendar_type.to_i rescue 0
right_col = 12
label_col = 2
input_col = 10
if calendar_type == 0
right_col -= 7
label_col += 2
input_col -= 2
end
%>
<style type="text/css">
.full-size-img img {
width: 100%;
}
.full-size-img {
width: 100%;
}
.s-annc__sub-img.pull-right {
margin-left: 2em;
}
.s-annc__sub-img.pull-left {
margin-right: 2em;
}
strong.carousel__description {
color: white;
}
.carousel_images{
<%=data["carousel_display_style"]%>
}
@media (max-width: 767px){
.carousel_images{
width: 100%;
}
}
.carousel_img_item{
display: none;
float: left;
}
.controlplay {
position: absolute;
right: 1em;
top: 3%;
z-index: 200;
}
.controlplay a {
display: inline-block;
margin-right: 0.25em;
cursor: pointer;
padding: 5px 10px;
border: 1px solid rgba(255,255,255,0.5);
background: rgba(0,0,0,0.2);
}
.controlplay a i {
font-family: FontAwesome;
position: relative;
font-size: 1rem;
line-height: 1;
color: #FFF;
vertical-align: middle;
font-style: unset;
}
.controlplay .resume-slide i::before {
content: "\f04b";
}
.controlplay .pause-slide i::before {
content: "\f04c";
}
ul.button-mid .prev-button {
transition: 0.4s;
position: relative;
float: left;
left: 0.5rem;
width: 2.5rem;
height: 2.5rem;
font-size: 2.2rem;
color: #ffffff;
background: rgba(0,0,0,0.2);
text-align: center;
line-height: 2.5rem;
top: 50%;
position: absolute;
transform: translateY(-50%);
z-index: 999;
}
ul.button-mid .next-button {
float: right;
transition: 0.4s;
position: relative;
right: 0.5rem;
width: 2.5rem;
height: 2.5rem;
font-size: 2.2rem;
color: #fff;
background: rgba(0,0,0,0.2);
text-align: center;
line-height: 2.5rem;
top: 50%;
position: absolute;
transform: translateY(-50%);
z-index: 999;
}
.carousel_images_slide{
padding: 3em;
}
.carousel_img_item img{
cursor: pointer;
}
@media (max-width: 479px){
.carousel_img_item:nth-child(-n+1){
display: block;
width: 100%;
float: left;
}
.carousel_img_item{
width: 100%;
}
}
@media (min-width: 480px){
.carousel_img_item:nth-child(-n+2){
display: block;
width: 50%;
float: left;
}
.carousel_img_item{
width: 50%;
}
}
@media (min-width: 768px){
.carousel_img_item:nth-child(-n+3){
display: block;
width: 33%;
float: left;
}
.carousel_img_item{
width: 33%;
}
}
@media (min-width: 1280px){
.carousel_img_item:nth-child(-n+4){
display: block;
width: 25%;
float: left;
}
.carousel_img_item{
width: 25%;
}
}
form#hire_form .form-group input,form#hire_form .form-group select, form#hire_form .form-group textarea{
min-width: 100%;
max-width: 300px;
}
form#hire_form .form-group input[name="_rucaptcha"], form#hire_form .form-group input[type="submit"], form#hire_form .form-group input[type="radio"], form#hire_form .form-group input[type="checkbox"]{
width: auto;
min-width: auto;
position: relative;
margin-left: 0;
}
</style>
<% if !property.can_be_hired %>
<script type="text/javascript">
alert("This property is unavailable for hire.");
window.location.href = "<%= "/" + I18n.locale.to_s + url %>";
</script>
<% end %>
<% if current_user.nil? %>
<% if !allow_no_logins_user && current_user.nil? %>
<script type="text/javascript">
alert("Please login before you hire.");
window.location.href = "<%= "/" + I18n.locale.to_s + url %>";
</script>
<% else %>
<h3><%= property.title %></h3>
<script type="text/javascript">
var pick_date_mode = <%=property.set_availability%>;
</script>
<h3 class="property_title"><%= property.title.html_safe %></h3>
<article class="s-annc s-property">
<section class="s-annc__post-wrap">
<% if property.display_img %>
<div class="s-annc__sub-img full-size-img">
<img src="<%=property.image.url%>" alt="<%=property.title%>">
<span class="s-annc__img_description"><%=property.title.html_safe%></span>
</div>
<% end %>
<h4 class="property_subtitle"><%= property.property_usage.html_safe %></h4>
<% property_carousel_images = property.property_carousel_images %>
<% if property_carousel_images.count != 0 %>
<div class="carousel_images">
<div class="w-ba-banner ba-banner-widget-1">
<div class="w-ba-banner__wrap cycle-slideshow"
data-list="property_carousel_images"
data-level="0"
data-cycle-slides=".property_carousel_slide"
data-cycle-log="false"
data-cycle-auto-height="0"
data-cycle-speed="300"
data-cycle-timeout="5000"
data-cycle-fx="fade"
data-pager-active-class="active-slide"
data-cycle-swipe=true
data-cycle-swipe-fx="scrollHorz"
>
<% property_carousel_images.each do |carousel_image| %>
<div class="w-ba-banner__slide property_carousel_slide"
data-cycle-title="{{description_text}}"
>
<img class="w-ba-banner__image banner-responsive" src="<%=carousel_image.file.url %>" alt="<%=carousel_image.description_text %>">
<div class="ad-overlay w-ad-banner__overlay property_carousel__overlay">
<p><strong class="carousel__description"><%=carousel_image.description %></strong></p>
</div>
<div class="transitionfade"></div>
</div>
<% end %>
</div>
<ul class="controlplay"><a class="resume-slide" title="<%=data["resume_btn_title"]%>"><i></i></a><a class="pause-slide" title="<%=data["pause_btn_title"]%>"><i></i></a></ul>
<ul class="button-mid">
<i class="fa fa-angle-left prev-button" aria-hidden="true" title="<%=data["prev_btn_title"]%>"></i>
<i class="fa fa-angle-right next-button" aria-hidden="true" title="<%=data["next_btn_title"]%>"></i>
</ul>
</div>
</div>
<% end %>
<div class="property_note"><%= property.note.html_safe %></div>
</section>
<ul class="s-property__related-wrap list-unstyled no-print">
<% if property.property_files.count != 0%>
<li class="s-annc__related-file s-property__related-file">
<i class="fa fa-fw fa-paperclip"></i>
<div class="s-annc__related-file-list s-property__related-file-list" data-list="property_files" data-level="0">
<% property.property_files.each do |property_file| %>
<a class="s-annc__flie-title s-property__flie-title btn btn-default btn-sm" href="<%=property_file.file.url %>" title="<%=property_file.title %>"><%=property_file.title %></a>
<% end %>
</div>
</li>
<% end %>
<% if property.property_links.count != 0%>
<li class="s-annc__related-link s-property__related-link">
<i class="fa fa-fw fa-link"></i>
<div class="s-annc__related-link-list s-property__related-link-list" data-list="bulletin_links" data-level="0">
<% property.property_links.each do |property_link| %>
<a class="s-annc__link-title s-property__link-title btn btn-default btn-sm" href="<%=property_link.url %>" target="_blank"><%=property_link.display_title %></a>
<% end %>
</div>
</li>
<% end %>
</ul>
<% if session["hire-save-msg"].present? %>
<div id="property-unavaialable-alert" class="alert alert-danger" role="alert"><b>Sorry! </b><span> <%= session["hire-save-msg"] %></span></div>
<div id="property-unavaialable-alert" class="alert alert-danger" role="alert"><b>Sorry! </b><br><span> <%= session["hire-save-msg"].gsub("\n",'<br>').html_safe %></span></div>
<script type="text/javascript">alert("<%= escape_javascript(session["hire-save-msg"]) %>")</script>
<% session.delete("hire-save-msg") %>
<% end %>
<%= form_for hire, :url => "/xhr/property_hires/make_booking", html: { class: "form-horizontal" } do |f| %>
</article>
<% if calendar_type == 0 %>
<div id="orbit_calendar" class="col-lg-<%=12-right_col%>">
<div id="sec1">
<div class="btn-toolbar" id="navigation">
<div id="calendar-nav">
<div class="btn-group">
<button class="btn btn-default btn-sm" id="today_btn"><%= t("property_hire.today") %></button>
</div>
</div>
</div>
<div class="form-inline" id="range_selection"></div>
</div>
<div id='sec3' class="btn-toolbar">
<div class="btn-group calendar_mode">
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridDay" ><%= t("property_hire.day") %></button>
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridWeek" ><%= t("property_hire.week") %></button>
<button class="btn btn-default active mode_switch btn-sm" data-mode="dayGridMonth" ><%= t("property_hire.month") %></button>
</div>
<button id="refresh_btn" class="btn btn-default btn-sm">
<i class="icons-cycle"></i>
</button>
</div>
<div class="pull-right">
<button class="btn btn-default btn-sm" id="prev_month_btn">
<i class="icon-chevron-left"></i>
</button>
<button class="btn btn-default btn-sm" id="next_month_btn">
<i class="icon-chevron-right"></i>
</button>
</div>
<div class="clearfix"></div>
<div id="view_holder">
<h3 id="current_title" class="current_day_title"></h3>
<div id="calendar"></div>
<div id="calendar_agenda"></div>
</div>
<div id="calendar-loading"></div>
<div id="hidden_timepicker" class="hide">
<span id="hidden_title" class="pull-left" style="margin-right: 1em;font-weight: bold;"></span>
<div style="display: grid;">
<span id="hidden_date" class="pull-left" style="margin-right: 1em;"></span>
<%= fields_for :timepicker do |f|%>
<%= f.time_picker :timepicker, :no_label => true, :new_record => hire.new_record? && !recover,:format=>"HH:mm", :class => "pull-left", :data=>{"picker-type" => "range", "range" => "end"} %>
<% end %>
<div class="pull-left btn-group" style="margin-top: 0.5em;">
<button id="confirm_date" class="btn btn-primary btn-sm" style="margin-right: 0.5em;" onclick="set_datetimepicker()"><%=t("property_hire.confirm")%></button>
<button id="cancel_date" class="btn btn-primary btn-sm" onclick="goto_calendar()"><%=t("property_hire.cancel")%></button>
</div>
</div>
<div style="clear: both;"></div>
<hr>
</div>
</div>
<div id="event_quick_view" class="modal" style="width: 300px; display:none; margin:0 0 0 0;"></div>
<script type="text/javascript">
var property_id = "<%= property.id.to_s %>";
var valid_range = {}
<% if property.p_open_start_time %>
valid_range["start"] = "<%= property.p_open_start_time.strftime("%Y-%m-%d") %>"
<% end %>
<% if property.p_open_end_time %>
valid_range["end"] = "<%= (property.p_open_end_time + 1.day).strftime("%Y-%m-%d") %>"
<% end %>
var calendar = new Calendar("#calendar", property_id, valid_range,"",true, "<%= locale %>");
function pick_hire_date(date,allow_times){
if(window.processing_hire)
return;
window.processing_hire = true;
try{
var date_target = $("#date_target_block").find("input");
var offset = date_target.offset();
if(date_target.val() == date){
scrollTo(0,offset.top - 40);
return;
}
$("#date_target_block").find("input").val(date);
var select_target;
if($("#hire_time_range_block").find("select").length == 0){
select_target = $("<select name=\""+$("#hire_time_range_block").find("input").attr("name")+"\"></select>");
$("#hire_time_range_block").find("input").remove();
}
else{
select_target = $("#hire_time_range_block").find("select").eq(0);
}
select_target = select_target.empty();
select_target.append("<option value=\"\"><%=t("property_hire.please_select")%></option>");
allow_times.forEach(function(allow_time){
select_target.append("<option value=\""+allow_time[2]+"\">"+allow_time[3]+"</option>");
});
select_target.appendTo($("#hire_time_range_block"));
scrollTo(0,offset.top - 40);
}catch(e){};
window.processing_hire = false;
}
function change_pick(target){
if( $(target).attr("id") == "pick_recurring_end_date"){
if($('#p_hire_recurring_interval').val() == ""){
alert("<%=t("property_hire.please_select_recurring_interval")%>");
$('#p_hire_recurring_interval').focus();
return;
}
$("#calendar").data("recurring_interval", $('#p_hire_recurring_interval').val());
}
$("#hidden_timepicker").addClass("hide");
$("#calendar").data("target","#"+$(target).attr("id"));
$("#calendar").data("title", $(target).parents(".col-sm-10").prev("label").text().replace("*",""));
$("#calendar").addClass("active_picker");
goto_calendar();
}
$("#calendar").on("select_time",function(ev,date_str){
$("#hidden_date").text(date_str);
$("#hidden_title").text($("#calendar").data("title"));
$('#hidden_timepicker .time_picker').addClass("pull-left");
$("#hidden_timepicker").removeClass("hide");
var target = $('#timepicker');
var window_width = $(window).width();
var window_height = $(window).height();
var target_offset = target.offset();
scrollTo(target_offset.left - window_width / 2, target_offset.top - window_height / 2);
$('#timepicker').trigger('focus');
})
$("#calendar").on("init_time",function(ev,time_str){
$('#timepicker').val(time_str);
})
function set_datetimepicker(){
var date_time = $("#hidden_date").text() + " " + $('#timepicker').val();
var start_date, end_date, interval = null, recurring_end_date = null;
var target = $("#calendar").data("target");
if(target == "#pick_start_date"){
start_date = date_time;
end_date = $("#p_hire_end_time").val();
}else if(target == "#pick_end_date"){
end_date = date_time;
start_date = $("#p_hire_start_time").val();
}else if(target == "#pick_recurring_end_date"){
if(pick_date_mode){
start_date = $("#p_hire_date").val();
end_date = start_date;
}else{
start_date = $("#p_hire_start_time").val();
end_date = $("#p_hire_end_time").val();
}
interval = $("#p_hire_recurring_interval").val();
recurring_end_date = date_time;
}
end_date = (end_date == "" ? null : end_date);
start_date = (start_date == "" ? null : start_date);
if(start_date != null && end_date != null && $("#p_hire_start_time").val() != "" && $("#p_hire_end_time").val() != ""){
if(start_date > end_date){
if(target == "#pick_start_date"){
end_date = start_date.split(" ")[0] + " " + end_date.split(" ")[1];
$("#p_hire_end_time").val(end_date);
}else{
start_date = end_date.split(" ")[0] + " " + start_date.split(" ")[1];
$("#p_hire_start_time").val(start_date);
}
}
}
var check_only = (start_date == null || end_date == null);
if(check_available(start_date,end_date,interval,recurring_end_date,check_only)){
var target = $($("#calendar").data("target"));
target.prev().find("input").val(date_time);
$("#hidden_timepicker").addClass("hide");
$("#calendar").removeClass("active_picker");
var window_width = $(window).width();
var window_height = $(window).height();
var target_offset = target.offset();
scrollTo(target_offset.left - window_width / 2, target_offset.top - window_height / 2);
}else{
if(window.check_message !== ""){
alert(window.check_message.replace(/(<|&lt;)br(>|&gt;)/g,"\n"));
}else{
alert('<%=t("property_hire.unavailability")%>');
}
}
}
function goto_calendar(){
$("#hidden_timepicker").addClass("hide");
var offset = $('#orbit_calendar').offset();
scrollTo(0,offset.top-40);
window.setTimeout(function(){
scrollTo(0,offset.top-40);
},500);
}
</script>
<% end %>
<div class="col-lg-<%=right_col%>">
<% if property.can_reserve === true || is_user_manager %>
<%= form_for hire, :url => "/xhr/property_hires/make_booking", html: { class: "form-horizontal", id: "hire_form" } do |f| %>
<% if property.set_availability %>
<div class="form-group">
<%= f.label :start_time, t("property_hires.start_time"), :class => "col-sm-2 control-label" %>
<div class="col-sm-10">
<%= f.datetime_picker :start_time, :no_label => true, :new_record => hire.new_record?, :data=>{"picker-type" => "range", "range" => "start", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<%= f.label :date, "*"+t("property_hire.date"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-<%=input_col%>" id="date_target_block">
<% if calendar_type == 0 %>
<%= f.text_field :date, :value=>(recover ? f.object.date.to_s : t("property_hire.please_choose_date")),:readonly=>"",:onclick=>"goto_calendar()" %>
<% else %>
<%= f.datetime_picker :date, :no_label => true, :new_record => hire.new_record? && !recover ,:class => "pull-left", :picker_type => "date", :format=>"yyyy/MM/dd", :data=>{ "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<% end %>
</div>
</div>
<div class="form-group">
<%= f.label :end_time, t("property_hires.end_time"), :class => "col-sm-2 control-label" %>
<div class="col-sm-10">
<%= f.datetime_picker :end_time, :no_label => true, :new_record => hire.new_record?, :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<%= f.label :time, "*"+t("property_hire.time"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-<%=input_col%>" id="hire_time_range_block">
<% property_day_setting = recover ? hire.property_day_setting : nil %>
<% if property_day_setting %>
<%= select_tag "#{f.object_name}[time]", options_for_select([[t("property_hire.please_select"),""],[property_day_setting.title,property_day_setting.id.to_s]],hire.property_day_setting_id), :required=>"required" %>
<% else %>
<% if property.calendar_type == 0 %>
<%= f.text_field :time, :value=>t("property_hire.please_choose_date"),:readonly=>"",:onclick=>"goto_calendar()" %>
<% else %>
<%= select_tag "#{f.object_name}[time]", options_for_select([[t("property_hire.please_choose_date"),""]]), :required=>"required" %>
<% end %>
<% end %>
</div>
</div>
<% else %>
<div class="form-group">
<%= f.label :start_time, "*"+t("property_hire.start_time"), :class => "col-sm-#{label_col} control-label" %>
<% if calendar_type == 0 %>
<div class="col-sm-<%=input_col%>">
<%= f.datetime_picker :start_time, :no_label => true, :new_record => hire.new_record? && !recover, :class => "pull-left", :data=>{"picker-type" => "range", "range" => "start", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<button type="button" id="pick_start_date" onclick="change_pick(this)" class="btn btn-primary btn-sm pull-left" style="margin-left: 1em;"><%=t("property_hire.pick_from_calendar")%></button>
</div>
<% end %>
</div>
<div class="form-group">
<%= f.label :end_time, "*"+t("property_hire.end_time"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-<%=input_col%>">
<%= f.datetime_picker :end_time, :no_label => true, :new_record => hire.new_record? && !recover,:class => "pull-left", :data=>{"picker-type" => "range", "range" => "end","fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<button type="button" id="pick_end_date" onclick="change_pick(this)" class="btn btn-primary btn-sm pull-left" style="margin-left: 1em;"><%=t("property_hire.pick_from_calendar")%></button>
</div>
</div>
<% end %>
<% if property.recurring_enable %>
<!-- ############# recurring ############# -->
<div class="form-group">
<%= f.label :recurring, t("property_hires.recurring"), :class => "col-sm-2 control-label" %>
<%= f.label :recurring, t("property_hire.recurring"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-1">
<%= f.check_box :recurring %>
</div>
</div>
<div id="recurring-block" <%= hire.recurring ? "" : "style=display:none;" %>>
<div class="form-group">
<%= f.label :recurring_interval, t("property_hires.recurring_interval"), :class => "col-sm-2 control-label" %>
<%= f.label :recurring_interval, t("property_hire.recurring_interval"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-1">
<%= f.select :recurring_interval, PHire::INTERVALS.collect{|int| [t("property_hire.recurring_interval_types.#{int}"), int] }, {:prompt => "Select interval"}, {:data => {"fv-validation" => "requiredifrecurring;" , "fv-messages" => "Cannot be empty;"}} %>
<%= f.select :recurring_interval, PHire::INTERVALS.collect{|int| [t("property_hire.recurring_interval_types.#{int}"), int] }, {:prompt => t('property_hire.select_interval'),:data=>{"fv-validation"=> "requiredifrecurring;", "fv-messages"=> "Cannot be empty;"}} %>
</div>
</div>
<div class="form-group">
<%= f.label :recurring_end_date, t("property_hires.recurring_end_date"), :class => "col-sm-2 control-label" %>
<div class="col-sm-10">
<%= f.datetime_picker :recurring_end_date, :no_label => true, :new_record => hire.new_record?, :data=>{"fv-validation" => "requiredifrecurring;", "fv-messages" => "Cannot be empty;"} %>
<%= f.label :recurring_end_date, "*"+t("property_hire.recurring_end_date"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-<%=input_col%>">
<%= f.datetime_picker :recurring_end_date, :no_label => true, :new_record => hire.new_record? && !recover, :class=>"pull-left", :data=>{"fv-validation" => "requiredifrecurring;", "fv-messages" => "Cannot be empty;"} %>
<% if calendar_type == 0 %>
<button type="button" id="pick_recurring_end_date" onclick="change_pick(this)" class="btn btn-primary btn-sm pull-left" style="margin-left: 1em;"><%=t("property_hire.pick_from_calendar")%></button>
<% end %>
</div>
</div>
</div>
<% end %>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-5">
<div id="property-avaialable-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-success" role="alert"><b>Hooray! </b>This property is available.</div>
<div class="col-sm-offset-<%=label_col%> col-sm-<%=input_col%>">
<div id="property-avaialable-alert" style="margin-bottom: 5px; padding: 10px;<%= 'display: none;' unless recover %>" class="alert alert-success" role="alert"><%=t("property_hire.this_property_is_available",:default=>"<b>Hooray! </b>This property is available.").html_safe%></div>
<div id="property-unavaialable-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-danger" role="alert"><b>Sorry! </b><span> This property is available.</span></div>
<div id="values-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-warning" role="alert"><b>Please! </b><span> Select an interval time and recurring event end date.</span></div>
<div id="values-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-warning" role="alert">
<% hint1 = t("property_hire.please_select_recurring_interval_and_recurring_end_time",:default=>"") %>
<% if hint1 == ""%>
<b>Please! </b><span> Select an interval time and recurring event end date.</span>
<% else %>
<span><b><%=hint1%></b></span>
<% end %>
</div>
</div>
<% if property.set_unavailibility %>
<div class="col-sm-offset-2 col-sm-5">
<b>Unavailibility Schedule</b>
<div class="col-sm-offset-<%=label_col%> col-sm-<%=input_col%>">
<b><%= t("property_hire.Unavailibility_Schedule") %></b>
<div>
This property is unavaliable <%= !property.start_date.nil? ? " from " + property.start_date.strftime("%Y-%m-%d") : "" %> <%= !property.end_date.nil? ? " to " + property.end_date.strftime("%Y-%m-%d") : "" %> every
<% property.weekdays.each_with_index do |d,i| %>
<% if i < (property.weekdays.count - 1) %>
<%= Property::WEEKDAYS[d.to_i] + ", " %>
<% else %>
<%= Property::WEEKDAYS[d.to_i] %>
<% end %>
<% end %>
between <%= property.start_time %> &amp; <%= property.end_time %>.
<%= property.render_unavailable_message%>
</div>
</div>
<% end %>
</div>
<div class="form-group">
<label for="" class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<a href="/xhr/property_hires/check_availability" id="check-avail-btn" class="btn btn-primary">Check Availibility</a>
<label for="" class="col-sm-<%=label_col%> control-label"></label>
<div class="col-sm-<%=input_col%>">
<a href="/xhr/property_hires/check_availability" id="check-avail-btn" class="btn btn-primary"><%= t('property_hire.check_availibility') %></a>
<img style="display: none;" width="40" src="/assets/spin.gif" id="spinner" />
</div>
</div>
<div class="form-group">
<%= f.label :hiring_person_email, t("property_hires.hiring_person_email"), :class => "col-sm-2 control-label" %>
<div class="col-sm-5">
<%= f.text_field :hiring_person_email, :class => "form-control", :value => current_user.member_profile.email, :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
</div>
</div>
<div class="form-group">
<%= f.label :hiring_person_number, t("property_hires.hiring_person_number"), :class => "col-sm-2 control-label" %>
<div class="col-sm-5">
<%= f.text_field :hiring_person_number, :class => "form-control", :value => current_user.member_profile.mobile_no, :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
</div>
</div>
<div class="form-group">
<%= f.label :hiring_person_name, t("property_hires.hiring_person_name"), :class => "col-sm-2 control-label" %>
<div class="col-sm-5">
<%= f.text_field :hiring_person_name, :class => "form-control", :value => (current_user.name rescue ""), :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<% default_values = {"hiring_person_email" => ( current_user.member_profile.email rescue ""),
"hiring_person_number" => ( current_user.member_profile.mobile_no rescue ""),
"hiring_person_name" => ( current_user.name rescue "")
} %>
<% if recover
default_values = default_values.merge(Property::FIELDSNAME.map{|f| [f,hire.send(f)]}.to_h)
end %>
<%= f.hidden_field :hiring_person_id, :value => (current_user.member_profile.id.to_s rescue "") %>
</div>
</div>
<% custom_field_inputs = {} %>
<% custom_field_type = {"note_for_hire"=>"text_area"} %>
<% if(property.enable_notes_selector rescue false) %>
<% custom_field_inputs["note_for_hire"] = render(:partial=>"property_hires/notes_selector",:locals=>{:f=>f,:property=>property,:label_col=>label_col,:input_col=>input_col,:hire=>nil}) %>
<% end %>
<% fields_name = property.get_all_fields %>
<% has_p_hire_fields = property.p_hire_fields_enabled.count != 0
p_hire_fields = {}
if has_p_hire_fields
p_hire_fields = property.p_hire_fields_enabled.map{|rf| [rf.id.to_s,rf]}.to_h
end
%>
<% @form_index = 0 %>
<% fields_name.each do |field_name| %>
<% if has_p_hire_fields && field_name.include?("p_hire_fields") %>
<div class="form-group">
<%= f.label :reason_for_hire, t("property_hires.reason_for_hire"), :class => "col-sm-2 control-label" %>
<div class="col-sm-5">
<%= f.text_field :reason_for_hire, :class => "form-control", :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
</div>
<% rf = p_hire_fields[field_name.sub("p_hire_fields.",'')] %>
<% next if rf.nil? %>
<%= rf.block_helper(property,@form_index,false,"p_hire",hire, rf.to_require,label_col) %>
</div>
<% @form_index = @form_index +1 %>
<% else %>
<% if(property[field_name]["enable"] == "1" rescue true) %>
<% required = (property[field_name]["required"] == "true" rescue false) %>
<% if custom_field_inputs[field_name] %>
<%= custom_field_inputs[field_name] %>
<% else %>
<div class="form-group">
<%= f.label :note_for_hire, t("property_hires.note_for_hire"), :class => "col-sm-2 control-label" %>
<div class="col-sm-5">
<%= f.text_area :note_for_hire, :class => "form-control" %>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<%= f.submit t("property_hire.save"), :class => "btn btn-primary" %>
<%= f.hidden_field :property_id, :value => property.id %>
<input type="hidden" name="url" value="<%= url %>" />
<input type="hidden" id="dates_validated" name="dates_validated" value="0" data-fv-validation="checkForDates;" data-fv-messages="Please make sure first if dates are available.;">
<%= f.label field_name, (required ? "*" : "") + property.custom_text(field_name,"name"), :class => "col-sm-#{label_col} control-label" %>
<div class="col-sm-<%=input_col%>">
<% placeholder = property.custom_text(field_name,"placeholder") %>
<% if custom_field_type[field_name] %>
<%= f.send(custom_field_type[field_name], field_name , {:class => "form-control", :placeholder => placeholder, :value => default_values[field_name], :required=>(required ? 'required' : nil)}) %>
<% else %>
<%= f.text_field field_name, :class => "form-control", :placeholder => placeholder, :value => default_values[field_name], :required=>(required ? 'required' : nil) %>
<% end %>
</div>
</div>
<% end %>
<% end %>
<% end %>
<% end %>
<% if allow_no_logins_user && current_user.nil? %>
<!-- 驗證碼 -->
<div class="form-group">
<label for="note" class="col-sm-<%=label_col%> control-label"><%= t('property_hire.recaptcha.recaptcha') %></label>
<div class="col-sm-<%=input_col%>">
<%= gotcha_error %>
<%= gotcha %>
</div>
</div>
<% end %>
<div class="form-group">
<div class="col-sm-offset-<%=label_col%> col-sm-<%=input_col%>">
<% if f.object.id.present? %>
<%= f.hidden_field :id %>
<% end %>
<div class="nano"><div class="content"></div></div>
<%= f.submit t("property_hire.save"), :class => "btn btn-primary" %>
<%= f.hidden_field :property_id, :value => property.id %>
<input type="hidden" name="url" value="<%= url %>" />
<input type="hidden" id="dates_validated" name="dates_validated" value="<%=recover ? 1 : 0 %>" data-fv-validation="checkForDates;" data-fv-messages="Please make sure first if dates are available.;">
</div>
</div>
<% end %>
<% end %>
</div>
<div class="clearfix"></div>
<div style="height: 50px;"></div>
<script type="text/javascript">
var property_id = "<%= property.id.to_s %>";
var timezone = (new Date().getTimezoneOffset() / -60).toString();
var all_day_settings = <%= all_day_settings.to_json.html_safe %>;
if(timezone[0] != "-"){
timezone = "+" + timezone;
}
$("#p_hire_date").on("change",function(){
var _this = $(this);
var date = new Date(_this.val());
if(date.getTime()){
var wday = date.getDay();
var select_target = $("#p_hire_time");
if(select_target.data("wday") == wday){
return;
}
select_target.empty();
select_target.data("wday",wday);
if(all_day_settings[wday]){
select_target.append("<option value=\"\"><%=t("property_hire.please_select")%></option>");
all_day_settings[wday].forEach(function(allow_time){
select_target.append("<option value=\""+allow_time[0]+"\">"+allow_time[1]+"</option>");
});
}else{
select_target.append("<option value=\"\"><%=t("property_hire.no_time_can_select",:default=>"No time can be selected!")%></option>");
}
}
})
var check_available = function(stime,etime,interval,recurring_end_date,check_only,property_id){
var el = $("#check-avail-btn"),
url = $("#check-avail-btn").attr("href"),
spinner = $("#spinner"),
time_setting_id = $("#hire_time_range_block select").val();
if(Number.isNaN(new Date(stime).getDate())){
window.check_message = "<%=t("property_hire.please_choose_date")%>";
if(!check_only){
$("#property-unavaialable-alert").find("span").html(window.check_message);
$("#property-unavaialable-alert").show();
}
spinner.hide();
el.show();
return false;
}
if(time_setting_id == ""){
window.check_message = "<%=t("property_hire.please_select_time")%>";
if(!check_only){
$("#property-unavaialable-alert").find("span").html(window.check_message);
$("#property-unavaialable-alert").show();
}
$("#hire_time_range_block select").focus();
$("#hire_time_range_block select").css("border","2px solid red");
spinner.hide();
el.show();
return false;
}
stime = stime || etime;
etime = etime || stime;
property_id = property_id || window.property_id;
data = {
"stime": stime,
"etime": etime,
"property_id": property_id,
"locale": "<%=I18n.locale%>",
"timezone": timezone,
"time_setting_id": time_setting_id,
"phire_id": "<%=hire.id.to_s%>"
}
data["interval"] = interval;
data["recurring_end_date"] = recurring_end_date;
var flag = false;
window.check_message = "";
$.ajax({
"url" : url,
"type" : "get",
"data" : data,
"dataType" : "json",
"async": false
}).done(function(data){
if(data.success){
$("#dates_validated").val("1");
$("#property-unavaialable-alert").hide();
flag = true;
if(!check_only){
$("#property-avaialable-alert").show();
}
}else{
$("#dates_validated").val("0");
$("#property-avaialable-alert").hide();
window.check_message = data.msg;
window.check_message = window.check_message.replace(/{(.*)}/,function(v){
return getDateString(new Date(RegExp.$1),datetime_format,is_chinese);
})
if(!check_only){
$("#property-unavaialable-alert").find("span").html(window.check_message);
$("#property-unavaialable-alert").show();
}
}
spinner.hide();
el.show();
})
return flag;
}
$(document).on("change","#hire_time_range_block select",function(){
$(this).css("border","");
})
$("#check-avail-btn").on("click",function(){
var el = $(this),
url = $(this).attr("href"),
spinner = $("#spinner");
$(".alert").hide();
data = {
"stime" : $("#p_hire_start_time").val(),
"etime" : $("#p_hire_end_time").val(),
"property_id" : property_id
var stime, etime;
if(pick_date_mode){
stime = $("#p_hire_date").val();
etime = stime;
}else{
stime = $("#p_hire_start_time").val();
etime = $("#p_hire_end_time").val();
}
var interval = null, recurring_end_date = null, is_recurring = false;;
if($("#p_hire_recurring").is(":checked")){
var interval = $("#p_hire_recurring_interval").val(),
is_recurring = true;
interval = $("#p_hire_recurring_interval").val(),
recurring_end_date = $("#p_hire_recurring_end_date").val();
if(interval == "" || recurring_end_date == ""){
$("#values-alert").show();
return false;
}
data["interval"] = interval;
data["recurring_end_date"] = recurring_end_date;
}
spinner.show();
el.hide();
$.ajax({
"url" : url,
"type" : "get",
"data" : data,
"dataType" : "json"
}).done(function(data){
if(data.success){
$("#property-avaialable-alert").show();
$("#dates_validated").val("1");
}else{
$("#property-unavaialable-alert").find("span").text(data.msg);
$("#property-unavaialable-alert").show();
}
spinner.hide();
el.show();
})
check_available(stime,etime,interval,recurring_end_date);
return false;
})
$("#unavailable-schedule").on("click",function(){
})
var hireForm = new FormValidator($("#new_p_hire"));
if( document.createElement('canvas').getContext == undefined ){ //html5 not supported
$('[required]:not([readonly])').attr({"data-fv-validation": "required;", "data-fv-messages": "Cannot be empty;"});
}
var hireForm = new FormValidator($("#hire_form"));
hireForm.validate_functions.checkForDates = function(value,element){
return value == "1";
}
@ -193,8 +787,11 @@
return true;
}
}
$("#p_hire_recurring").on("click",function(){
$("#dates_validated").val("0");
$("#property-avaialable-alert").hide();
$("#property-unavaialable-alert").hide();
if($(this).is(":checked")){
$("#recurring-block").slideDown();
}else{
@ -202,10 +799,18 @@
}
})
</script>
<script>
$(document).ready(function(){
<% if property.p_open_start_time %>
$("#p_hire_start_time").datepicker('option', 'minDate', new Date("<%= property.p_open_start_time.strftime("%Y-%m-%d") %>"));
$("#p_hire_end_time").datepicker('option', 'minDate', new Date("<%= property.p_open_start_time.strftime("%Y-%m-%d") %>"));
$("#p_hire_recurring_end_date").datepicker('option', 'minDate', new Date("<%= property.p_open_start_time.strftime("%Y-%m-%d") %>"));
<% end %>
<% if property.p_hire_end_time && property.p_open_end_time %>
$("#p_hire_start_time").datepicker('option', 'maxDate', new Date("<%= property.p_open_end_time.strftime("%Y-%m-%d") %>"));
$("#p_hire_end_time").datepicker('option', 'maxDate', new Date("<%= property.p_open_end_time.strftime("%Y-%m-%d") %>"));
$("#p_hire_recurring_end_date").datepicker('option', 'maxDate', new Date("<%= property.p_open_end_time.strftime("%Y-%m-%d") %>"));
<% end %>
})
</script>
<% end %>

View File

@ -0,0 +1,440 @@
<% OrbitHelper.render_css_in_head(["basic/bootstrap-datetimepicker.css","property_hire_fullcalendar.css","property_hire_calendar"]) %>
<%= javascript_include_tag "validator.js" %>
<script src="https://polyfill.io/v3/polyfill.min.js?features=Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.en,Intl.NumberFormat.~locale.en"></script>
<script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script>
<script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script>
<%
data = action_data
hire = data["hire"]
property = data["property"]
url = data["page"]
current_user = data["current_user"]
%>
<% if !property.can_be_hired_frontend %>
<script type="text/javascript">
alert("This property is unavailable for hire.");
window.location.href = "<%= "/" + I18n.locale.to_s + url %>";
</script>
<% end %>
<% if current_user.nil? %>
<script type="text/javascript">
alert("Please login before you hire.");
window.location.href = "<%= "/" + I18n.locale.to_s + url %>";
</script>
<% else %>
<h3 class="property_title"><%= property.title %></h3>
<% if session["hire-save-msg"].present? %>
<div id="property-unavaialable-alert" class="alert alert-danger" role="alert"><b>Sorry! </b><span> <%= session["hire-save-msg"] %></span></div>
<% session.delete("hire-save-msg") %>
<% end %>
<div id="orbit_calendar">
<div id="sec1">
<div class="btn-toolbar" id="navigation">
<div id="calendar-nav">
<div class="btn-group">
<button class="btn btn-default btn-sm" id="prev_month_btn">
<i class="icon-chevron-left"></i>
</button>
<button class="btn btn-default btn-sm" id="next_month_btn">
<i class="icon-chevron-right"></i>
</button>
<button class="btn btn-default btn-sm" id="today_btn">Today</button>
</div>
</div>
</div>
<div class="form-inline" id="range_selection"></div>
</div>
<div id='sec3' class="btn-toolbar">
<div class="btn-group calendar_mode">
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridDay" >day</button>
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridWeek" >week</button>
<button class="btn btn-default active mode_switch btn-sm" data-mode="dayGridMonth" >month</button>
</div>
<button id="refresh_btn" class="btn btn-default btn-sm">
<i class="icons-cycle"></i>
</button>
</div>
<div id="view_holder">
<h3 id="current_title" class="current_day_title"></h3>
<div id="calendar"></div>
<div id="calendar_agenda"></div>
</div>
</div>
<div id="event_quick_view" class="modal" style="width: 300px; display:none; margin:0 0 0 0;"></div>
<div id="calendar-loading"></div>
<script type="text/javascript">
var property_id = "<%= property.id.to_s %>";
var calendar = new Calendar("#calendar",property_id);
function change_pick(target){
if( $(target).attr("id") == "pick_recurring_end_date"){
if($('#p_hire_recurring_interval').val() == ""){
alert("<%=t("property_hire.please_select_recurring_interval")%>");
$('#p_hire_recurring_interval').focus();
return;
}
$("#calendar").data("recurring_interval", $('#p_hire_recurring_interval').val());
}
$("#hidden_timepicker").addClass("hide");
$("#calendar").data("target","#"+$(target).attr("id"));
$("#calendar").data("title", $(target).parents(".col-sm-10").prev("label").text().replace("*",""));
$("#calendar").addClass("active_picker");
document.getElementById("main-content").scrollIntoView();
}
$("#calendar").on("select_time",function(ev,date_str){
$("#hidden_date").text(date_str);
$("#hidden_title").text($("#calendar").data("title"));
$('#hidden_timepicker .time_picker').addClass("pull-left");
$("#hidden_timepicker").removeClass("hide");
var target = $('#timepicker');
var window_width = $(window).width();
var window_height = $(window).height();
var target_offset = target.offset();
scrollTo(target_offset.left - window_width / 2, target_offset.top - window_height / 2);
$('#timepicker').trigger('focus');
})
$("#calendar").on("init_time",function(ev,time_str){
$('#timepicker').val(time_str);
})
function set_datetimepicker(){
var date_time = $("#hidden_date").text() + " " + $('#timepicker').val();
var start_date, end_date, interval = null, recurring_end_date = null;
var target = $("#calendar").data("target");
if(target == "#pick_start_date"){
start_date = date_time;
end_date = $("#p_hire_end_time").val();
}else if(target == "#pick_end_date"){
end_date = date_time;
start_date = $("#p_hire_start_time").val();
}else if(target == "#pick_recurring_end_date"){
start_date = $("#p_hire_start_time").val();
end_date = $("#p_hire_end_time").val();
interval = $("#p_hire_recurring_interval").val();
recurring_end_date = date_time;
}
end_date = (end_date == "" ? null : end_date);
start_date = (start_date == "" ? null : start_date);
if(start_date != null && end_date != null && $("#p_hire_start_time").val() != "" && $("#p_hire_end_time").val() != ""){
if(start_date > end_date){
if(target == "#pick_start_date"){
end_date = start_date.split(" ")[0] + " " + end_date.split(" ")[1];
$("#p_hire_end_time").val(end_date);
}else{
start_date = end_date.split(" ")[0] + " " + start_date.split(" ")[1];
$("#p_hire_start_time").val(start_date);
}
}
}
console.log(start_date)
var check_only = (start_date == null || end_date == null);
if(check_available(start_date,end_date,interval,recurring_end_date,check_only)){
var target = $($("#calendar").data("target"));
target.prev().find("input").val(date_time);
$("#hidden_timepicker").addClass("hide");
$("#calendar").removeClass("active_picker");
var window_width = $(window).width();
var window_height = $(window).height();
var target_offset = target.offset();
scrollTo(target_offset.left - window_width / 2, target_offset.top - window_height / 2);
}else{
if(window.check_message !== ""){
alert(window.check_message.replace(/<br>/g,"\n"));
}else{
alert('<%=t("property_hire.unavailability")%>');
}
}
}
function goto_calendar(){
$("#hidden_timepicker").addClass("hide");
var target = $("#calendar");
var window_width = $(window).width();
var window_height = $(window).height();
var target_offset = target.offset();
scrollTo(target_offset.left - window_width / 2, target_offset.top - window_height / 2);
}
</script>
<div id="hidden_timepicker" class="hide">
<span id="hidden_title" class="pull-left" style="margin-right: 1em;font-weight: bold;"></span>
<div style="display: grid;">
<span id="hidden_date" class="pull-left" style="margin-right: 1em;"></span>
<%= fields_for :timepicker do |f|%>
<%= f.time_picker :timepicker, :no_label => true, :new_record => hire.new_record?,:format=>"HH:mm", :class => "pull-left", :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<% end %>
<div class="pull-left btn-group" style="margin-top: 0.5em;">
<button id="confirm_date" class="btn btn-primary btn-sm" style="margin-right: 0.5em;" onclick="set_datetimepicker()"><%=t("property_hire.confirm")%></button>
<button id="cancel_date" class="btn btn-primary btn-sm" onclick="goto_calendar()"><%=t("property_hire.cancel")%></button>
</div>
</div>
<div style="clear: both;"></div>
<hr>
</div>
<%= form_for hire, :url => "/xhr/property_hires/make_booking", html: { class: "form-horizontal" } do |f| %>
<div class="form-group">
<%= f.label :start_time, "*"+t("property_hire.start_time"), :class => "col-sm-2 control-label" %>
<div class="col-sm-10">
<%= f.datetime_picker :start_time, :no_label => true, :new_record => hire.new_record?,:class => "pull-left", :data=>{"picker-type" => "range", "range" => "start", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<button type="button" id="pick_start_date" onclick="change_pick(this)" class="btn btn-primary btn-sm pull-left" style="margin-left: 1em;"><%=t("property_hire.pick_from_calendar")%></button>
</div>
</div>
<div class="form-group">
<%= f.label :end_time, "*"+t("property_hire.end_time"), :class => "col-sm-2 control-label" %>
<div class="col-sm-10">
<%= f.datetime_picker :end_time, :no_label => true, :new_record => hire.new_record?,:class => "pull-left", :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<button type="button" id="pick_end_date" onclick="change_pick(this)" class="btn btn-primary btn-sm pull-left" style="margin-left: 1em;"><%=t("property_hire.pick_from_calendar")%></button>
</div>
</div>
<!-- ############# recurring ############# -->
<div class="form-group">
<%= f.label :recurring, t("property_hire.recurring"), :class => "col-sm-2 control-label" %>
<div class="col-sm-1">
<%= f.check_box :recurring %>
</div>
</div>
<div id="recurring-block" <%= hire.recurring ? "" : "style=display:none;" %>>
<div class="form-group">
<%= f.label :recurring_interval, t("property_hire.recurring_interval"), :class => "col-sm-2 control-label" %>
<div class="col-sm-1">
<%= f.select :recurring_interval, PHire::INTERVALS.collect{|int| [t("property_hire.recurring_interval_types.#{int}"), int] }, {:prompt => t('property_hire.select_interval')}, {:data => {"fv-validation" => "requiredifrecurring;" , "fv-messages" => "Cannot be empty;"}} %>
</div>
</div>
<div class="form-group">
<%= f.label :recurring_end_date, "*"+t("property_hire.recurring_end_date"), :class => "col-sm-2 control-label" %>
<div class="col-sm-10">
<%= f.datetime_picker :recurring_end_date, :no_label => true, :new_record => hire.new_record?, :class=>"pull-left", :data=>{"fv-validation" => "requiredifrecurring;", "fv-messages" => "Cannot be empty;"} %>
<button type="button" id="pick_recurring_end_date" onclick="change_pick(this)" class="btn btn-primary btn-sm pull-left" style="margin-left: 1em;"><%=t("property_hire.pick_from_calendar")%></button>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-5">
<div id="property-avaialable-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-success" role="alert"><b>Hooray! </b>This property is available.</div>
<div id="property-unavaialable-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-danger" role="alert"><b>Sorry! </b><span> This property is available.</span></div>
<div id="values-alert" style="margin-bottom: 5px; padding: 10px; display: none;" class="alert alert-warning" role="alert">
<% hint1 = t("property_hire.please_select_recurring_interval_and_recurring_end_time",:default=>"") %>
<% if hint1 == ""%>
<b>Please! </b><span> Select an interval time and recurring event end date.</span>
<% else %>
<span><b><%=hint1%></b></span>
<% end %>
</div>
</div>
<% if property.set_unavailibility %>
<div class="col-sm-offset-2 col-sm-5">
<b><%= t("property_hire.Unavailibility_Schedule") %></b>
<div>
<%= property.render_unavailable_message%>
</div>
</div>
<% end %>
</div>
<div class="form-group">
<label for="" class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<a href="/xhr/property_hires/check_availability" id="check-avail-btn" class="btn btn-primary"><%= t('property_hire.check_availibility') %></a>
<img style="display: none;" width="40" src="/assets/spin.gif" id="spinner" />
</div>
</div>
<div class="form-group">
<%= f.label :hiring_person_email, "*"+t("property_hire.hiring_person_email"), :class => "col-sm-2 control-label" %>
<div class="col-sm-5">
<%= f.text_field :hiring_person_email, :class => "form-control", :value => current_user.member_profile.email, :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
</div>
</div>
<div class="form-group">
<%= f.label :hiring_person_number, "*"+t("property_hire.hiring_person_number"), :class => "col-sm-2 control-label" %>
<div class="col-sm-5">
<%= f.text_field :hiring_person_number, :class => "form-control", :value => current_user.member_profile.mobile_no, :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
</div>
</div>
<div class="form-group">
<%= f.label :hiring_person_name, "*"+t("property_hire.hiring_person_name"), :class => "col-sm-2 control-label" %>
<div class="col-sm-5">
<%= f.text_field :hiring_person_name, :class => "form-control", :value => (current_user.name rescue ""), :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<%= f.hidden_field :hiring_person_id, :value => (current_user.member_profile.id.to_s rescue "") %>
</div>
</div>
<div class="form-group">
<%= f.label :reason_for_hire, "*"+t("property_hire.reason_for_hire"), :class => "col-sm-2 control-label" %>
<div class="col-sm-5">
<%= f.text_field :reason_for_hire, :class => "form-control", :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
</div>
</div>
<% if(property.enable_notes_selector rescue false) %>
<% property.notes_selector.each do |index,sub_hash| %>
<% name = sub_hash["name"][I18n.locale.to_s] %>
<% name = sub_hash["name"].values.select{|v| v.present?}.first.to_s if name.blank? %>
<% values = sub_hash["value"][I18n.locale.to_s] %>
<% values = sub_hash["value"].values.select{|v| v.present?}.first.to_s if values.blank? %>
<% type = sub_hash["type"] %>
<div class="form-group">
<%= f.label "notes_selector[#{index}]", name, :class => "col-sm-2 control-label" %>
<div class="col-sm-5">
<% values.each_with_index do |v,i| %>
<label class="checkbox-inline">
<input type="<%=type%>" name="p_hire[notes_selector][<%=index.to_s%>][]" value="<%=i%>" <%= (type=="radio" && i == 0) ? "checked=\"checked\"" : "" %>>
<%=v%>
</label>
<% end %>
<% if type == "checkbox" && (values.count > 1) %>
<small class="help-block"><%= t("property_hire.checkbox_hint") %></small>
<% end %>
</div>
</div>
<% end %>
<% else %>
<div class="form-group">
<%= f.label :note_for_hire, t("property_hire.note_for_hire"), :class => "col-sm-2 control-label" %>
<div class="col-sm-5">
<%= f.text_area :note_for_hire, :class => "form-control" %>
</div>
</div>
<% end %>
<% fields_name = ["organization" ,"person_in_charge" , "tel_of_person_in_charge" , "department" , "contact_person" , "tel_of_contact_person" , "mobile_phone_of_contact_person" , "contact_person_Email" , "contact_person_department"] %>
<% fields_name.each do |field_name| %>
<% if(property[field_name]["enable"] == "1" rescue false) %>
<% required = (property[field_name]["required"] == "true" rescue false) %>
<div class="form-group">
<%= f.label field_name, (required ? "*" : "") + property.custom_text(field_name,"name"), :class => "col-sm-2 control-label" %>
<div class="col-sm-5">
<% placeholder = property.custom_text(field_name,"placeholder") %>
<% if required %>
<%= f.text_field field_name, :class => "form-control", :placeholder => placeholder, :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %>
<% else %>
<%= f.text_field field_name, :class => "form-control", :placeholder => placeholder %>
<% end %>
</div>
</div>
<% end %>
<% end %>
<% if property.p_hire_fields_enabled.count != 0 %>
<% p_hire = PHire.new(:id=>nil) %>
<% @form_index = 0 %>
<% property.p_hire_fields_enabled.asc(:_id).each do |rf| %>
<div class="form-group">
<%= rf.block_helper(property,@form_index,false,"p_hire",p_hire, rf.to_require) %>
</div>
<% @form_index = @form_index +1 %>
<% end %>
<% end %>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<%= f.submit t("property_hire.save"), :class => "btn btn-primary" %>
<%= f.hidden_field :property_id, :value => property.id %>
<input type="hidden" name="url" value="<%= url %>" />
<input type="hidden" id="dates_validated" name="dates_validated" value="0" data-fv-validation="checkForDates;" data-fv-messages="Please make sure first if dates are available.;">
</div>
</div>
<% end %>
<div style="height: 50px;"></div>
<script type="text/javascript">
var property_id = "<%= property.id.to_s %>";
var check_available = function(stime,etime,interval,recurring_end_date,check_only,property_id){
var el = $("#check-avail-btn"),
url = $("#check-avail-btn").attr("href"),
spinner = $("#spinner");
stime = stime || etime;
etime = etime || stime;
property_id = property_id || window.property_id;
var timezone = new Date().toString().match(/([-\+][0-9]+)\s/)[1];
data = {
"stime": stime,
"etime": etime,
"property_id": property_id,
"locale": "<%=I18n.locale%>",
"timezone": timezone
}
data["interval"] = interval;
data["recurring_end_date"] = recurring_end_date;
var flag = false;
window.check_message = "";
$.ajax({
"url" : url,
"type" : "get",
"data" : data,
"dataType" : "json",
"async": false
}).done(function(data){
if(data.success){
$("#dates_validated").val("1");
$("#property-unavaialable-alert").hide();
flag = true;
if(!check_only){
$("#property-avaialable-alert").show();
}
}else{
$("#dates_validated").val("0");
$("#property-avaialable-alert").hide();
window.check_message = data.msg;
window.check_message = window.check_message.replace(/{(.*)}/,function(v){
return getDateString(new Date(RegExp.$1),datetime_format,is_chinese);
})
if(!check_only){
$("#property-unavaialable-alert").find("span").html(window.check_message);
$("#property-unavaialable-alert").show();
}
}
spinner.hide();
el.show();
})
return flag;
}
$("#check-avail-btn").on("click",function(){
var el = $(this),
url = $(this).attr("href"),
spinner = $("#spinner");
$(".alert").hide();
var stime = $("#p_hire_start_time").val(),
etime = $("#p_hire_end_time").val();
var interval = null, recurring_end_date = null, is_recurring = false;;
if($("#p_hire_recurring").is(":checked")){
is_recurring = true;
interval = $("#p_hire_recurring_interval").val(),
recurring_end_date = $("#p_hire_recurring_end_date").val();
if(interval == "" || recurring_end_date == ""){
$("#values-alert").show();
return false;
}
}
spinner.show();
el.hide();
check_available(stime,etime,interval,recurring_end_date);
return false;
})
$("#unavailable-schedule").on("click",function(){
})
var hireForm = new FormValidator($("#new_p_hire"));
hireForm.validate_functions.checkForDates = function(value,element){
return value == "1";
}
hireForm.validate_functions.requiredifrecurring = function(value, element){
if($("#p_hire_recurring").is(":checked")){
return value != "";
}else{
return true;
}
}
$("#p_hire_recurring").on("click",function(){
$("#dates_validated").val("0");
$("#property-avaialable-alert").hide();
$("#property-unavaialable-alert").hide();
if($(this).is(":checked")){
$("#recurring-block").slideDown();
}else{
$("#recurring-block").slideUp();
}
})
</script>
<% end %>

View File

@ -0,0 +1,9 @@
<%
data = action_data
back_url = data["back_url"]
back_button_text = data["back_button_text"]
%>
<h4><%=t("property_hire.the_reservation_was_successfully_sent")%></h4>
<div>
<a href="<%=back_url%>" class="btn btn-warning"><%=back_button_text%></a>
</div>

View File

@ -1 +1,11 @@
<% OrbitHelper.render_css_in_head(["property_hire_fullcalendar.css","property_hire_calendar"]) %>
<script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script>
<script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script>
<script type="text/javascript" src="/assets/locale-all.min.js"></script>
<% data = action_data %>
<% if data["manage_booking_btn"] %>
<div class="pull-right">
<a href="<%= data["manage_booking_url"] %>" class="btn btn-primary" target="_blank"><%= data["manage_booking"] %>
</div>
<% end %>
<%= render_view %>

View File

@ -1,5 +1,5 @@
<% OrbitHelper.render_css_in_head(["property_hire_fullcalendar.css","property_hire_calendar.scss"]) %>
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<% OrbitHelper.render_css_in_head(["property_hire_fullcalendar.css","property_hire_calendar"]) %>
<script src="https://polyfill.io/v3/polyfill.min.js?features=Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.en,Intl.NumberFormat.~locale.en"></script>
<script type="text/javascript" src="/assets/property_hire_fullcalendar.min.js"></script>
<script type="text/javascript" src="/assets/property_hire_calendar_frontend.js"></script>
<%
@ -7,7 +7,7 @@
property = data["property"]
url = data["url"]
%>
<% if !property.can_be_hired %>
<% if property.disable_view_calendar_page %>
<script type="text/javascript">
alert("This property is unavailable for hire.");
window.location.href = "<%= "/" + I18n.locale.to_s + url %>";
@ -25,7 +25,7 @@
<button class="btn btn-default btn-sm" id="next_month_btn">
<i class="icon-chevron-right"></i>
</button>
<button class="btn btn-default btn-sm" id="today_btn">Today</button>
<button class="btn btn-default btn-sm" id="today_btn"><%= t("property_hire.today") %></button>
</div>
</div>
</div>
@ -33,9 +33,9 @@
</div>
<div id='sec3' class="btn-toolbar">
<div class="btn-group calendar_mode">
<button class="btn btn-default mode_switch btn-sm" data-mode="agendaDay" >day</button>
<button class="btn btn-default mode_switch btn-sm" data-mode="agendaWeek" >week</button>
<button class="btn btn-default active mode_switch btn-sm" data-mode="month" >month</button>
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridDay" ><%= t("property_hire.day") %></button>
<button class="btn btn-default mode_switch btn-sm" data-mode="timeGridWeek" ><%= t("property_hire.week") %></button>
<button class="btn btn-default active mode_switch btn-sm" data-mode="dayGridMonth" ><%= t("property_hire.month") %></button>
</div>
<button id="refresh_btn" class="btn btn-default btn-sm">
<i class="icons-cycle"></i>
@ -52,5 +52,5 @@
<a href="<%= "/" + I18n.locale.to_s + url %>" class="btn btn-warning">Back</a>
<script type="text/javascript">
var property_id = "<%= property.id.to_s %>";
var calendar = new Calendar("#calendar",property_id);
var calendar = new Calendar("#calendar",property_id,false);
</script>

View File

@ -0,0 +1,72 @@
<% site = Site.first%>
<div id="address-field" class="modal hide fade">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3><%= (field_name rescue nil) || t("address_modal.default_title") %></h3>
</div>
<div class="modal-body form-horizontal address-modal">
<div class="tabbable">
<ul class="nav nav-tabs">
<% site.valid_locales.each do |locale|%>
<% active = (locale == I18n.locale.to_s ? ["active"] : [] ) %>
<%= content_tag :li,:class=>active,:for=>locale do%>
<%= link_to t(locale).to_s,".#{btn_class}.address_modal.#{locale}",:data=>{:toggle=>"tab"}%>
<% end %>
<% end %>
</ul>
<div class="tab-content">
<% site.valid_locales.each do |locale|%>
<!-- start of lang tab context -->
<% active = (locale == I18n.locale.to_s ? "active" : "" ) %>
<div class="tab-pane fade <%= active %> in %>" for="<%= locale %>">
<div class="control-group">
<label class="control-label muted" for="street_address"><%= t("address_modal.street_address") %></label>
<div class="controls">
<%= text_area_tag("#{field_name_basic}[temp][address_ext][#{locale}][street_address]",nil,:rows=>3,:func=>'street_address', :class=>"input-xlarge") %>
</div>
</div>
<div class="control-group">
<label class="control-label muted" for="city"><%= t("address_modal.city") %></label>
<div class="controls">
<%= text_field_tag("#{field_name_basic}[temp][address_ext][#{locale}][city]",'',:func=>'city', :class=>"input-xlarge") %>
</div>
</div>
<div class="control-group">
<label class="control-label muted" for="counties"><%= t("address_modal.county") %></label>
<div class="controls">
<%= text_field_tag("#{field_name_basic}[temp][address_ext][#{locale}][county]",'',:func=>'county', :class=>"input-xlarge") %>
</div>
</div>
<div class="control-group">
<label class="control-label muted" for="zip"><%= t("address_modal.zip") %></label>
<div class="controls">
<%= text_field_tag("#{field_name_basic}[temp][address_ext][#{locale}][zip]",nil,:class=>"input-mini",:func=>'zip', :class=>"input-xlarge") %>
</div>
</div>
<div class="control-group">
<label class="control-label muted" for="country"><%= t("address_modal.country") %></label>
<div class="controls">
<%= text_field_tag("#{field_name_basic}[temp][address_ext][#{locale}][country]",'',:func=>'country', :class=>"input-xlarge") %>
</div>
</div>
<div class="control-group hide">
<label class="control-label muted" for="indicator"><%= t("address_modal.Indicator") %></label>
<div class="controls">
<%= text_field_tag("#{field_name_basic}[temp][address_ext][#{locale}][indicator]",'',:func=>'country', :class=>"input-xlarge") %>
</div>
</div>
</div>
<!-- end of tab context -->
<% end %>
</div>
</div>
</div>
<div class="modal-footer">
<a class="btn" data-dismiss="modal" aria-hidden="true"><%=t(:close)%></a>
<a class="btn btn-primary returnDecide" data-dismiss="modal" aria-hidden="true"><%=t(:save_and_close)%></a>
</div>
</div>

View File

@ -0,0 +1,2 @@
<% @field_name = 'info' %>
<%= render :partial=>'admin/roles/attribute_field.html.erb',:locals => {attribute_field: attribute_field,attribute_field_counter: attribute_field_counter} %>

View File

@ -0,0 +1,25 @@
<% values ||=[]%>
<%= content_tag :div,:class=>"control-group" do%>
<label class="control-label muted" for=""><%= (defined? label_ext) ? label_ext : t("lists.markups.hint_text") %></label>
<div class="controls">
<div class="input-append">
<div class="tab-content">
<% @site_in_use_locales.each do |locale| %>
<% active = (locale == @site_in_use_locales.first ? "active in" : "'") %>
<%= content_tag :div,:class=>"tab-pane fade #{active}",:id=>"#{name_to_id(field_name)}_#{locale}" do%>
<% locale_value = values[locale.to_s] rescue nil%>
<%= text_area(field_name, locale,:value=>locale_value,:placeholder=> "#{t(locale).to_s}",:data=>{:type=>"lang_#{locale}"}) %>
<% end %>
<% end %>
</div>
<div class="btn-group" data-toggle="buttons-radio">
<% @site_in_use_locales.each do |locale| %>
<% active = (locale == @site_in_use_locales.first ? "active" : "") %>
<%= link_to t(locale).to_s,"##{name_to_id(field_name)}_#{locale}",:class=>"btn #{active}",:data=>{:toggle=>"tab"}%>
<% end %>
</div>
</div>
</div>
<% end %>

View File

@ -0,0 +1,62 @@
<% temp_field_name = field_name.gsub /\[\D*\]$/,'[temp]'%>
<% flag = (field_name.split(/\[.*\](?=\[)/)[-1][1...-1] != 'member_relations') %>
<div class="control-group" style="<%= 'display: flex;' if !flag %>">
<% if flag %>
<%= hidden_field_tag "#{temp_field_name}[count]",((values.keys.collect{|t| t.to_i}.max rescue nil) || 0 ),:class=>"list_count"%>
<%= hidden_field_tag "#{temp_field_name}[name]",field_name,:class=>"field_name"%>
<label class="control-label muted" for=""><%= t(:options)%></label>
<% else %>
<div>
<label class="control-label muted"><%= t('list.mode')%></label>
<div class="member_related">
<br>
<label class="control-label muted"><%= t('list.related')%></label>
</div>
</div>
<% end %>
<div class="controls add-input" style="<%= 'margin-left: 1em;' if !flag %>">
<div class="add-target single">
<% if flag %>
<%if values.blank? %>
<%= content_tag :div,:class=>"input-append" do%>
<% @site_in_use_locales.each do |locale| %>
<% last = (locale == @site_in_use_locales.last ? true : false) %>
<% p_value = value[locale.to_s] rescue nil%>
<%= text_field("#{field_name}[0]", locale,:placeholder=>t(locale).to_s,:class=>"input-medium",:data=>{:type=>"option_lang_0_#{locale}"}) %>
<% if last %>
<a href="#" class="btn remove-input"> <i class="icon-trash"></i> </a>
<% end %>
<% end %>
<% end %>
<%else%>
<%values.each do |index,value|%>
<%= content_tag :div,:class=>"input-append" do%>
<% @site_in_use_locales.each do |locale| %>
<% last = (locale == @site_in_use_locales.last ? true : false) %>
<% p_value = value[locale.to_s] rescue nil%>
<%= text_field("#{field_name}[#{index}]", locale,:value=>p_value,:placeholder=>t(locale).to_s,:class=>"input-medium", :data=>{:type=>"option_lang_#{index}_#{locale}"}) %>
<% if last %>
<a href="#" class="btn remove-input"> <i class="icon-trash"></i> </a>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<% else %>
<%= content_tag :div,:class=>"input-append" do %>
<%= (hidden_field_tag "#{field_name}[0][_id]",values[0].id.to_s) if !values.blank? %>
<%= select_tag "#{field_name}[0][mode]", options_for_select([[t('list.passive'),'passive'],[t('list.active'),'active']],:selected => (values[0]['mode'] rescue nil)),:onChange => 'hidden_option(this)',:class=>'member_relations_opt' %>
<% relates = values.blank? ? [nil] : values[0]['related'] %>
<% relates = [nil] if relates.nil? %>
<div class="member_related">
<% Array(relates).each do |related|%>
<%= select_tag "#{field_name}[0][related][]", options_for_select(Role.all.desc(:created_at).map{|v1| [v1.title,v1.attribute_fields.sort_by{|v| v.key.to_i}.select{|v| v.id.to_s != id}.map{|v| ["&nbsp;&nbsp;#{v.title}".html_safe,v.id]}]}.flatten(2),:disabled=>Role.all.map{|v| v.title},:selected=> related), :class => 'member-relations-related' %>
<% end %>
</div>
<% end %>
<% end %>
</div>
<p class="add-btn"> <a href="#" class="member-relations-add trigger btn btn-mini btn-primary"><i class="icons-plus"></i> <%= t(:add) %></a> </p>
</div>
</div>

View File

@ -0,0 +1,25 @@
<% privacy_settings = ["public","logged_in","locked","only_admin"]%>
<% privacy_settings.each do |privacy_setting|%>
<% case privacy_setting
when "public"
icon = "icons-earth"
when "logged_in"
icon = "icons-users"
when "locked"
icon = "icons-lock"
when "only_admin"
icon = "fa fa-user-secret"
end
%>
<%= radio_button(field_key, "privacy_default", privacy_setting,:checked => (((attribute_field.privacy_default == privacy_setting) rescue false) ? true : false), :data=>{:type=>"radio"}) %><div class="<%=icon%>"></div><%= t("privacy_type.#{privacy_setting}").html_safe %>
<% end %>
<span style="margin-left: 2em;display: inline-flex;">
<label style="margin: 0;font-size: 1em;display: inline-flex;">
<%= hidden_field(field_key, "privacy_default_apply", :value=> "0") %>
<%= check_box_tag("#{field_key}[privacy_default_apply]","1",attribute_field["privacy_default_apply"]) %>
<%= t('apply_to_current_members.content') %>
</label>
<span style="margin-left: 3em;color: #E91E63;">
<%= t('apply_to_current_members.warning') %>
</span>
</span>

36
config/list.yml Normal file
View File

@ -0,0 +1,36 @@
forbidden_item_names:
- admin
- panel
- appfront
#NO_MULTI_TAG = ["select","date","radio_button","checkbox","date_durnation"]
markups:
text_field:
muti_lang_input_supprt: true
ext_support: true
panel: typeA
select:
muti_lang_input_supprt: false
ext_support: false
panel: typeB
date:
muti_lang_input_supprt: false
ext_support: false
panel: typeC
text_area:
muti_lang_input_supprt: true
ext_support: false
panel: typeD
radio_button:
muti_lang_input_supprt: false
ext_support: false
panel: typeE
checkbox:
muti_lang_input_supprt: false
ext_support: false
panel: typeE
hint_text:
muti_lang_input_supprt: false
ext_support: false
panel: typeF

View File

@ -1,5 +1,110 @@
en:
lists:
markups:
hint_text: Hint Text
restful_actions:
copy: Copy
fields_display_order: "Fields display order"
property_hire:
copy: Copy
unfilled: Unfilled
hire_time: Reservation time
back_to_hire_page: "Back to Reserve Page"
apply_default_time_settings: Apply default time settings
default_time_settings: Default time settings
the_reservation_was_successfully_sent: "The reservation was successfully sent!Please see email to get more information"
go_to_infos_page: Go to infos page
display_in_reason_for_hire: "Display in reason for hire"
need_hire_before: "How late does the user need to reserve?"
_month: Month
_week: Week
_day: Day
_hour: Hour
_minute: Minute
sort_number: Sort Number
enable_fields_sort: Enable fields sort
fields_display_order: "Fields display order"
this_property_is_available: "<b>Hooray! </b>This property is available."
recaptcha:
recaptcha: Recaptcha
errors:
verification_failed: Verification Failed
no_time_can_select: "No time can be selected!"
custom_calendar_type:
default: Default
display: Display
not_display: Not display
page_setting: Page Setting
display_calendar_default: "Display calendar in reserved page?(default)"
display_calendar: "Display calendar in reservation page?"
allow_no_logins_user: "Allow no logins user to reserve property."
please_select_time: "Please select Time!"
date: "Date"
time: "Time"
please_choose_date: "Please choose date"
please_select: "Please select"
reserve: Reserve
files_links: "Files, Links"
disable_content_page: Disable content page
disable_view_calendar_page: 'Disable "Calendar" page'
disable_no_logins_view_calendar: 'Disable Calendar page for no logins user'
display_img: Display Cover Image in Content Page
carousel_image: Carousel Image
carousel_image_title: Carousel Image(display at the bottom of show page)
custom_carousel_image_width_hint: "If blank, width will be default value."
carousel_image_width: Carousel Image Width
default_carousel_image_width: Default Carousel Image Width
cover_image_display_setting: Cover Image display setting
full_width: Full width
up_left_corner: Up-left corner
up_right_corner: Up-right corner
name: Show Name
placeholder: Placeholder
disable: Disable
time_title: Title
reservation_limit: "Reservation limit(0 present no limit)"
set_availability: Set Availability
reservation_fields: Reservation Fields
to_require: Should Be Filled?
please_save: 'Please click "Save Order" button when you done.'
position: Position
save_order: Save Order
order: Order
custom_fields_setting: Custom fields Setting
custom_fields: Custom fields
please_hire_after_date: "Please reserve after %{date}!"
property_is_unavailable_during_this_time: "Property is unavailable during this time."
property_is_already_hired_during_this_time: "Property is already reserved during this time."
starting_time_cannot_be_greater_than_ending_time: "Starting time cannot be greater than ending time."
please_select_recurring_interval: "Please select recurring interval!"
confirm: Confirm
cancel: Cancel
pick_from_calendar: Pick from calendar
how_many_months_ago_can_be_hired: "Unavailable for reservation before how many months?"
month: "%{month} month"
no_limit: No limit
none: None
checkbox_hint: You Can Select Mulitple Places
add_choice: Add choice
radio: Radio
checkbox: Checkbox
field_name: Field name
field_value: Field choices
field_type: Field type
notes_selector: Note field selector
enable_notes_selector: Enable Note field selector
editor: Editor
email_p_hire_success: Reserve Success
email_edit_success: 'Property Hire Module:Edit Success'
email_delete_success: 'Property Hire Module:Delete Success'
email_p_hire_content: Reserve Success
email_edit_content: 'Property Hire Module:Edit Success'
email_delete_content: 'Property Hire Module:Delete Success'
edit: Edit
delete: Delete
auto_send_email_set: Auto Send Email Setting
email_title: Email Title
email_content: Email Content
recurring: Recurring
recurring_interval: Recurring Interval
recurring_interval_types:
@ -7,7 +112,7 @@ en:
week: Week
recurring_end_date: Recurring End Date
save: Save
property_hire: Property
property_hire: Reservation
my_bookings: My Bookings
settings: Settings
auto_approve: Auto approve
@ -17,33 +122,42 @@ en:
edit_location: Edit Location
add_location: Add Location
unavailability: Unavailability
unavailable_time: Unavailability
available_time: Time Period
title: Property Title
property_usage: Usage for property
property_usage: Subtitle
note: Note
property_number: Property Number
can_be_hired: Available for hire
can_be_hired: Available for reservation
purchase_date: Purchase Date
owners: Owners
other_owner: Other Owner
owner_email: Owner Email
owner_email_rule: Owner Email Rule
owner_phone: Owner Phone
price: Price
set_unavailibility: Set Unavailability
limit_start_time: Limit start time
limit_end_time: Limit end time
p_hire_start_time: Start Date
p_hire_end_time: End Date
p_open_start_time: Open Date
p_open_end_time: Close Date
start_time: Start Time
end_time: End Time
weekdays: Weekdays
weekdays: Unavailable days in a week
start_date: From Date
end_date: To Date
description: Unavailability Description
unavailibility_note: Unavailability Note
property_location: Property Location
available_for_hire: Available for hire
hire: Hire
available_for_hire: Available for reservation
hire: Reserve
view_calendar: Calendar
image: Property Image
actions: Actions
start_time: Hire Start Time
end_time: Hire End Time
start_time: Reserve Start Time
end_time: Reserve End Time
hiring_person_email: Hiring Person Email
hiring_person_number: Hiring Person Number
hiring_person_name: Hiring Person
@ -51,3 +165,45 @@ en:
note_for_hire: Note For Hire
period: Period
passed: Accepted
'yes': 'Yes'
'no': 'No'
wait_for_permit: 'Wait for permit'
select_interval: Select interval
check_availibility: Check Availibility
Unavailibility_Schedule: Unavailibility Schedule
required: Required
organization: Organization
person_in_charge: Person in charge
tel_of_person_in_charge: Tel. of person in charge
department: Department
contact_person: Contact person
tel_of_contact_person: Tel. of contact person
mobile_phone_of_contact_person: Mobile phone of contact person
contact_person_Email: Contact person Email
contact_person_department: Contact person department
special_unavailable_date: Special Unavailable Date
manage_booking: Manage Bookings
recurring_enable: Enable Recurring
owner_email_rules:
'0': 'Only Owners'
'1': 'Only Owner Email'
'2': 'Owners and Owner Email'
p_display_start_time: Display in front-page
p_display_end_time: Remove from front-page
hours_restriction: Limit reservation hours for single user
hours_restriction_message: "This property can only be hired for %{no_of_hours} hours every %{duration}"
time_period_note: Time period user can use reservation service
available_time_note: Available time period
calendar: Calendar
table: Table
view: View
reject: Reject
edit: Edit
delete: Delete
accept: Accept
today: Today
day: Day
week: Week
month: Month
all_properties: All Properties
export_reservation_data: Export data

View File

@ -1,53 +1,231 @@
zh_tw:
lists:
markups:
hint_text: 提示文字
restful_actions:
copy: 複製
fields_display_order: "欄位顯示順序"
property_hire:
recurring: Recurring
recurring_interval: Recurring Interval
copy: 複製
unfilled: 未填寫
hire_time: 預約時間
back_to_hire_page: "回到預約頁面"
apply_default_time_settings: 套用預設時段設定
default_time_settings: 預設時段設定
the_reservation_was_successfully_sent: "預約成功送出請查看Email確認預約資訊!"
go_to_infos_page: 前往資訊頁面
display_in_reason_for_hire: "顯示於使用用途"
need_hire_before: "需提早多久預約"
_month: 個月
_week:
_day:
_hour: 個小時
_minute: 分鐘
sort_number: 排序數
enable_fields_sort: 啟用欄位排序
fields_display_order: "欄位顯示順序"
this_property_is_available: "<b>可預約</b>"
recaptcha:
recaptcha: 驗證碼
errors:
verification_failed: 驗證碼錯誤
no_time_can_select: "無時段可選擇!"
custom_calendar_type:
default: 預設
display: 顯示
not_display: 不顯示
page_setting: 頁面設定
display_calendar_default: "是否顯示行事曆在租借頁面(預設值)"
display_calendar: "是否顯示行事曆在租借頁面"
allow_no_logins_user: "允許未登入使用者預約"
please_select_time: "請選擇時段!"
date: "日期"
time: "時段"
please_choose_date: "請選擇日期"
please_select: "請選擇"
reserve: 預約本日
files_links: "檔案與連結"
disable_content_page: 關閉內容頁
disable_view_calendar_page: '關閉"查詢目前預約狀況"頁面'
disable_no_logins_view_calendar: '關閉未登入使用者"查詢目前預約狀況"頁面'
display_img: 內容頁顯示封面圖片
carousel_image: 輪播圖片
carousel_image_title: 輪播圖片(在show頁面底部顯示)
custom_carousel_image_width_hint: "未填寫,則使用預設寬度"
carousel_image_width: 輪播圖片寬度
default_carousel_image_width: 預設輪播圖片寬度
cover_image_display_setting: 封面圖片顯示設定
full_width: 滿版呈現
up_left_corner: 左上角
up_right_corner: 右上角
name: 顯示名稱
placeholder: 提示文字
disable: 關閉
time_title: 時段名稱
reservation_limit: "預約數限制(0代表無限制)"
set_availability: 設定開放時段
reservation_fields: 預約欄位設定
to_require: 是否必填
please_save: '調整完後, 請點選"儲存順序"'
position: 位置
save_order: 儲存順序
order: 排序
custom_fields_setting: 客製化欄位設定
custom_fields: 客製預約欄位
recurring_end_date_must_exceed_time: "週期結束時間需超過預約結束時間%{time}!"
1_week: "一週"
1_month: "一個月"
values_are_not_ok: "預約開始時間和結束時間不可為空"
dot: " 、 "
from: " 從 "
to: " 到 "
of: "的"
at: "在"
from_time: "從%{time}開始"
from_now_on: "從現在起"
every: 每個
time1_to_time2: "%{time1}到%{time2}之間"
unavailable_hint1: "此地點或設備%{str1}%{str2}%{week_str}%{str3}為不可預約。"
unavailable_hint2: "此地點或設備在%{month}個月之前不可預約。"
unavailable_hint3: "此地點或設備須提前%{month}%{unit}預約。"
Sunday: 週日
Monday: 週一
Tuesday: 週二
Wednesday: 週三
Thursday: 週四
Friday: 週五
Saturday: 週六
please_hire_after_date: "請在%{date}之後再預約!"
property_is_unavailable_during_this_time: "該時段不可預約。"
property_is_already_hired_during_this_time: "該時段已被預約,請再選擇其他時段!"
starting_time_cannot_be_greater_than_ending_time: "預約開始時間不能超過預約結束時間!"
please_select_recurring_interval: "請選擇預約週期!"
please_select_recurring_interval_and_recurring_end_time: "請選擇預約週期和週期結束時間"
confirm: 確認
cancel: 取消
pick_from_calendar: 從日曆上選擇
how_many_months_ago_can_be_hired: 多少個月前不開放預約
month: "%{month}月"
no_limit: 無限制
none:
checkbox_hint: 可重複勾選
add_choice: 新增選項
radio: 單選
checkbox: 多選
field_name: 欄位名稱
field_value: 欄位選項
field_type: 欄位類型
notes_selector: 備註選項
enable_notes_selector: 啟用備註選項
editor: 編輯者
email_p_hire_success: 預約成功
email_edit_success: '租借模組:編輯成功'
email_delete_success: '租借模組:刪除成功'
email_p_hire_content: 預約成功
email_edit_content: '租借模組:編輯成功'
email_delete_content: '租借模組:刪除成功'
edit: 編輯
delete: 刪除
auto_send_email_set: 自動發信設定
email_title: 主旨
email_content: 內文
recurring: 週期性預約
recurring_interval: 預約週期
recurring_interval_types:
month: Month
week: Week
recurring_end_date: Recurring End Date
save: Save
my_bookings: My Bookings
settings: Settings
property_hire: Property
manage_locations: Manage Locations
location: Location
month:
week:
recurring_end_date: 週期結束時間
save: 送出
my_bookings: 我的預約記錄
settings: 設定
property_hire: 預約
manage_locations: 管理位置
location: 位置
auto_approve: Auto approve
property_count: Property Count
edit_location: Edit Location
add_location: Add Location
unavailability: Unavailability
title: Property Title
property_usage: Usage for property
note: Note
property_number: Property Number
can_be_hired: Available for hire
unavailability: 不可預約
unavailable_time: 不開放時段
available_time: 開放時段
title: 名稱
select_interval: 選擇週期
check_availibility: 檢查是否可預約
property_usage: 副標題
note: 說明
property_number: 編號
can_be_hired: 可供預約
purchase_date: Purchase Date
owners: Owners
other_owner: Other Owner
owner_email: Owner Email
owner_phone: Owner Phone
owners: 管理人
other_owner: 其他管理人
owner_email: 管理人Email
owner_email_rule: 管理人Email規則
owner_phone: 管理人聯絡電話
price: Price
set_unavailibility: Set Unavailability
start_time: Start Time
end_time: End Time
weekdays: Weekdays
start_date: From Date
end_date: To Date
set_unavailibility: 設定不開放時段
weekdays: 每週不開放預約日
start_date: 套用限制開始日期
end_date: 套用限制結束日期
p_hire_start_time: 開始日期
p_hire_end_time: 截止日期
p_open_start_time: 開放日期
p_open_end_time: 結束日期
description: Unavailability Description
unavailibility_note: Unavailability Note
property_location: Property Location
available_for_hire: Available for hire
hire: Hire
view_calendar: Calendar
available_for_hire: 可供預約
hire: 線上預約
view_calendar: 查詢目前預約狀況
image: Property Image
actions: Actions
start_time: Hire Start Time
end_time: Hire End Time
hiring_person_email: Hiring Person Email
hiring_person_number: Hiring Person Number
hiring_person_name: Hiring Person
reason_for_hire: Reason For Hire
note_for_hire: Note For Hire
period: Period
passed: Accepted
actions: 動作
limit_start_time: 限制開始時間
limit_end_time: 限制結束時間
start_time: 預約開始時間
end_time: 預約結束時間
hiring_person_email: 預約人電子信箱
hiring_person_number: 預約人聯絡電話
hiring_person_name: 預約人姓名
reason_for_hire: 使用用途
note_for_hire: 備註
period: 預約時段
passed: 允許預約
'yes':
'no':
wait_for_permit: 等待授權
Unavailibility_Schedule: 不提供預約時段
required: 必填
organization: 預約單位
person_in_charge: 單位負責人
tel_of_person_in_charge: 負責人聯絡電話
department: 服務單位
contact_person: 聯絡人
tel_of_contact_person: 聯絡人聯絡電話
mobile_phone_of_contact_person: 聯絡人行動電話
contact_person_Email: 聯絡Email
contact_person_department: 聯絡人服務單位
special_unavailable_date: 特定不開放預約⽇
manage_booking: 管理我的預約
recurring_enable: 啟用週期性預約
owner_email_rules:
'0': '僅管理人'
'1': '僅管理人Email'
'2': '管理人+管理人Email'
p_display_start_time: 呈現於網頁前台
p_display_end_time: 於網頁前台下架
hours_restriction: 限制單一使用者預約時數
hours_restriction_message: "每 %{duration}限制僅能預約 %{no_of_hours}"
time_period_note: 使用者可以進行預約
available_time_note: 可供預約的日期區間
calendar: 日曆
table: 列表
view: 查看
reject: 拒絕
edit: 編輯
delete: 刪除
accept: 同意
today: 今天
day: 日模式
week: 週模式
month: 月模式
all_properties: All Properties
export_reservation_data: Export data

View File

@ -4,16 +4,26 @@ Rails.application.routes.draw do
scope "(:locale)", locale: Regexp.new(locales.join("|")) do
get "/xhr/property_hires/check_availability" => "property_hires#check_availability"
post "/xhr/property_hires/make_booking" => "property_hires#make_booking"
patch "/xhr/property_hires/make_booking" => "property_hires#make_booking"
get "/xhr/property_hires/get_bookings" => "property_hires#get_bookings"
namespace :admin do
get "property_hires/checkforthread", to: "property_hires#checkforthread"
resources :property_hires do
member do
get 'copy'
get "edit_location"
patch "update_location"
delete "destroy_location"
get "show_booking_details"
get "pass_booking"
delete "delete_booking_details"
get "edit_hire"
patch "update_hire"
get "custom_fields"
get "fields_display_order"
get "export_reservation_data"
post "update_fields_display_order"
patch "update_fields_display_order"
end
collection do
get "my_bookings"
@ -22,6 +32,8 @@ Rails.application.routes.draw do
get "manage_locations"
get "add_location"
post "create_location"
get "order"
post "updateorder"
end
end
end

View File

@ -11,11 +11,29 @@ module PropertyHire
authorizable
frontend_enabled
data_count 1..30
require File.expand_path('../../../app/models/property_hire_setting', __FILE__)
if defined?(PropertyHireSetting)
settings_count = PropertyHireSetting.count
if settings_count == 0
PropertyHireSetting.create
elsif settings_count > 1
PropertyHireSetting.all[1..-1].each{|s| s.destroy}
end
end
if File.basename($0) != 'rake'
begin
avoid_page_cache HireEmailSet
avoid_page_cache PHire
rescue => e
puts ["avoid_page_cache", e.to_s]
end
end
side_bar do
head_label_i18n 'property_hire.property_hire', icon_class: "icons-map"
available_for "users"
active_for_controllers (['admin/property_hires'])
head_link_path "my_bookings_admin_property_hires_path"
head_link_path "admin_property_hires_path"
context_link 'property_hire.my_bookings',
:link_path=>"my_bookings_admin_property_hires_path" ,
@ -28,7 +46,11 @@ module PropertyHire
:priority=>2,
:active_for_action=>{'admin/property_hires'=>"index"},
:available_for => 'sub_managers'
context_link 'property_hire.order',
:link_path=>"order_admin_property_hires_path" ,
:priority=>2,
:active_for_action=>{'admin/property_hires'=>"order"},
:available_for => 'managers'
context_link 'new_',
:link_path=>"new_admin_property_hire_path" ,
:priority=>3,

View File

@ -2,3 +2,26 @@
# task :property_hire do
# # Task goes here
# end
namespace :property_hire_tasks do
task :prepare_download,[:property_id, :url] => :environment do |task,args|
id = args.property_id
I18n.locale = :zh_tw
property = Property.find(id)
ac = ActionController::Base.new()
host_url = Site.first.root_url
if host_url == "http://"
host_url = "http://#{args.url}"
end
xlsx = ac.render_to_string handlers: [:axlsx], formats: [:xlsx], template: "property_hire_export/export", locals: {property: property, site_in_use_locales: Site.first.in_use_locales, url: host_url}
dirname = "public/uploads/reservation_export/#{id}"
FileUtils.mkdir_p(dirname) unless File.exist?(dirname)
f = "#{dirname}/#{property.title.gsub(/[ "'*@#$%^&()+=;:.,?>|\\\/<~_!:,、。!?;「」〈〉【】/]/,'')}.xlsx"
if File.exist?(f)
File.delete(f)
end
file = File.open(f, "w")
xlsx.force_encoding("utf-8")
file.write(xlsx)
end
end

View File

@ -0,0 +1,17 @@
<table class="table table-striped">
<thead>
<tr data-list="headers" data-level="0">
<th>{{column}}</th>
</tr>
</thead>
<tbody data-list="properties" data-level="0">
<tr>
<td><a href="{{url_to_show}}">{{title}}</a></td>
<td>{{location}}</td>
<td data-list="actions" data-level="1">
<a href="{{link}}" class="btn {{btn-class}}">{{text}}</a>
</td>
</tr>
</tbody>
</table>
{{pagination_goes_here}}

View File

@ -0,0 +1,18 @@
<table class="table table-striped">
<thead>
<tr data-list="headers" data-level="0">
<th>{{column}}</th>
</tr>
</thead>
<tbody data-list="properties" data-level="0">
<tr>
<td><a href="{{url_to_show}}">{{title}}</a></td>
<td><img width="150" src="{{image-thumb}}" alt="property image"></td>
<td>{{location}}</td>
<td data-list="actions" data-level="1">
<a href="{{link}}" class="btn {{btn-class}}">{{text}}</a>
</td>
</tr>
</tbody>
</table>
{{pagination_goes_here}}

View File

@ -0,0 +1,14 @@
<div class="property_index_3_col" >
<ul class="property_list" data-level="0" data-list="properties">
<li class="property_item col-md-4 col-xl-3">
<div class="property_img_wrap">
<a href="{{url_to_show}}" title="{{title}}"><img src="{{image-thumb}}" alt="{{title}}"></a>
</div>
<div class="property_content_wrap">
<h4><a href="{{url_to_show}}" title="{{title}}">{{title}}</a></h4>
</div>
</li>
</ul>
</div>
<div class="clearfix"></div>
{{pagination_goes_here}}

View File

@ -0,0 +1,14 @@
<div class="property_index_3_col" >
<ul class="property_list" data-level="0" data-list="properties">
<li class="property_item col-sm-4 col-md-3">
<div class="property_img_wrap">
<a href="{{url_to_show}}" title="{{title}}"><img src="{{image-thumb}}" alt="{{title}}"></a>
</div>
<div class="property_content_wrap">
<h4><a href="{{url_to_show}}" title="{{title}}">{{title}}</a></h4>
</div>
</li>
</ul>
</div>
<div class="clearfix"></div>
{{pagination_goes_here}}

View File

@ -0,0 +1,38 @@
{
"frontend": [
{
"filename" : "index",
"name" : {
"zh_tw" : "1. 列表",
"en" : "1. List"
},
"thumbnail" : "thumb.png"
},
{
"filename" : "index_3_col",
"name" : {
"zh_tw" : "2. 三欄式圖文",
"en" : "2. 3-Column Standard Image + Text Lite"
},
"thumbnail" : "event_news_thumb1.png"
},
{
"filename" : "index_4_col",
"name" : {
"zh_tw" : "3. 四欄式圖文",
"en" : "3. 4-Column Standard Image + Text Lite"
},
"thumbnail" : "event_news_thumb2.png"
}
],
"widgets" : [
{
"filename" : "widget1",
"name" : {
"zh_tw" : "1. 列表",
"en" : "1. List"
},
"thumbnail" : "thumb.png"
}
]
}

View File

@ -0,0 +1,19 @@
<table class="table table-striped">
<thead>
<tr style="text-align: center;">
<td colspan="2"><img width="600" src="{{image}}"></td>
</tr>
</thead>
<tbody data-list="data" data-level="0">
<tr>
<td>{{header}}</td>
<td>{{value}}</td>
</tr>
</tbody>
</table>
<div>
<a href="{{back_url}}" class="btn btn-warning">Back</a>
<span data-list="actions" data-level="0">
<a href="{{link}}" class="btn {{btn-class}}">{{text}}</a>
</span>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -2,7 +2,30 @@ $:.push File.expand_path("../lib", __FILE__)
# Maintain your gem's version:
require "property_hire/version"
begin
require "yaml"
require "erb"
data = File.open(File.join(File.dirname(__FILE__), 'config', 'list.yml')).read
$property_list = YAML.safe_load(ERB.new(data).result(binding)).map{|k,v| [k.to_sym,v]}.to_h
rescue => e
puts [e.to_s,e.backtrace]
end
bundle_update_flag = ARGV[0]=='update' || ARGV[0]=='install'
if bundle_update_flag
app_path = File.expand_path(__dir__)
template_path = ENV['PWD'] + '/app/templates'
all_template = Dir.glob(template_path+'/*/')
puts 'copying module'
all_template.each do |folder|
if folder.split('/')[-1] != 'mobile'
begin
system ('cp -r '+ app_path + '/modules/ ' + folder)
rescue
puts 'error copy'
end
end
end
end
# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
s.name = "property_hire"