Skip to content
This repository has been archived by the owner on May 3, 2022. It is now read-only.

Commit

Permalink
Merge pull request #437 from ezsystems/ezp-24864-breadcrumbs_locations
Browse files Browse the repository at this point in the history
EZP-24864: Add breadcrumbs for each location in the Location tab
  • Loading branch information
yannickroger committed Nov 25, 2015
2 parents 32491cb + 39b6d03 commit d7d0375
Show file tree
Hide file tree
Showing 12 changed files with 247 additions and 56 deletions.
2 changes: 1 addition & 1 deletion Resources/config/yui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ system:
requires: ['ez-restmodel']
path: %ez_platformui.public_dir%/js/models/ez-versionmodel.js
ez-locationmodel:
requires: ['ez-restmodel', 'ez-contentinfomodel']
requires: ['ez-restmodel', 'ez-contentinfomodel', array-extras]
path: %ez_platformui.public_dir%/js/models/ez-locationmodel.js
ez-usermodel:
requires: ['ez-restmodel']
Expand Down
21 changes: 21 additions & 0 deletions Resources/public/css/theme/views/tabs/locations.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,24 @@
padding: 0 0.2em;
opacity: 1;
}

.ez-view-locationviewlocationstabview .ez-breadcrumbs-list {
font-size: 90%;
list-style-type: none;
padding: 0;
margin-bottom: 0.5em;
}

.ez-view-locationviewlocationstabview .ez-breadcrumbs-item {
display: inline;
}

.ez-view-locationviewlocationstabview .ez-breadcrumbs-item:after {
content: "/";
padding: 0 0.1em 0 0.1em;
}

.ez-view-locationviewlocationstabview .ez-breadcrumbs-item:last-of-type:after {
content: "";
padding: 0;
}
37 changes: 36 additions & 1 deletion Resources/public/js/models/ez-locationmodel.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ YUI.add('ez-locationmodel', function (Y) {
* Loads path of the current location. The result is the array containing
* eZ.Location objects present on the path sorted by depth.
* The array doesn't contain current location.
* The result is available in the `path` attribute or in the `callback`.
*
* @method loadPath
* @param {Object} options
Expand Down Expand Up @@ -219,6 +220,8 @@ YUI.add('ez-locationmodel', function (Y) {
return (a.get('depth') - b.get('depth'));
});

that._set('path', locations);

callback(error, locations);
});
},
Expand All @@ -245,7 +248,26 @@ YUI.add('ez-locationmodel', function (Y) {
query,
callback
);
}
},

