您的位置:首页 > Web前端 > JQuery

基于jQuery试卷自动排版系统

2010-07-18 00:00 531 查看
需求
根据提供的试卷题目(是一个干净的只有“数据”的HTML网页)生成一份多页的试卷,用户能执行翻页、具有答题时间限制,展示给用户的试卷中题目需要占用尽量少的空间(比如选择题中把两条较短的选项由两行合并到一行)、同一道题目不要跨页面显示以方便答题者,管理员能够改变试卷的样式(字体、颜色、行距、页面边距,像字处理软件一样……),题目之间可以插入一些说明性的文字(比如告知答题者作答的须知等等)。题目提干、选择题的选项、说明文字可以包含多媒体信息(文字、图片、列表、表格、视频等等……)。选择题选项数目不限、单选多选不限。翻页要有可订制的动画效果

提供的试卷样板类似如下(Input):
<ol id="olThePaper"> 
<div class="Desc">选择题:说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。</div> 
<div class="Problem" id="1"> 
<li>1.你认为怎样的老师是好老师?</li> 
<div class="Choices"> 
<label><input type="radio" name="prob1" value="A" />和学生平等相处,能全面满足学生各种需要</label> 
<label><input type="radio" name="prob1" value="B" />所在教学班的成绩优于其他平行班</label> 
<label><input type="radio" name="prob1" value="C" />严格管理学生、所带的班级班风良好</label> 
<label><input type="radio" name="prob1" value="D" />父母般地关心学生的生活和情绪状态</label> 
</div> 
</div> 
<div class="Problem" id="2"> 
<li>2.一位有15年教龄的英语教师,教了多年高三,可谓学校的核心骨干。一次接受邀请到外校介绍教学经验,台下有老师发表了观点并问到几个英语教法发面的问题,一下子把她给卡住了。这是因为</li> 
<div class="Choices"> 
<label><input type="radio" name="prob2" value="A" />她最近工作太累,注意力不够集中。</label> 
<label><input type="radio" name="prob2" value="B" />提问老师的观点和她的有很大不同。</label> 
<label><input type="radio" name="prob2" value="C" />由于长时间在教学一线拼搏,她对教学理论问题的关注度不高。</label> 
<label><input type="radio" name="prob2" value="D" />对学科教学的归纳和思考少,一时加工不过来。</label> 
</div> 
</div> 
<div class="Problem" id="3"> 
<li>3.哪张图片最好看?</li> 
<div class="Choices"> 
<label><input type="radio" name="prob3" value="A" />这一张<img src="img1.png" height="300px" width="400px" alt="img1"/>好看。</label> 
<label><input type="radio" name="prob3" value="B" />这一张<img src="img2.png" height="300px" width="400px" alt="img2"/>好看。</label> 
<label><input type="radio" name="prob3" value="C" />这一张<img src="img3.png" height="300px" width="400px" alt="img3"/>好看。</label> 
<label><input type="radio" name="prob3" value="D" />这一张<img src="img4.png" height="300px" width="400px" alt="img4"/>好看。</label> 
<label><input type="radio" name="prob3" value="E" />不知道。</label> 
</div> 
</div> 
<div class="Desc">填空题和选择题:一大堆的说明文字。一大堆的说明文字。一大堆的说明文字。一大堆的说明文字。一大堆的说明文字。</div> 
<div class="Problem" id="4"> 
<li>4.床前明月光,<input type="text" name="prob4" /></li> 
</div> 
<div class="Problem" id="5"> 
<li>5.你认为怎样的老师是好老师?</li> 
<div class="Choices"> 
<label><input type="checkbox" name="prob6" value="D" />和</label> 
<label><input type="checkbox" name="prob6" value="A" />所</label> 
<label><input type="checkbox" name="prob6" value="B" />严</label> 
<label><input type="checkbox" name="prob6" value="C" />父</label> 
<label><input type="checkbox" name="prob6" value="E" />和班的成绩班的成绩班的成绩班的成绩班的成绩</label> 
<label><input type="checkbox" name="prob6" value="F" />所班的成绩班的成绩班的成绩</label> 
<label><input type="checkbox" name="prob6" value="G" />严班的班的成绩班的成绩班的成绩班的成绩</label> 
<label><input type="checkbox" name="prob6" value="H" />啊</label> 
</div> 
</div> 
</ol>

