diff options
author | Alvin Li <liweitianux@gmail.com> | 2013-10-09 15:52:53 +0800 |
---|---|---|
committer | Alvin Li <liweitianux@gmail.com> | 2013-10-09 15:52:53 +0800 |
commit | 02afd8a32edb13ea7fc2266ac80092ea15c0930c (patch) | |
tree | c7a2a3f50378c017b425da47e04a71c6beaae56c /97suifangqa/apps/recommend/static | |
parent | fafce2cfc72f4e1cd14ff6cb693c8ec7854159c5 (diff) | |
download | 97dev-02afd8a32edb13ea7fc2266ac80092ea15c0930c.tar.bz2 |
* treat 'apps/utils' as regular django app; which used to store
general tools for used in other apps
* moved 'templatetags' from 'apps/indicator' to 'apps/utils'
* '.gitignore' to ignore 'fixtures_bak'
* moved js plugins from 'apps/indicator/static/plugins' to
'staticfiles/plugins'
apps/recommend:
* updated 'recommend.models';
o commented 'recommend.models.ResearchCombination' (not used)
* implemented views 'add_edit_blog_info' and 'ajax_add_edit_configs';
* added pages 'templates/recommend/add_edit_blog_info.html',
'add_edit_blog_info_error.html';
o related css and javascripts files
* added 'tools.py';
* added 'utils/tools.py' for placing generic functions;
* deleted 'initial_data.json' (mv 'fixtures' to 'fixtures_bak');
* small fixes to 'indicator.models', 'sciblog.models' and
'sfaccount.views'
* fixed automatically show 'proper_nouns' annotation in blog:
recovered the line 'import signals' in 'sciblog.models'
* added 'is_ok()' method for 'recommend.models.ResearchConfig';
Diffstat (limited to '97suifangqa/apps/recommend/static')
3 files changed, 458 insertions, 0 deletions
diff --git a/97suifangqa/apps/recommend/static/css/add_edit_blog_info.css b/97suifangqa/apps/recommend/static/css/add_edit_blog_info.css new file mode 100644 index 0000000..6d2137e --- /dev/null +++ b/97suifangqa/apps/recommend/static/css/add_edit_blog_info.css @@ -0,0 +1,107 @@ +/* + * css for 'add_edit_blog_info' page + * + * 2013/10/07 + */ + +section { + margin: 0.8em; +} + +h4 { + margin: 0.5em; +} + +p { + margin: 0.3em; +} + +section.categories { + border: 1px solid #4A4A4A; + border-radius: 2px; + padding: 0.8em; +} + +section.combinations { + border: 1px solid #4A4A4A; + border-radius: 2px; + padding: 0.8em; +} + +section.configs { + border: 1px solid #99CC33; + border-radius: 2px; + padding: 0.8em; +} + +input[type="button"], input[type="submit"] { + background-color: #99CC33; + border: 1px solid #F3F2F0; + border-radius: 3px; + box-shadow: 0 0 2px #FFFFFF; + color: #FFFFFF; + cursor: pointer; + height: 2.1em; + padding-left: 0.8em; + padding-right: 0.8em; + vertical-align: middle; +} + +input.selected[type="button"] { + background-color: #99CC33; + color: #FFFFFF; + border-color: #F3F2F0; +} + +input.unselected[type="button"] { + background-color: #FFFFFF; + color: #7E7E7E; + border-color: #4A4A4A; +} + +input[type="text"] { + width: 50px; + border-radius: 1px; + border: 1px solid #9C9C9C; +} +input.weight.valid { + border: 2px solid green; +} +input.weight.invalid { + border: 2px solid red; +} + +table { + width: 100%; +} +table th.name { + width: 70%; +} +table th.response { + width: 20%; +} +table th.weight { + width: 10%; +} +th, td { + /* border: 1px solid black; */ + padding: 0.2em; +} +table tr.odd { + background-color: #E0F0C2; +} +table tr.invalid { + background-color: #FFCCCC; +} + +select.treat_response { + border: 1px solid #9C9C9C; + background-color: #FFFFFF; + color: #000000; +} + +span.error { + background-color: #FFB3B3; + padding: 2px; +} + diff --git a/97suifangqa/apps/recommend/static/css/recommend_index.css b/97suifangqa/apps/recommend/static/css/recommend_index.css new file mode 100644 index 0000000..0039a2c --- /dev/null +++ b/97suifangqa/apps/recommend/static/css/recommend_index.css @@ -0,0 +1,21 @@ +/* + * css for 'recommend_index' page + * + * 2013/10/07 + */ + + +ul li { + padding: 4px +} + +span.has_info, .has_info a { + background-color: #B8DB70; + padding: 2px; +} + +span.error { + background-color: #FFB3B3; + padding: 2px; +} + diff --git a/97suifangqa/apps/recommend/static/javascripts/add_edit_blog_info.js b/97suifangqa/apps/recommend/static/javascripts/add_edit_blog_info.js new file mode 100644 index 0000000..1d994e5 --- /dev/null +++ b/97suifangqa/apps/recommend/static/javascripts/add_edit_blog_info.js @@ -0,0 +1,330 @@ +// +// js for 'add_edit_blog_info' page +// +// 2013/10/08 +// + +// a list contains all the configs data objects +var research_configs_list = new Array(); + +$(document).ready(function() { + // make a configs list from 'research_configs {{{ + var obj_keys = Object.keys(research_configs); + for (var i=0; i<obj_keys.length; i++) { + var key = obj_keys[i]; + var configs = research_configs[key].configs; + research_configs_list = research_configs_list.concat(configs); + } + // }}} + + // categories buttons {{{ + var cate_btns_html = ''; + for (var i=1; i<=rind_num; i++) { + var btn_id = 'btn_cate_'+i; + var btn_value = i+'个指标'; + cate_btns_html += '<input type="button" class="unselected" id="'+btn_id + '" value="'+btn_value + '" />   '; + }; + $("#cate_btns").html(cate_btns_html); + // button actions + $('#cate_btns input[type="button"]').on("click", document, function() { + // unselect all buttons + //console.log(this); + $('#cate_btns input[type="button"]').removeClass("selected"); + $('#cate_btns input[type="button"]').addClass("unselected"); + $(this).removeClass("unselected"); + $(this).addClass("selected"); + // unselect buttons of combinations + $('#comb_divs input[type="button"]').removeClass("selected"); + $('#comb_divs input[type="button"]').addClass("unselected"); + // hide configs div's + $('#conf_divs .conf_comb').hide(); + // display category of combinations + var cate_id = $(this).attr('id').replace('btn_cate_', ''); + $('#comb_divs .comb').hide(); + $('#div_comb_'+cate_id).show(); + }); + // }}} + + // indicator combinations div's and buttons {{{ + var comb_divs_html = ''; + for (var i=1; i<=rind_num; i++) { + var id = 'div_comb_'+i; + comb_divs_html += '<div class="comb" id="'+id + '" style="display: none;">\n'; + // combinations buttons + var btn_comb_html = ''; + var combs = rind_categories['N'+i]; + for (var j=0; j<combs.length; j++) { + var btn_id = combs[j].tag; + // get value for button + var btn_value = get_comb_btn_value(combs[j].data); + btn_comb_html += '<input type="button" class="unselected" id="'+btn_id + '" value="'+btn_value + '" />   '; + }; + comb_divs_html += btn_comb_html + '\n</div>\n'; + }; + $("#comb_divs").html(comb_divs_html); + // button actions + $('#comb_divs input[type="button"]').on("click", document, function() { + // unselect all buttons + $('#comb_divs input[type="button"]').removeClass("selected"); + $('#comb_divs input[type="button"]').addClass("unselected"); + $(this).removeClass("unselected"); + $(this).addClass("selected"); + // display configs of the combination + var comb_id = $(this).attr('id'); + $('#conf_divs .conf_comb').hide(); + $('#div_conf_'+comb_id).show(); + }); + // }}} + + // config div's & info input {{{ + var conf_divs_html = ''; + for (var i=0; i<rind_combs.length; i++) { + var comb = rind_combs[i]; + var id = 'div_conf_'+comb.tag; + conf_divs_html += '<div class="conf_comb" id="'+id + '" style="display: none;">\n'; + // configs input + var conf_input_html = '<table class="conf">\n'; + // table head + conf_input_html += '<thead style="display: none;">\n<tr class="head">'; + conf_input_html += '<th class="name"></th> <th class="response"></th> <th class="weight"></th>'; + conf_input_html += '</tr></thead>\n'; + // table body + conf_input_html += '<tbody>\n'; + var configs = research_configs[comb.tag].configs; + //console.log(configs); + for (var j=0; j<configs.length; j++) { + // odd or even (for table tr style) + if (j%2 == 0) { + var odd_even = 'odd'; + } + else { + var odd_even = 'even'; + } + var conf = configs[j]; + var conf_id = conf.tag; + var conf_tr_html = '<tr class="conf '+odd_even + '" id="'+conf_id + '">'; + // display name column + conf_tr_html += '<td class="name">' + conf.display + '</td>'; + // treat response column (prompt & select input) + conf_tr_html += '<td class="response">' + treat_responses_objs.name + ': <select class="treat_response"></select></td>'; + // weight column + conf_tr_html += '<td class="weight">权重: <input type="text" class="weight" value="" /></td>'; + // + conf_tr_html += '</tr>\n'; + conf_input_html += conf_tr_html; + }; + conf_input_html += '</tbody>\n</table>'; + //console.log(conf_input_html); + conf_divs_html += conf_input_html + '\n</div>\n'; + }; + $("#conf_divs").html(conf_divs_html); + // }}} + + // treat response select {{{ + $("select.treat_response").each(function() { + // add options for 'select' + var select_html = ''; + // add empty value + select_html += '<option value="" selected="selected">----</option>\n'; + for (var i=0; i<treat_responses_list.length; i++) { + var tr = treat_responses_list[i]; + select_html += '<option class="response tr'+tr.id+'" value="id'+tr.id + '">' + tr.name + '</option>\n'; + } + $(this).html(select_html); + }); + // }}} + + // validate weight {{{ + $("input.weight").on("validate", null, function(e) { + e.stopPropagation(); + var value = $(this).val(); + var number = parseFloat(value); + if (value == "") { + $(this).removeClass("valid invalid"); + } + else if (isNaN(number)) { + $(this).removeClass("valid"); + $(this).addClass("invalid"); + } + else if (number<0.0 || number>10.0) { + $(this).removeClass("valid"); + $(this).addClass("invalid"); + } + else { + $(this).removeClass("invalid"); + $(this).addClass("valid"); + } + }); + $("input.weight").on("change", null, function() { + $(this).trigger("validate"); + }); + // }}} + + // validate tr conf {{{ + // if only one of the 'treat_response' or 'weight' has data + // then 'invalid' + $("tr.conf").on("validate", null, function(e) { + e.stopPropagation(); + var weight_jq = $(this).find("input.weight"); + var response_jq = $(this).find("select.treat_response"); + //console.log(weight_jq); + // NOTES: + // only trigger 'validate' of '.weight' element, when + // the event originated on any element apart from '.weight' + // REF: http://stackoverflow.com/questions/5967923/jquery-trigger-click-gives-too-much-recursion + if (! $(e.target).is(".weight")) { + weight_jq.trigger("validate"); + } + if (weight_jq.hasClass("invalid")) { + $(this).addClass("invalid"); + } + // only one of the 'treat_response' or 'weight' has data + if (weight_jq.val() !== '' && response_jq.val() === '') { + $(this).addClass("invalid"); + } + else if (weight_jq.val() === '' && response_jq.val() !== '') { + $(this).addClass("invalid"); + } + }); + // }}} + + // fill provided configs data {{{ + $("tr.conf").each(function() { + var conf_id = $(this).attr('id'); + var conf_obj = get_config_obj(conf_id); + if (conf_obj.hasOwnProperty('id')) { + // this config already in database + var tr_id = conf_obj.treatResponse_id; + $(this).find('select>option.tr'+tr_id).prop('selected', true); + $(this).find('.weight').val(conf_obj.weight); + // validate tr config + $(this).trigger('validate'); + } + }); + // }}} + + + // back_to_list button {{{ + $("#back_to_list").bind("click", function() { + var msg = '注意:当前页面未保存的信息将会丢失。是否继续?'; + var ans = confirm(msg); + if (ans) { + window.location.href = recommend_index_url; + } + else { + return false; + } + }); + // }}} + + // submit info button {{{ + $("#submit_info").on("click", null, function() { + // validate tr conf data + $("tr.conf").trigger("validate"); + if ($("tr.conf.invalid").length) { + alert('存在有错误数据的行,请更正后再提交'); + return false; + } + // collect conf data + var configs_list = new Array(); + $("tr.conf").each(function() { + var conf_id = $(this).attr('id'); + var conf_obj = get_config_obj(conf_id); + // get config data + var weight_jq = $(this).find("input.weight"); + var response_jq = $(this).find("select.treat_response"); + var weight = weight_jq.val(); + var tr_id = response_jq.val().replace('id', ''); + // + if (conf_obj.hasOwnProperty('id')) { + if (weight === '' && tr_id === '') { + // delete config + conf_obj['action'] = 'delete'; + conf_obj['weight'] = null; + conf_obj['treatResponse_id'] = null; + } + else { + // edit config + conf_obj['action'] = 'edit'; + conf_obj['weight'] = parseFloat(weight); + conf_obj['treatResponse_id'] = parseInt(tr_id); + } + } + else { + if (weight !== '' && tr_id !== '') { + // add config + conf_obj['action'] = 'add'; + conf_obj['weight'] = parseFloat(weight); + conf_obj['treatResponse_id'] = parseInt(tr_id); + } + else { + // null config + conf_obj['action'] = null; + conf_obj['weight'] = null; + conf_obj['treatResponse_id'] = null; + } + } + // push config data + configs_list.push(conf_obj); + }); + //console.log(configs_list); + + // ajax post configs data {{{ + var time = moment().valueOf(); + $.ajax({ + type: 'post', + url: recommend_url + 'ajax/add_edit_configs/', + data: { + csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value, + configs_list: JSON.stringify(configs_list), + blog_id: blog_id, + time: time + }, + dataType: 'json', + success: function(dataJson) { + if (dataJson.failed == true) { + // submit failed + alert('Error: submit failed'); + return false; + } + else { + alert('submit successful'); + // reload page (do not use cache) + location.reload(true); + } + } + }); + // }}} + }); + // }}} +}); + + +// generate value for combination button +// sort id list by magnitude +function get_comb_btn_value(rid_list) { + // sort id list numerically (smallest first) + rid_list.sort(function(a, b) { return a-b }); + var value = ''; + for (var i=0; i<rid_list.length; i++) { + var key = 'id'+rid_list[i]; + value += rind_objs[key].indicator_name + ' | '; + } + value = value.replace(/\s*\|\s*$/, ''); + return value; +}; + +// return the config js obj (copy) +// by searching the given 'tag' in 'research_configs_list' +function get_config_obj(tag) { + var result = $.grep(research_configs_list, + function(e) { return e.tag == tag }); + if (result.length == 1) { + return $.extend({}, result[0]); + } + else { + return null; + } +}; + +// vim: set ts=8 sw=4 tw=0 fenc= ft=javascript: // |