/**
* Overrides the RestModel implementation to also deal with the `path` attribute
*
* @method toJSON
* @return {Object}
*/
toJSON: function () {
var attrs = Y.eZ.RestModel.prototype.toJSON.call(this);

if (attrs.path) {
attrs.path = Y.Array.map(attrs.path, function (value) {
return value.toJSON();
});
}

return attrs;
},

}, {
REST_STRUCT_ROOT: "Location",
ATTRS_REST_MAP: [
Expand Down Expand Up @@ -381,6 +403,19 @@ YUI.add('ez-locationmodel', function (Y) {
return contentInfo;
}
},

/**
* The location's path. By default it is empty. You need to call the loadPath method to set this attribute.
*
* @attribute path
* @default false
* @type array
* @readOnly
*/
path: {
value: false,
readOnly: true
},
}
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,38 @@ YUI.add('ez-locationsloadplugin', function (Y) {
* @method _loadLocations
* @private
* @param {EventFacade} e loadLocations event facade
* @param {eZ.Location} e.location the current location
* @param {eZ.Content} e.content the content
* @param {Boolean} e.loadPath (optional) will also load the path if set to `true`
*
*/
_loadLocations: function (e) {
var service = this.get('host'),
capi = service.get('capi'),
options = {
api: capi,
location: e.location,
};
},
tasks = new Y.Parallel();

e.content.loadLocations(options, function (error, locations) {
if (error) {
e.target.set('loadingError', true);
} else {
e.target.set('locations', locations);
if (e.loadPath) {
Y.Array.each(locations, function (item) {
item.loadPath(options, tasks.add(function (error) {
if (error) {
e.target.set('loadingError', true);
}
}));
});
}
tasks.done(function () {
e.target.set('locations', locations);
});
}
});

},
}, {
NS: 'locationsLoad'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ YUI.add('ez-locationviewlocationstabview', function (Y) {
*/
this.fire('loadLocations', {
content: this.get('content'),
location: this.get('location')
location: this.get('location'),
loadPath:true,
});
},

Expand Down
11 changes: 10 additions & 1 deletion Resources/public/templates/tabs/locations.hbt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,16 @@
data-main-location="{{#if isMainLocation}}1{{else}}0{{/if}}">
</td>
<td>
<a href="{{ path "viewLocation" id=id languageCode=contentInfo.mainLanguageCode }}">{{ pathString }}</a>
<ul class="ez-breadcrumbs-list">
{{#each this.path}}
<li class="ez-breadcrumbs-item">
<a href="{{ path "viewLocation" id=id languageCode=contentInfo.mainLanguageCode }}">{{ contentInfo.name }}</a>
</li>
{{/each}}
<li class="ez-breadcrumbs-item">
<a href="{{ path "viewLocation" id=id languageCode=contentInfo.mainLanguageCode }}">{{ contentInfo.name }}</a>
</li>
</ul>
</td>
<td class="ez-table-data-childcount">{{ childCount }}</td>
<td class="ez-table-data-visibility">
Expand Down
115 changes: 85 additions & 30 deletions Tests/js/models/assets/ez-locationmodel-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* For full copyright and license information view LICENSE file distributed with this source code.
*/
YUI.add('ez-locationmodel-tests', function (Y) {
var modelTest, trashTest, moveTest, hideTest, removeTest, loadPathTest,
var modelTest, trashTest, moveTest, hideTest, removeTest, loadPathTest, toJSONTest,
Assert = Y.Assert, Mock = Y.Mock;

modelTest = new Y.Test.Case(Y.merge(Y.eZ.Test.ModelTests, {
Expand Down Expand Up @@ -556,8 +556,44 @@ YUI.add('ez-locationmodel-tests', function (Y) {
delete this.model;
},

_assertLocations: function (locations) {
var i,
that = this;

Assert.isArray(
locations,
"The result in callback should be an array"
);
Assert.areEqual(
this.loadAncestorsResponse.document.View.Result.searchHits.searchHit.length-1,
locations.length,
"The result array should be reduced by current location"
);
Y.Array.each(locations, function (location) {
Assert.isObject(location, "The item included in result array should be an object");
Assert.areEqual(
location.name,
'locationModel',
"The item included in result array should be the locationModel instance"
);
Assert.areNotEqual(
location.get('id'),
that.model.get('id'),
"Current location should not be included in the result"
);
});

for (i = 0; i != locations.length; ++i) {
Y.Assert.areSame(
i, locations[i].get('depth'),
"The path should be sorted by depth"
);
}
},


"Should load path for the location": function () {
var that = this, i;
var that = this;

Y.Mock.expect(this.contentService, {
method: 'createView',
Expand All @@ -583,35 +619,9 @@ YUI.add('ez-locationmodel-tests', function (Y) {
error,
"No error should be detected"
);
Assert.isArray(
locations,
"The result in callback should be an array"
);
Assert.areEqual(
that.loadAncestorsResponse.document.View.Result.searchHits.searchHit.length-1,
locations.length,
"The result array should be reduced by current location"
);
Y.Array.each(locations, function (location) {
Assert.isObject(location, "The item included in result array should be an object");
Assert.areEqual(
location.name,
'locationModel',
"The item included in result array should be the locationModel instance"
);
Assert.areNotEqual(
location.get('id'),
that.model.get('id'),
"Current location should not be included in the result"
);
});

for (i = 0; i != locations.length; ++i) {
Y.Assert.areSame(
i, locations[i].get('depth'),
"The path should be sorted by depth"
);
}
that._assertLocations(locations);
that._assertLocations(that.model.get('path'));
});
},

Expand All @@ -635,11 +645,56 @@ YUI.add('ez-locationmodel-tests', function (Y) {
}
});

toJSONTest = new Y.Test.Case({
name: "eZ Location Model toJSON test",

setUp: function () {
this.model = new Y.eZ.Location();
this.pathItemMock = new Mock();
this.pathMock = [this.pathItemMock];
this.mockJSON = {'whatever': ''};

Mock.expect(this.pathItemMock, {
method: 'toJSON',
returns: this.mockJSON,
});
},

tearDown: function () {
this.model.destroy();
delete this.model;
},

"Should convert path in attribute": function () {
var json;

this.model._set('path', this.pathMock);

json = this.model.toJSON();

Mock.verify(this.pathItemMock);
Assert.areSame(
this.mockJSON, json.path[0],
"The path attribute should be jsonified"
);
},

"Should not convert path in attribute if path is not set": function () {
var json = this.model.toJSON();

Assert.isFalse (
json.path,
"Path should be set to its default value"
);
},
});

Y.Test.Runner.setName("eZ Location Model tests");
Y.Test.Runner.add(modelTest);
Y.Test.Runner.add(trashTest);
Y.Test.Runner.add(moveTest);
Y.Test.Runner.add(hideTest);
Y.Test.Runner.add(removeTest);
Y.Test.Runner.add(loadPathTest);
Y.Test.Runner.add(toJSONTest);
}, '', {requires: ['test', 'model-tests', 'ez-locationmodel', 'ez-restmodel']});
2 changes: 1 addition & 1 deletion Tests/js/models/assets/ez-restmodel-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ YUI.add('ez-restmodel-tests', function (Y) {

m.set('date', ts);
Y.Assert.isInstanceOf(Date, m.get('date'));
Y.Assert.areEqual(+m.get('date'), ts);
Y.Assert.areEqual(ts, +m.get('date'));
},

"Should ignore unrecognized date": function () {
Expand Down
1 change: 1 addition & 0 deletions Tests/js/models/ez-locationmodel.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"ez-locationmodel": {
requires: [
'ez-restmodel',
'array-extras',
'ez-contentinfomodel'
],
fullpath: "../../../Resources/public/js/models/ez-locationmodel.js"
Expand Down
Loading

0 comments on commit d7d0375

Please sign in to comment.