思路
面对这种需求该怎么办呢?使用JavaScript了,看来。后来决定用jQuery,Aptana作IDE(虽然jQuery支持库在Windows上死活装不上去,换了个OS就好了,奇怪),格式么就用CSS了。

具体步骤:

导入试卷题目HTML
对所有选择题进行排版,把一行划分为四个位置,使选项尽量适应一个位置、两个位置或四个位置(也就是一行四项、一行两项或者一行一项的效果)
对所有题目进行分页
思路还是清晰的,但是由于浏览器众多,还是比较麻烦的,并且我是新手,没接触过jQuery之前……

实现
页面文件(和例子不同,但是格式一样的)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<title>No title...</title> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<script language="JavaScript" src="lib/jquery/jquery-1.4.2.js" type="text/javascript"></script> 
<script language="JavaScript" src="lib/countdown/jquery.countdown.pack.js" type="text/javascript"></script> 
<script language="JavaScript" src="TestPaperProcessor.js" type="text/javascript"></script> 
<link href="style.css" rel="stylesheet" type="text/css" /> 
</head> 
<body> 
<div id="divToolbar"> 
<div id="divPrev">PrevPage</div> 
<div id="divNext">NextPage</div> 
<div id="divPageInfo">Loading the test...</div> 
<div id="divTimer"></div> 
</div> 
<form id="formPaper" action="demo.html" method="post" accept-charset="utf-8"> 
<ul> 
<div class="Display" id="divLeft"> 
left<!--the left page--> 
</div> 
<div class="Display" id="divRight"> 
right<!--the right page--> 
</div> 
</ul> 
<ol id="olThePaper"> 
<div class="Desc">选择题:说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。说明文字。</div> 
<div class="Problem" id="1"> 
<li>1你认为怎样的老师是好老师?</li> 
<div class="Choices"> 
<label> 
<input type="radio" name="prob1" value="D" />和学生平等相处,能全面满足学生各种需要 
</label> 
<label> 
<input type="radio" name="prob1" value="A" />所在教学班的成绩优于其他平行班 
</label> 
<label> 
<input type="radio" name="prob1" value="B" />严格管理学生/所带的班级班风良好 
</label> 
<label> 
<input type="radio" name="prob1" value="C" />父母般地关心学生的生活和情绪状态 
</label> 
</div> 
</div> 
<div class="Problem" id="2"> 
<li>2你认为怎样的老师是好老师?</li> 
<div class="Choices"> 
<label> 
<input type="radio" name="prob2" value="D" />和学生平jlsdjklsdf生各种需要 
</label> 
<label> 
<input type="radio" name="prob2" value="A" />所 
</label> 
<label> 
<input type="radio" name="prob2" value="B" />严格好 
</label> 
<label> 
<input type="radio" name="prob2" value="C" />父母关心学生的生活和情绪状态 
</label> 
</div> 
</div> 
<div class="Problem" id="3"> 
<li>3你认为怎样的老师是好老师?</li> 
<div class="Choices"> 
<label> 
<input type="radio" name="prob3" value="D" />和学生平等相处,能全面满足学生各种需要 
</label> 
<label> 
<input type="radio" name="prob3" value="A" />所在教学班的成绩优于其他平行班 
</label> 
<label> 
<input type="radio" name="prob3" value="B" />严格管理学生/所带的班级班风良好 
</label> 
<label> 
<input type="radio" name="prob3" value="C" />父母般地关心学生的生活和情绪状态 
</label> 
</div> 
</div> 
<div class="Problem" id="4"> 
<li>4你认为怎样的老师是好老师?</li> 
<div class="Choices"> 
<label> 
<input type="radio" name="prob4" value="D" />和学生平等相处,能全面满足学和学生平等相处,能全面满足学和学生平等相处,能全面满足学和学生平等相处,能全面满足学和学生平等相处,能全面满足学和学生平等相处,能全面满足学和学生平等相处,能全面满足学和学生平等相处,能全面满足学和学生平等相处,能全面满足学生各种需要 
</label> 
<label> 
<input type="radio" name="prob4" value="A" />所在教学班的成绩优于其他平行班 
</label> 
<label> 
<input type="radio" name="prob4" value="B" />严格管理学生/所带的班级班风良好 
</label> 
<label> 
<input type="radio" name="prob4" value="C" />父母般地关心学生的生活和情绪状态 
</label> 
</div> 
</div> 
<div class="Desc">还是选择题:一大堆的说明文字。一大堆的说明文字。一大堆的说明文字。一大堆的说明文字。一大堆的说明文字。</div> 
<div class="Problem" id="10"> 
<li>5你认为怎样的老师是好老师?</li> 
<div class="Choices"> 
<label> 
<input type="radio" name="prob5" value="D" />和10学生平等相处,能全面满足学生各种需要 
</label> 
<label> 
<input type="radio" name="prob5" value="A" />所10在教学班的成绩优于其他平行班 
</label> 
<label> 
<input type="radio" name="prob5" value="B" />严10jhjhjhjhkljlkjjkljjkjjkllkjlkjljkjljlkj格管文字 
</label> 
<label> 
<input type="radio" name="prob5" value="C" />父10母般地关心学生的生活和情绪状态 
</label> 
</div> 
</div> 
<div class="Problem" id="5"> 
<li>5你认为怎样的老师是好老师?</li> 
<div class="Choices"> 
<label> 
<input type="radio" name="prob5" value="D" />和学生平等相处,能全面满足学生各种需要 
</label> 
<label> 
<input type="radio" name="prob5" value="A" />所在教学班的成绩优于其他平行班 
</label> 
<label> 
<input type="radio" name="prob5" value="B" />严jhjhjhjhkljlkjjkljjkjjkllkjlkjljkjljlkj格管<img src="aaaa9.jpg" height="300px" width="400px" alt="pic"/>文字 
</label> 
<label> 
<input type="radio" name="prob5" value="C" />父母般地关心学生的生活和情绪状态 
</label> 
</div> 
</div> 
<div class="Problem" id="6"> 
<li>6你认为怎样的老师是好老师?</li> 
<div class="Choices"> 
<label> 
<input type="radio" name="prob6" value="D" />和 
</label> 
<label> 
<input type="radio" name="prob6" value="A" />所 
</label> 
<label> 
<input type="radio" name="prob6" value="B" />严 
</label> 
<label> 
<input type="radio" name="prob6" value="C" />父 
</label> 
<label> 
<input type="radio" name="prob6" value="E" />和班的成绩班的成绩班的成绩班的成绩班的成绩 
</label> 
<label> 
<input type="radio" name="prob6" value="F" />所班的成绩班的成绩班的成绩 
</label> 
<label> 
<input type="radio" name="prob6" value="G" />严班的班的成绩班的成绩班的成绩班的成绩 
</label> 
<label> 
<input type="radio" name="prob6" value="H" />父 
</label> 
</div> 
</div> 
</ol> 
</form> 
</body> 
</html>

