Changeset 64729b in indico


Ignore:
Timestamp:
03/17/10 20:31:23 (3 years ago)
Author:
Pedro Ferreira <jose.pedro.ferreira@…>
Branches:
master, burotel, hello-world-walkthrough, ipv6, new-webex, prov-dual-interface, v0.97-series, v0.98-series, v0.98.2, v0.98.3, v0.98b1, v0.98b2, v0.99, 051b2622c51afb171a1dedb46a0df4fbb0cbd02e, d9941f8582b36b24821a11ea5ba16fda6a457fb1
Children:
7dd15f, f3d0f4
Parents:
382574
git-author:
Pedro Ferreira <jose.pedro.ferreira@…> (03/05/10 17:24:34)
git-committer:
Pedro Ferreira <jose.pedro.ferreira@…> (03/17/10 20:31:23)
Message:

[IMP] Better material creation Widget

  • Clearer, nicer - file uploads and links in one single tab;
  • Slight refactor on the server side, regarding material factories and the file upload code;
  • Some bug fixes since last improvements;
  • There shouldn't be such a promiscuity between material names and ids, but fixing it would require major changes in the DB. To be addressed later;
  • Some changes to the TabWidgets? that required some refactoring, and changes in the timetable - fixed some other dialogs as well;
  • fixes #247
Location:
indico
Files:
1 added
17 edited

Legend:

