source: Dev/trunk/src/client/dojox/atom/io/model.js @ 533

Last change on this file since 533 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 34.7 KB
Line 
1define([
2        "dojo/_base/kernel",
3        "dojo/_base/declare",
4         "dojo/_base/lang",
5        "dojo/date/stamp",
6        "dojox/xml/parser"
7], function (dojo, declare, lang, stamp, parser) {
8
9var model = {};
10
11dojo.setObject("dojox.atom.io.model", model);
12
13model._Constants = {
14        // summary:
15        //              Container for general constants.
16
17        "ATOM_URI": "http://www.w3.org/2005/Atom",
18        "ATOM_NS": "http://www.w3.org/2005/Atom",
19        "PURL_NS": "http://purl.org/atom/app#",
20        "APP_NS": "http://www.w3.org/2007/app"
21};
22
23model._actions = {
24        // summary:
25        //              Container for tag handling functions.
26        // description:
27        //              Container for tag handling functions.  Each child of this container is
28        //              a handler function for the given type of node. Each accepts two parameters:
29        // obj:  Object.
30        //                The object to insert data into.
31        // node: DOM Node.
32        //                The dom node containing the data
33        "link": function(obj,node){
34                if(obj.links === null){obj.links = [];}
35                var link = new model.Link();
36                link.buildFromDom(node);
37                obj.links.push(link);
38        },
39        "author": function(obj,node){
40                if(obj.authors === null){obj.authors = [];}
41                var person = new model.Person("author");
42                person.buildFromDom(node);
43                obj.authors.push(person);
44        },
45        "contributor": function(obj,node){
46                if(obj.contributors === null){obj.contributors = [];}
47                var person = new model.Person("contributor");
48                person.buildFromDom(node);
49                obj.contributors.push(person);
50        },
51        "category": function(obj,node){
52                if(obj.categories === null){obj.categories = [];}
53                var cat = new model.Category();
54                cat.buildFromDom(node);
55                obj.categories.push(cat);
56        },
57        "icon": function(obj,node){
58                obj.icon = parser.textContent(node);
59        },
60        "id": function(obj,node){
61                obj.id = parser.textContent(node);
62        },
63        "rights": function(obj,node){
64                obj.rights = parser.textContent(node);
65        },
66        "subtitle": function(obj,node){
67                var cnt = new model.Content("subtitle");
68                cnt.buildFromDom(node);
69                obj.subtitle = cnt;
70        },
71        "title": function(obj,node){
72                var cnt = new model.Content("title");
73                cnt.buildFromDom(node);
74                obj.title = cnt;
75        },
76        "updated": function(obj,node){
77                obj.updated = model.util.createDate(node);
78        },
79        // Google news
80        "issued": function(obj,node){
81                obj.issued = model.util.createDate(node);
82        },
83        // Google news
84        "modified": function(obj,node){
85                obj.modified = model.util.createDate(node);
86        },
87        "published": function(obj,node){
88                obj.published = model.util.createDate(node);
89        },
90        "entry": function(obj,node){
91                if(obj.entries === null){obj.entries = [];}
92                //The object passed in should be a Feed object, since only feeds can contain Entries
93                var entry = obj.createEntry ? obj.createEntry() : new model.Entry();
94                entry.buildFromDom(node);
95                obj.entries.push(entry);
96        },
97        "content": function(obj, node){
98                var cnt = new model.Content("content");
99                cnt.buildFromDom(node);
100                obj.content = cnt;
101        },
102        "summary": function(obj, node){
103                var summary = new model.Content("summary");
104                summary.buildFromDom(node);
105                obj.summary = summary;
106        },
107
108        "name": function(obj,node){
109                obj.name = parser.textContent(node);
110        },
111        "email" : function(obj,node){
112                obj.email = parser.textContent(node);
113        },
114        "uri" : function(obj,node){
115                obj.uri = parser.textContent(node);
116        },
117        "generator" : function(obj,node){
118                obj.generator = new model.Generator();
119                obj.generator.buildFromDom(node);
120        }
121};
122
123model.util = {
124        createDate: function(/*DOMNode*/ node){
125                // summary:
126                //              Utility function to create a date from a DOM node's text content.
127                // node:
128                //              The DOM node to inspect.
129                // returns:
130                //              Date object from a DOM Node containing a ISO-8610 string.
131                var textContent = parser.textContent(node);
132                if(textContent){
133                        return stamp.fromISOString(lang.trim(textContent));
134                }
135                return null;
136        },
137        escapeHtml: function(/*String*/ str){
138                // summary:
139                //              Utility function to escape XML special characters in an HTML string.
140                // str:
141                //              The string to escape
142                // returns:
143                //              HTML String with special characters (<,>,&, ", etc,) escaped.
144                return str.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;")
145                        .replace(/'/gm, "&#39;"); // String
146        },
147        unEscapeHtml: function(/*String*/ str){
148                // summary:
149                //              Utility function to un-escape XML special characters in an HTML string.
150                // str:
151                //              The string to un-escape.
152                // returns:
153                //              HTML String converted back to the normal text (unescaped) characters (<,>,&, ", etc,).
154                return str.replace(/&lt;/gm, "<").replace(/&gt;/gm, ">").replace(/&quot;/gm, "\"")
155                        .replace(/&#39;/gm, "'").replace(/&amp;/gm, "&"); // String
156        },
157        getNodename: function(/*DOMNode*/ node){
158                // summary:
159                //              Utility function to get a node name and deal with IE's bad handling of namespaces
160                //              on tag names.
161                // node:
162                //              The DOM node whose name to retrieve.
163                // returns: String
164                //              The name without namespace prefixes.
165                var name = null;
166                if(node !== null){
167                        name = node.localName ? node.localName: node.nodeName;
168                        if(name !== null){
169                                var nsSep = name.indexOf(":");
170                                if(nsSep !== -1){
171                                        name = name.substring((nsSep + 1), name.length);
172                                }
173                        }
174                }
175                return name;
176        }
177};
178
179model.Node = declare(null, {
180        constructor: function(name_space,name, attributes,content, shortNs){
181                this.name_space = name_space;
182                this.name = name;
183                this.attributes = [];
184                if(attributes){
185                        this.attributes = attributes;
186                }
187                this.content = [];
188                this.rawNodes = [];
189                this.textContent = null;
190                if(content){
191                        this.content.push(content);
192                }
193                this.shortNs = shortNs;
194                this._objName = "Node";//for debugging purposes
195                this.nodeType = "Node";
196        },
197        buildFromDom: function(node){
198                this._saveAttributes(node);
199                this.name_space = node.namespaceURI;
200                this.shortNs = node.prefix;
201                this.name = model.util.getNodename(node);
202                for(var x=0; x < node.childNodes.length; x++){
203                        var c = node.childNodes[x];
204                        if(model.util.getNodename(c) != "#text" ){
205                                this.rawNodes.push(c);
206                                var n = new model.Node();
207                                n.buildFromDom(c, true);
208                                this.content.push(n);
209                        }else{
210                                this.content.push(c.nodeValue);
211                        }
212                }
213                this.textContent = parser.textContent(node);
214        },
215        _saveAttributes: function(node){
216                if(!this.attributes){this.attributes = [];}
217                // Work around lack of hasAttributes() in IE
218                var hasAttributes = function(node){
219                        var attrs = node.attributes;
220                        if(attrs === null){return false;}
221                        return (attrs.length !== 0);
222                };
223       
224                if(hasAttributes(node) && this._getAttributeNames){
225                        var names = this._getAttributeNames(node);
226                        if(names && names.length > 0){
227                                for(var x in names){
228                                        var attrib = node.getAttribute(names[x]);
229                                        if(attrib){this.attributes[names[x]] = attrib;}
230                                }
231                        }
232                }
233        },
234        addAttribute: function(name, value){
235                this.attributes[name]=value;
236        },
237        getAttribute: function(name){
238                return this.attributes[name];
239        },
240        //if child objects want their attributes parsed, they should override
241        //to return an array of attrib names
242        _getAttributeNames: function(node){
243                var names = [];
244                for(var i =0; i<node.attributes.length; i++){
245                        names.push(node.attributes[i].nodeName);
246                }
247                return names;
248        },
249        toString: function(){
250                var xml = [];
251                var x;
252                var name = (this.shortNs?this.shortNs+":":'')+this.name;
253                var cdata = (this.name == "#cdata-section");
254                if(cdata){
255                        xml.push("<![CDATA[");
256                        xml.push(this.textContent);
257                        xml.push("]]>");
258                }else{
259                        xml.push("<");
260                        xml.push(name);
261                        if(this.name_space){
262                                xml.push(" xmlns='" + this.name_space + "'");
263                        }
264                        if(this.attributes){
265                                for(x in this.attributes){
266                                        xml.push(" " + x + "='" + this.attributes[x] + "'");
267                                }
268                        }
269                        if(this.content){
270                                xml.push(">");
271                                for(x in this.content){
272                                        xml.push(this.content[x]);
273                                }
274                                xml.push("</" + name + ">\n");
275                        }else{
276                                xml.push("/>\n");
277                        }
278                }
279                return xml.join('');
280        },
281        addContent: function(content){
282                this.content.push(content);
283        }
284});
285//Types are as follows: links: array of Link, authors: array of Person, categories: array of Category
286//contributors: array of Person, ico
287model.AtomItem = declare(model.Node,{
288        // summary:
289        //              Class container for generic Atom items.
290
291        constructor: function(args){
292                this.ATOM_URI = model._Constants.ATOM_URI;
293                this.links = null;                                              //Array of Link
294                this.authors = null;                                    //Array of Person
295                this.categories = null;                                 //Array of Category
296                this.contributors = null;                               //Array of Person
297                this.icon = this.id = this.logo = this.xmlBase = this.rights = null; //String
298                this.subtitle = this.title = null;              //Content
299                this.updated = this.published = null;   //Date
300                // Google news
301                this.issued = this.modified = null;             //Date
302                this.content =  null;                                   //Content
303                this.extensions = null;                                 //Array of Node, non atom based
304                this.entries = null;                                    //Array of Entry
305                this.name_spaces = {};
306                this._objName = "AtomItem";                      //for debugging purposes
307                this.nodeType = "AtomItem";
308        },
309
310        _getAttributeNames: function(){return null;},
311        _accepts: {},
312        accept: function(tag){return Boolean(this._accepts[tag]);},
313        _postBuild: function(){},//child objects can override this if they want to be called after a Dom build
314        buildFromDom: function(node){
315                var i, c, n;
316                for(i=0; i<node.attributes.length; i++){
317                        c = node.attributes.item(i);
318                        n = model.util.getNodename(c);
319                        if(c.prefix == "xmlns" && c.prefix != n){
320                                this.addNamespace(c.nodeValue, n);
321                        }
322                }
323                c = node.childNodes;
324                for(i = 0; i< c.length; i++){
325                        if(c[i].nodeType == 1) {
326                                var name = model.util.getNodename(c[i]);
327                                if(!name){continue;}
328                                if(c[i].namespaceURI != model._Constants.ATOM_NS && name != "#text"){
329                                        if(!this.extensions){this.extensions = [];}
330                                        var extensionNode = new model.Node();
331                                        extensionNode.buildFromDom(c[i]);
332                                        this.extensions.push(extensionNode);
333                                }
334                                if(!this.accept(name.toLowerCase())){
335                                        continue;
336                                }
337                                var fn = model._actions[name];
338                                if(fn) {
339                                        fn(this,c[i]);
340                                }
341                        }
342                }
343                this._saveAttributes(node);
344                if(this._postBuild){this._postBuild();}
345        },
346        addNamespace: function(fullName, shortName){
347                if(fullName && shortName){
348                        this.name_spaces[shortName] = fullName;
349                }
350        },
351        addAuthor: function(/*String*/ name, /*String*/ email, /*String*/ uri){
352                // summary:
353                //              Function to add in an author to the list of authors.
354                // name:
355                //              The author's name.
356                // email:
357                //              The author's e-mail address.
358                // uri:
359                //              A URI associated with the author.
360                if(!this.authors){this.authors = [];}
361                this.authors.push(new model.Person("author",name,email,uri));
362        },
363        addContributor: function(/*String*/ name, /*String*/ email, /*String*/ uri){
364                // summary:
365                //              Function to add in an author to the list of authors.
366                // name:
367                //              The author's name.
368                // email:
369                //              The author's e-mail address.
370                // uri:
371                //              A URI associated with the author.
372                if(!this.contributors){this.contributors = [];}
373                this.contributors.push(new model.Person("contributor",name,email,uri));
374        },
375        addLink: function(/*String*/ href,/*String*/ rel,/*String*/ hrefLang,/*String*/ title,/*String*/ type){
376                // summary:
377                //              Function to add in a link to the list of links.
378                // title:
379                //              A title to associate with the link.
380                // type:
381                //              The type of link is is.
382                if(!this.links){this.links=[];}
383                this.links.push(new model.Link(href,rel,hrefLang,title,type));
384        },
385        removeLink: function(/*String*/ href, /*String*/ rel){
386                // summary:
387                //              Function to remove a link from the list of links.
388                // href:
389                //              The href.
390                if(!this.links || !lang.isArray(this.links)){return;}
391                var count = 0;
392                for(var i = 0; i < this.links.length; i++){
393                        if((!href || this.links[i].href === href) && (!rel || this.links[i].rel === rel)){
394                                this.links.splice(i,1); count++;
395                        }
396                }
397                return count;
398        },
399        removeBasicLinks: function(){
400                // summary:
401                //              Function to remove all basic links from the list of links.
402                if(!this.links){return;}
403                var count = 0;
404                for(var i = 0; i < this.links.length; i++){
405                        if(!this.links[i].rel){this.links.splice(i,1); count++; i--;}
406                }
407                return count;
408        },
409        addCategory: function(/*String*/ scheme, /*String*/ term, /*String*/ label){
410                // summary:
411                //              Function to add in a category to the list of categories.
412
413                if(!this.categories){this.categories = [];}
414                this.categories.push(new model.Category(scheme,term,label));
415        },
416        getCategories: function(/*String*/ scheme){
417                // summary:
418                //              Function to get all categories that match a particular scheme.
419                // scheme:
420                //              The scheme to filter on.
421
422                if(!scheme){return this.categories;}
423                //If categories belonging to a particular scheme are required, then create a new array containing these
424                var arr = [];
425                for(var x in this.categories){
426                        if(this.categories[x].scheme === scheme){arr.push(this.categories[x]);}
427                }
428                return arr;
429        },
430        removeCategories: function(/*String*/ scheme, /*String*/ term){
431                // summary:
432                //              Function to remove all categories that match a particular scheme and term.
433                // scheme:
434                //              The scheme to filter on.
435                // term:
436                //              The term to filter on.
437                if(!this.categories){return;}
438                var count = 0;
439                for(var i=0; i<this.categories.length; i++){
440                        if((!scheme || this.categories[i].scheme === scheme) && (!term || this.categories[i].term === term)){
441                                this.categories.splice(i, 1); count++; i--;
442                        }
443                }
444                return count;
445        },
446        setTitle: function(/*String*/ str, /*String*/ type){
447                // summary:
448                //              Function to set the title of the item.
449                // str:
450                //              The title to set.
451                // type:
452                //              The type of title format, text, xml, xhtml, etc.
453                if(!str){return;}
454                this.title = new model.Content("title");
455                this.title.value = str;
456                if(type){this.title.type = type;}
457        },
458        addExtension: function(/*String*/ name_space,/*String*/ name, /*Array*/ attributes, /*String*/ content, /*String*/ shortNS){
459                // summary:
460                //              Function to add in an extension namespace into the item.
461                // name_space:
462                //              The namespace of the extension.
463                // name:
464                //              The name of the extension
465                // attributes:
466                //              The attributes associated with the extension.
467                // content:
468                //              The content of the extension.
469                if(!this.extensions){this.extensions=[];}
470                this.extensions.push(new model.Node(name_space,name,attributes,content, shortNS || "ns"+this.extensions.length));
471        },
472        getExtensions: function(/*String*/ name_space, /*String*/ name){
473                // summary:
474                //              Function to get extensions that match a namespace and name.
475                // name_space:
476                //              The namespace of the extension.
477                // name:
478                //              The name of the extension
479                var arr = [];
480                if(!this.extensions){return arr;}
481                for(var x in this.extensions){
482                        if((this.extensions[x].name_space === name_space || this.extensions[x].shortNs === name_space) && (!name || this.extensions[x].name === name)){
483                                arr.push(this.extensions[x]);
484                        }
485                }
486                return arr;
487        },
488        removeExtensions: function(/*String*/ name_space, /*String*/ name){
489                // summary:
490                //              Function to remove extensions that match a namespace and name.
491                // name_space:
492                //              The namespace of the extension.
493                // name:
494                //              The name of the extension
495                if(!this.extensions){return;}
496                for(var i=0; i< this.extensions.length; i++){
497                        if((this.extensions[i].name_space == name_space || this.extensions[i].shortNs === name_space) && this.extensions[i].name === name){
498                                this.extensions.splice(i,1);
499                                i--;
500                        }
501                }
502        },
503        destroy: function() {
504                this.links = null;
505                this.authors = null;
506                this.categories = null;
507                this.contributors = null;
508                this.icon = this.id = this.logo = this.xmlBase = this.rights = null;
509                this.subtitle = this.title = null;
510                this.updated = this.published = null;
511                // Google news
512                this.issued = this.modified = null;
513                this.content =  null;
514                this.extensions = null;
515                this.entries = null;
516        }
517});
518
519model.Category = declare(model.Node,{
520        // summary:
521        //              Class container for 'Category' types.
522
523        constructor: function(/*String*/ scheme, /*String*/ term, /*String*/ label){
524                this.scheme = scheme; this.term = term; this.label = label;
525                this._objName = "Category";//for debugging
526                this.nodeType = "Category";
527        },
528        _postBuild: function(){},
529        _getAttributeNames: function(){
530                return ["label","scheme","term"];
531        },
532        toString: function(){
533                // summary:
534                //              Function to construct string form of the category tag, which is an XML structure.
535                var s = [];
536                s.push('<category ');
537                if(this.label){s.push(' label="'+this.label+'" ');}
538                if(this.scheme){s.push(' scheme="'+this.scheme+'" ');}
539                if(this.term){s.push(' term="'+this.term+'" ');}
540                s.push('/>\n');
541                return s.join('');
542        },
543        buildFromDom: function(/*DOMNode*/ node){
544                // summary:
545                //              Function to do construction of the Category data from the DOM node containing it.
546                // node:
547                //              The DOM node to process for content.
548                this._saveAttributes(node);//just get the attributes from the node
549                this.label = this.attributes.label;
550                this.scheme = this.attributes.scheme;
551                this.term = this.attributes.term;
552                if(this._postBuild){this._postBuild();}
553        }
554});
555
556model.Content = declare(model.Node,{
557        // summary:
558        //              Class container for 'Content' types. Such as summary, content, username, and so on types of data.
559
560        constructor: function(tagName, value, src, type,xmlLang){
561                this.tagName = tagName; this.value = value; this.src = src; this.type=type; this.xmlLang = xmlLang;
562                this.HTML = "html"; this.TEXT = "text"; this.XHTML = "xhtml"; this.XML="xml";
563                this._useTextContent = "true";
564                this.nodeType = "Content";
565        },
566        _getAttributeNames: function(){return ["type","src"];},
567        _postBuild: function(){},
568        buildFromDom: function(/*DOMNode*/ node){
569                // summary:
570                //              Function to do construction of the Content data from the DOM node containing it.
571                // node:
572                //              The DOM node to process for content.
573
574                // Handle checking for XML content as the content type
575                var type = node.getAttribute("type");
576                if(type){
577                        type = type.toLowerCase();
578                        if(type == "xml" || "text/xml"){
579                                type = this.XML;
580                        }
581                }else{
582                        type="text";
583                }
584                if(type === this.XML){
585                        if(node.firstChild){
586                                var i;
587                                this.value = "";
588                                for(i = 0; i < node.childNodes.length; i++){
589                                        var c = node.childNodes[i];
590                                        if(c){
591                                                this.value += parser.innerXML(c);
592                                        }
593                                }
594                        }
595                } else if(node.innerHTML){
596                        this.value = node.innerHTML;
597                }else{
598                        this.value = parser.textContent(node);
599                }
600
601                this._saveAttributes(node);
602
603                if(this.attributes){
604                        this.type = this.attributes.type;
605                        this.scheme = this.attributes.scheme;
606                        this.term = this.attributes.term;
607                }
608                if(!this.type){this.type = "text";}
609
610                //We need to unescape the HTML content here so that it can be displayed correctly when the value is fetched.
611                var lowerType = this.type.toLowerCase();
612                if(lowerType === "html" || lowerType === "text/html" || lowerType === "xhtml" || lowerType === "text/xhtml"){
613                        this.value = this.value?model.util.unEscapeHtml(this.value):"";
614                }
615
616                if(this._postBuild){this._postBuild();}
617        },
618        toString: function(){
619                // summary:
620                //              Function to construct string form of the content tag, which is an XML structure.
621
622                var s = [];
623                s.push('<'+this.tagName+' ');
624                if(!this.type){this.type = "text";}
625                if(this.type){s.push(' type="'+this.type+'" ');}
626                if(this.xmlLang){s.push(' xml:lang="'+this.xmlLang+'" ');}
627                if(this.xmlBase){s.push(' xml:base="'+this.xmlBase+'" ');}
628               
629                //all HTML must be escaped
630                if(this.type.toLowerCase() == this.HTML){
631                        s.push('>'+model.util.escapeHtml(this.value)+'</'+this.tagName+'>\n');
632                }else{
633                        s.push('>'+this.value+'</'+this.tagName+'>\n');
634                }
635                var ret = s.join('');
636                return ret;
637        }
638});
639
640model.Link = declare(model.Node,{
641        // summary:
642        //              Class container for 'link' types.
643
644        constructor: function(href,rel,hrefLang,title,type){
645                this.href = href; this.hrefLang = hrefLang; this.rel = rel; this.title = title;this.type = type;
646                this.nodeType = "Link";
647        },
648        _getAttributeNames: function(){return ["href","jrefLang","rel","title","type"];},
649        _postBuild: function(){},
650        buildFromDom: function(node){
651                // summary:
652                //              Function to do construction of the link data from the DOM node containing it.
653                // node:
654                //              The DOM node to process for link data.
655                this._saveAttributes(node);//just get the attributes from the node
656                this.href = this.attributes.href;
657                this.hrefLang = this.attributes.hreflang;
658                this.rel = this.attributes.rel;
659                this.title = this.attributes.title;
660                this.type = this.attributes.type;
661                if(this._postBuild){this._postBuild();}
662        },
663        toString: function(){
664                // summary:
665                //              Function to construct string form of the link tag, which is an XML structure.
666
667                var s = [];
668                s.push('<link ');
669                if(this.href){s.push(' href="'+this.href+'" ');}
670                if(this.hrefLang){s.push(' hrefLang="'+this.hrefLang+'" ');}
671                if(this.rel){s.push(' rel="'+this.rel+'" ');}
672                if(this.title){s.push(' title="'+this.title+'" ');}
673                if(this.type){s.push(' type = "'+this.type+'" ');}
674                s.push('/>\n');
675                return s.join('');
676        }
677});
678
679model.Person = declare(model.Node,{
680        // summary:
681        //              Class container for 'person' types, such as Author, contributors, and so on.
682
683        constructor: function(personType, name, email, uri){
684                this.author = "author";
685                this.contributor = "contributor";
686                if(!personType){
687                        personType = this.author;
688                }
689                this.personType = personType;
690                this.name = name || '';
691                this.email = email || '';
692                this.uri = uri || '';
693                this._objName = "Person";//for debugging
694                this.nodeType = "Person";
695        },
696        _getAttributeNames: function(){return null;},
697        _postBuild: function(){},
698        accept: function(tag){return Boolean(this._accepts[tag]);},
699        buildFromDom: function(node){
700                // summary:
701                //              Function to do construction of the person data from the DOM node containing it.
702                // node:
703                //              The DOM node to process for person data.
704                var c = node.childNodes;
705                for(var i = 0; i< c.length; i++){
706                        var name = model.util.getNodename(c[i]);
707                       
708                        if(!name){continue;}
709
710                        if(c[i].namespaceURI != model._Constants.ATOM_NS && name != "#text"){
711                                if(!this.extensions){this.extensions = [];}
712                                var extensionNode = new model.Node();
713                                extensionNode.buildFromDom(c[i]);
714                                this.extensions.push(extensionNode);
715                        }
716                        if(!this.accept(name.toLowerCase())){
717                                continue;
718                        }
719                        var fn = model._actions[name];
720                        if(fn) {
721                                fn(this,c[i]);
722                        }
723                }
724                this._saveAttributes(node);
725                if(this._postBuild){this._postBuild();}
726        },
727        _accepts: {
728                'name': true,
729                'uri': true,
730                'email': true
731        },
732        toString: function(){
733                // summary:
734                //              Function to construct string form of the Person tag, which is an XML structure.
735
736                var s = [];
737                s.push('<'+this.personType+'>\n');
738                if(this.name){s.push('\t<name>'+this.name+'</name>\n');}
739                if(this.email){s.push('\t<email>'+this.email+'</email>\n');}
740                if(this.uri){s.push('\t<uri>'+this.uri+'</uri>\n');}
741                s.push('</'+this.personType+'>\n');
742                return s.join('');
743        }
744});
745
746model.Generator = declare(model.Node,{
747        // summary:
748        //              Class container for 'Generator' types.
749
750        constructor: function(/*String*/ uri, /*String*/ version, /*String*/ value){
751                this.uri = uri;
752                this.version = version;
753                this.value = value;
754        },
755        _postBuild: function(){},
756        buildFromDom: function(node){
757                // summary:
758                //              Function to do construction of the generator data from the DOM node containing it.
759                // node:
760                //              The DOM node to process for link data.
761
762                this.value = parser.textContent(node);
763                this._saveAttributes(node);
764
765                this.uri = this.attributes.uri;
766                this.version = this.attributes.version;
767
768                if(this._postBuild){this._postBuild();}
769        },
770        toString: function(){
771                // summary:
772                //              Function to construct string form of the Generator tag, which is an XML structure.
773
774                var s = [];
775                s.push('<generator ');
776                if(this.uri){s.push(' uri="'+this.uri+'" ');}
777                if(this.version){s.push(' version="'+this.version+'" ');}
778                s.push('>'+this.value+'</generator>\n');
779                var ret = s.join('');
780                return ret;
781        }
782});
783
784model.Entry = declare(model.AtomItem,{
785        // summary:
786        //              Class container for 'Entry' types.
787
788        constructor: function(/*String*/ id){
789                this.id = id; this._objName = "Entry"; this.feedUrl = null;
790        },
791        _getAttributeNames: function(){return null;},
792        _accepts: {
793                'author': true,
794                'content': true,
795                'category': true,
796                'contributor': true,
797                'created': true,
798                'id': true,
799                'link': true,
800                'published': true,
801                'rights': true,
802                'summary': true,
803                'title': true,
804                'updated': true,
805                'xmlbase': true,
806                'issued': true,
807                'modified': true
808        },
809        toString: function(amPrimary){
810                // summary:
811                //              Function to construct string form of the entry tag, which is an XML structure.
812
813                var s = [];
814                var i;
815                if(amPrimary){
816                        s.push("<?xml version='1.0' encoding='UTF-8'?>");
817                        s.push("<entry xmlns='"+model._Constants.ATOM_URI+"'");
818                }else{s.push("<entry");}
819                if(this.xmlBase){s.push(' xml:base="'+this.xmlBase+'" ');}
820                for(i in this.name_spaces){s.push(' xmlns:'+i+'="'+this.name_spaces[i]+'"');}
821                s.push('>\n');
822                s.push('<id>' + (this.id ? this.id: '') + '</id>\n');
823                if(this.issued && !this.published){this.published = this.issued;}
824                if(this.published){s.push('<published>'+stamp.toISOString(this.published)+'</published>\n');}
825                if(this.created){s.push('<created>'+stamp.toISOString(this.created)+'</created>\n');}
826                //Google News
827                if(this.issued){s.push('<issued>'+stamp.toISOString(this.issued)+'</issued>\n');}
828
829                //Google News
830                if(this.modified){s.push('<modified>'+stamp.toISOString(this.modified)+'</modified>\n');}
831
832                if(this.modified && !this.updated){this.updated = this.modified;}
833                if(this.updated){s.push('<updated>'+stamp.toISOString(this.updated)+'</updated>\n');}
834                if(this.rights){s.push('<rights>'+this.rights+'</rights>\n');}
835                if(this.title){s.push(this.title.toString());}
836                if(this.summary){s.push(this.summary.toString());}
837                var arrays = [this.authors,this.categories,this.links,this.contributors,this.extensions];
838                for(var x in arrays){
839                        if(arrays[x]){
840                                for(var y in arrays[x]){
841                                        s.push(arrays[x][y]);
842                                }
843                        }
844                }
845                if(this.content){s.push(this.content.toString());}
846                s.push("</entry>\n");
847                return s.join(''); //string
848        },
849        getEditHref: function(){
850                // summary:
851                //              Function to get the href that allows editing of this feed entry.
852                // returns:
853                //              The href that specifies edit capability.
854                if(this.links === null || this.links.length === 0){
855                        return null;
856                }
857                for(var x in this.links){
858                        if(this.links[x].rel && this.links[x].rel == "edit"){
859                                return this.links[x].href; //string
860                        }
861                }
862                return null;
863        },
864        setEditHref: function(url){
865                if(this.links === null){
866                        this.links = [];
867                }
868                for(var x in this.links){
869                        if(this.links[x].rel && this.links[x].rel == "edit"){
870                                this.links[x].href = url;
871                                return;
872                        }
873                }
874                this.addLink(url, 'edit');
875        }
876});
877
878model.Feed = declare(model.AtomItem,{
879        // summary:
880        //              Class container for 'Feed' types.
881
882        _accepts: {
883                'author': true,
884                'content': true,
885                'category': true,
886                'contributor': true,
887                'created': true,
888                'id': true,
889                'link': true,
890                'published': true,
891                'rights': true,
892                'summary': true,
893                'title': true,
894                'updated': true,
895                'xmlbase': true,
896                'entry': true,
897                'logo': true,
898                'issued': true,
899                'modified': true,
900                'icon': true,
901                'subtitle': true
902        },
903        addEntry: function(/*object*/ entry){
904                // summary:
905                //              Function to add an entry to this feed.
906                // entry:
907                //              The entry object to add.
908                if(!entry.id){
909                        throw new Error("The entry object must be assigned an ID attribute.");
910                }
911                if(!this.entries){this.entries = [];}
912                entry.feedUrl = this.getSelfHref();
913                this.entries.push(entry);
914        },
915        getFirstEntry: function(){
916                // summary:
917                //              Function to get the first entry of the feed.
918                // returns:
919                //              The first entry in the feed.
920                if(!this.entries || this.entries.length === 0){return null;}
921                return this.entries[0]; //object
922        },
923        getEntry: function(/*String*/ entryId){
924                // summary:
925                //              Function to get an entry by its id.
926                // returns:
927                //              The entry desired, or null if none.
928                if(!this.entries){return null;}
929                for(var x in this.entries){
930                        if(this.entries[x].id == entryId){
931                                return this.entries[x];
932                        }
933                }
934                return null;
935        },
936        removeEntry: function(/*object*/ entry){
937                // summary:
938                //              Function to remove an entry from the list of links.
939                // entry:
940                //              The entry.
941                if(!this.entries){return;}
942                var count = 0;
943                for(var i = 0; i < this.entries.length; i++){
944                        if(this.entries[i] === entry){
945                                this.entries.splice(i,1);
946                                count++;
947                        }
948                }
949                return count;
950        },
951        setEntries: function(/*array*/ arrayOfEntry){
952                // summary:
953                //              Function to add a set of entries to the feed.
954                // arrayOfEntry:
955                //              An array of entry objects to add to the feed.
956                for(var x in arrayOfEntry){
957                        this.addEntry(arrayOfEntry[x]);
958                }
959        },
960        toString: function(){
961                // summary:
962                //              Function to construct string form of the feed tag, which is an XML structure.
963                var s = [];
964                var i;
965                s.push('<?xml version="1.0" encoding="utf-8"?>\n');
966                s.push('<feed xmlns="'+model._Constants.ATOM_URI+'"');
967                if(this.xmlBase){s.push(' xml:base="'+this.xmlBase+'"');}
968                for(i in this.name_spaces){s.push(' xmlns:'+i+'="'+this.name_spaces[i]+'"');}
969                s.push('>\n');
970                s.push('<id>' + (this.id ? this.id: '') + '</id>\n');
971                if(this.title){s.push(this.title);}
972                if(this.copyright && !this.rights){this.rights = this.copyright;}
973                if(this.rights){s.push('<rights>' + this.rights + '</rights>\n');}
974               
975                // Google news
976                if(this.issued){s.push('<issued>'+stamp.toISOString(this.issued)+'</issued>\n');}
977                if(this.modified){s.push('<modified>'+stamp.toISOString(this.modified)+'</modified>\n');}
978
979                if(this.modified && !this.updated){this.updated=this.modified;}
980                if(this.updated){s.push('<updated>'+stamp.toISOString(this.updated)+'</updated>\n');}
981                if(this.published){s.push('<published>'+stamp.toISOString(this.published)+'</published>\n');}
982                if(this.icon){s.push('<icon>'+this.icon+'</icon>\n');}
983                if(this.language){s.push('<language>'+this.language+'</language>\n');}
984                if(this.logo){s.push('<logo>'+this.logo+'</logo>\n');}
985                if(this.subtitle){s.push(this.subtitle.toString());}
986                if(this.tagline){s.push(this.tagline.toString());}
987                //TODO: need to figure out what to do with xmlBase
988                var arrays = [this.alternateLinks,this.authors,this.categories,this.contributors,this.otherLinks,this.extensions,this.entries];
989                for(i in arrays){
990                        if(arrays[i]){
991                                for(var x in arrays[i]){
992                                        s.push(arrays[i][x]);
993                                }
994                        }
995                }
996                s.push('</feed>');
997                return s.join('');
998        },
999        createEntry: function(){
1000                // summary:
1001                //              Function to Create a new entry object in the feed.
1002                // returns:
1003                //              An empty entry object in the feed.
1004                var entry = new model.Entry();
1005                entry.feedUrl = this.getSelfHref();
1006                return entry; //object
1007        },
1008        getSelfHref: function(){
1009                // summary:
1010                //              Function to get the href that refers to this feed.
1011                // returns:
1012                //              The href that refers to this feed or null if none.
1013                if(this.links === null || this.links.length === 0){
1014                        return null;
1015                }
1016                for(var x in this.links){
1017                        if(this.links[x].rel && this.links[x].rel == "self"){
1018                                return this.links[x].href; //string
1019                        }
1020                }
1021                return null;
1022        }
1023});
1024
1025model.Service = declare(model.AtomItem,{
1026        // summary:
1027        //              Class container for 'Feed' types.
1028
1029        constructor: function(href){
1030                this.href = href;
1031        },
1032        //builds a Service document.  each element of this, except for the namespace, is the href of
1033        //a service that the server supports.  Some of the common services are:
1034        //"create-entry" , "user-prefs" , "search-entries" , "edit-template" , "categories"
1035        buildFromDom: function(/*DOMNode*/ node){
1036                // summary:
1037                //              Function to do construction of the Service data from the DOM node containing it.
1038                // node:
1039                //              The DOM node to process for content.
1040                var i;
1041                this.workspaces = [];
1042                if(node.tagName != "service"){
1043                        // FIXME: Need 0.9 DOM util...
1044                        //node = dojox.xml.parser.firstElement(node,"service");
1045                        //if(!node){return;}
1046                        return;
1047                }
1048                if(node.namespaceURI != model._Constants.PURL_NS && node.namespaceURI != model._Constants.APP_NS){return;}
1049                var ns = node.namespaceURI;
1050                this.name_space = node.namespaceURI;
1051                //find all workspaces, and create them
1052                var workspaces ;
1053                if(typeof(node.getElementsByTagNameNS)!= "undefined"){
1054                        workspaces = node.getElementsByTagNameNS(ns,"workspace");
1055                }else{
1056                        // This block is IE only, which doesn't have a 'getElementsByTagNameNS' function
1057                        workspaces = [];
1058                        var temp = node.getElementsByTagName('workspace');
1059                        for(i=0; i<temp.length; i++){
1060                                if(temp[i].namespaceURI == ns){
1061                                        workspaces.push(temp[i]);
1062                                }
1063                        }
1064                }
1065                if(workspaces && workspaces.length > 0){
1066                        var wkLen = 0;
1067                        var workspace;
1068                        for(i = 0; i< workspaces.length; i++){
1069                                workspace = (typeof(workspaces.item)==="undefined"?workspaces[i]:workspaces.item(i));
1070                                var wkspace = new model.Workspace();
1071                                wkspace.buildFromDom(workspace);
1072                                this.workspaces[wkLen++] = wkspace;
1073                        }
1074                }
1075        },
1076        getCollection: function(/*String*/ url){
1077                // summary:
1078                //              Function to collections that match a specific url.
1079                // url:
1080                //              e URL to match collections against.
1081                for(var i=0;i<this.workspaces.length;i++){
1082                        var coll=this.workspaces[i].collections;
1083                        for(var j=0;j<coll.length;j++){
1084                                if(coll[j].href == url){
1085                                        return coll;
1086                                }
1087                        }
1088                }
1089                return null;
1090        }
1091});
1092
1093model.Workspace = declare(model.AtomItem,{
1094        // summary:
1095        //              Class container for 'Workspace' types.
1096        constructor: function(title){
1097                this.title = title;
1098                this.collections = [];
1099        },
1100
1101        buildFromDom: function(/*DOMNode*/ node){
1102                // summary:
1103                //              Function to do construction of the Workspace data from the DOM node containing it.
1104                // node:
1105                //              The DOM node to process for content.
1106                var name = model.util.getNodename(node);
1107                if(name != "workspace"){return;}
1108                var c = node.childNodes;
1109                var len = 0;
1110                for(var i = 0; i< c.length; i++){
1111                        var child = c[i];
1112                        if(child.nodeType === 1){
1113                                name = model.util.getNodename(child);
1114                                if(child.namespaceURI == model._Constants.PURL_NS || child.namespaceURI == model._Constants.APP_NS){
1115                                        if(name === "collection"){
1116                                                var coll = new model.Collection();
1117                                                coll.buildFromDom(child);
1118                                                this.collections[len++] = coll;
1119                                        }
1120                                }else if(child.namespaceURI === model._Constants.ATOM_NS){
1121                                        if(name === "title"){
1122                                                this.title = parser.textContent(child);
1123                                        }
1124                                }
1125                                //FIXME: Add an extension point so others can impl different namespaces.  For now just
1126                                //ignore unknown namespace tags.
1127                        }
1128                }
1129        }
1130});
1131
1132model.Collection = declare(model.AtomItem,{
1133        // summary:
1134        //              Class container for 'Collection' types.
1135
1136        constructor: function(href, title){
1137                this.href = href;
1138                this.title = title;
1139                this.attributes = [];
1140                this.features = [];
1141                this.children = [];
1142                this.memberType = null;
1143                this.id = null;
1144        },
1145
1146        buildFromDom: function(/*DOMNode*/ node){
1147                // summary:
1148                //              Function to do construction of the Collection data from the DOM node containing it.
1149                // node:
1150                //              The DOM node to process for content.
1151                this.href = node.getAttribute("href");
1152                var c = node.childNodes;
1153                for(var i = 0; i< c.length; i++){
1154                        var child = c[i];
1155                        if(child.nodeType === 1){
1156                                var name = model.util.getNodename(child);
1157                                if(child.namespaceURI == model._Constants.PURL_NS || child.namespaceURI == model._Constants.APP_NS){
1158                                        if(name === "member-type"){
1159                                                this.memberType = parser.textContent(child);
1160                                        }else if(name == "feature"){//this IF stmt might need some more work
1161                                                if(child.getAttribute("id")){this.features.push(child.getAttribute("id"));}
1162                                        }else{
1163                                                var unknownTypeChild = new model.Node();
1164                                                unknownTypeChild.buildFromDom(child);
1165                                                this.children.push(unknownTypeChild);
1166                                        }
1167                                }else if(child.namespaceURI === model._Constants.ATOM_NS){
1168                                        if(name === "id"){
1169                                                this.id = parser.textContent(child);
1170                                        }else if(name === "title"){
1171                                                this.title = parser.textContent(child);
1172                                        }
1173                                }
1174                        }
1175                }
1176        }
1177});
1178
1179return model;
1180});
Note: See TracBrowser for help on using the repository browser.