样式文件(CSS)
/* YahooUI CSS Reset */ 
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td { padding: 0; margin: 0; } 
table { border-collapse: collapse; border-spacing: 0; } 
fieldset,img { border: 0; } 
address,caption,cite,code,dfn,em,strong,th,var { font-weight: normal; font-style: normal; } 
ol,ul { list-style: none; } 
caption,th { text-align: left; } 
h1,h2,h3,h4,h5,h6 { font-weight: normal; font-size: 100%; } 
q:before,q:after { content:''; } 
abbr,acronym { border: 0;} 

label { padding: 0; margin: 0; } 

/* My css */ 
.Choices { line-height: 150%; margin: 5px 0; } 
.Page { height: 500px; border: solid 1px gray; } 
#olThePaper, .Display { padding: 0; width: 500px; } 
/* NOTICE: the width of .Display and #olThePaper should be the SAME. */ 
.Display { float: left; } 

#divToolbar { height: 35px; } 
#divPrev, #divNext { float: left; width: 100px; height: 30px; border: solid 1px green; background-color: #999999; } 
#divPageInfo { float: left; width: 100px; height: 30px; } 
#divTimer { float: left; width: 500px; height: 30px; } 
/*for debugging... perhaps for non-IE only*/ 
/**label { outline: dotted 1px red; background-color: gray; }**/ 
/**div {outline: dashed 1px blue;}**/

