Changeset 145


Ignore:
Timestamp:
Jan 28, 2010, 5:34:50 PM (9 years ago)
Author:
duh
Message:
  • wizard subjects page now build a table with features, does not work properly yet
  • youtube autoplay help items are possible now
  • development grouping page for selecting subjects and grouping them by dragging and dropping
Location:
trunk
Files:
3 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/dbnp/studycapturing/WizardController.groovy

    r140 r145  
    5151                                [title: 'Study'],               // study
    5252                                [title: 'Subjects'],    // subjects
     53                                [title: 'Groups'],              // groups
    5354                                [title: 'Form elements demo page']
    5455                        ]
     
    8081                                if (params.get('startDate')) {
    8182                                        params.startDate = new Date().parse("d/M/yyyy", params.get('startDate').toString())
     83                                }
     84
     85                                // if a template is selected, get template instance
     86                                if (params.get('template')) {
     87                                        params.template = Template.findByName(params.get('template'))
    8288                                }
    8389
     
    125131                                        error()
    126132                                }
    127                         }.to "pageThree"
     133                        }.to "groups"
    128134                        on("previous") {
    129                                 // handle data?
    130                                 // go to study page
     135                                // TODO
    131136                        }.to "study"
    132137                }
    133138
     139                groups {
     140                        render(view: "_groups")
     141                        onRender {
     142                                flow.page = 3
     143
     144                                if (!flow.groups) {
     145                                        flow.groups = []
     146                                }
     147                        }
     148                        on("next") {
     149                                // TODO
     150                        }.to "groups"
     151                        on("previous") {
     152                                // TODO
     153                        }.to "subjects"
     154                }
     155
    134156                // render page three
    135                 pageThree {
     157                demo {
    136158                        render(view: "_three")
    137159                        onRender {
  • trunk/grails-app/domain/dbnp/data/Term.groovy

    r139 r145  
    77 * The Term object should point to an existing term in an online ontology, therefore instances of this class can also
    88 * be seen as a cache of elements of the external ontology.
     9 *
     10 * Revision information:
     11 * $Rev$
     12 * $Author$
     13 * $Date$
    914 */
    10 class Term {
    11     static searchable = true
    12     String name
    13     Ontology ontology
    14     String accession
     15class Term implements Serializable {
     16        static searchable = true
     17        String name
     18        Ontology ontology
     19        String accession
    1520
    16     static constraints = {
    17     }
     21        static constraints = {
     22        }
    1823
    19   def String toString() {
    20     return name
    21   }
    22 
    23 
     24        def String toString() {
     25                return name
     26        }
    2427}
  • trunk/grails-app/domain/dbnp/studycapturing/Subject.groovy

    r139 r145  
    55/**
    66 * This domain class describes the subjects in a study.
     7 *
     8 * Revision information:
     9 * $Rev$
     10 * $Author$
     11 * $Date$
    712 */
    8 class Subject {
     13class Subject implements Serializable {
    914        static searchable = true
    1015        String name
     
    1621
    1722        static hasMany = [
    18                 templateStringFields : String, // stores both STRING and STRINGLIST items (latter should be checked against the list)
    19                 templateIntegerFields : int,
    20                 templateFloatFields : float,
    21                 templateTermFields : Term
     23                templateStringFields: String, // stores both STRING and STRINGLIST items (latter should be checked against the list)
     24                templateIntegerFields: int,
     25                templateFloatFields: float,
     26                templateTermFields: Term
    2227        ]
    23        
     28
    2429        static constraints = {
    2530        }
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateField.groovy

    r136 r145  
    33/**
    44 * This is the superclass for template fields. Normally, this class will not be instantiated.
     5 *
     6 * Revision information:
     7 * $Rev$
     8 * $Author$
     9 * $Date$
    510 */
    6 abstract class TemplateField {
    7     String name
    8     TemplateFieldType type
    9     String unit
     11abstract class TemplateField implements Serializable {
     12        String name
     13        TemplateFieldType type
     14        String unit
    1015
    11     static constraints = {
    12             name(unique:true)
    13             unit(nullable:true, blank:true)
    14     }
     16        static constraints = {
     17                name(unique: true)
     18                unit(nullable: true, blank: true)
     19        }
    1520
    1621        def String toString() {
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateFieldType.groovy

    r139 r145  
    33/**
    44 * Enum describing the type of a templated field.
     5 * Revision information:
     6 * $Rev$
     7 * $Author$
     8 * $Date$
    59 */
    610public enum TemplateFieldType {
    7     STRING('String'),
    8     INTEGER('Integer number'),
    9     FLOAT('Decimal number'),
    10     STRINGLIST('List of items'),
    11     ONTOLOGYTERM('Ontology Reference')
     11        STRING('String'),
     12        INTEGER('Integer number'),
     13        FLOAT('Decimal number'),
     14        STRINGLIST('List of items'),
     15        ONTOLOGYTERM('Ontology Reference')
    1216
    13     String name
     17        String name
    1418
    15     TemplateFieldType(String name) {
    16      this.name = name
    17     }
     19        TemplateFieldType(String name) {
     20                this.name = name
     21        }
    1822
    19     static list() {
    20      [STRING, INTEGER, FLOAT, STRINGLIST, ONTOLOGYTERM]
    21     }
     23        static list() {
     24                [STRING, INTEGER, FLOAT, STRINGLIST, ONTOLOGYTERM]
     25        }
    2226
    23   // It would be nice to see the description string in the scaffolding,
    24   // and the following works, but then the item cannot be saved properly.
    25   // TODO: find a way to display the enum description but save the enum value in the scaffolding
    26   /*def String toString() {
    27       return this.name
    28   }*/
    29 
     27        // It would be nice to see the description string in the scaffolding,
     28        // and the following works, but then the item cannot be saved properly.
     29        // TODO: find a way to display the enum description but save the enum value in the scaffolding
     30        /*
     31        def String toString() {
     32                  return this.name
     33        }
     34        */
    3035}
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateSubjectField.groovy

    r131 r145  
    33/**
    44 * Instances of this class describe an extra (template) field for the Subject entity.
     5 *
     6 * Revision information:
     7 * $Rev$
     8 * $Author$
     9 * $Date$
    510 */
    611class TemplateSubjectField extends TemplateField {
  • trunk/grails-app/taglib/dbnp/studycapturing/WizardTagLib.groovy

    r140 r145  
    176176
    177177        /**
     178         * generate a base form element
     179         * @param String        inputElement name
     180         * @param Map           attributes
     181         * @param Closure       help content
     182         */
     183        def baseElement = { inputElement, attrs, help ->
     184                // work variables
     185                def description = attrs.remove('description')
     186                def addExampleElement = attrs.remove('addExampleElement')
     187
     188                // render a form element
     189                out << '<div class="element">'
     190                out << ' <div class="description">'
     191                out << description
     192                out << ' </div>'
     193                out << ' <div class="input">'
     194                out << "$inputElement"(attrs)
     195                if(help()) {
     196                        out << '        <div class="helpIcon"></div>'
     197                }
     198
     199                // add an disabled input box for feedback purposes
     200                // @see dateElement(...)
     201                if (addExampleElement) {
     202                        def exampleAttrs = new LinkedHashMap()
     203                        exampleAttrs.name = attrs.get('name')+'Example'
     204                        exampleAttrs.class  = 'isExample'
     205                        exampleAttrs.disabled = 'disabled'
     206                        exampleAttrs.size = 30
     207                        out << textField(exampleAttrs)
     208                }
     209
     210                out << ' </div>'
     211
     212                // add help content if it is available
     213                if (help()) {
     214                        out << '  <div class="helpContent">'
     215                        out << '    ' + help()
     216                        out << '  </div>'
     217                }
     218
     219                out << '</div>'
     220        }
     221
     222        /**
    178223         * render a textFieldElement
    179224         * @param Map attrs
    180225         * @param Closure body  (help text)
    181226         */
    182         def textFieldElement = {attrs, body ->
     227        def textFieldElement = { attrs, body ->
    183228                // set default size, or scale to max length if it is less than the default size
    184229                if (!attrs.get("size")) {
     
    190235                }
    191236
    192                 // work variables
    193                 def addExampleElement = attrs.remove('addExampleElement')
    194                 //attrs.remove('addExampleElement')
    195 
    196                 // render a text element
    197                 out << '<div class="element">'
    198                 out << ' <div class="description">'
    199                 out << attrs.get('description')
    200                 out << ' </div>'
    201                 out << ' <div class="input">'
    202 
    203                 // add text input field
    204                 out << textField(attrs)
    205 
    206                 // add a help icon if help information is available
    207                 if (body()) {
    208                         out << '        <div class="helpIcon" />'
    209                 }
    210 
    211                 // add an disabled input box for feedback purposes
    212                 // @see dateElement(...)
    213                 if (addExampleElement) {
    214                         def exampleAttrs = new LinkedHashMap()
    215                         exampleAttrs.name = attrs.get('name')+'Example'
    216                         exampleAttrs.class  = 'isExample'
    217                         exampleAttrs.disabled = 'disabled'
    218                         out << textField(exampleAttrs)
    219                 }
    220 
    221                 // end HTML
    222                 out << ' </div>'
    223 
    224                 // add help content if it is available
    225                 if (body()) {
    226                         out << '  <div class="helpContent">'
    227                         out << '    ' + body()
    228                         out << '  </div>'
    229                 }
    230 
    231                 out << '</div>'
    232         }
    233 
    234         //def baseElement
    235 
    236         def templateElement = { attrs, body ->
    237 
     237                // render template element
     238                baseElement.call(
     239                        'textField',
     240                        attrs,
     241                        body
     242                )
    238243        }
    239244
    240245        /**
    241246         * render a dateElement
     247         * NOTE: datepicker is attached through wizard.js!
    242248         * @param Map attrs
    243249         * @param Closure body  (help text)
     
    255261               
    256262                // render a normal text field
    257                 out << textFieldElement(attrs,body)
    258 
    259                 // and attach the jquery-ui datepicker
    260                 out << '<script type="text/javascript">'
    261                 out << '$(document).ready(function() {'
    262                 out << '        $("#' + attrs.get('name') + '").datepicker({'
    263                 out << '                dateFormat: \'dd/mm/yy\','
    264                 out << '                altField: \'#' + attrs.get('name') + 'Example\', altFormat: \'DD, d MM, yy\''
    265                 out << '        });'
    266                 out << '});'
    267                 out << '</script>'
     263                //out << textFieldElement(attrs,body)
     264                textFieldElement.call(
     265                        attrs,
     266                        body
     267                )
     268        }
     269       
     270        /**
     271         * Template form element
     272         * @param Map           attributes
     273         * @param Closure       help content
     274         */
     275        def speciesElement = { attrs, body ->
     276                // render template element
     277                baseElement.call(
     278                        'speciesSelect',
     279                        attrs,
     280                        body
     281                )
    268282        }
    269283
     
    285299
    286300        /**
     301         * Template form element
     302         * @param Map           attributes
     303         * @param Closure       help content
     304         */
     305        def templateElement = { attrs, body ->
     306                // render template element
     307                baseElement.call(
     308                        'templateSelect',
     309                        attrs,
     310                        body
     311                )
     312        }
     313       
     314        /**
    287315         * render a template select element
    288316         * @param Map attrs
     
    296324                        attrs.name = 'template'
    297325                }
    298 
     326               
    299327                out << select(attrs)
    300328        }
     329
     330        def templateColumnHeaders = { attrs, body ->
     331                TemplateSubjectField.findAll().each() {
     332                        out << '<div class="column">' + it + '</div>'
     333                }
     334        }
     335
     336        def templateColumns = { attrs, body ->
     337                def subjectId = attrs.remove('id')
     338               
     339                // for now, fetch them all
     340                // also, this should probably be cached to reduce database load...
     341                TemplateSubjectField.findAll().each() {
     342                        out << '<div class="column">'
     343                        out << '<input type="text">'
     344                        out << '</div>'
     345                }
     346        }
    301347}
  • trunk/grails-app/views/wizard/common/_navigation.gsp

    r101 r145  
    1515%>
    1616    <div class="navigation">
    17       <g:if test="${page>1}"><wizard:ajaxButton name="previous" value="&laquo; prev" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" afterSuccess="attachHelpTooltips()" class="prevnext" /></g:if>
     17      <g:if test="${page>1}"><wizard:ajaxButton name="previous" value="&laquo; prev" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" afterSuccess="onWizardPage()" class="prevnext" /></g:if>
    1818      <g:if test="${page>1 && page<pages.size}"> | </g:if>
    19       <g:if test="${page<pages.size}"><wizard:ajaxButton name="next" value="next &raquo;" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" afterSuccess="attachHelpTooltips()" class="prevnext" /></g:if>
     19      <g:if test="${page<pages.size}"><wizard:ajaxButton name="next" value="next &raquo;" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" afterSuccess="onWizardPage()" class="prevnext" /></g:if>
    2020    </div>
  • trunk/grails-app/views/wizard/common/_wizard.gsp

    r107 r145  
    1919        <g:form action="pages" name="wizardForm" id="wizardForm">
    2020                <div id="wizardPage">
    21                         <wizard:ajaxFlowRedirect form="form#wizardForm" name="next" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" afterSuccess="attachHelpTooltips()" />
     21                        <wizard:ajaxFlowRedirect form="form#wizardForm" name="next" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" afterSuccess="onWizardPage()" />
    2222                </div>
    2323        </g:form>
  • trunk/grails-app/views/wizard/index.gsp

    r98 r145  
    1919        <meta name="layout" content="main"/>
    2020        <link rel="stylesheet" href="${resource(dir: 'css', file: 'wizard.css')}"/>
     21        <script type="text/javascript" src="${resource(dir: 'js', file: 'development.js')}"></script>
    2122        <script type="text/javascript" src="${resource(dir: 'js', file: 'jquery.qtip-1.0.0-rc3.min.js')}"></script>
     23        <script type="text/javascript" src="${resource(dir: 'js', file: 'swfobject.js')}"></script>
    2224        <script type="text/javascript" src="${resource(dir: 'js', file: 'wizard.js')}"></script>
    2325</head>
  • trunk/grails-app/views/wizard/pages/_study.gsp

    r140 r145  
    1616%>
    1717<wizard:pageContent>
    18         <wizard:templateSelect />
    1918        <wizard:textFieldElement name="title" description="Title" error="title" value="${study?.title}">
    2019                The title of the study you are creating
     
    3130                The start date of the study     
    3231        </wizard:dateElement>
     32        <wizard:templateElement name="template" description="Template" value="${study?.template}">
     33                The meta data template to use for this study
     34        </wizard:templateElement>
    3335</wizard:pageContent>
  • trunk/grails-app/views/wizard/pages/_subjects.gsp

    r140 r145  
    1616%>
    1717<wizard:pageContent>
    18 <wizard:ajaxButton name="add" value="Add" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" afterSuccess="attachHelpTooltips()" />
     18<wizard:ajaxButton name="add" value="Add" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" afterSuccess="onWizardPage()" />
    1919<input name="addNumber" size="4" maxlength="4" value="1">
    2020subjects of species
    2121<wizard:speciesSelect name="addSpecies" />
    2222<g:if test="${subjects}">
    23 <div class="subjects">
     23<div class="table">
     24        <div class="header">
     25                <div class="firstColumn">#</div>
     26                <div class="column">name</div>
     27                <div class="column">species</div>
     28            <wizard:templateColumnHeaders/>
     29        </div>
    2430<g:each var="subject" status="i" in="${subjects}">
    25         <div class="subject<g:if test="${i>0}"> topborder</g:if>">
    26                 <div class="row">${i+1}</div>
    27                 <div class="row"><g:textField name="test" value="test" size="12" maxlength="12" /></div>
    28                 <div class="row">
    29                         <wizard:speciesSelect value="${subject.species}" name="species_${i}" />
     31        <div class="row">
     32                <div class="firstColumn">${i}</div>
     33                <div class="column"><g:textField name="subject_${i}_name" value="${subject.name}" size="12" maxlength="12" /></div>
     34                <div class="column">
     35                        <wizard:speciesSelect value="${subject.species}" name="subject_${i}_species" />
    3036                </div>
    31                 <div class="row">${subject.name}</div>
     37                <wizard:templateColumns id="${i}" />
    3238        </div>
    3339</g:each>
  • trunk/grails-app/views/wizard/pages/_three.gsp

    r138 r145  
    3131        </wizard:textFieldElement>
    3232        <wizard:dateElement name="startDate" description="Date element" error="startDate" value="${study?.startDate}">
    33                 <object width="320" height="265"><param name="movie" value="http://www.youtube.com/v/2WNrx2jq184&hl=en_US&fs=1&rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/2WNrx2jq184&hl=en_US&fs=1&rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="320" height="265"></embed></object>
     33                [youtube:2WNrx2jq184]
    3434        </wizard:dateElement>
    3535</wizard:pageContent>
  • trunk/web-app/css/wizard.css

    r138 r145  
    9595}
    9696
     97/** START ::  HELP **/
    9798.wizard .element .helpIcon {
    9899    display: inline-block;
     
    122123    display: none;
    123124}
    124 
    125 .wizard .subjects {
    126     display: block;
    127     /*
    128     background-color: #c0ddea;
    129     border: 1px solid #575a5d;
    130     margin-top: 2px;
    131     */
     125/** END :: HELP **/
     126
     127/* START ::  TABLE */
     128.wizard .table {
     129    display: block;
    132130    border: 1px solid #575a5d;
    133131    background-color: #ebf7fc;
    134132    margin-top: 10px;
    135 }
    136 
    137 .wizard .subjects .subject {
    138     display: block;
    139 }
    140 
    141 .wizard .topborder {
     133    font-size: 11px;
     134    overflow: hidden;   
     135}
     136
     137.wizard .column {
     138    display: inline-block;
     139    padding: 2px 4px;
     140    width: 120px;
     141}
     142
     143.wizard .firstColumn {
     144    display: inline-block;
     145    padding: 2px 4px;
     146    width: 40px;
     147}
     148
     149.wizard .table .header {
     150    display: block;
     151    background-color: #006DBA;
     152    color: #fff;
     153    font-weight: bold;
     154    width: 2000px;
     155}
     156
     157.wizard .table .header .column .first {
     158    width: 40px;
     159}
     160
     161.wizard .table .row {
     162    display: block;
     163    width: 2000px;
     164    height: 28px;
    142165    border-top: 1px solid #8e908f;
    143166}
    144167
    145 .wizard .subjects .subject .row {
    146     display: inline-block;
    147     /*
    148     border: 1px solid #575a5d;
    149     margin: 1px 1px 0px 0px;
    150     */
    151 }
     168.wizard .table input, .wizard .table select {
     169    border: 1px solid #8e908f;
     170    margin: 2px 0;
     171    padding: 2px 4px;
     172    background-color: transparent;
     173    width: 100px;
     174}
     175
     176.wizard .table .highlight, .wizard .table .highlight input, .wizard .table .highlight select {
     177    background-color: #006DBA;
     178    color: #fff;
     179}
     180/* END :: TABLE */
     181
     182
     183.selectable .ui-selecting { background: #FECA40; }
     184.selectable .ui-selected { background: #F39814; color: white; }
     185.selectable { list-style-type: none; margin: 0; padding: 0; width: 200px; }
     186.selectable li { margin: 3px; padding: 0.4em; font-size: 1em; height: 18px; }
     187
     188.wizard .grouping {
     189    display: block;
     190}
     191
     192.wizard .subjects {
     193    display: inline-block;
     194}
     195
     196.wizard .groups {
     197    display: inline-block;
     198    height: 100%
     199}
     200
     201.droppable { width: 300px; }
     202
     203
  • trunk/web-app/js/wizard.js

    r107 r145  
    1414 */
    1515$(document).ready(function() {
     16    // check if user is using Firefox 3.6 and warm the user
     17    // about the XMLHttpRequest bug that causes the wizard to break...
    1618    re = /Firefox\/3\.6/gi;
    1719    if (navigator.userAgent.match(re)) {
     
    2224
    2325    // attach Tooltips
     26    onWizardPage();
     27});
     28
     29// runs when document is ready or a wizard action has been performs
     30// @see _wizard.gsp, _navigation.gsp, _subjects.gsp
     31function onWizardPage() {
     32    // attach help tooltips
     33    //insertYoutubePlayers();
    2434    attachHelpTooltips();
    25 });
     35    attachDatePickers();
     36    attachTableEvents();
     37    attachGroupingEvents();
     38}
    2639
    2740// attach help tooltips
     
    2942    // attach help action on all wizard help icons
    3043    $('div#wizard').find('div.helpIcon').each(function() {
    31         $(this).qtip({
     44        helpIcon = $(this)
     45        helpContent = helpIcon.parent().parent().find('div.helpContent')
     46
     47        // handle special content
     48        var specialContent = helpContent.html().match(/\[([^:]+)\:([^\]]+)\]/)
     49        if (specialContent) {
     50            // replace content by calling a helper function
     51            eval(specialContent[1]+"('"+specialContent[2]+"',helpContent)");
     52        }
     53
     54        // attach tooltip
     55        helpIcon.qtip({
    3256            content: 'leftMiddle',
    3357            position: {
     
    4771                name: 'blue'
    4872            },
    49             content: $(this).parent().parent().find('div.helpContent').html(),
     73            content: helpContent.html(),
    5074            show: 'mouseover',
    51             hide: 'mouseout'
     75            hide: 'mouseout',
     76            api: {
     77                beforeShow: function() {
     78                    // not used at this moment
     79                }
     80            }
    5281        })
     82
     83        // remove helpcontent div as we don't need it anymore
     84        helpContent.remove();
    5385    });
    5486}
     87
     88// insert a youtube player in a certain element
     89function youtube(video,element) {
     90    // insert a div we will replace with a youtube player
     91    element.html("<div id='"+video+"'></div>")
     92
     93    // insert youtube player
     94    var params = { allowScriptAccess: "always" };
     95    var atts = { id: 'myytplayer_'+video };
     96    swfobject.embedSWF("http://www.youtube.com/v/"+video+"?enablejsapi=1&playerapiid=ytplayer_"+video,
     97                       video, "200", "150", "8", null, null, params, atts)
     98}
     99
     100// when a youtube player is ready, play the video
     101function onYouTubePlayerReady(playerId) {
     102    ytplayer = document.getElementById("my"+playerId);
     103    ytplayer.playVideo();
     104}
     105
     106// add datepickers to date fields
     107function attachDatePickers() {
     108    $('div#wizard').find("input[type=text][name$='Date']").each(function() {
     109        $(this).datepicker({
     110            dateFormat  : 'dd/mm/yy',
     111            altField    : '#' + $(this).attr('name') + 'Example',
     112            altFormat   : 'DD, d MM, yy'
     113        });
     114    })
     115}
     116
     117// attach subject events
     118function attachTableEvents() {
     119    $('div#wizard').find('div.row').each(function() {
     120        $(this).hover(
     121            function() {
     122                $(this).addClass('highlight');
     123            },
     124            function() {
     125                $(this).removeClass('highlight');
     126            }
     127        )
     128    });
     129}
     130
     131function attachGroupingEvents() {
     132    console.log('attach drag and drop events')
     133
     134    $(".groups").find('div.droppable').droppable({
     135                drop: function(event, ui) {
     136                        $(this).addClass('ui-state-highlight').find('p').html('Dropped!');
     137                }
     138        });
     139
     140
     141    $(".subjects").find(".selectable").selectable({
     142        stop: function() {
     143            // remove draggable from unselected items
     144            $('.ui-selectee:not(.ui-selected)', this).each(function() {
     145                $(this).draggable('destroy')   
     146            })
     147
     148            // attach draggable to selected items
     149            var subjects = $('.ui-selected', this);
     150            subjects.each(function() {
     151                var d = this
     152                var D = $(this)
     153                var content = D.html()
     154                var offset = D.offset()
     155
     156                D.draggable({
     157                    revert: 'invalid',
     158                    start: function(event, ui) {
     159                        // change dragged item's content to summarize selected items
     160                        D.html(subjects.length + ' subjects');
     161
     162                        // hide the other items
     163                        subjects.each(function() {
     164                            if (this != d) {
     165                                $(this).animate(
     166                                    {
     167                                        opacity: 0
     168                                    },
     169                                    200
     170                                );
     171                            }
     172                        });
     173                    },                 
     174                    stop: function(event, ui) {
     175                        // restore original content
     176                        D.html(content);
     177
     178                        // make selected items visible
     179                        subjects.each(function() {
     180                            if (this != d) {
     181                                $(this).animate(
     182                                    {
     183                                        opacity: 100
     184                                    },
     185                                    200
     186                                );
     187                            }
     188                        });
     189                    }
     190                });
     191            });
     192        }
     193    });
     194}
     195
Note: See TracChangeset for help on using the changeset viewer.