Unmodified
Added
Removed
  • indico/MaKaC/common/output.py

    r382574 r64729b  
    111111        self.webFactory = WebFactoryRegistry() 
    112112 
     113    # TODO: Put this out of here, and unify with WShowExistingMaterial._generateMaterialList 
     114    # (when we have a better class hierarchy) 
     115    def _generateMaterialList(self, obj): 
     116        """ 
     117        Generates a list containing all the materials, with the 
     118        corresponding Ids for those that already exist 
     119        """ 
     120 
     121        from MaKaC.webinterface.rh.conferenceBase import RHSubmitMaterialBase 
     122        if isinstance(obj, conference.Category): 
     123            _allowedMats = RHSubmitMaterialBase._allowedMatsCategory 
     124        else: 
     125            _allowedMats = RHSubmitMaterialBase._allowedMatsEvent[obj.getConference().getType()] 
     126 
     127        matDict = dict((title.lower(), title) for title in _allowedMats) 
     128 
     129        for material in obj.getMaterialList(): 
     130            title = material.getTitle().lower() 
     131            matDict[title] = material.getId() 
     132 
     133        return sorted(list((matId, title.title()) for title, matId in matDict.iteritems())) 
     134 
     135 
    113136    def getOutput(self, conf, stylesheet, vars=None, includeSession=1,includeContribution=1,includeMaterial=1,showSession="all",showDate="all",showContribution="all"): 
    114137        # get xml conference 
     
    188211        else: 
    189212            out.writeTag("category","") 
     213 
     214        out.writeTag("parentProtection", simplejson.dumps(conf.getAccessController().isProtected())) 
     215        out.writeTag("materialList", simplejson.dumps(self._generateMaterialList(conf))) 
    190216 
    191217        if conf.canModify( self.__aw ) and vars and modificons: 
     
    216242 
    217243        out.writeTag("customMaterialList", simplejson.dumps(customMaterials)) 
    218              
     244 
    219245        if conf.getOrgText() != "": 
    220246            out.writeTag("organiser", conf.getOrgText()) 
     
    452478        out.openTag("session") 
    453479        out.writeTag("ID",session.getId()) 
     480 
    454481        if session.getCode() not in ["no code", ""]: 
    455482            out.writeTag("code",session.getCode()) 
     
    535562        out.openTag("session") 
    536563        out.writeTag("ID",session.getId()) 
     564 
     565        out.writeTag("parentProtection", simplejson.dumps(session.getAccessController().isProtected())) 
     566        out.writeTag("materialList", simplejson.dumps(self._generateMaterialList(session))) 
     567 
     568 
    537569        slotCode = session.getSortedSlotList().index(slot) + 1 
    538570        if session.getCode() not in ["no code", ""]: 
     
    609641        out.openTag("contribution") 
    610642        out.writeTag("ID",cont.getId()) 
     643 
     644        out.writeTag("parentProtection", simplejson.dumps(cont.getAccessController().isProtected())) 
     645        out.writeTag("materialList", simplejson.dumps(self._generateMaterialList(cont))) 
     646 
    611647        if cont.getBoardNumber() != "": 
    612648            out.writeTag("board",cont.getBoardNumber()) 
     
    708744        out.openTag("subcontribution") 
    709745        out.writeTag("ID",subCont.getId()) 
     746 
     747        out.writeTag("parentProtection", simplejson.dumps(subCont.getContribution().getAccessController().isProtected())) 
     748        out.writeTag("materialList", simplejson.dumps(self._generateMaterialList(subCont))) 
     749 
    710750        if subCont.canModify( self.__aw ) and vars and modificons: 
    711751            out.writeTag("modifyLink",vars["subContribModifyURLGen"](subCont)) 
  • indico/MaKaC/webinterface/materialFactories.py

    r0d29a2 r64729b  
    333333    and creates new one if needed. """ 
    334334 
    335     # inheritance from MaterialFactory is actually not needed 
    336  
    337     def __init__(self, name): 
    338         self.name = name 
    339      
     335    def __init__(self, matId): 
     336        self.name = matId 
     337 
    340338    def get( self, owner ): 
    341339        """returns the material""" 
    342340 
    343341        for mat in owner.getMaterialList(): 
    344             if mat.getTitle() == self.name: 
     342            if mat.getTitle().lower() == self.name.lower(): 
    345343                return mat 
    346  
    347         return None 
    348  
    349     def getTitle(self): 
    350         return self.name 
    351  
    352     def getId(self): 
    353         return self.id 
    354344 
    355345    def remove( self, owner ): 
     
    358348 
    359349    def canAdd( self, target ): 
    360         #only one slide can be added to a contribution 
    361350        return True 
    362351 
    363352    def canDelete( self, target ): 
    364         #only a slide which is already set in a contribution can be deleted 
    365353        return len(target.getMaterialList) > 0 
    366354 
    367355    def getModificationURL( self, mat ): 
    368         """returns the URL for accessing to the modification view of the  
    369             material""" 
    370         return urlHandlers.UHMaterialModification.getURL( mat ) 
    371  
    372     def create( self, target ): 
     356        """returns the URL for accessing to the modification view of the 
     357            material""" 
     358        return urlHandlers.UHMaterialModification.getURL( mat ) 
     359 
     360    def create(self, target): 
    373361        m = conference.Material() 
    374         m.setTitle(self.name) 
     362        m.setTitle(self.name.title()) 
    375363        target.addMaterial( m ) 
    376364        return m 
     365 
    377366 
    378367    @classmethod 
     
    380369        return cls(name) 
    381370 
     371 
    382372class MaterialFactoryRegistry: 
    383     """Keeps a list of material factories. When a new material type wants to be  
     373    """Keeps a list of material factories. When a new material type wants to be 
    384374        added one just needs to implement the corresponding factory and add the 
    385375        entry in the "_registry" attribute of this class 
    386376    """ 
    387     _registry = {}  
     377    _registry = {} 
    388378 
    389379    @classmethod 
    390     def getById( cls, id ): 
    391         return cls._registry.get(id.lower().strip(), DefaultMaterialFactory.getInstance(id)) 
     380    def getById( cls, matId ): 
     381        return cls._registry.get(matId, DefaultMaterialFactory.getInstance(matId)) 
    392382 
    393383    @classmethod 
    394384    def getList( cls ): 
    395385        return cls._registry.values() 
     386 
     387    @classmethod 
     388    def getIdList( cls ): 
     389        return cls._registry.keys() 
    396390 
    397391    @classmethod 
  • indico/MaKaC/webinterface/rh/conferenceBase.py

    r382574 r64729b  
    207207    _allowedMatsCategory = [ "paper", "slides", "poster", "minutes", "agenda", "video", "pictures", "text", "more information", "document", "list of actions", "drawings", "proceedings", "live broadcast" ] 
    208208 
     209    _allowedMatsEvent = { 
     210        'simple_event': [ "paper", "slides", "poster", "minutes", "agenda", "pictures", "text", "more information", "document", "list of actions", "drawings", "proceedings", "live broadcast", "video", "streaming video", "downloadable video" ], 
     211        'meeting': [ "paper", "slides", "poster", "minutes", "agenda", "video", "pictures", "text", "more information", "document", "list of actions", "drawings", "proceedings", "live broadcast" ], 
     212        'conference' : ["paper", "slides", "poster", "minutes"] 
     213        } 
     214 
    209215    def __init__(self, target, rh = None): 
    210216        self._target=target 
     
    247253        self._userList = json.decode(params.get("userList", "")) 
    248254 
    249  
    250255        if self._uploadType == "file": 
    251256            if type(params["file"]) != str and params["file"].filename.strip() != "": 
     
    253258                fDict["filePath"]=self._saveFileToTemp(params["file"].file) 
    254259 
    255                 # TODO: Check this! 
    256260                if self._callerRH != None: 
    257261                    self._callerRH._tempFilesToDelete.append(fDict["filePath"]) 
     
    286290 
    287291    def _getMaterial(self): 
    288  
    289         """ Returns the Material object to which the ressource is being submitted 
    290292        """ 
    291  
    292         mf = self._target.getMaterialRegistry().getById(self._materialId) 
    293  
    294         material = mf.get(self._target) 
    295         if material is None: 
    296             material = mf.create(self._target) 
    297  
    298         return material 
     293        Returns the Material object to which the resource is being added 
     294        """ 
     295 
     296        material = None 
     297        registry = self._target.getMaterialRegistry() 
     298 
     299        if isinstance(self._target, Category): 
     300            namedMats = RHSubmitMaterialBase._allowedMatsCategory 
     301        else: 
     302            namedMats = RHSubmitMaterialBase._allowedMatsEvent[self._target.getConference().getType()] 
     303 
     304        material = self._target.getMaterialById(self._materialId) 
     305 
     306        if material: 
     307            return material, False 
     308        # there's a defined id (not new type) 
     309        elif self._materialId: 
     310            # get a material factory for it 
     311            mf = registry.getById(self._materialId) 
     312            # get a material from the material factory 
     313            material = mf.get(self._target) 
     314 
     315            # if the factory returns an empty material (doesn't exist) 
     316            if material == None: 
     317                # create one 
     318                material = mf.create(self._target) 
     319                newlyCreated = True 
     320            else: 
     321                newlyCreated = False 
     322 
     323            return material, newlyCreated 
     324        else: 
     325            # else, something has gone wrong 
     326            raise Exception("""A material ID must be specified.""") 
     327 
     328    def _addMaterialType(self, text, user): 
     329 
     330        from MaKaC.common.PickleJar import DictPickler 
     331 
     332        Logger.get('requestHandler').debug('Adding %s - request %s ' % (self._uploadType, id(self._callerRH._req))) 
     333 
     334        mat, newlyCreated = self._getMaterial() 
     335 
     336        # if the material still doesn't exist, create it 
     337        if newlyCreated: 
     338            protectedAtResourceLevel = False 
     339        else: 
     340            protectedAtResourceLevel = True 
     341 
     342        if self._uploadType in ['file','link']: 
     343            if self._uploadType == "file": 
     344 
     345                resource = LocalFile() 
     346                resource.setFileName(self._file["fileName"]) 
     347                resource.setName(resource.getFileName()) 
     348                resource.setFilePath(self._file["filePath"]) 
     349                resource.setDescription(self._description) 
     350 
     351                if not type(self._target) is Category: 
     352                    self._target.getConference().getLogHandler().logAction({"subject":"Added file %s%s" % (self._file["fileName"],text)},"Files",user) 
     353                # in case of db conflict we do not want to send the file to conversion again, nor re-store the file 
     354 
     355            elif self._uploadType == "link": 
     356 
     357                resource = Link() 
     358                resource.setURL(self._link["url"]) 
     359                resource.setName(resource.getURL()) 
     360                resource.setDescription(self._description) 
     361 
     362                if not type(self._target) is Category: 
     363                    self._target.getConference().getLogHandler().logAction({"subject":"Added link %s%s" % (resource.getURL(),text)},"Files",user) 
     364 
     365            status = "OK" 
     366            info = resource 
     367        else: 
     368            status = "ERROR" 
     369            info = "Unknown upload type" 
     370            return mat, status, info 
     371 
     372        mat.addResource(resource, forcedFileId=self._repositoryId) 
     373 
     374        #apply conversion 
     375        if self._topdf and fileConverter.CDSConvFileConverter.hasAvailableConversionsFor(os.path.splitext(resource.getFileName())[1].strip().lower()): 
     376            Logger.get('conv').debug('Queueing %s for conversion' % resource.getFilePath()) 
     377 
     378            fileConverter.CDSConvFileConverter.convert(resource.getFilePath(), "pdf", mat) 
     379 
     380        self._topdf = False 
     381 
     382        # store the repo id, for files 
     383        if isinstance(resource, LocalFile): 
     384            self._repositoryId = resource.getRepositoryId() 
     385 
     386        if protectedAtResourceLevel: 
     387            protectedObject = resource 
     388        else: 
     389            protectedObject = mat 
     390            mat.setHidden(self._visibility) 
     391            mat.setAccessKey(self._password) 
     392 
     393        protectedObject.setProtection(self._statusSelection) 
     394 
     395        from MaKaC.user import AvatarHolder, GroupHolder 
     396 
     397        for userElement in self._userList: 
     398            if 'isGroup' in userElement and userElement['isGroup']: 
     399                avatar = GroupHolder().getById(userElement['id']) 
     400            else: 
     401                avatar = AvatarHolder().getById(userElement['id']) 
     402            protectedObject.grantAccess(avatar) 
     403 
     404        return mat, status, DictPickler.pickle(info) 
    299405 
    300406    def _process(self, rh, params): 
    301407 
    302408        # We will need to pickle the data back into JSON 
    303         from MaKaC.common.PickleJar import DictPickler 
    304409 
    305410        errorList=[] 
     
    325430 
    326431        errorList=self._getErrorList() 
    327         fDict = self._file 
    328         link = self._link 
    329432        resource = None 
    330433 
    331         Logger.get('requestHandler').debug('Adding %s - request %s ' % (self._uploadType, id(self._callerRH._req))) 
    332         if self._uploadType == "file": 
    333             if len(errorList)==0: 
    334                 mat = self._getMaterial() 
    335  
    336                 if mat == None: 
    337                     errorList.append("Unknown material"); 
    338                 else: 
    339                     mat.setProtection(self._statusSelection) 
    340                     mat.setHidden(self._visibility) 
    341                     mat.setAccessKey(self._password) 
    342                     from MaKaC.user import AvatarHolder 
    343                     ah = AvatarHolder() 
    344                     for userElement in self._userList: 
    345                         userAvatar = ah.getById(userElement['id']) 
    346                         mat.grantAccess(userAvatar) 
    347  
    348                     resource = LocalFile() 
    349                     resource.setFileName(fDict["fileName"]) 
    350                     resource.setName(resource.getFileName()) 
    351                     resource.setFilePath(fDict["filePath"]) 
    352                     resource.setDescription(self._description) 
    353                     mat.addResource(resource, forcedFileId=self._repositoryId) 
    354  
    355                     #apply conversion 
    356                     if self._topdf and fileConverter.CDSConvFileConverter.hasAvailableConversionsFor(os.path.splitext(resource.getFileName())[1].strip().lower()): 
    357                         fileConverter.CDSConvFileConverter.convert(resource.getFilePath(), "pdf", mat) 
    358                     if not type(self._target) is Category: 
    359                         self._target.getConference().getLogHandler().logAction({"subject":"Added file %s%s" % (fDict["fileName"],text)},"Files",user) 
    360                     # in case of db conflict we do not want to send the file to conversion again, nor re-store the file 
    361                     self._topdf = False 
    362                     self._repositoryId = resource.getRepositoryId() 
    363  
    364             if len(errorList) > 0: 
    365                 status = "ERROR" 
    366                 info = errorList 
    367             else: 
    368                 status = "OK" 
    369                 info = DictPickler.pickle(resource) 
     434        if len(errorList) > 0: 
     435            status = "ERROR" 
     436            info = errorList 
     437        else: 
     438            mat, status, info = self._addMaterialType(text, user) 
     439 
     440            if status == "OK": 
    370441                info['material'] = mat.getId(); 
    371  
    372         elif self._uploadType == "link": 
    373             if len(errorList)==0: 
    374                 mat = self._getMaterial() 
    375                 if mat == None: 
    376                     mat = Material() 
    377                     mat.setTitle(link["matType"]) 
    378                     self._target.addMaterial( mat ) 
    379                 else: 
    380                     mat.setProtection(self._statusSelection) 
    381                     mat.setHidden(self._visibility) 
    382                     mat.setAccessKey(self._password) 
    383                     from MaKaC.user import AvatarHolder 
    384                     ah = AvatarHolder() 
    385                     for userElement in self._userList: 
    386                         userAvatar = ah.getById(userElement['id']) 
    387                         mat.grantAccess(userAvatar) 
    388  
    389                 resource = Link() 
    390                 resource.setURL(link["url"]) 
    391                 resource.setName(resource.getURL()) 
    392                 resource.setDescription(self._description) 
    393                 mat.addResource(resource) 
    394                 if not type(self._target) is Category: 
    395                     self._target.getConference().getLogHandler().logAction({"subject":"Added link %s%s" % (resource.getURL(),text)},"Files",user) 
    396  
    397                 status = "OK" 
    398                 info = DictPickler.pickle(resource) 
    399                 info['material'] = mat.getId(); 
    400             else: 
    401                 status = "ERROR" 
    402                 info = errorList 
    403  
    404         else: 
    405             status = "ERROR" 
    406             info = "Unknown upload type" 
    407442 
    408443        # hackish, because of mime types. Konqueror, for instance, would assume text if there were no tags, 
  • indico/MaKaC/webinterface/stylesheets/include/common.xsl

    r382574 r64729b  
    128128                '<xsl:value-of select="$contId"/>', 
    129129                '<xsl:value-of select="$subContId"/>', 
    130                 Indico.Data.MaterialTypes.meeting, 
     130                <xsl:value-of select="$item/parentProtection"/>, 
     131                <xsl:value-of select="$item/materialList"/>, 
    131132                <xsl:value-of select="$uploadURL"/>, 
    132133                true, 
  • indico/MaKaC/webinterface/tpls/AdminPlugins.tpl

    r9033fd r64729b  
    101101 
    102102<script type="text/javascript"> 
    103 var tabControl = new TabWidget([ 
     103var tabList = [ 
    104104    <%= ",\n".join(['["' + plugin.getName() + '" , $E("' + plugin.getName() + 'OptionsDiv")]' for plugin in pluginList])%> 
    105 ], null, null, <%= InitialPlugin %>); 
     105] 
     106var tabControl = new TabWidget(tabList, null, null, tabList[<%= InitialPlugin %>][0]); 
    106107$E('pluginTabs').set(tabControl.draw()); 
    107108 
  • indico/MaKaC/webinterface/tpls/ShowExistingMaterial.tpl

    r382574 r64729b  
    7979<% end %> 
    8080 
    81 var matList = Indico.Data.MaterialTypes[targetType]; 
    82 var customMatList = $L(); 
     81var matList = <%= DictPickler.pickle(materialList) %> 
    8382 
    84 each(<%= jsonEncode(DictPickler.pickle(self._target.getMaterialList())) %>, function(material){ 
    85     if (!contains(matList, material.title)){ 
    86         customMatList.append(material.title); 
    87     } 
    88     }); 
    89  
    90 var mlist = new MaterialListWidget(args, matList, customMatList, uploadAction); 
     83var mlist = new MaterialListWidget(args, matList, uploadAction); 
    9184 
    9285$E('materialListPlace').set(mlist.draw()); 
  • indico/MaKaC/webinterface/tpls/js/vars.js.tpl

    r159c54 r64729b  
    119119 
    120120    Data: { 
    121         MaterialTypes: { meeting : <%= RHSubmitMaterialBase._allowedMatsForMeetings %>, 
    122         simple_event: <%= RHSubmitMaterialBase._allowedMatsForSE %>, 
    123         conference: <%= RHSubmitMaterialBase._allowedMatsConference %>, 
    124         category: <%= RHSubmitMaterialBase._allowedMatsCategory %>}, 
     121        MaterialTypes: { meeting : <%= simplejson.dumps(list((k,k.title()) for k in RHSubmitMaterialBase._allowedMatsForMeetings)) %>, 
     122        simple_event: <%= simplejson.dumps(list((k,k.title()) for k in RHSubmitMaterialBase._allowedMatsForSE)) %>, 
     123        conference: <%= simplejson.dumps(list((k,k.title()) for k in RHSubmitMaterialBase._allowedMatsConference)) %>, 
     124        category: <%= simplejson.dumps(list((k,k.title()) for k in RHSubmitMaterialBase._allowedMatsCategory)) %>}, 
    125125        WeekDays: <%= [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ] %>, 
    126126        DefaultLocation: '<%= str(Location.getDefaultLocation().friendlyName) %>', 
  • indico/MaKaC/webinterface/wcomponents.py

    rb5b87e r64729b  
    4242from MaKaC.common import Config 
    4343from MaKaC.webinterface.common.person_titles import TitlesRegistry 
    44 from MaKaC.conference import Conference 
     44from MaKaC.conference import Conference, Category 
    4545 
    4646from MaKaC.webinterface.common.timezones import TimezoneRegistry, DisplayTimezoneRegistry 
     
    55415541        self._target=target 
    55425542 
     5543        from MaKaC.webinterface.rh.conferenceBase import RHSubmitMaterialBase 
     5544        if isinstance(target, Category): 
     5545            self._allowedMats = RHSubmitMaterialBase._allowedMatsCategory 
     5546        else: 
     5547            self._allowedMats = RHSubmitMaterialBase._allowedMatsEvent[self._target.getConference().getType()] 
     5548 
     5549    # TODO: Put this out of here, and unify with outputGenerator._generateMaterialList 
     5550    # (when we have a better class hierarchy) 
     5551    def _generateMaterialList(self): 
     5552        """ 
     5553        Generates a list containing all the materials, with the 
     5554        corresponding Ids for those that already exist 
     5555        """ 
     5556 
     5557        matDict = dict((title.lower(), title) for title in self._allowedMats) 
     5558 
     5559        for material in self._target.getMaterialList(): 
     5560            title = material.getTitle().lower() 
     5561            matDict[title] = material.getId() 
     5562 
     5563        return sorted(list((matId, title.title()) for title, matId in matDict.iteritems())) 
    55435564 
    55445565    def getVars(self): 
    55455566        vars=WTemplated.getVars(self) 
     5567 
     5568        vars["materialList"] = self._generateMaterialList() 
    55465569 
    55475570        vars["materialModifHandler"] = vars.get("materialModifHandler", None) 
  • indico/htdocs/css/Default.css

    r1b3372 r64729b  
    45044504    height: 15px; 
    45054505} 
     4506div.exclusivePopup .buttonBar { 
     4507    text-align: center; 
     4508    background: #F8F8F8; 
     4509    border: 0px; 
     4510    -moz-border-radius-bottomleft: 10px; 
     4511    -webkit-border-bottom-left-radius:10px; 
     4512    -moz-border-radius-bottomright: 10px; 
     4513    -webkit-border-bottom-right-radius:10px; 
     4514    behavior: url(border-radius.htc); 
     4515    border-top: 1px solid #CCC; 
     4516    min-height: 40px; 
     4517    padding-top: 10px; 
     4518} 
     4519 
    45064520 
    45074521div.balloonPopup { 
     
    45214535    background-repeat: no-repeat; 
    45224536    background-position: 0 -19px; 
    4523 } 
     4537    opacity: 0.95; 
     4538} 
     4539 
     4540div.yellowBalloon { 
     4541    color: #000; 
     4542    border: 1px solid black; 
     4543    background-color: #ffed92; 
     4544    opacity: 0.95; 
     4545} 
     4546 
     4547div.yellowArrow { 
     4548    background: transparent url('../images/balloon_popup_arrows_yellow.png') scroll no-repeat 0 -19px; 
     4549} 
     4550 
    45244551 
    45254552div.balloonPopupCloseButton { 
     
    51625189} 
    51635190 
     5191ul.nobulletsListWrapping 
     5192{ 
     5193    position: relative; 
     5194    margin:0px; 
     5195    margin-top: 10px; 
     5196    padding-left: 0px; 
     5197    color: #777; 
     5198} 
     5199 
     5200ul.nobulletsListWrapping li 
     5201{ 
     5202    margin-top: 5px; 
     5203    overflow: visible; 
     5204    list-style-type: none; 
     5205} 
     5206 
    51645207div.FavoritePeopleListDiv { 
    51655208    margin-bottom: 10px; 
     
    56865729    border-right: 1px dotted #999; 
    56875730} 
     5731 
     5732label.normal { 
     5733    font-weight: normal; 
     5734} 
     5735 
     5736label.emphasis { 
     5737    font-weight: normal; 
     5738    font-style: italic; 
     5739} 
     5740 
     5741.smallGrey { 
     5742    margin-top: 2px; 
     5743    font-size: 9px; 
     5744    color: #777; 
     5745} 
     5746 
     5747tr.selectedItem td { 
     5748    color: #000; 
     5749} 
  • indico/htdocs/js/indico/Core/Data.js

    r62a512 r64729b  
    186186        // check if the emails given are valid and if valid separators are used 
    187187        return exists(emails.toLowerCase().match(/^(?:[ ,;]*)(?:[a-z0-9!#$%&\'*+\/=?\^_`{|}~\-]+(?:\.[a-z0-9!#$%&\'*+\/=?\^_`{|}~\-]+)*@(?:[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?)(?:[ ,;]+(?:[a-z0-9!#$%&\'*+\/=?\^_`{|}~\-]+(?:\.[a-z0-9!#$%&\'*+\/=?\^_`{|}~\-]+)*@(?:[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?))*(?:[ ,;]*)$/)); 
     188    }, 
     189    isURL: function(address) { 
     190        // thanks to Jan Goyvaerts 
     191        return exists(address.match(/^http\:\/\/(.+)$/)); 
     192    } 
     193 
     194 
     195}; 
     196 
     197Protection = { 
     198 
     199    ParentRestrictionMessages: { 
     200        '1': $T("(currently restricted to some users, but can change)"), 
     201        '-1': $T("(currently open to everyone, but can change)") }, 
     202 
     203    resolveProtection: function(resourceProtection, parentProtection) { 
     204        if (resourceProtection === 0) { 
     205            return parentProtection; 
     206        } else { 
     207            return resourceProtection; 
     208        } 
    188209    } 
    189210}; 
  • indico/htdocs/js/indico/Core/Dialogs/Popup.js

    r156de9 r64729b  
    281281); 
    282282 
     283/* ExclusivePopup with a grey bar where buttons can be put */ 
     284type("ButtonBarExclusivePopup", ["ExclusivePopup"], 
     285     { 
     286         draw: function(content, style) { 
     287 
     288             var menu = Html.div("buttonBar", this._drawButtons()); 
     289 
     290             var canvas = this.ExclusivePopup.prototype.draw.call(this, content, style); 
     291             this.container.append(menu); 
     292 
     293             return canvas; 
     294         } 
     295     }, 
     296     function(title, closeButtonHandler, printable, showPrintButton) { 
     297         this.ExclusivePopup(title, closeButtonHandler, printable, showPrintButton); 
     298     }); 
     299 
    283300type("BalloonPopup", ["PopupDialog"], { 
    284301    draw: function(x, y) { 
     
    286303 
    287304        this.closeButton = Html.div({className: 'balloonPopupCloseButton'}); 
    288         this.balloonContent = Html.div({className: 'balloonPopup'}, this.closeButton, this.content); 
    289         this.arrowDiv = Html.div({className: 'balloonPopupArrow', style: {width: this.arrowWidth, height: this.arrowHeight}}); 
     305        this.balloonContent = Html.div({className: this.balloonClass}, this.hasCloseButton ? this.closeButton : '', this.content); 
     306        this.arrowDiv = Html.div({className: this.arrowClass, style: {width: this.arrowWidth, height: this.arrowHeight}}); 
    290307        this.mainDiv = Html.div({}, this.balloonContent, this.arrowDiv); 
    291308 
     
    299316 
    300317        this.arrowDiv.dom.style.left = pixels(0); 
    301         this.closeButton.observeClick(function() {self.close();}); 
     318 
     319        if (this.hasCloseButton) { 
     320            this.closeButton.observeClick(function() {self.close();}); 
     321        } 
    302322 
    303323        return toReturn; 
     
    387407    } 
    388408    }, 
    389      function(content, triggerElement, closeHandler, nonCloseElements) { 
     409     function(content, triggerElement, closeHandler, nonCloseElements, balloonClass, arrowClass) { 
    390410         this.PopupDialog(content, triggerElement, closeHandler, nonCloseElements); 
     411 
     412         this.hasCloseButton = exists(closeHandler); 
     413 
     414         this.balloonClass = balloonClass || 'balloonPopup'; 
     415         this.arrowClass = arrowClass || 'balloonPopupArrow'; 
    391416 
    392417         // Constants 
     
    396421     } 
    397422); 
     423 
     424/** 
     425 * Utility function to display a simple notification popup. 
     426 * @param {XElement} pointElement The element that triggers the event (onClick on it will be ignored) 
     427 * @param {XElement} content Anything you want to put inside. 
     428 */ 
     429type("NotificationBalloonPopup", ["BalloonPopup"], 
     430     { 
     431     }, 
     432     function(pointElement, content) { 
     433         this.pointElement = pointElement; 
     434 
     435         var canvas = Html.div({style: 
     436                                {padding: '5px'}}, content); 
     437 
     438         this.BalloonPopup(canvas, 
     439                           pointElement, 
     440                           null, 
     441                           null, 
     442                           'balloonPopup yellowBalloon', 
     443                           'balloonPopupArrow yellowArrow'); 
     444     }); 
     445 
    398446 
    399447/** 
  • indico/htdocs/js/indico/Core/Widgets/Base.js

    r06ec19 r64729b  
    109109); 
    110110 
    111 type("TabWidget", ["Chooser", "IWidget"],{ 
     111type("TabWidget", ["IWidget"],{ 
    112112    _titleTemplate: function(text) { 
    113113        return text; 
    114114    }, 
    115115 
     116    enableTab: function(index) { 
     117        this.tabs[index].dom.style.display = 'inline'; 
     118    }, 
     119 
     120    disableTab: function(index) { 
     121        this.tabs[index].dom.style.display = 'none'; 
     122    }, 
     123 
    116124    enable: function() { 
    117125        this.disableOverlay.dom.style.display = 'none'; 
     
    120128    disable: function() { 
    121129        this.disableOverlay.dom.style.display = 'block'; 
     130    }, 
     131 
     132    _drawContent: function() { 
     133 
     134        var self = this; 
     135 
     136        try { 
     137 
     138            each(this.optionDict, 
     139                 function(value, key) { 
     140                     if (key == self.selected.get()) { 
     141                         value.dom.style.display = 'block'; 
     142                     } else { 
     143                         value.dom.style.display = 'none'; 
     144                     } 
     145                 }); 
     146 
     147        } catch(e) { 
     148            if (e == "stopDrawing") { 
     149                // Otherwise stop drawing 
     150            } 
     151        } 
    122152    }, 
    123153 
     
    210240        // this piece of code is sensitive to exceptions 
    211241        // coming from the drawing functions (for LookupTabWidget) 
    212         try { 
    213             if(dataRetrievalFunc) { 
    214                 dataRetrievalFunc.call(this); 
    215             } 
    216  
    217             // if everything goes OK, replace the canvas 
    218             this.canvas.set(Widget.block(this)); 
    219  
    220         } catch(e) { 
    221             if (e == "stopDrawing") { 
    222                 // Otherwise stop drawing 
    223             } 
    224         } 
     242        if(dataRetrievalFunc) { 
     243            dataRetrievalFunc.call(this); 
     244        } else { 
     245            each(this.optionDict, 
     246                 function(value, key) { 
     247                     self.canvas.append(value); 
     248                 }); 
     249        } 
     250 
     251        this._drawContent(); 
    225252 
    226253        var wrapperStyle = this.width?{width: pixels(this.width)}:{}; 
     
    424451 
    425452         if (!exists(initialSelection)) { 
    426              initialSelection = 0; 
     453             initialSelection = options[0][0]; 
    427454         } 
    428455 
     
    435462 
    436463             self.options.append(key); 
    437              if (value.getParent()) { 
    438                  value.getParent().dom.removeChild(value.dom); 
    439                  value.setStyle('display',''); 
    440              } 
    441464         }); 
    442465 
    443          this.selected = new WatchValue(this.options.item(initialSelection)); 
     466         this.optionDict = {}; 
     467         each(options, function(item) { 
     468             self.optionDict[item[0]] = item[1]; 
     469         }); 
     470 
     471         this.selected = new WatchValue(); 
    444472 
    445473         this.selected.observe(function(value) { 
    446              self.set(value); 
     474             self._drawContent(); 
    447475         }); 
    448476 
    449          var optionDict = {}; 
    450          each(options, function(item) { 
    451              optionDict[item[0]] = item[1]; 
    452          }); 
    453  
    454          this.Chooser(optionDict); 
    455          this.set(this.selected.get()); 
     477         this.selected.set(initialSelection); 
    456478 
    457479         this.initializeDisableOverlay(); 
     
    461483type("LookupTabWidget", ["TabWidget"], 
    462484     { 
     485         _drawContent: function() { 
     486             var self = this; 
     487 
     488             try { 
     489                 this.canvas.set(this.optionDict[self.selected.get()]()); 
     490 
     491             } catch(e) { 
     492                 if (e == "stopDrawing") { 
     493                     // Otherwise stop drawing 
     494                 } 
     495             } 
     496         }, 
     497 
    463498         draw: function() { 
    464499             return this.TabWidget.prototype.draw.call( 
    465500                 this, 
    466501                 function() { 
    467                      this.set(this.selected.get()); 
     502                     this.canvas.set(Html.div({})); 
    468503                 }); 
    469504         } 
    470505     }, 
     506 
    471507     function(options, width, height, initialSelection, extraButtons, canvas) { 
    472  
    473          var self = this; 
    474          this.width = width; 
    475          this.height = height; 
    476          this.tabs = []; 
    477          this.leftTabIndex = 0; 
    478          this.rightTabIndex = 0; 
    479          this.scrollArrows = {}; 
    480          this.scrollArrowStates = {}; 
    481          this.extraButtons = any(extraButtons, []); 
    482          this.canvas = canvas || Html.div('canvas'); 
    483  
    484          this.initializeDisableOverlay(); 
    485  
    486          if (!exists(initialSelection)) { 
    487              initialSelection = 0; 
    488          } 
    489          this.options = $L(translate(options, 
    490                                      function(value) { 
    491                                          return value[0]; 
    492                                      })); 
    493  
    494          this.selected = new WatchValue(this.options.item(initialSelection)); 
    495  
    496          this.selected.observe(function(value) { 
    497              self.set(value); 
    498          }); 
    499  
    500          var optionDict = {}; 
    501          each(options, function(item) { 
    502              optionDict[item[0]] = item[1]; 
    503          }); 
    504  
    505          this.Chooser(new Lookup(optionDict)); 
    506  
     508         this.TabWidget(options, width, height, initialSelection, extraButtons, canvas); 
    507509     } 
     510 
    508511    ); 
    509512 
     
    742745    } 
    743746    }, 
    744     function() { 
    745         this.canvas = Html.div(); 
     747    function(styleData) { 
     748        this.canvas = Html.div({style: styleData}||{}); 
    746749    } 
    747750); 
  • indico/htdocs/js/indico/Core/Widgets/Inline.js

    r382574 r64729b  
    150150 
    151151 
    152 type("RadioFieldWidget", ["InlineWidget"], 
     152type("RadioFieldWidget", ["InlineWidget", "WatchAccessor"], 
    153153     { 
    154154         draw: function() { 
    155155             var self = this; 
    156156 
    157              return $B(Html.ul(this.cssClassRadios), 
    158                        this.orderedItems, 
    159                        function(item) { 
    160                            var radio = self.radioDict[item.key]; 
    161                            radio.observeClick(function() { 
    162                                self.select(item.key); 
    163                            }); 
    164                            self.options.accessor(item.key).observe( 
    165                                function(value) { 
    166                                    radio.set(value); 
    167                                }); 
    168  
    169                            var itemContent = item.get(); 
    170  
    171                            if (itemContent.IWidget) { 
    172                                itemContent = itemContent.draw(); 
    173                            } 
    174  
    175                            // create li item, add visibility info too 
    176                            var liItem = Html.li(self.visibility.get(item.key)?{}:'disabledRadio', keys(self.radioDict).length > 1?radio:'', itemContent); 
    177                            radio.dom.disabled = !self.visibility.get(item.key); 
    178  
    179  
    180                            // observe future changes in visibility 
    181                            self.visibility.accessor(item.key).observe( 
    182                                function(value) { 
    183                                    if (!value) { 
    184                                        liItem.dom.className = 'disabledRadio'; 
    185                                        radio.dom.disabled = true; 
    186                                    } else { 
    187                                        liItem.dom.className = 'enabledRadio'; 
    188                                        radio.dom.disabled = false; 
    189                                    } 
    190                                    if (!value && radio.get()) { 
    191                                        self.selectLast(); 
    192                                    } 
    193                                }); 
    194  
    195  
    196                            return liItem; 
    197                        }); 
     157             return $B( 
     158                 Html.table( 
     159                     this.cssClassRadios, 
     160                     Html.tbody({}) 
     161                 ), 
     162                 this.orderedItems, 
     163                 function(item) { 
     164                     var radio = self.radioDict[item.key]; 
     165                     radio.observeClick(function() { 
     166                         self.select(item.key); 
     167                     }); 
     168                     self.options.accessor(item.key).observe( 
     169                         function(value) { 
     170                             radio.set(value); 
     171                             if (value) { 
     172                                 liItem.dom.className = 'selectedItem'; 
     173                             } else { 
     174                                 liItem.dom.className = ''; 
     175                             } 
     176                         }); 
     177 
     178                     var itemContent = item.get(); 
     179 
     180                     if (itemContent.IWidget) { 
     181                         itemContent = itemContent.draw(); 
     182                     } else { 
     183                         itemContent = Html.span({style:{verticalAlign: 'middle'}}, itemContent); 
     184                     } 
     185 
     186                     // create li item, add visibility info too 
     187                     var liItem = Html.tr( 
     188                         self.visibility.get(item.key) ? {} : 'disabledRadio', 
     189                         keys(self.radioDict).length > 1 ? Html.td({}, radio):'', 
     190                         Html.td( {}, itemContent )); 
     191                     radio.dom.disabled = !self.visibility.get(item.key); 
     192 
     193                     if (self.options.get(item.key)) { 
     194                         liItem.dom.className = 'selectedItem'; 
     195                     } 
     196 
     197 
     198                     // observe future changes in visibility 
     199                     self.visibility.accessor(item.key).observe( 
     200                         function(value) { 
     201                             if (!value) { 
     202                                 liItem.dom.className = 'disabledRadio'; 
     203                                 radio.dom.disabled = true; 
     204                             } else { 
     205                                 liItem.dom.className = 'enabledRadio'; 
     206                                 radio.dom.disabled = false; 
     207                             } 
     208                             if (!value && radio.get()) { 
     209                                 self.selectLast(); 
     210                             } 
     211                         }); 
     212 
     213 
     214                     return liItem; 
     215                 }); 
    198216         }, 
    199217 
     
    203221 
    204222         onSelect: function(state) { 
     223         }, 
     224 
     225         set: function(state) { 
     226             this.select(state); 
     227         }, 
     228 
     229         get: function() { 
     230             var selKey = null; 
     231 
     232             each(this.options, function(value, key){ 
     233                 if (value) { 
     234                     selKey = key; 
     235                 } 
     236             }); 
     237 
     238             return selKey; 
     239         }, 
     240 
     241         enable: function() { 
     242             each(this.radioDict, 
     243                  function(value, key) { 
     244                      value.dom.disabled = false; 
     245                  }); 
     246         }, 
     247 
     248         disable: function() { 
     249             each(this.radioDict, 
     250                  function(value, key) { 
     251                      value.dom.disabled = true; 
     252                  }); 
     253         }, 
     254 
     255         observe: function(callback) { 
     256             this.options.observe(function(value, key){ 
     257                 if (value) { 
     258                     callback(key); 
     259                 } 
     260             }); 
    205261         }, 
    206262 
     
    220276             // set every other option to false 
    221277             self.options.each(function(value, key) { 
     278 
    222279                 if (value) { 
    223280                     self.options.set(key, false); 
     
    231288 
    232289             }); 
     290 
    233291             self.options.set(state, true); 
    234292 
     
    260318     }, 
    261319 
    262      function(items, order, cssClassRadios) { 
    263          this.items = items; 
     320     function(items, cssClassRadios) { 
     321         this.items = {}; 
    264322         this.radioDict = {}; 
    265323         this.options = new WatchObject(); 
     
    272330         var name = Html.generateId(); 
    273331 
    274          // consider ordering of elements, if specified 
    275          if (order) { 
    276              this.orderedItems = $L(); 
    277              each(order, 
    278                   function(key) { 
    279                       self.orderedItems.append(new WatchPair(key, items[key])); 
    280  
    281                       // add some extra stuff, since we're in the loop 
    282                       self.visibility.set(key, true); 
    283                       self.options.set(key, false); 
    284                       self.radioDict[key] = Html.radio({'name': name}); 
    285                   }); 
    286  
    287          } else { 
    288              this.orderedItems = $L(items); 
    289          } 
     332         this.orderedItems = $L(); 
     333         each(items, 
     334              function(item) { 
     335                  var key = item[0]; 
     336                  self.items[key] = item[1]; 
     337                  self.orderedItems.append(new WatchPair(key, item[1])); 
     338 
     339                  // add some extra stuff, since we're in the loop 
     340                  self.visibility.set(key, true); 
     341                  self.options.set(key, false); 
     342                  self.radioDict[key] = Html.radio({'name': name, 
     343                                                    style: {verticalAlign: 'middle'}}); 
     344              }); 
    290345 
    291346         this.state = new Chooser(map(items, 
     
    9561011                return Html.div({}, bind.element(self.select, $L(self.types), 
    9571012                                          function(value) { 
    958                                               return Html.option({'value': value}, value); 
     1013                                              return Html.option({'value': value[0]}, value[1]); 
    9591014                                          }), 
    9601015                         " ", 
     
    9631018                         Widget.link(command(function() { 
    9641019                             chooser.set('write'); 
     1020                             self.text.dom.focus(); 
    9651021                         }, $T("other")))); 
    9661022            }, 
     
    9771033                                Widget.link(command(function() { 
    9781034                                    chooser.set('select'); 
     1035                                    self.select.dom.focus(); 
    9791036                                }, $T("select from list")))); 
    9801037            } 
     
    9881045        var self = this; 
    9891046        return self.selected; 
     1047    }, 
     1048 
     1049    set: function(value) { 
     1050        if(this.selected){ 
     1051            this.select.set(value); 
     1052        } else { 
     1053            this.text.set(value); 
     1054        } 
     1055 
     1056        each(this.observers, 
     1057             function(observer) { 
     1058                 observer(value); 
     1059             }); 
    9901060    }, 
    9911061 
     
    10001070    }, 
    10011071 
     1072    observe: function(callback) { 
     1073        var self = this; 
     1074        this.observers.push(callback); 
     1075 
     1076        this.select.observe( 
     1077            function(value) { 
     1078                if (self.selected) { 
     1079                    callback(value); 
     1080                } 
     1081            }); 
     1082 
     1083        this.text.observe( 
     1084            function(value) { 
     1085                if (!self.selected) { 
     1086                    callback(value); 
     1087                } 
     1088            }); 
     1089 
     1090    }, 
     1091 
    10021092    getSelectBox: function() { 
    10031093        return this.select; 
    10041094    } 
    10051095}, 
    1006 function(parameterManager, types){ 
    1007     //var self = this; 
    1008     this.select = Html.select({name: 'materialId', id:Html.generateId()}); 
    1009     this.text = Html.edit({name: 'materialId', id:Html.generateId()}); 
    1010     this.pm = parameterManager; 
    1011     this.types = types; 
    1012 } 
    1013 ); 
     1096     function(parameterManager, types, params){ 
     1097         params = params || {}; 
     1098 
     1099         this.select = Html.select(params); 
     1100         params.id = Html.generateId(); 
     1101         this.text = Html.edit(params); 
     1102 
     1103         this.selected = true; 
     1104         this.pm = parameterManager; 
     1105         this.types = types; 
     1106 
     1107         this.observers = []; 
     1108     } 
     1109    ); 
    10141110 
    10151111type("InlineEditWidget", ["InlineRemoteWidget"], 
  • indico/htdocs/js/indico/Legacy/Dialogs.js

    r721175 r64729b  
    121121                           $B(info.accessor('conveners'), convListWidget.getUsers()); 
    122122 
    123                            var sesType = new RadioFieldWidget({'standard':$T('Standard'),'poster':$T('Poster')},['standard','poster'],'nobulletsListInline'); 
     123                           var sesType = new RadioFieldWidget([['standard', $T('Standard')],['poster',$T('Poster')]],'nobulletsListInline'); 
     124                           $B(info.accessor('sessionType'), sesType); 
     125 
    124126                           sesType.select('standard'); 
    125                            $B(info.accessor('sessionType'), sesType.state); 
    126127 
    127128                           //Create the list of the days in which the conference is being held 
  • indico/htdocs/js/indico/Legacy/Util.js

    r0f3143 r64729b  
    491491                    error = Html.span({}, "List contains invalid e-mail address or invalid separator"); 
    492492                } 
     493                else if (dataType == 'url' && !(allowEmpty && trim(component.get()) === '') && !Util.Validation.isURL(component.get())) { 
     494                    error = Html.span({}, "Invalid URL"); 
     495                } 
    493496                else if (dataType == 'ip' && !(allowEmpty && trim(component.get()) === '') &&  !Util.Validation.isIPAddress(component.get())) { 
    494497                    error = Html.span({}, "That doesn't seem like a valid IP Address. Example of valid IP Address: 132.156.31.38"); 
     
    505508                    hasErrors = true; 
    506509 
    507                     var oList = []; 
     510                    var oList; 
    508511 
    509512                    if (component.dom.type != 'radio') { 
  • indico/htdocs/js/indico/MaterialEditor/Editor.js

    r382574 r64729b  
    1  
    2 type("AddMaterialDialog", ["ExclusivePopup"], { 
    3     _preload: [ 
    4                function(hook){ 
    5                    var self = this; 
    6                    var users = indicoSource('material.listAllowedUsers', self.args); 
    7  
    8                    users.state.observe(function(state) { 
    9                        if (state == SourceState.Loaded) { 
    10                            self.allowedUsers = users.get(); 
    11                            hook.set(true); 
    12                        } 
    13                    }); 
    14                } 
    15            ], 
     1type("AddMaterialDialog", ["ButtonBarExclusivePopup"], { 
     2 
     3    _drawButtons: function() { 
     4 
     5        var self = this; 
     6 
     7        var buttonDiv = Html.div({}, 
     8            Widget.button(command(function() { 
     9                self._upload(); 
     10            }, "Create Resource"))); 
     11 
     12        return buttonDiv; 
     13    }, 
    1614 
    1715    _iFrameLoaded : function(iframeId) { 
     
    4442    }, 
    4543 
    46     _makeProtectionRequest: function(value){ 
    47         var self = this; 
    48  
    49         self.args['matId'] = value; 
    50         var protection = indicoSource('material.getProtection', self.args); 
    51  
    52         protection.state.observe(function(state) { 
    53                     self.protectionLabel.set('statusSelection', protection); 
    54         }) 
    55     }, 
    56  
    57     _drawFileUpload: function() { 
    58         var self = this; 
    59  
    60         var pm = new IndicoUtil.parameterManager(); 
    61  
    62         var uploadType = Html.input('hidden', {name: 'uploadType'}); 
    63         var convert = Html.checkbox({}, true); 
    64         var selectorFile = new TypeSelector(pm, self.types); 
    65         var selectorF = selectorFile.draw(); 
     44    /* 
     45     * Draws a pane that switches between a URL input and a file upload dialog. 
     46     * 
     47     * pm - A parameter manager 
     48     * locationSelector - the locationSelector that will 'control' the pane 
     49     */ 
     50    _drawResourcePathPane: function(locationSelector) { 
     51 
    6652        var file = Html.input('file', {name: 'file'}); 
    67         var description = Html.textarea({name: 'description'}); 
    68         var statusSelection = Html.input('hidden', {name: 'statusSelection'}); 
    69         var visibility = Html.input('hidden', {name: 'visibility'}); 
    70         var password = Html.input('hidden', {name: 'password'}); 
    71         var userList = Html.input('hidden', {name: 'userList'}); 
    72  
    73         uploadType.set('file'); 
    74  
    75         // FIX: presentation issue 
    76         convert.dom.name = 'topdf'; 
    77  
    78         //pm.add(selectorF, 'text', false); 
    79         pm.add(file, 'text', false); 
    80         pm.add(description, 'text', true); 
    81  
    82         //make request and save it 
    83         this._makeProtectionRequest(self.args.materialIdsList.get(selectorFile.getSelectBox().get())); 
    84  
    85         selectorFile.getSelectBox().observe(function(value){ 
    86             //make request and save it 
    87             self._makeProtectionRequest(self.args.materialIdsList.get(value)); 
    88         } 
    89         ) 
     53        var url = Html.edit({name: 'url'}); 
     54        var toPDFCheckbox = Html.checkbox({name: 'topdf', style: {verticalAlign: 'middle'}}, true); 
     55 
     56        var self = this; 
     57 
     58        var resourcePathPane = new Chooser( 
     59            new Lookup({ 
     60                'local':  function() { 
     61                    self.pm.remove(url); 
     62                    return Html.div({}, 
     63                                    self.pm.add(file, 'text'), 
     64                                    Html.div({style:{marginTop: '5px'}}, 
     65                                             toPDFCheckbox, 
     66                                             Html.label({style: {verticalAlign: 'middle'}, className: 'emphasis'} 
     67                                                        , $T("Convert to PDF (when applicable)"))) 
     68                                   ); 
     69                }, 
     70                'remote': function() { 
     71                    self.pm.remove(file); 
     72                    url.set('http://'); 
     73                    url.dom.focus(); 
     74                    return Html.div({}, 
     75                                    Html.label('popUpLabel', $T("URL")), 
     76                                    self.pm.add(url, 'url'), 
     77                                    Html.div("smallGrey", "Example: http://www.example.com/YourPDFFile.pdf")); 
     78                } 
     79            })); 
     80 
     81        // whenever the user selects a different location, 
     82        // change between an http link field and an upload box. 
     83        // This could be done simply with: 
     84        // $B(resourcePathPane, locationSelector); 
     85        // but we need to change the focus too, so let's use an observer 
     86 
     87        locationSelector.observe(function(value) { 
     88            // switch to the appropriate panel 
     89            resourcePathPane.set(value); 
     90 
     91            // set the focus 
     92            if (value == 'local') { 
     93                file.dom.focus(); 
     94            } else { 
     95                url.dom.focus(); 
     96            } 
     97        }); 
     98 
     99        // change the upload type that will be sent in the request 
     100        // (bind it with the selection box) 
     101        $B(this.uploadType, 
     102           locationSelector, 
     103           { 
     104               toSource: function(value) { 
     105                   // unused; 
     106               }, 
     107               toTarget: function(value) { 
     108                   return value=='local'?'file':'link'; 
     109               } 
     110           }); 
     111 
     112        // default is 'local' (local file) 
     113        locationSelector.set('local'); 
     114 
     115        return resourcePathPane; 
     116 
     117    }, 
     118 
     119    _parentText: function(args) { 
     120        var text = null; 
     121 
     122        if (args.subContId) { 
     123            text = $T("Same people as parent Subcontribution"); 
     124        } else if (args.contribId) { 
     125            text = $T("Same people as parent Contribution"); 
     126        } else if (args.sessionId) { 
     127            text = $T("Same people as parent Session"); 
     128        } else if (args.confId) { 
     129            text = $T("Same people as parent Conference"); 
     130        } else if (args.categId) { 
     131            text = $T("Same people as parent Category"); 
     132        } 
     133 
     134        text = Html.span({}, text, " ", 
     135                         Html.span({style: {fontStyle: 'italic'}}," ", 
     136                                   Protection.ParentRestrictionMessages[args.parentProtected?1:-1])); 
     137 
     138        return text; 
     139    }, 
     140 
     141    _drawProtectionPane: function(value) { 
     142 
     143        var text = null; 
     144        var entry = this.list.get(value); 
     145        var selector = null; 
     146 
     147        // if the material is already in the tree, protection inheritance must 
     148        // be resolved 
     149        if (exists(entry)) { 
     150 
     151            this.creationMode = 'resource'; 
     152 
     153            text = Html.span({}, $T("You're adding a resource to the existing material type"), " ", Html.span({style:{fontWeight: 'bold'}}, entry.get('title')), ". ", $T("Please specify who will be able to access it.")); 
     154 
     155            // if the material is set to inherit from the parent, display it properly 
     156            // and set the inherited protection accordingly 
     157            var protection = Protection.resolveProtection( 
     158                entry.get('protection'), 
     159                entry.get('protectedOwner')?1:-1); 
     160 
     161            var inheritanceText = Html.span({style: {fontStyle: 'italic'}}, 
     162                                            Protection.ParentRestrictionMessages[protection]); 
     163 
     164 
     165            selector = new RadioFieldWidget([ 
     166                ['inherit', Html.span({}, $T("Same people as the parent material type ")+"\""+entry.get('title')+"\" ", inheritanceText)], 
     167                ['private', $T("Only me and the users I specify")], 
     168                ['public', $T("Everyone")] 
     169            ], 'nobulletsListWrapping'); 
     170 
     171 
     172        } else { 
     173 
     174            this.creationMode = 'material'; 
     175 
     176            text = $T("You're about to create a new material type. Please select who can access it."); 
     177 
     178            selector = new RadioFieldWidget([ 
     179                ['inherit', this._parentText(this.args)], 
     180                ['private', $T("Only me and the users I specify")], 
     181                ['public', $T("Everyone")] 
     182            ], 'nobulletsListWrapping'); 
     183        } 
     184 
     185        this.protectionSelector = selector; 
     186 
     187        var self = this; 
     188 
     189        this.protectionSelector.observe(function(state) { 
     190 
     191            self.userList.userList.clear(); 
     192            self.visibility.set(0); 
     193            self.password.set(''); 
     194 
     195            // if 'private' is chosen or 'inherit' was chosen 
     196            // and the parent resource is protected 
     197            if (state == 'private') { 
     198                self.tabWidget.enableTab(1); 
     199 
     200                // depending on whether we're creating a new 
     201                // material or just a result, we will enable/disable 
     202                // visibility and access key 
     203                if (self.creationMode == 'material') { 
     204                    self.visibility.enable(); 
     205                    self.password.enable(); 
     206                } else { 
     207                    self.visibility.disable(); 
     208                    self.password.disable(); 
     209                } 
     210 
     211                // draw a little notification saying that 
     212                // the added tab can be used 
     213                self.notification  = new NotificationBalloonPopup( 
     214                    selector.radioDict[state], 
     215                    Html.div({style:{width: '120px'}}, $T("You can specify users using this tab"))); 
     216 
     217                var pos = self.tabWidget.tabs[1].getAbsolutePosition(); 
     218 
     219                // open it, pointing to tab 
     220                self.notification.open(pos.x + self.tabWidget.tabs[1].dom.offsetWidth/2, pos.y); 
     221 
     222            } else { 
     223                self.tabWidget.disableTab(1); 
     224            } 
     225 
     226            // set the appropriate data structure behind the scenes 
     227            self.protectionStatus.set('statusSelection', 
     228                                      {'private': 1, 
     229                                       'inherit': 0, 
     230                                       'public': -1}[state]); 
     231        }); 
     232 
     233        // set protection default to 'inherit' 
     234        if (this.tabWidget) { 
     235            this.protectionSelector.set('inherit'); 
     236        } 
     237 
     238        return Html.div({style:{marginTop: '10px', 
     239                                height: '150px' 
     240                               }}, 
     241                        Html.div({style: {textAlign: 'center', fontStyle: 'italic', color: '#881122'}}, 
     242                                 $T(text)), 
     243                        Html.div({style: {marginTop: '10px'}}, 
     244                                 selector ? selector.draw() : '')); 
     245    }, 
     246 
     247    _drawUpload: function() { 
     248 
     249        var self = this; 
     250 
     251        this.pm = new IndicoUtil.parameterManager(); 
     252        var typeSelector = new TypeSelector(this.pm, this.types, {style:{width: '150px'}}); 
     253        var description = Html.textarea({name: 'description', style:{width:'220px', height: '60px'}}); 
     254 
     255        // local file vs. url 
     256        var locationSelector = new RadioFieldWidget([['local',$T('Local file')],['remote',$T('External resource (hyperlink)')]]); 
     257 
     258        // draw the resource pane 
     259        var resourcePathPane = this._drawResourcePathPane(locationSelector); 
     260        // protection page 
     261        var protectionPane = $B( 
     262            Html.div({}), 
     263            typeSelector, 
     264            function(value) { 
     265                return self._drawProtectionPane(value); 
     266            }); 
     267 
     268        // make typeSelector available to the object 
     269        this.typeSelector = typeSelector; 
    90270 
    91271        return Html.div({}, 
    92272                        IndicoUtil.createFormFromMap( 
    93273                            [ 
    94                                 [$T('Type'), selectorF], 
    95                                 [$T('File'), file], 
    96                                 [$T('Description'), description], 
    97                                 [$T('Convert to PDF'), convert] 
     274                                [ 
     275                                    $T('Location'), 
     276                                    Html.div({}, 
     277                                             locationSelector.draw(), 
     278                                             Html.div({style:{paddingTop: '15px', 
     279                                                              paddingBottom: '10px', 
     280                                                              minHeight: '50px'}}, 
     281                                                      Widget.block(resourcePathPane))) 
     282                                ], 
     283                                [ 
     284                                    $T('Description'), 
     285                                    description 
     286                                ], 
     287                                [ 
     288                                    $T('Material type'), 
     289                                    typeSelector.draw() 
     290                                ] 
     291 
    98292                            ]), 
    99                         uploadType, 
    100                         statusSelection, 
    101                         visibility, 
    102                         password, 
    103                         userList, 
    104                         Html.div({style: {'textAlign': 'center'}}, 
    105                                  Widget.button(command( 
    106                                      function() { 
    107                                          if (pm.check()) { 
    108                                              self.killProgress = IndicoUI.Dialogs.Util.progress($T('Uploading...')); 
    109                                              self.uploading = true; 
    110  
    111                                              userList.set(Json.write(self.userList.getUsers())); 
    112                                              statusSelection.set(self.protectionLabel.get('statusSelection').get()); 
    113                                              visibility.set(self.protectionLabel.get('visibility')); 
    114                                              password.set(self.protectionLabel.get('password')); 
    115                                              self.form.dom.submit(); 
    116  
    117                                              //if we are adding a custom type and it's not in the list already, then we add it 
    118                                              if(!selectorFile.isSelect() && !contains(self.types, selectorFile.get())){ 
    119                                                  self.customTypes.append(selectorFile.get()); 
    120                                              } 
    121                                          } 
    122                                      }, $T("Upload"))))); 
    123     }, 
    124  
    125     _drawLinkUpload: function() { 
    126         var self = this; 
    127  
    128         var pm = new IndicoUtil.parameterManager(); 
    129  
    130         var uploadType = Html.input('hidden', {name: 'uploadType'}); 
    131         var selectorLink = new TypeSelector(pm, self.types); 
    132         var selectorL = selectorLink.draw(); 
    133         var url = Html.edit({name: 'url'}); 
    134         var description = Html.textarea({name: 'description'}); 
    135         var statusSelection = Html.input('hidden', {name: 'statusSelection'}); 
    136         var visibility = Html.input('hidden', {name: 'visibility'}); 
    137         var password = Html.input('hidden', {name: 'password'}); 
    138         var userList = Html.input('hidden', {name: 'userList'}); 
    139  
    140         uploadType.set('link'); 
    141  
    142         //pm.add(selectorL, 'text', false); 
    143         pm.add(url, 'text', false); 
    144         pm.add(description, 'text', true); 
    145  
    146         //make request and save it 
    147         this._makeProtectionRequest(self.args.materialIdsList.get(selectorLink.getSelectBox().get())); 
    148  
    149         selectorLink.getSelectBox().observe(function(value){ 
    150             //make request and save it 
    151             self._makeProtectionRequest(self.args.materialIdsList.get(value)); 
    152         } 
    153         ) 
    154  
    155         return Html.div({}, 
    156                         IndicoUtil.createFormFromMap( 
    157                             [ 
    158                                 [$T('Type'),selectorL], 
    159                                 [$T('URL'), url], 
    160                                 [$T('Description'), description] 
    161                             ]), 
    162                         uploadType, 
    163                         statusSelection, 
    164                         visibility, 
    165                         password, 
    166                         userList, 
    167                         Html.div({style: {'textAlign': 'center'}}, 
    168                                  Widget.button(command( 
    169                                      function() { 
    170                                          if (pm.check()) { 
    171                                              self.killProgress = IndicoUI.Dialogs.Util.progress(); 
    172                                              self.uploading = true; 
    173  
    174                                              userList.set(Json.write(self.userList.getUsers())); 
    175                                              statusSelection.set(self.protectionLabel.get('statusSelection').get()); 
    176                                              visibility.set(self.protectionLabel.get('visibility')); 
    177                                              password.set(self.protectionLabel.get('password')); 
    178                                              self.form.dom.submit(); 
    179  
    180                                              //if we are adding a custom type and it's not in the list already, then we add it 
    181                                              if(!selectorLink.isSelect() && !contains(self.types, selectorLink.get())){ 
    182                                                  self.customTypes.append(selectorLink.get()); 
    183                                              } 
    184                                          } 
    185                                      }, $T("Upload"))))); 
    186     }, 
     293                        protectionPane); 
     294 
     295   }, 
     296 
     297    _upload: function() { 
     298 
     299        var check = this.pm.check(); 
     300 
     301        if (check) { 
     302            this.killProgress = IndicoUI.Dialogs.Util.progress(); 
     303 
     304            this.uploading = true; 
     305 
     306            this.formDict.userList.set(Json.write(this.userList.getUsers())); 
     307 
     308            this.formDict.statusSelection.set(this.protectionStatus.get('statusSelection')); 
     309 
     310            this.formDict.visibility.set(this.protectionStatus.get('visibility')); 
     311            this.formDict.password.set(this.protectionStatus.get('password')); 
     312            this.formDict.uploadType.set(this.uploadType.get()); 
     313 
     314            // depending on whether we are selecting a material from the list 
     315            // or adding a new one, we'll send either an id or a name 
     316 
     317            this.formDict.materialId.set(this.typeSelector.get()); 
     318 
     319            this.form.dom.submit(); 
     320 
     321        } 
     322    }, 
     323 
    187324 
    188325    _drawWidget: function() { 
    189326        var self = this; 
    190327 
     328        this.formDict = {}; 
    191329        this.frameId = Html.generateId(); 
    192330 
     
    203341            this.tabWidget.draw()); 
    204342 
     343        each(['statusSelection', 'visibility', 'password', 'userList', 'uploadType', 'materialId'], 
     344             function(fieldName) { 
     345                 var elem = Html.input('hidden', {name: fieldName}); 
     346                 self.formDict[fieldName] = elem; 
     347                 self.form.append(elem); 
     348             }); 
     349 
    205350        var loadFunc = function() { 
    206351            if (self.uploading) { 
     
    213358 
    214359        if (Browser.IE) { 
    215             // cof! cof! 
    216360            iframe.dom.onreadystatechange = loadFunc; 
    217361        } else { 
     
    224368        }); 
    225369 
    226         return Html.div({}, this.form, iframe); 
    227  
    228     }, 
    229  
    230     draw: function() { 
    231         var self = this; 
    232  
    233         self.newMaterial = $O(); 
    234  
    235         var visibility = Html.select( 
    236                 {}, 
    237                 Html.option({value: 0},$T('Visible for unauth. users')), 
    238                 Html.option({value: 1},$T('Hidden from unauth. users')) 
    239             ); 
    240  
    241         var password = Html.input('password',{}); 
    242  
    243         self.userList =  new UserListField('ShortPeopleListDiv', 
     370        return Html.div({}, 
     371                        this.form, 
     372                        iframe); 
     373 
     374    }, 
     375 
     376    postDraw: function() { 
     377 
     378        var selection = "slides"; 
     379 
     380        // We're not sure that the type "Slides" 
     381        // will have a "standard" id 
     382        for (i in this.types) { 
     383            if (this.types[i][1] == "Slides") { 
     384                selection = this.types[i][0]; 
     385            } 
     386        } 
     387 
     388        this.typeSelector.set(selection); 
     389        this.ButtonBarExclusivePopup.prototype.postDraw.call(this); 
     390    }, 
     391 
     392    _drawProtectionDiv: function() { 
     393        this.visibility = new RadioFieldWidget([ 
     394            [0, Html.span({}, $T("This resource is visible to everyone"))], 
     395            [1, $T("Only people who can access the resource can see it")]]); 
     396 
     397        this.password = Html.input('password',{}); 
     398 
     399        this.userList =  new UserListField('ShortPeopleListDiv', 
    244400                'PluginPeopleList', 
    245                 self.allowedUsers, 
     401                this.allowedUsers, 
    246402                null, 
    247403                null, 
     
    249405                userListNothing, userListNothing, userListNothing, true); 
    250406 
    251         self.privateInfoDiv = Html.div( 
    252                 {style:{padding:pixels(2)}}, 
    253                 Html.div({}, 
    254                          Html.label({}, $T('Allowed users')), 
    255                          self.userList.draw()), 
    256                 Html.div({style:{marginTop: pixels(8)}}, 
    257                          Html.label({}, $T('Visibility: ')), 
    258                          visibility), 
    259                 Html.div({style:{marginTop: pixels(5)}}, 
    260                          Html.label({}, $T('Access Key: ')), 
    261                          password) 
    262             ); 
    263  
    264         var statusSelection = Widget.select( 
    265                 $L({ 
    266                     0:(self.args.parentProtected?$T('Private'):$T('Public'))+' '+$T('(from parent)'), 
    267                     1:$T('Private (by itself)'), 
    268                     '-1':$T('Public (by itself)') 
    269                 }) 
    270             ); 
    271  
    272         self.protectionLabel.accessor("statusSelection").observe(function(value) { 
    273                 if (value.get() == 0 && self.args.parentProtected || value.get() == 1) { 
    274                     self.privateInfoDiv.show(); 
    275                 } 
    276                 else { 
    277                     self.privateInfoDiv.hide(); 
    278                 } 
    279         }); 
    280  
    281         $B(statusSelection, self.protectionLabel.accessor("statusSelection")); 
    282         $B(self.protectionLabel.accessor("visibility"), visibility); 
    283         $B(self.protectionLabel.accessor("password"), password); 
    284  
    285  
    286         if ( !self.args.parentProtected) 
    287             self.privateInfoDiv.hide(); 
    288  
    289         var protectionDiv = Html.div( 
    290                 {style: {marginTop: pixels(5)}}, 
    291                 Html.div({}, 
    292                          Html.label({},$T("Status: ")), 
    293                          statusSelection 
    294                         ), 
    295                 self.privateInfoDiv); 
    296  
    297         this.tabWidget = new TabWidget([[$T('Upload File'), this._drawFileUpload()], 
    298                                         [$T('Add Link'), this._drawLinkUpload()], 
    299                                         [$T("Protection")   , protectionDiv]], 
     407        // Bind fields to data structure 
     408        $B(this.protectionStatus.accessor('visibility'), this.visibility); 
     409        $B(this.protectionStatus.accessor('password'), this.password); 
     410 
     411        this.visibility.set(0); 
     412        this.password.set(''); 
     413 
     414        var privateInfoDiv = IndicoUtil.createFormFromMap( 
     415                            [ 
     416                                [ 
     417                                    $T('Allowed users and groups'), 
     418                                    this.userList.draw() 
     419                                ], 
     420                                [ 
     421                                    $T('Visibility'), 
     422                                    this.visibility.draw() 
     423                                ], 
     424                                [ 
     425                                    $T('Access key'), 
     426                                    this.password 
     427                                ] 
     428                            ]); 
     429 
     430        return privateInfoDiv; 
     431    }, 
     432 
     433    draw: function() { 
     434        var self = this; 
     435 
     436        self.newMaterial = $O(); 
     437 
     438        var protectionDiv = this._drawProtectionDiv(); 
     439 
     440        this.tabWidget = new TabWidget([[$T('Upload'), this._drawUpload()], 
     441                                        [$T("Protection"), protectionDiv]], 
    300442                                       400, 300); 
    301443 
    302         return this.ExclusivePopup.prototype.draw.call(this, 
     444        return this.ButtonBarExclusivePopup.prototype.draw.call(this, 
    303445                                                       this._drawWidget()); 
    304     }, 
    305  
    306  
    307 }, function(args, list, types, customTypes, uploadAction, onUpload) { 
     446    } 
     447 
     448 
     449}, function(args, list, types, uploadAction, onUpload) { 
     450 
    308451    var self = this; 
    309452    this.list = list; 
    310     this.customTypes = customTypes; 
    311     this.types = $L(concat(types, customTypes.allItems())); 
     453    this.types = types; 
    312454    this.uploadAction = uploadAction; 
    313455    this.uploading = false; 
     
    317459//    this.args.materialId = material; 
    318460 
    319     this.protectionLabel = $O(); 
    320  
    321     this.ExclusivePopup($T("Upload Material"), 
     461    this.protectionStatus = $O(); 
     462    this.uploadType = new WatchValue(); 
     463 
     464    this.ButtonBarExclusivePopup($T("Upload Material"), 
    322465                        function() { 
    323466                            self.close(); 
     
    345488        params.materialInfo = this.newMaterial; 
    346489        this.newMaterial.set('userList', this.userList.getUsers()); 
     490 
     491        // get a list of material titles 
     492        var matTitles = translate(this.list, 
     493            function(mat){ 
     494                return mat.get('title'); 
     495            }); 
     496 
     497        // look for one with the same name 
     498        var i = -1; 
     499        for (var j in matTitles) { 
     500            if (matTitles[i] == params.materialInfo.get('title')) { 
     501                i = j; 
     502            } 
     503        } 
     504 
     505        if (i < 0) { 
     506            this.types.push([params.materialInfo.get('id'), params.materialInfo.get('title')]); 
     507        } 
     508 
    347509        this.request(params); 
    348  
    349         if(this.customTypes.indexOf(this.material.title.get()) != null){ 
    350             //it was in the custom types list, so we just change its name 
    351             this.customTypes.remove(this.material.title.get()); 
    352             this.customTypes.append(params.materialInfo.get('title')); 
    353         } 
    354         else{ 
    355             //it was a predefined material, so we add the new one 
    356             this.customTypes.append(params.materialInfo.get('title')); 
    357         } 
    358510    }, 
    359511 
     
    377529 
    378530        statusSelection.observe(function(value) { 
    379             if (value === 0 && self.material.get('protectedOwner') || 
     531            if (value == 0 && self.material.get('protectedOwner') || 
    380532                value == 1) { 
    381533                self.privateInfoDiv.show(); 
     
    414566                        self.newMaterial.accessor('accessKey'))) 
    415567        ); 
    416         if ( !self.material.get('protectedOwner')) 
     568        if ( !self.material.get('protectedOwner')) { 
    417569            self.privateInfoDiv.hide(); 
     570        } 
    418571 
    419572        var protectionDiv = Html.div( 
     
    430583        var description = Html.textarea({name:'description',style: {width: '250px'}}); 
    431584        var descDiv = Widget.block([Widget.block(Html.label({},"Description: ")),description]); 
     585 
    432586        var buttonDiv = Widget.block([ 
    433587            Widget.button(command(function() { 
     
    442596        $B(description, self.newMaterial.accessor('description')); 
    443597 
     598        statusSelection.notifyObservers(); 
     599 
    444600        var tabControl = new TabWidget([ 
    445601            [$T("Information"), Widget.block([titleDiv,descDiv])], 
    446             [$T("Protection") , protectionDiv]], 300,300, 0); 
     602            [$T("Protection") , protectionDiv]], 300,300); 
    447603 
    448604        return this.ExclusivePopup.prototype.draw.call( 
     
    454610}, 
    455611 
    456      function(args, material, list, customTypes, title) { 
     612     function(args, types, material, list, title) { 
    457613         this.material = material; 
    458614         this.materialId = this.material.get('id'); 
     615         this.types = types; 
    459616         this.list = list; 
    460          this.customTypes = customTypes; 
    461617 
    462618         args = clone(args); 
     
    553709            ); 
    554710 
    555             statusSelection.observe(function(value) { 
    556                 if (value == 0 && isFatherProtected || value == 1) { 
    557                     self.privateInfoDiv.show(); 
    558                 } 
    559                 else { 
    560                     self.privateInfoDiv.hide(); 
    561                 } 
    562             }); 
     711        statusSelection.observe(function(value) { 
     712 
     713            if (value == 0 && isFatherProtected || value == 1) { 
     714                self.privateInfoDiv.show(); 
     715            } 
     716            else { 
     717                self.privateInfoDiv.hide(); 
     718            } 
     719        }); 
    563720 
    564721        self.privateInfoDiv = Html.div( 
     
    567724                     Html.label({}, $T('Allowed users')), 
    568725                     self.userList.draw())); 
    569         if ( !isFatherProtected) 
     726 
     727        if ( !isFatherProtected) { 
    570728            self.privateInfoDiv.hide(); 
    571  
     729        } 
    572730 
    573731        var protectionDiv = Html.div( 
     
    580738        var tabControl = new TabWidget([ 
    581739            [$T("Information"), Widget.block([nameDiv,this.resource.type=='stored'?[]:urlDiv,descDiv])], 
    582             [$T("Protection")   , protectionDiv]], 300,200, 0); 
     740            [$T("Protection")   , protectionDiv]], 300,200); 
    583741        tabControl.options = $L([$T("Information"), $T("Protection")]); 
    584742        tabControl.selected.set($T("Information")); 
     743 
     744        statusSelection.notifyObservers(); 
     745 
    585746 
    586747        return this.ExclusivePopup.prototype.draw.call( 
     
    686847                                self.set(resourceId, null); 
    687848                                //if it's in the custom material list and it's the last resource in it, we delete it 
    688                                 self.customTypes.remove(self.materialName); 
    689849                                killProgress(); 
    690850                            } 
     
    763923    } 
    764924 
    765 }, function(resources, matParams, customTypes, materialTitle) { 
     925}, function(resources, matParams, materialTitle) { 
    766926    this.matParams = matParams; 
    767927    this.resources = resources; 
    768     this.customTypes = customTypes; 
    769928    this.materialName = materialTitle; 
    770929    this.ListWidget(); 
     
    819978                                self.set(materialId, null); 
    820979                                //if it's in the custom material list, we delete it 
    821                                 self.customTypes.remove(material.get('title')); 
    822980                                killProgress(); 
    823981                            } 
     
    8461004                        IndicoUI.Dialogs.Material.editMaterial( 
    8471005                            self.args, 
     1006                            self.types, 
    8481007                            material, 
    849                             self.customTypes, 
    8501008                            self); 
    8511009                    }, 
     
    8701028        } 
    8711029 
    872         args['materialProtection'] = material.get('protection'); 
    873         var matWidget = new ResourceListWidget(material.get('resources'), args, self.customTypes, material.get('title')); 
     1030        args.materialProtection = material.get('protection'); 
     1031        var matWidget = new ResourceListWidget(material.get('resources'), args, material.get('title')); 
    8741032 
    8751033        // check whenever a material gets empty (no resources) and delete it 
     
    9371095    }, 
    9381096 
     1097    _updateMaterialList: function(material) { 
     1098        // add type to custom list, if not there 
     1099        var i = -1; 
     1100 
     1101        for (var j in this.types) { 
     1102            if (this.types[i][1] == material.get('title')) { 
     1103                i = j; 
     1104                break; 
     1105            } 
     1106        } 
     1107 
     1108        var newElement = [material.get('id'), material.get('title')]; 
     1109 
     1110        if (i >= 0) { 
     1111            this.types[i] = newElement; 
     1112        } else { 
     1113            this.types.push(newElement); 
     1114        } 
     1115    }, 
     1116 
    9391117    _loadMaterial: function(id) { 
    9401118        var self = this; 
     
    9461124 
    9471125        source.state.observe(function(state) { 
     1126 
    9481127            if (state == SourceState.Loaded) { 
    9491128                var material = $O($O(source).getAll()); 
     
    9541133                         material); 
    9551134 
     1135                self._updateMaterialList(material); 
    9561136 
    9571137            } 
     
    9681148        }); 
    9691149 
     1150        var materialLoadFunction = function(info) { 
     1151            if (self.get(info.material)) { 
     1152                self.get(info.material).get('resources').append(watchize(info)); 
     1153            } else { 
     1154                self._loadMaterial(info.material); 
     1155            } 
     1156        }; 
     1157 
    9701158        var link = Widget.link(command(function(){ 
    9711159 
     
    9731161                                          self, 
    9741162                                          self.types, 
    975                                           self.customTypes, 
    9761163                                          self.uploadAction, 
    977                                           function(info) { 
    978                                               if (self.get(info.material)) { 
    979                                                   self.get(info.material).get('resources').append(watchize(info)); 
    980                                               } else { 
    981                                                   self._loadMaterial(info.material); 
    982                                               } 
    983                                           }); 
     1164                                          materialLoadFunction); 
    9841165        }, $T("Add Material"))); 
    9851166        return Html.div( 
     
    9921173}, 
    9931174 
    994      function(args, types, customTypes, uploadAction, width, height) { 
     1175     function(args, types, uploadAction, width, height) { 
    9951176         var self = this; 
    9961177         this.width = width; 
     
    9981179         this.args = args; 
    9991180         this.types = types; 
    1000          this.customTypes = customTypes; 
    10011181         this.uploadAction = uploadAction; 
    10021182         this.ListWidget("materialList"); 
     
    10071187); 
    10081188 
    1009 type("MaterialEditorDialog", ["ExclusivePopup"], { 
     1189type("MaterialEditorDialog", ["ButtonBarExclusivePopup"], { 
     1190 
     1191    _drawButtons: function() { 
     1192 
     1193        var self = this; 
     1194        var buttonDiv = Html.div({}, 
     1195            Widget.button(command(function() { 
     1196                self.close(); 
     1197                window.location.reload(true); 
     1198            }, $T("Close")))); 
     1199 
     1200        return buttonDiv; 
     1201    }, 
     1202 
     1203 
    10101204    draw: function() { 
    10111205        var self = this; 
     
    10171211            'sessionId': intToStr(this.sessId), 
    10181212            'contribId': intToStr(this.contId), 
    1019             'subContId': intToStr(this.subContId) 
     1213            'subContId': intToStr(this.subContId), 
     1214            'parentProtected': this.parentProtected 
    10201215        }; 
    10211216 
     
    10271222        }); 
    10281223 
    1029         var mlist = new MaterialListWidget(args, this.types, this.customTypes, this.uploadAction, this.width, this.height); 
    1030  
    1031         return this.ExclusivePopup.prototype.draw.call( 
     1224        var mlist = new MaterialListWidget(args, this.types, this.uploadAction, this.width, this.height); 
     1225 
     1226        return this.ButtonBarExclusivePopup.prototype.draw.call( 
    10321227            this, 
    10331228            Html.div({style: {width: pixels(this.width), 
    10341229                              height: pixels(this.height+50)}}, 
    1035                      mlist.draw(), 
    1036                      Widget.button(command(function() { 
    1037                          self.close(); 
    1038                          window.location.reload(true); 
    1039                      }, $T("Close"))))); 
     1230                     mlist.draw())); 
    10401231    } 
    10411232}, 
    10421233 
    1043      function(confId, sessId, contId, subContId, types, uploadAction, title, width, height, refresh, customTypes) { 
     1234     function(confId, sessId, contId, subContId, parentProtected, types, uploadAction, title, width, height, refresh) { 
    10441235         this.confId = confId; 
    10451236         this.sessId = sessId; 
     
    10471238         this.subContId = subContId; 
    10481239         this.types = types; 
    1049          this.customTypes = customTypes; 
    10501240         this.uploadAction = uploadAction; 
    10511241         this.width = width; 
    10521242         this.height = height; 
    10531243         this.refresh = refresh; 
    1054          this.ExclusivePopup(title); 
     1244         this.parentProtected = parentProtected; 
     1245         this.ButtonBarExclusivePopup(title); 
    10551246     }); 
    10561247 
    10571248IndicoUI.Dialogs.Material = { 
    10581249 
    1059     add: function(args, list, types, customTypes, uploadAction, onUpload) { 
    1060         var dialog = new AddMaterialDialog(args, list, types, customTypes, uploadAction, onUpload); 
     1250    add: function(args, list, types, uploadAction, onUpload) { 
     1251        var dialog = new AddMaterialDialog(args, list, types, uploadAction, onUpload); 
    10611252        dialog.open(); 
    10621253    }, 
    1063     editMaterial: function(args, material, customTypes, list) { 
    1064         var dialog = new EditMaterialDialog(args, material, list, customTypes, $T("Edit Material")); 
     1254    editMaterial: function(args, types, material, list) { 
     1255        var dialog = new EditMaterialDialog(args, types, material, list, $T("Edit Material")); 
    10651256        dialog.execute(); 
    10661257    }, 
     
    10711262    }, 
    10721263 
    1073     editor: function(confId, sessId, contId, subContId, types, uploadAction, refresh, customTypes) { 
    1074         var dialog = new MaterialEditorDialog(confId, sessId, contId, subContId, types, uploadAction, $T("Edit Materials"), 400, 300, refresh, customTypes); 
     1264    editor: function(confId, sessId, contId, subContId, parentProtected, types, uploadAction, refresh) { 
     1265        var dialog = new MaterialEditorDialog(confId, sessId, contId, subContId, parentProtected, types, uploadAction, $T("Edit Materials"), 400, 300, refresh); 
    10751266        dialog.open(); 
    10761267    } 
  • indico/htdocs/js/indico/Timetable/Base.js

    r68f9a3 r64729b  
    300300 
    301301    _followArgs_interval: function(hash, data) { 
     302 
    302303        var m = hash.match(/#(\d{8})(?:\.(s\d+l\d+))?/); 
    303304 
    304305        if (m) { 
    305  
    306             this.currentDay = m[1]; 
    307306 
    308307            if (m[2]) { 
     
    319318        var m = hash.match(/#(\d{8}|all)(?:\.(s\d+l\d+))?/); 
    320319 
    321         if (m) { 
    322  
    323             this.currentDay = m[1]; 
    324  
    325             var tab = 0; 
    326  
    327             for (k in this.sortedKeys) { 
    328                 if (this.sortedKeys[k] == this.currentDay) { 
    329                     return tab; 
    330                 } 
    331                 tab++; 
    332             } 
    333             return -1; 
    334         } 
     320        var currentDay = m ? m[1] : null; 
     321 
     322        return exists(data[currentDay]) ? currentDay : null; 
    335323    }, 
    336324 
     
    364352    switchToTopLevel : function() { 
    365353        this.enable(); 
    366         this.set(this.currentDay); 
    367         this.canvas.set(Widget.block(this)); 
     354        this.setSelectedTab(this.currentDay); 
     355        this._drawContent(); 
    368356        this.menu.dom.style.display = 'block'; 
    369357        this.timetableDrawer.redraw(); 
     
    396384         var todayStr = IndicoUtil.formatDate2(today); 
    397385 
     386         var originalHash = window.location.hash; 
     387 
    398388         // parse "command line" arguments 
    399          var initialTab = this._followArgs_day(window.location.hash, data); 
     389         var initialTab = this._followArgs_day(originalHash, data); 
    400390 
    401391         // if nothing is found 
    402          if (initialTab == -1) { 
     392         if (initialTab === null) { 
    403393             // look for today 
    404              while (exists(data[todayStr])) { 
    405                  today.setDate(today.getDate()-1); 
    406                  todayStr = IndicoUtil.formatDate2(today); 
    407                  initialTab++; 
     394             if (exists(data[todayStr])) { 
     395                 initialTab = todayStr; 
     396             } else { 
     397                 // otherwise use the default 
     398                 initialTab = keys(data)[0]; 
    408399             } 
    409400         } 
    410401 
    411          // if today not found, set initial tab to the first one 
    412          if (initialTab == -1) { 
    413              initialTab = 0; 
    414          } 
     402         this.currentDay = initialTab; 
    415403 
    416404         this.LookupTabWidget( translate(this.sortedKeys, function(key) { 
     405 
    417406             return [key, function() { 
    418407                 self.currentDay = key; 
     
    437426         }), this.width, 100, initialTab, this._functionButtons(), this.canvas); 
    438427 
    439          this._followArgs_interval(window.location.hash, data); 
     428         this._followArgs_interval(originalHash, data); 
    440429 
    441430     }); 
     
    715704 
    716705    _retrieveHistoryState: function(hash) { 
    717         this._followArgs_day(hash, this.data); 
    718         this.setSelectedTab(this.currentDay); 
     706        var currentDay = this._followArgs_day(hash, this.data); 
     707        this.setSelectedTab(currentDay); 
    719708    } 
    720709 
     
    861850 
    862851    _retrieveHistoryState: function(hash) { 
    863         this._followArgs_day(hash, this.data); 
     852        var currentDay = this._followArgs_day(hash, this.data) || keys(this.data)[0]; 
    864853        if (!this._followArgs_interval(hash, this.data)) { 
    865854            this.switchToTopLevel(); 
    866             this.setSelectedTab(this.currentDay); 
     855            this.setSelectedTab(currentDay); 
    867856        } 
    868857    } 
Note: See TracChangeset for help on using the changeset viewer.