下面是重点,TTestPaperProcessor.js:
/** 
* 
* @param {String} PaperOlId the id value of the ol tags indicating pages. 
* @param {String} ProblemClass the css class name for problem area. 
* @param {String} DescClass the css class name for description area. 
* @param {String} ChoicesClass the css class name for choices area. 
* @param {String} LeftPageId the id of the left page. 
* @param {String} RightPageId the id of the right page. 
* @author ExSystem<exsystemchina@gmail.com> 
*/ 
function TTestPaperProcessor(PaperOlId, ProblemClass, DescClass, ChoicesClass, LeftPageId, RightPageId) { 
this.FPaperOlId = PaperOlId; 
this.FProblemClass = ProblemClass; 
this.FDescClass = DescClass; 
this.FChoicesClass = ChoicesClass; 
this.FLeftPageId = LeftPageId; 
this.FRightPageId =RightPageId; 
$('#' + this.FLeftPageId).html(''); 
$('#' + this.FRightPageId).html(''); 
this._FormatProblemOptions(); 
this._DivideIntoPages(); 
this.setCurrPage(1); 
} 

TTestPaperProcessor.prototype = { 
FPaperOlId: '', //the id property of the ol tag contains the whole test paper. 
FProblemClass: '', //the css class name for problem area. 
FDescClass: '', //the css class name for description area. 
FChoicesClass: '', //the css class name for choices area. 
FLeftPageId: '', //the left page. 
FRightPageId: '', //the right page. 
CPageClass: 'Page', 
FIsDisplayTableSupported: null, //whether the browser is the EVIL M$IE6,7 that does not support display: table(-cell). 
FCurrPage: 0, //start from 1, 0 for no page has been displayed yet. 
FPageCount: 0, //page count. 
// /** 
// * Get external css stylesheet info. 
// * @param {String} Selector The selector in the css style sheet. 
// * @param {String} Property The property name. 
// * @return {String} The value of the property, or null for undefined property. 
// */ 
// _GetCssInfo: function(Selector, Property) { 
// var mCss = document.styleSheets[0].cssRules || document.styleSheets[0].rules; 
// for (var mIndex = 0; mIndex < mCss.length; ++mIndex) { 
// if (mCss[mIndex].selectorText.toLowerCase() == Selector) { 
// return mCss[mIndex].style[Property]; 
// } 
// } 
// return null; 
// }, 

/** 
* @return {Boolean} 
*/ 
_IsDisplayTableSupported: function() { 
if (this.FIsDisplayTableSupported != null) { 
return this.FIsDisplayTableSupported; 
} 

this.FIsDisplayTableSupported = !(jQuery.browser.msie && jQuery.browser.version < 8.0); 
return this.FIsDisplayTableSupported; 
}, 

/** 
* Formats radios and checkboxes for the Choices quiz. 
*/ 
_FormatProblemOptions: function() { 
var mThis = this; 
var mSelector = '.' + this.FProblemClass + ' .' + this.FChoicesClass; 
$(mSelector).each(function() { 
//Rearrange the options for each problem ordered by offsetWidth of the label tag. 
var mLabels = new Array(); 
mLabels = jQuery.makeArray($('label', this)); 
mLabels.sort(function(First, Second) { 
return $(Second).outerWidth(true) > $(First).outerWidth(true); 
}); 
$(mLabels).appendTo(this); 

//Layout the options into the appropreate form. 
var mSlots = -1; //Force to create a new row, inside the while() loop. 
var mSlotWidth = $(mSelector).width() / 4.0; 
var mCellSize = 0; 
if (mThis._IsDisplayTableSupported()) { 
while (mLabels.length > 0) { 
//alert($(mLabels[0]).outerWidth(true) + '::' + $(mLabels[0]).outerHeight(true) + '::' + $(mLabels[0]).html()); 
if (mSlots <= 0) { //If no empty slot, create a new row. 
mCurrRow = $('<div class="___table" style="display: table;"></div>'); 
mCurrRow.appendTo(this); 
mSlots = 4; 
mCellSize = 0; 

var mRealCellWidth = $(mLabels[0]).outerWidth(true); 
if (mRealCellWidth < mSlotWidth) { 
mCellSize = 1; 
} 
if (mRealCellWidth >= mSlotWidth && mRealCellWidth < mSlotWidth * 2) { 
mCellSize = 2; 
} 
if (mRealCellWidth >= mSlotWidth * 2) { 
mCellSize = 4; 
} 
} 
mSlots -= mCellSize; 
if (mSlots >= 0) { //If empty slots exists, put the cell into the row. 
mLabel = mLabels.shift(); 
$(mLabel).addClass('___cell'); 
$(mLabel).css('display', 'table-cell'); 
$(mLabel).appendTo(mCurrRow); 
} 
} 
$('.___table').each(function() { //Align all the tables and cells. 
$(this).css('width', '100%'); 
var mCellWidth = 100 / $('.___cell', this).length; 
$('.___cell', this).css('width', mCellWidth + '%'); 
}); 
} 
else { // for the evil M$IE6, use table, tr, td tags. 
while (mLabels.length > 0) { 
if (mSlots <= 0) { //If no empty slot, create a new row. 
mCurrRow = $('<table class="___table" cellspacing="0" cellpadding="0"></table>'); 
mRow = $('<tr></tr>'); 
mRow.appendTo(mCurrRow); 
mCurrRow.appendTo(this); 
mSlots = 4; 
mCellSize = 0; 

var mRealCellWidth = $(mLabels[0]).attr('offsetWidth'); 
//The EVIL IE only: 
//be sure to use this css reset: table { border-collapse: collapse; border-spacing: 0; } 
//otherwise, 2 lines will be occupied by some long problem options instead of 1. 
//or use this code instead: var mRealCellWidth = $(mLabels[0]).attr('offsetWidth') * 1.3; 
if (mRealCellWidth <= mSlotWidth) { 
mCellSize = 1; 
} 
if (mRealCellWidth > mSlotWidth && mRealCellWidth <= mSlotWidth * 2) { 
mCellSize = 2; 
} 
if (mRealCellWidth > mSlotWidth * 2) { 
mCellSize = 4; 
} 
} 
mSlots -= mCellSize; 
if (mSlots >= 0) { //If empty slots exists, put the cell into the row. 
mLabel = mLabels.shift(); 
mCell = $('<td class="___cell"></td>'); 
$(mLabel).appendTo(mCell); 
mCell.appendTo($('tr', mCurrRow)[0]); 
} 
} 
$('.___table').each(function() { //Align all the tables and cells. 
$(this).css('width', '100%'); 
var mCellWidth = 100 / $('tbody tr .___cell', this).length; 
$('tbody tr .___cell', this).css('width', mCellWidth + '%'); 
}); 
} 
}); 
}, 

/** 
* Create a new page, and add it to the paper. 
* @return {jQuery} the new page. 
*/ 
_CreateNewPage: function() { 
++this.FPageCount; 

mPage = $('<div class="' + this.CPageClass + '" id="___page_' + this.FPageCount + '"></div>'); 
mPage.appendTo($('#' + this.FPaperOlId)); 

return mPage; 
}, 

/** 
* 
* @param {Number} PageNumber 
* @return {jQuery} 
*/ 
_GetPage: function(PageNumber) { 
if (PageNumber < 1 || PageNumber > this.FPageCount) { 
throw new Error('invalid page number: ' + PageNumber + '.'); 
} 
return $('#___page_' + PageNumber); 
}, 

/** 
* 
*/ 
_DivideIntoPages: function() { 
var mProblems = $('.' + this.FProblemClass + ', .' + this.FDescClass); 
var mProblemsCount = mProblems.length; 
var mCurrPage = this._CreateNewPage(); 
//var mPageHeight = mCurrPage.attr('offsetHeight'); chrome: sometimes 0. safari: always 0, IF PUTTED IN $(window).ready(). 
var mPageHeight = mCurrPage.outerHeight(true); //the same as the code above. FIX: PUT IT INTO $(window).load(). 
var mUsedPageHeight = 0; 
for (var mCurrProblem = 0; mCurrProblem < mProblemsCount; ++mCurrProblem) { 
if (mUsedPageHeight + $(mProblems[mCurrProblem]).outerHeight(true) > mPageHeight) { 
mCurrPage.hide(); 
mCurrPage = this._CreateNewPage(); 
mPageHeight = mCurrPage.outerHeight(true); 
mUsedPageHeight = 0; 
} 
$(mProblems[mCurrProblem]).appendTo(mCurrPage); 
mUsedPageHeight += $(mProblems[mCurrProblem]).outerHeight(true); 
} 
mCurrPage.hide(); 
}, 
/** 
* Get the current page of the left side, started from 1. 
* @return {Number} The current page. 
*/ 
getCurrPage: function() { 
if (this.FPageCount == 0) { 
throw new Error('No page has been created yet.'); 
} 
return this.FCurrPage; 
}, 
/** 
* Trun to a specific page in the left side. 
* @param {Number} Value The page number. 
*/ 
setCurrPage: function(Value) { 
if (Value < 1 || Value > this.FPageCount) { 
throw new Error('No such page: ' + Value + '.'); 
} 
this.FCurrPage = parseInt(Value / 2) * 2 + 1; // to get an odd number. 
$('#' + this.FLeftPageId + ' .' + this.CPageClass).hide(); 
$('#' + this.FRightPageId + ' .' + this.CPageClass).hide(); 
if (this.FCurrPage >= 0) { 
$('#___page_' + this.FCurrPage).appendTo($('#' + this.FLeftPageId)); 
$('#___page_' + this.FCurrPage).show('fast'); 
if (this.FCurrPage < this.FPageCount) { 
++this.FCurrPage; 
$('#___page_' + this.FCurrPage).appendTo($('#' + this.FRightPageId)); 
$('#___page_' + this.FCurrPage).show('fast'); 
--this.FCurrPage; 
} 
} 
}, 
/** 
* @retrun {Number} 
*/ 
getPageCount: function() { 
return this.FPageCount; 
}, 
/** 
* 
*/ 
Prev: function() { 
this.setCurrPage(this.FCurrPage - 2); 
}, 
/** 
* 
*/ 
Next: function() { 
this.setCurrPage(this.FCurrPage + 2); 
} 
}; 

