开发者

Dojo widget controller

I am working on a new project and have been trying to get a JS controller to decide which dojo widgets are needed for any particular page.

I have this working, but only when I inject / hardcode the dojo widget's JS into the page. As soon as I try to get it working with dojo's provide and require mechanisms, everything stops working and I get the following error:

Could not load 'pf.PasswordStrength'; last tried '../dojop开发者_开发百科f/widget/PasswordStrength.js'
http://pf-dev-ad/wcsstore/js/dojo131/dojo/dojo.js
Line 16

Firebug shows this error right after it includes the file!

I am having real problems with this as dojo 1.3.1 (which I'm not allowed to upgrade) is very poorly documented and there aren't many tutorials.

The requirement is as follows:

  • 1 site-wide JS controller (lib.js)
  • 1 widget specific JS file (PasswordStrength.js)
  • 1 widget template file (PasswordStrength.html)
  • 1 pointer node

The file structre is setup as follows:

js
  dojo131
    dijit
    dojo
    dojotest
        widget
            templates
                PasswordStrength.html
                PasswordStrength.css
            PasswordStrength.js
    dojox

//JS controller (lib.js):

if(!ad){ var ad = {} }

ad.base = new (function(){
    // init function will run on page load. Called by dojo.addOnLoad
    this.init = function (){
        /* This function acts as a controller for Dojo widgets.
        // it uses a variable ('pageName') set by the JSTL in the parent JSP of a particular page

        switch(ad.pageName){
            case 'Home':            
                _getTemplateAssets('PasswordStrength');
                break;
        }

    }

    var $ = dojo.query;
    var templatePath = 'js/dojo131/dojotest/widget';
    var debug = false; // This should be set to false when on production

    /*** PRIVATE FUNCTIONS ***/ 
    function _getTemplateAssets(templateName){
        // Injects the JS and CSS template assets into the page head

        dojo.registerModulePath("ad", '../dojotest/widget'); // relative to dojo.js
        //dojo.provide('ad.' + templateName);
        dojo.require('ad.' + templateName);

        //var headTag = document.getElementsByTagName('head').item(0);
        //dojo.create("script", { src: templatePath + '/' + templateName + '.js', type: 'text/javascript' }, headTag);
        //dojo.create("link", { href: templatePath + '/templates/' + templateName + '.css', type: 'text/css', rel: 'stylesheet' }, headTag);
    }


});

/*** ONLOAD ***/
dojo.addOnLoad(ad.base.init);

// Widget JS (PasswordStrength.js)

if(!ad){ var ad = {} }

ad.passwordCheck = new (function(){
    // init function will run on page load. Called by dojo.addOnLoad
    this.init = function (){
        _temp_addPasswordCheck();
    }


    /*** PRIVATE VARIABLES ***/
    var $ = dojo.query;
    var templateName = 'PasswordStrength';
    var insertPointID = 'ins_passStrength';
    var minLength = 6;
    var objAdvice = { enterPass: 'Please enter a password', addChars: 'Add more characters (min ' + minLength + ')', addSpecials: 'Use special characters (!@#$%^&*)', addUppers: 'Use some upper case characters', addLowers: 'Use some lower case characters', addNums: 'Use some numbers', remRepeats: 'Too many repeated repeat characters', passPass: 'Your password has been verified as Excellent!' };
    var complexity = ['Bad', 'Very weak', 'Weak', 'Good', 'Strong', 'Excellent'];
    var content =   {
                        titles: {
                                    h1: 'Password Strength'
                                },
                        labels: {
                                    password: 'Password:',
                                    confirmPassword: 'Confirm Password',
                                    obscure: 'Obscure:',
                                    strength: 'Password strength:',
                                    advice: 'Advice:'
                                },
                        content:{
                                    advice: 'Please enter a password',
                                    strength: 'None'
                                }
                    }

    /*** PRIVATE FUNCTIONS ***/
    function _temp_addPasswordCheck(){
        // Include extras

        dojo.provide("ad.PasswordStrength");
        dojo.require("ad.PasswordStrength");
        dojo.require("dijit._Widget");
        dojo.require("dijit._Templated");
        dojo.require("dojo.parser");

        dojo.declare(templateName, [dijit._Widget, dijit._Templated], {

            // calls the HTML template to be used
            templatePath: dojo.moduleUrl ('dojotest.widget','templates/' + templateName + '.html'),
            // Content (titles, labels and general content)
            label_password: content.labels.password,
            label_confirmPassword: content.labels.confirmPassword,
            label_obscure: content.labels.obscure,
            label_passwordStrength: content.labels.strength,
            label_advice: content.labels.advice,
            title_passwordStrength: content.titles.h1,
            content_advice: content.content.advice,
            content_strength: content.content.strength,
            obscurePassword: function(){
                if(this.obscurePass.checked){  dojo.attr(this.passwordValue, 'type', 'password'); }
                else{ dojo.attr(this.passwordValue, 'type', 'text'); }
            },
            checkPassword: function(){
                            // This function checks the password strength on keyup and alters the passwordAdvice div to reflect the strength of the password entered

                            // Runs the password through a validation function which returns the results
                            var results = _checkPassWord(this.passwordValue.value), score = results['score'];
                            var ele = dojo.byId('passStrength');

                            // Update the markup to inform the user of their passwords score
                            if(results['count'] == 0){
                                this.complexity.innerHTML = 'None';
                                ele.className = '';
                                this.advice.innerHTML = _doInsert([objAdvice.enterPass]);
                            }
                            else if(score <= 50){
                                this.complexity.innerHTML = complexity[0];
                                ele.className = 'bad';
                                this.advice.innerHTML = _doInsert(results.advice);
                            }
                            if(score == 60){
                                this.complexity.innerHTML = complexity[1];
                                ele.className = 'veryWeak';
                                this.advice.innerHTML = _doInsert(results.advice);
                            }
                            if(score == 70){
                                this.complexity.innerHTML = complexity[2];
                                ele.className = 'weak';
                                this.advice.innerHTML = _doInsert(results.advice);
                            }
                            if(score == 80){
                                this.complexity.innerHTML = complexity[3];
                                ele.className = 'good';
                                this.advice.innerHTML = _doInsert(results.advice);
                            }
                            if(score == 90){
                                this.complexity.innerHTML = complexity[4];
                                ele.className = 'strong';
                                this.advice.innerHTML = _doInsert(results.advice);
                            }
                            if(score >= 100){
                                this.complexity.innerHTML = complexity[5];
                                ele.className = 'excellent';
                                this.advice.innerHTML = _doInsert([objAdvice.passPass]);
                            }
            }
        });
        // Calls the template into the right ID defined as the insert point as the first child
        if(dojo.byId(insertPointID)){
            var passStrength = new PasswordStrength().placeAt(insertPointID);
        }
    };

    function _doInsert(arrInsert){
        var content = '';
        dojo.forEach(arrInsert, function(item, i){
            content = content + '<p>' + item + '</p>';
        });
        return content; 
    }

    function _checkPassWord(strPassword){
        // Grades the password string and returns the results
        var objResults = {}, scoreFactor = 10, score = 0, advice = [], lengthPass, alphaLCpass, alphaUCpass, numPass, specialsPass, repeatPass, count = strPassword.length;

        // Check password string for uppercase alphas, lowercase alphas, numerals, special characters and repeated characters
        alphaUCpass = strPassword.match(/[A-Z]/g) ? true : false;
        alphaLCpass = strPassword.match(/[a-z]/g) ? true : false;
        numPass = strPassword.match(/[0-9]/g) ? true: false;
        specialsPass = strPassword.match(/[^a-zA-Z0-9]/g) ? true : false;
        repeatPass = strPassword.match(/(.)\1\1/g) ? false : true;
        lengthPass = count >= minLength ? true : false;

        // Score the password based on the results of the check
        if(alphaUCpass){ score += scoreFactor; }
        else{ advice.push(objAdvice.addUppers); }

        if(alphaLCpass){ score += scoreFactor; }
        else{ advice.push(objAdvice.addLowers); }

        if(numPass){ score += scoreFactor; }
        else{ advice.push(objAdvice.addNums); }

        if(specialsPass){ score += scoreFactor; }
        else{ advice.push(objAdvice.addSpecials); }

        if(repeatPass){ score += scoreFactor; }
        else{ advice.push(objAdvice.remRepeats); }

        if(lengthPass){ score += scoreFactor * 5; }
        else{ advice.push(objAdvice.addChars); }

        // Inserts the results into object to be returned
        objResults =    {
                            'alphaUC': alphaUCpass,
                            'alphaLC': alphaLCpass,
                            'numerals': numPass,
                            'specials': specialsPass,
                            'length': lengthPass,
                            'repeat': repeatPass,
                            'count': count,
                            'score': score,
                            'advice': advice
                        }

        // Return results to parent function
        return objResults;  
    }

    /*** PUBLIC FUNCTIONS ***/
});

/*** ONLOAD ***/
dojo.addOnLoad(ad.passwordCheck.init);

// Widget HTML template (PasswordStrength.html)

<div>
    <h1>${title_passwordStrength}</h1>
    <form method="post" action="">
        <fieldset>
            <div class="formFields">
                <label for="password">${label_password}</label>
                <input type="password" name="password" id="password" dojoAttachPoint="passwordValue" dojoAttachEvent="onkeyup: checkPassword" />
            </div>
            <div class="formFields">
                <label for="confirmPassword">${label_confirmPassword}</label>
                <input type="password" name="confirmPassword" id="confirmPassword" dojoAttachPoint="passwordConfirmValue" dojoAttachEvent="onkeyup: checkPassword" />
            </div>
            <div class="formFields">
                <label for="obscurePassword" class="wAuto">${label_obscure}</label>
                <input class="wAuto" type="checkbox" value="true" checked="checked" name="obscurePassword" id="obscurePassword" dojoAttachPoint="obscurePass"  dojoAttachEvent="onchange: obscurePassword" />
            </div>
            <div class="formFields">
                <label>${label_passwordStrength}</label>
                <div dojoAttachPoint="strength" id="passStrength" class=""></div>
                <div dojoAttachPoint="complexity" id="passStrengthCaption">${content_strength}</div>
            </div>
            <div class="formFields">
                <label>${label_advice}</label>
                <div dojoAttachPoint="advice" id="passAdvice"><p>${content_advice}</p></div>
            </div>
        </fieldset> 
    </form>

The parent file has a HTML pointer in it as follows:

<div id="ins_passStrength" dojoType="PasswordStrength"></div>

If I change the following function in parent controller (lib.js):

function _getTemplateAssets(templateName){
        // Injects the JS and CSS template assets into the page head

        dojo.registerModulePath("ad", '../dojotest/widget'); // relative to dojo.js
        //dojo.provide('ad.' + templateName);
        dojo.require('ad.' + templateName);

        //var headTag = document.getElementsByTagName('head').item(0);
        //dojo.create("script", { src: templatePath + '/' + templateName + '.js', type: 'text/javascript' }, headTag);
        //dojo.create("link", { href: templatePath + '/templates/' + templateName + '.css', type: 'text/css', rel: 'stylesheet' }, headTag);
    }

To:

function _getTemplateAssets(templateName){
        // Injects the JS and CSS template assets into the page head

        dojo.registerModulePath("ad", '../dojotest/widget'); // relative to dojo.js
        dojo.provide('ad.' + templateName);
        dojo.require('ad.' + templateName);

        //var headTag = document.getElementsByTagName('head').item(0);
        //dojo.create("script", { src: templatePath + '/' + templateName + '.js', type: 'text/javascript' }, headTag);
        //dojo.create("link", { href: templatePath + '/templates/' + templateName + '.css', type: 'text/css', rel: 'stylesheet' }, headTag);
    }

The error goes away but the widegt JS isn't included.

And if you change it to:

function _getTemplateAssets(templateName){
        // Injects the JS and CSS template assets into the page head

        dojo.registerModulePath("ad", '../dojotest/widget'); // relative to dojo.js
        //dojo.provide('ad.' + templateName);
        //dojo.require('ad.' + templateName);

        var headTag = document.getElementsByTagName('head').item(0);
        dojo.create("script", { src: templatePath + '/' + templateName + '.js', type: 'text/javascript' }, headTag);
        dojo.create("link", { href: templatePath + '/templates/' + templateName + '.css', type: 'text/css', rel: 'stylesheet' }, headTag);
    }

It works fine but this is a dirty sidestep... I need to use dojo's prescribed methods.

Any help greatly appreciated.

Thank you!


I believe your error is that you have put your dojo.provide("ad.PasswordStrength") inside a bunch of functions. It needs to be at the top of the file. Dojo evaluates the file it believes to be correct (based on module path), but how is it supposed to know if PasswordStrength is in there, unless you tell it "yes, this file provides ad.PasswordStrength".

Edit: considering what you said on IRC, here's how I think PasswordStrength.js should look:

dojo.provide("ad.PasswordStrength");

if(!ad){ var ad = {} }

ad.passwordCheck = new (function(){

    // init function will run on page load. Called by dojo.addOnLoad
    this.init = function (){
        _temp_addPasswordCheck();
        dojo.parser.parse();
    }


    /*** PRIVATE VARIABLES ***/
    var $ = dojo.query;
    var templateName = 'PasswordStrength';
    ....

    /*** PRIVATE FUNCTIONS ***/
    function _temp_addPasswordCheck(){

        // Include extras
        dojo.require("dijit._Widget");
        dojo.require("dijit._Templated");
        dojo.require("dojo.parser");

        dojo.declare("ad." + templateName, [dijit._Widget, dijit._Templated], {

            // calls the HTML template to be used
            templatePath: dojo.moduleUrl ('dojotest.widget','templates/' + templateName + '.html'),
            // Content (titles, labels and general content)
            label_password: content.labels.password,
            label_confirmPassword: content.labels.confirmPassword,
            label_obscure: content.labels.obscure,
            label_passwordStrength: content.labels.strength,
            label_advice: content.labels.advice,
            title_passwordStrength: content.titles.h1,
            content_advice: content.content.advice,
            content_strength: content.content.strength,

            obscurePassword: function(){
                ....
            },
            checkPassword: function(){
                ....
            }
        });

        /*
        if(dojo.byId(insertPointID)){
            var passStrength = new PasswordStrength().placeAt(insertPointID);
        }
        */

    };

    function _doInsert(arrInsert){
        ....
    }

    function _checkPassWord(strPassword){
        ....
    }

    /*** PUBLIC FUNCTIONS ***/
});

/*** ONLOAD ***/
dojo.addOnLoad(ad.passwordCheck.init);
  • Moved dojo.provide("ad.PasswordStrength"); to the top of the file.
  • Removed dojo.require("ad.PasswordStrength"); from _temp_addPasswordCheck() - if this code is executed, ad.PasswordStrength (PasswordStrength.js) has obviously already been required and loaded.
  • Added dojo.parser.parse(); to the end of init(), so that after the widget has been declared, any widget dojoTypes in the HTML will be parsed. However, I still don't understand why you have to declare the widget inside _temp_addPasswordCheck. Why not have the widget in it's on file, and ad.passwordCheck wherever your applications other "page" files are?
  • Added "ad." to the widget declaration (dojo.declare("ad." + templateName)), it needs to have the full namespaced name here.
  • Commented out new PasswordStrength().placeAt(.... Since you want to insert your widgets declaratively in your HTML, it doesn't make sense to manually instantiate one here, and place it manually.

Now you should be able to put PasswordStrength widgets in your HTML, like so:

<script type="text/javascript" src="js/dojo131/dojo/dojo.js"></script>
<script type="text/javascript" src="js/dojo131/dojotest/lib.js"></script>
....
<div id="ins_passStrength" dojoType="ad.PasswordStrength"></div>
<div id="anotherOne" dojoType="ad.PasswordStrength"></div>

Remember that you need the whole namespaced name here as well (i.e. the ad. prerfix).

This worked nicely for me, using Dojo 1.3.3. Uploaded the sandbox if it's any use.


Your error:

Could not load 'pf.PasswordStrength'; last tried '../dojopf/widget/PasswordStrength.js'
http://pf-dev-ad/wcsstore/js/dojo131/dojo/dojo.js
Line 16

Is this a typo? Because it should be trying ../dojotest/widget/PasswordStrength.js

Do you have another dojo.require that is referring to dojopf? Or any other line like dojo.require("pf.PasswordStrength")?

If not, perhaps the registering of the module path is not happening before dojo tries to load your .js. Perhaps try using dojo.require to load your lib.js.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