//client code goes here... 
$(window).load(function() { 
var obj = new TTestPaperProcessor('olThePaper', 'Problem', 'Desc', 'Choices', 'divLeft', 'divRight'); 
$('#divPrev').click(function() { 
try { 
obj.Prev(); 
$('#divPageInfo').text(obj.getCurrPage() + ' of ' + obj.getPageCount()); 
} 
catch (e) { 
alert('No such page!'); 
} 
}); 
$('#divNext').click(function() { 
try { 
obj.Next(); 
$('#divPageInfo').text(obj.getCurrPage() + ' of ' + obj.getPageCount()); 
} 
catch (e) { 
alert('No such page!'); 
} 
}); 
//USAGE: http://keith-wood.name/countdown.html 
function TimeUp() { 
$('#formPaper').submit(); 
} 
$('#divTimer').countdown({ 
until: '+90m', 
compact: true, 
format: 'HMS', 
description: '', 
onExpiry: TimeUp 
}); 
$('#divPageInfo').text(obj.getCurrPage() + ' of ' + obj.getPageCount()); 
});


嘿嘿,其实这是一个俺们学校一位博导老师的项目的一部分~~托给我做了。马上要出门了,回来放源文件下载,就可以看到效果了~~昨天回来太晚了,现在放出源代码文件下载:点击此处
/201007/yuanma/TestPaperProcessor.rar
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: